]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/bind9/lib/dns/sdlz.c
MFC r363988:
[FreeBSD/stable/9.git] / contrib / bind9 / lib / dns / sdlz.c
1 /*
2  * Portions Copyright (C) 2005-2012, 2015  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 findnodeext(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
542             dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
543             dns_dbnode_t **nodep)
544 {
545         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
546         dns_sdlznode_t *node = NULL;
547         isc_result_t result;
548         isc_buffer_t b;
549         char namestr[DNS_NAME_MAXTEXT + 1];
550         isc_buffer_t b2;
551         char zonestr[DNS_NAME_MAXTEXT + 1];
552         isc_boolean_t isorigin;
553         dns_sdlzauthorityfunc_t authority;
554
555         REQUIRE(VALID_SDLZDB(sdlz));
556         REQUIRE(nodep != NULL && *nodep == NULL);
557
558         if (sdlz->dlzimp->methods->newversion == NULL) {
559                 REQUIRE(create == ISC_FALSE);
560         }
561
562         isc_buffer_init(&b, namestr, sizeof(namestr));
563         if ((sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVEOWNER) != 0) {
564                 dns_name_t relname;
565                 unsigned int labels;
566
567                 labels = dns_name_countlabels(name) -
568                          dns_name_countlabels(&db->origin);
569                 dns_name_init(&relname, NULL);
570                 dns_name_getlabelsequence(name, 0, labels, &relname);
571                 result = dns_name_totext(&relname, ISC_TRUE, &b);
572                 if (result != ISC_R_SUCCESS)
573                         return (result);
574         } else {
575                 result = dns_name_totext(name, ISC_TRUE, &b);
576                 if (result != ISC_R_SUCCESS)
577                         return (result);
578         }
579         isc_buffer_putuint8(&b, 0);
580
581         isc_buffer_init(&b2, zonestr, sizeof(zonestr));
582         result = dns_name_totext(&sdlz->common.origin, ISC_TRUE, &b2);
583         if (result != ISC_R_SUCCESS)
584                 return (result);
585         isc_buffer_putuint8(&b2, 0);
586
587         result = createnode(sdlz, &node);
588         if (result != ISC_R_SUCCESS)
589                 return (result);
590
591         isorigin = dns_name_equal(name, &sdlz->common.origin);
592
593         /* make sure strings are always lowercase */
594         dns_sdlz_tolower(zonestr);
595         dns_sdlz_tolower(namestr);
596
597         MAYBE_LOCK(sdlz->dlzimp);
598
599         /* try to lookup the host (namestr) */
600         result = sdlz->dlzimp->methods->lookup(zonestr, namestr,
601                                                sdlz->dlzimp->driverarg,
602                                                sdlz->dbdata, node,
603                                                methods, clientinfo);
604
605         /*
606          * if the host (namestr) was not found, try to lookup a
607          * "wildcard" host.
608          */
609         if (result == ISC_R_NOTFOUND && !create)
610                 result = sdlz->dlzimp->methods->lookup(zonestr, "*",
611                                                        sdlz->dlzimp->driverarg,
612                                                        sdlz->dbdata, node,
613                                                        methods, clientinfo);
614
615         MAYBE_UNLOCK(sdlz->dlzimp);
616
617         if (result == ISC_R_NOTFOUND && (isorigin || create))
618                 result = ISC_R_SUCCESS;
619
620         if (result != ISC_R_SUCCESS) {
621                 destroynode(node);
622                 return (result);
623         }
624
625         if (isorigin && sdlz->dlzimp->methods->authority != NULL) {
626                 MAYBE_LOCK(sdlz->dlzimp);
627                 authority = sdlz->dlzimp->methods->authority;
628                 result = (*authority)(zonestr, sdlz->dlzimp->driverarg,
629                                       sdlz->dbdata, node);
630                 MAYBE_UNLOCK(sdlz->dlzimp);
631                 if (result != ISC_R_SUCCESS &&
632                     result != ISC_R_NOTIMPLEMENTED) {
633                         destroynode(node);
634                         return (result);
635                 }
636         }
637
638         if (node->name == NULL) {
639                 node->name = isc_mem_get(sdlz->common.mctx,
640                                          sizeof(dns_name_t));
641                 if (node->name == NULL) {
642                         destroynode(node);
643                         return (ISC_R_NOMEMORY);
644                 }
645                 dns_name_init(node->name, NULL);
646                 result = dns_name_dup(name, sdlz->common.mctx, node->name);
647                 if (result != ISC_R_SUCCESS) {
648                         isc_mem_put(sdlz->common.mctx, node->name,
649                                     sizeof(dns_name_t));
650                         destroynode(node);
651                         return (result);
652                 }
653         }
654
655         *nodep = node;
656         return (ISC_R_SUCCESS);
657 }
658
659 static isc_result_t
660 findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
661          dns_dbnode_t **nodep)
662 {
663         return (findnodeext(db, name, create, NULL, NULL, nodep));
664 }
665
666 static isc_result_t
667 findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
668             isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
669             dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
670 {
671         UNUSED(db);
672         UNUSED(name);
673         UNUSED(options);
674         UNUSED(now);
675         UNUSED(nodep);
676         UNUSED(foundname);
677         UNUSED(rdataset);
678         UNUSED(sigrdataset);
679
680         return (ISC_R_NOTIMPLEMENTED);
681 }
682
683 static void
684 attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
685         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
686         dns_sdlznode_t *node = (dns_sdlznode_t *)source;
687
688         REQUIRE(VALID_SDLZDB(sdlz));
689
690         UNUSED(sdlz);
691
692         LOCK(&node->lock);
693         INSIST(node->references > 0);
694         node->references++;
695         INSIST(node->references != 0);          /* Catch overflow. */
696         UNLOCK(&node->lock);
697
698         *targetp = source;
699 }
700
701 static void
702 detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
703         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
704         dns_sdlznode_t *node;
705         isc_boolean_t need_destroy = ISC_FALSE;
706
707         REQUIRE(VALID_SDLZDB(sdlz));
708         REQUIRE(targetp != NULL && *targetp != NULL);
709
710         UNUSED(sdlz);
711
712         node = (dns_sdlznode_t *)(*targetp);
713
714         LOCK(&node->lock);
715         INSIST(node->references > 0);
716         node->references--;
717         if (node->references == 0)
718                 need_destroy = ISC_TRUE;
719         UNLOCK(&node->lock);
720
721         if (need_destroy)
722                 destroynode(node);
723
724         *targetp = NULL;
725 }
726
727 static isc_result_t
728 expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
729         UNUSED(db);
730         UNUSED(node);
731         UNUSED(now);
732         INSIST(0);
733         return (ISC_R_UNEXPECTED);
734 }
735
736 static void
737 printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
738         UNUSED(db);
739         UNUSED(node);
740         UNUSED(out);
741         return;
742 }
743
744 static isc_result_t
745 createiterator(dns_db_t *db, unsigned int options, dns_dbiterator_t **iteratorp)
746 {
747         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
748         sdlz_dbiterator_t *sdlziter;
749         isc_result_t result;
750         isc_buffer_t b;
751         char zonestr[DNS_NAME_MAXTEXT + 1];
752
753         REQUIRE(VALID_SDLZDB(sdlz));
754
755         if (sdlz->dlzimp->methods->allnodes == NULL)
756                 return (ISC_R_NOTIMPLEMENTED);
757
758         if ((options & DNS_DB_NSEC3ONLY) != 0 ||
759             (options & DNS_DB_NONSEC3) != 0)
760                  return (ISC_R_NOTIMPLEMENTED);
761
762         isc_buffer_init(&b, zonestr, sizeof(zonestr));
763         result = dns_name_totext(&sdlz->common.origin, ISC_TRUE, &b);
764         if (result != ISC_R_SUCCESS)
765                 return (result);
766         isc_buffer_putuint8(&b, 0);
767
768         sdlziter = isc_mem_get(sdlz->common.mctx, sizeof(sdlz_dbiterator_t));
769         if (sdlziter == NULL)
770                 return (ISC_R_NOMEMORY);
771
772         sdlziter->common.methods = &dbiterator_methods;
773         sdlziter->common.db = NULL;
774         dns_db_attach(db, &sdlziter->common.db);
775         sdlziter->common.relative_names = ISC_TF(options & DNS_DB_RELATIVENAMES);
776         sdlziter->common.magic = DNS_DBITERATOR_MAGIC;
777         ISC_LIST_INIT(sdlziter->nodelist);
778         sdlziter->current = NULL;
779         sdlziter->origin = NULL;
780
781         /* make sure strings are always lowercase */
782         dns_sdlz_tolower(zonestr);
783
784         MAYBE_LOCK(sdlz->dlzimp);
785         result = sdlz->dlzimp->methods->allnodes(zonestr,
786                                                  sdlz->dlzimp->driverarg,
787                                                  sdlz->dbdata, sdlziter);
788         MAYBE_UNLOCK(sdlz->dlzimp);
789         if (result != ISC_R_SUCCESS) {
790                 dns_dbiterator_t *iter = &sdlziter->common;
791                 dbiterator_destroy(&iter);
792                 return (result);
793         }
794
795         if (sdlziter->origin != NULL) {
796                 ISC_LIST_UNLINK(sdlziter->nodelist, sdlziter->origin, link);
797                 ISC_LIST_PREPEND(sdlziter->nodelist, sdlziter->origin, link);
798         }
799
800         *iteratorp = (dns_dbiterator_t *)sdlziter;
801
802         return (ISC_R_SUCCESS);
803 }
804
805 static isc_result_t
806 findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
807              dns_rdatatype_t type, dns_rdatatype_t covers,
808              isc_stdtime_t now, dns_rdataset_t *rdataset,
809              dns_rdataset_t *sigrdataset)
810 {
811         dns_rdatalist_t *list;
812         dns_sdlznode_t *sdlznode = (dns_sdlznode_t *)node;
813
814         REQUIRE(VALID_SDLZNODE(node));
815
816         UNUSED(db);
817         UNUSED(version);
818         UNUSED(covers);
819         UNUSED(now);
820         UNUSED(sigrdataset);
821
822         if (type == dns_rdatatype_sig || type == dns_rdatatype_rrsig)
823                 return (ISC_R_NOTIMPLEMENTED);
824
825         list = ISC_LIST_HEAD(sdlznode->lists);
826         while (list != NULL) {
827                 if (list->type == type)
828                         break;
829                 list = ISC_LIST_NEXT(list, link);
830         }
831         if (list == NULL)
832                 return (ISC_R_NOTFOUND);
833
834         list_tordataset(list, db, node, rdataset);
835
836         return (ISC_R_SUCCESS);
837 }
838
839 static isc_result_t
840 findext(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
841         dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
842         dns_dbnode_t **nodep, dns_name_t *foundname,
843         dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
844         dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
845 {
846         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
847         dns_dbnode_t *node = NULL;
848         dns_fixedname_t fname;
849         dns_rdataset_t xrdataset;
850         dns_name_t *xname;
851         unsigned int nlabels, olabels;
852         isc_result_t result;
853         unsigned int i;
854
855         REQUIRE(VALID_SDLZDB(sdlz));
856         REQUIRE(nodep == NULL || *nodep == NULL);
857         REQUIRE(version == NULL || version == (void*)&sdlz->dummy_version);
858
859         UNUSED(options);
860         UNUSED(sdlz);
861
862         if (!dns_name_issubdomain(name, &db->origin))
863                 return (DNS_R_NXDOMAIN);
864
865         olabels = dns_name_countlabels(&db->origin);
866         nlabels = dns_name_countlabels(name);
867
868         dns_fixedname_init(&fname);
869         xname = dns_fixedname_name(&fname);
870
871         if (rdataset == NULL) {
872                 dns_rdataset_init(&xrdataset);
873                 rdataset = &xrdataset;
874         }
875
876         result = DNS_R_NXDOMAIN;
877
878         for (i = olabels; i <= nlabels; i++) {
879                 /*
880                  * Look up the next label.
881                  */
882                 dns_name_getlabelsequence(name, nlabels - i, i, xname);
883                 result = findnodeext(db, xname, ISC_FALSE,
884                                      methods, clientinfo, &node);
885                 if (result == ISC_R_NOTFOUND) {
886                         result = DNS_R_NXDOMAIN;
887                         continue;
888                 } else if (result != ISC_R_SUCCESS)
889                         break;
890
891                 /*
892                  * Look for a DNAME at the current label, unless this is
893                  * the qname.
894                  */
895                 if (i < nlabels) {
896                         result = findrdataset(db, node, version,
897                                               dns_rdatatype_dname, 0, now,
898                                               rdataset, sigrdataset);
899                         if (result == ISC_R_SUCCESS) {
900                                 result = DNS_R_DNAME;
901                                 break;
902                         }
903                 }
904
905                 /*
906                  * Look for an NS at the current label, unless this is the
907                  * origin or glue is ok.
908                  */
909                 if (i != olabels && (options & DNS_DBFIND_GLUEOK) == 0) {
910                         result = findrdataset(db, node, version,
911                                               dns_rdatatype_ns, 0, now,
912                                               rdataset, sigrdataset);
913                         if (result == ISC_R_SUCCESS) {
914                                 if (i == nlabels && type == dns_rdatatype_any)
915                                 {
916                                         result = DNS_R_ZONECUT;
917                                         dns_rdataset_disassociate(rdataset);
918                                         if (sigrdataset != NULL &&
919                                             dns_rdataset_isassociated
920                                                         (sigrdataset)) {
921                                                 dns_rdataset_disassociate
922                                                         (sigrdataset);
923                                         }
924                                 } else
925                                         result = DNS_R_DELEGATION;
926                                 break;
927                         }
928                 }
929
930                 /*
931                  * If the current name is not the qname, add another label
932                  * and try again.
933                  */
934                 if (i < nlabels) {
935                         destroynode(node);
936                         node = NULL;
937                         continue;
938                 }
939
940                 /*
941                  * If we're looking for ANY, we're done.
942                  */
943                 if (type == dns_rdatatype_any) {
944                         result = ISC_R_SUCCESS;
945                         break;
946                 }
947
948                 /*
949                  * Look for the qtype.
950                  */
951                 result = findrdataset(db, node, version, type, 0, now,
952                                       rdataset, sigrdataset);
953                 if (result == ISC_R_SUCCESS)
954                         break;
955
956                 /*
957                  * Look for a CNAME
958                  */
959                 if (type != dns_rdatatype_cname) {
960                         result = findrdataset(db, node, version,
961                                               dns_rdatatype_cname, 0, now,
962                                               rdataset, sigrdataset);
963                         if (result == ISC_R_SUCCESS) {
964                                 result = DNS_R_CNAME;
965                                 break;
966                         }
967                 }
968
969                 result = DNS_R_NXRRSET;
970                 break;
971         }
972
973         if (rdataset == &xrdataset && dns_rdataset_isassociated(rdataset))
974                 dns_rdataset_disassociate(rdataset);
975
976         if (foundname != NULL) {
977                 isc_result_t xresult;
978
979                 xresult = dns_name_copy(xname, foundname, NULL);
980                 if (xresult != ISC_R_SUCCESS) {
981                         if (node != NULL)
982                                 destroynode(node);
983                         if (dns_rdataset_isassociated(rdataset))
984                                 dns_rdataset_disassociate(rdataset);
985                         return (DNS_R_BADDB);
986                 }
987         }
988
989         if (nodep != NULL)
990                 *nodep = node;
991         else if (node != NULL)
992                 detachnode(db, &node);
993
994         return (result);
995 }
996
997 static isc_result_t
998 find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
999      dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
1000      dns_dbnode_t **nodep, dns_name_t *foundname,
1001      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1002 {
1003         return (findext(db, name, version, type, options, now, nodep,
1004                         foundname, NULL, NULL, rdataset, sigrdataset));
1005 }
1006
1007 static isc_result_t
1008 allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1009              isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
1010 {
1011         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *) db;
1012         sdlz_rdatasetiter_t *iterator;
1013
1014         REQUIRE(VALID_SDLZDB(sdlz));
1015
1016         REQUIRE(version == NULL ||
1017                 version == (void*)&sdlz->dummy_version ||
1018                 version == sdlz->future_version);
1019
1020         UNUSED(version);
1021         UNUSED(now);
1022
1023         iterator = isc_mem_get(db->mctx, sizeof(sdlz_rdatasetiter_t));
1024         if (iterator == NULL)
1025                 return (ISC_R_NOMEMORY);
1026
1027         iterator->common.magic = DNS_RDATASETITER_MAGIC;
1028         iterator->common.methods = &rdatasetiter_methods;
1029         iterator->common.db = db;
1030         iterator->common.node = NULL;
1031         attachnode(db, node, &iterator->common.node);
1032         iterator->common.version = version;
1033         iterator->common.now = now;
1034
1035         *iteratorp = (dns_rdatasetiter_t *)iterator;
1036
1037         return (ISC_R_SUCCESS);
1038 }
1039
1040 static isc_result_t
1041 modrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1042             dns_rdataset_t *rdataset, unsigned int options,
1043             dns_sdlzmodrdataset_t mod_function)
1044 {
1045         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
1046         dns_master_style_t *style = NULL;
1047         isc_result_t result;
1048         isc_buffer_t *buffer = NULL;
1049         isc_mem_t *mctx;
1050         dns_sdlznode_t *sdlznode;
1051         char *rdatastr = NULL;
1052         char name[DNS_NAME_MAXTEXT + 1];
1053
1054         REQUIRE(VALID_SDLZDB(sdlz));
1055
1056         if (mod_function == NULL)
1057                 return (ISC_R_NOTIMPLEMENTED);
1058
1059         sdlznode = (dns_sdlznode_t *)node;
1060
1061         UNUSED(options);
1062
1063         dns_name_format(sdlznode->name, name, sizeof(name));
1064
1065         mctx = sdlz->common.mctx;
1066
1067         result = isc_buffer_allocate(mctx, &buffer, 1024);
1068         if (result != ISC_R_SUCCESS)
1069                 return (result);
1070
1071         result = dns_master_stylecreate(&style, 0, 0, 0, 0, 0, 0, 1, mctx);
1072         if (result != ISC_R_SUCCESS)
1073                 goto cleanup;
1074
1075         result = dns_master_rdatasettotext(sdlznode->name, rdataset,
1076                                            style, buffer);
1077         if (result != ISC_R_SUCCESS)
1078                 goto cleanup;
1079
1080         if (isc_buffer_usedlength(buffer) < 1) {
1081                 result = ISC_R_BADADDRESSFORM;
1082                 goto cleanup;
1083         }
1084
1085         rdatastr = isc_buffer_base(buffer);
1086         if (rdatastr == NULL) {
1087                 result = ISC_R_NOMEMORY;
1088                 goto cleanup;
1089         }
1090         rdatastr[isc_buffer_usedlength(buffer) - 1] = 0;
1091
1092         MAYBE_LOCK(sdlz->dlzimp);
1093         result = mod_function(name, rdatastr, sdlz->dlzimp->driverarg,
1094                               sdlz->dbdata, version);
1095         MAYBE_UNLOCK(sdlz->dlzimp);
1096
1097 cleanup:
1098         isc_buffer_free(&buffer);
1099         if (style != NULL)
1100                 dns_master_styledestroy(&style, mctx);
1101
1102         return (result);
1103 }
1104
1105 static isc_result_t
1106 addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1107             isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
1108             dns_rdataset_t *addedrdataset)
1109 {
1110         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
1111         isc_result_t result;
1112
1113         UNUSED(now);
1114         UNUSED(addedrdataset);
1115         REQUIRE(VALID_SDLZDB(sdlz));
1116
1117         if (sdlz->dlzimp->methods->addrdataset == NULL)
1118                 return (ISC_R_NOTIMPLEMENTED);
1119
1120         result = modrdataset(db, node, version, rdataset, options,
1121                              sdlz->dlzimp->methods->addrdataset);
1122         return (result);
1123 }
1124
1125
1126 static isc_result_t
1127 subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1128                  dns_rdataset_t *rdataset, unsigned int options,
1129                  dns_rdataset_t *newrdataset)
1130 {
1131         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
1132         isc_result_t result;
1133
1134         UNUSED(newrdataset);
1135         REQUIRE(VALID_SDLZDB(sdlz));
1136
1137         if (sdlz->dlzimp->methods->subtractrdataset == NULL) {
1138                 return (ISC_R_NOTIMPLEMENTED);
1139         }
1140
1141         result = modrdataset(db, node, version, rdataset, options,
1142                              sdlz->dlzimp->methods->subtractrdataset);
1143         return (result);
1144 }
1145
1146 static isc_result_t
1147 deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1148                dns_rdatatype_t type, dns_rdatatype_t covers)
1149 {
1150         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
1151         char name[DNS_NAME_MAXTEXT + 1];
1152         char b_type[DNS_RDATATYPE_FORMATSIZE];
1153         dns_sdlznode_t *sdlznode;
1154         isc_result_t result;
1155
1156         UNUSED(covers);
1157
1158         REQUIRE(VALID_SDLZDB(sdlz));
1159
1160         if (sdlz->dlzimp->methods->delrdataset == NULL)
1161                 return (ISC_R_NOTIMPLEMENTED);
1162
1163         sdlznode = (dns_sdlznode_t *)node;
1164         dns_name_format(sdlznode->name, name, sizeof(name));
1165         dns_rdatatype_format(type, b_type, sizeof(b_type));
1166
1167         MAYBE_LOCK(sdlz->dlzimp);
1168         result = sdlz->dlzimp->methods->delrdataset(name, b_type,
1169                                                     sdlz->dlzimp->driverarg,
1170                                                     sdlz->dbdata, version);
1171         MAYBE_UNLOCK(sdlz->dlzimp);
1172
1173         return (result);
1174 }
1175
1176 static isc_boolean_t
1177 issecure(dns_db_t *db) {
1178         UNUSED(db);
1179
1180         return (ISC_FALSE);
1181 }
1182
1183 static unsigned int
1184 nodecount(dns_db_t *db) {
1185         UNUSED(db);
1186
1187         return (0);
1188 }
1189
1190 static isc_boolean_t
1191 ispersistent(dns_db_t *db) {
1192         UNUSED(db);
1193         return (ISC_TRUE);
1194 }
1195
1196 static void
1197 overmem(dns_db_t *db, isc_boolean_t over) {
1198         UNUSED(db);
1199         UNUSED(over);
1200 }
1201
1202 static void
1203 settask(dns_db_t *db, isc_task_t *task) {
1204         UNUSED(db);
1205         UNUSED(task);
1206 }
1207
1208
1209 /*
1210  * getoriginnode() is used by the update code to find the
1211  * dns_rdatatype_dnskey record for a zone
1212  */
1213 static isc_result_t
1214 getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) {
1215         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
1216         isc_result_t result;
1217
1218         REQUIRE(VALID_SDLZDB(sdlz));
1219         if (sdlz->dlzimp->methods->newversion == NULL)
1220                 return (ISC_R_NOTIMPLEMENTED);
1221
1222         result = findnodeext(db, &sdlz->common.origin, ISC_FALSE,
1223                              NULL, NULL, nodep);
1224         if (result != ISC_R_SUCCESS)
1225                 sdlz_log(ISC_LOG_ERROR, "sdlz getoriginnode failed : %s",
1226                          isc_result_totext(result));
1227         return (result);
1228 }
1229
1230 static dns_dbmethods_t sdlzdb_methods = {
1231         attach,
1232         detach,
1233         beginload,
1234         endload,
1235         dump,
1236         currentversion,
1237         newversion,
1238         attachversion,
1239         closeversion,
1240         findnode,
1241         find,
1242         findzonecut,
1243         attachnode,
1244         detachnode,
1245         expirenode,
1246         printnode,
1247         createiterator,
1248         findrdataset,
1249         allrdatasets,
1250         addrdataset,
1251         subtractrdataset,
1252         deleterdataset,
1253         issecure,
1254         nodecount,
1255         ispersistent,
1256         overmem,
1257         settask,
1258         getoriginnode,
1259         NULL,                   /* transfernode */
1260         NULL,                   /* getnsec3parameters */
1261         NULL,                   /* findnsec3node */
1262         NULL,                   /* setsigningtime */
1263         NULL,                   /* getsigningtime */
1264         NULL,                   /* resigned */
1265         NULL,                   /* isdnssec */
1266         NULL,                   /* getrrsetstats */
1267         NULL,                   /* rpz_enabled */
1268         NULL,                   /* rpz_findips */
1269         findnodeext,
1270         findext
1271 };
1272
1273 /*
1274  * Database Iterator Methods.  These methods were "borrowed" from the SDB
1275  * driver interface.  See the SDB driver interface documentation for more info.
1276  */
1277
1278 static void
1279 dbiterator_destroy(dns_dbiterator_t **iteratorp) {
1280         sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)(*iteratorp);
1281         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)sdlziter->common.db;
1282
1283         while (!ISC_LIST_EMPTY(sdlziter->nodelist)) {
1284                 dns_sdlznode_t *node;
1285                 node = ISC_LIST_HEAD(sdlziter->nodelist);
1286                 ISC_LIST_UNLINK(sdlziter->nodelist, node, link);
1287                 destroynode(node);
1288         }
1289
1290         dns_db_detach(&sdlziter->common.db);
1291         isc_mem_put(sdlz->common.mctx, sdlziter, sizeof(sdlz_dbiterator_t));
1292
1293         *iteratorp = NULL;
1294 }
1295
1296 static isc_result_t
1297 dbiterator_first(dns_dbiterator_t *iterator) {
1298         sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1299
1300         sdlziter->current = ISC_LIST_HEAD(sdlziter->nodelist);
1301         if (sdlziter->current == NULL)
1302                 return (ISC_R_NOMORE);
1303         else
1304                 return (ISC_R_SUCCESS);
1305 }
1306
1307 static isc_result_t
1308 dbiterator_last(dns_dbiterator_t *iterator) {
1309         sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1310
1311         sdlziter->current = ISC_LIST_TAIL(sdlziter->nodelist);
1312         if (sdlziter->current == NULL)
1313                 return (ISC_R_NOMORE);
1314         else
1315                 return (ISC_R_SUCCESS);
1316 }
1317
1318 static isc_result_t
1319 dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
1320         sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1321
1322         sdlziter->current = ISC_LIST_HEAD(sdlziter->nodelist);
1323         while (sdlziter->current != NULL) {
1324                 if (dns_name_equal(sdlziter->current->name, name))
1325                         return (ISC_R_SUCCESS);
1326                 sdlziter->current = ISC_LIST_NEXT(sdlziter->current, link);
1327         }
1328         return (ISC_R_NOTFOUND);
1329 }
1330
1331 static isc_result_t
1332 dbiterator_prev(dns_dbiterator_t *iterator) {
1333         sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1334
1335         sdlziter->current = ISC_LIST_PREV(sdlziter->current, link);
1336         if (sdlziter->current == NULL)
1337                 return (ISC_R_NOMORE);
1338         else
1339                 return (ISC_R_SUCCESS);
1340 }
1341
1342 static isc_result_t
1343 dbiterator_next(dns_dbiterator_t *iterator) {
1344         sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1345
1346         sdlziter->current = ISC_LIST_NEXT(sdlziter->current, link);
1347         if (sdlziter->current == NULL)
1348                 return (ISC_R_NOMORE);
1349         else
1350                 return (ISC_R_SUCCESS);
1351 }
1352
1353 static isc_result_t
1354 dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
1355                    dns_name_t *name)
1356 {
1357         sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1358
1359         attachnode(iterator->db, sdlziter->current, nodep);
1360         if (name != NULL)
1361                 return (dns_name_copy(sdlziter->current->name, name, NULL));
1362         return (ISC_R_SUCCESS);
1363 }
1364
1365 static isc_result_t
1366 dbiterator_pause(dns_dbiterator_t *iterator) {
1367         UNUSED(iterator);
1368         return (ISC_R_SUCCESS);
1369 }
1370
1371 static isc_result_t
1372 dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
1373         UNUSED(iterator);
1374         return (dns_name_copy(dns_rootname, name, NULL));
1375 }
1376
1377 /*
1378  * Rdataset Methods. These methods were "borrowed" from the SDB driver
1379  * interface.  See the SDB driver interface documentation for more info.
1380  */
1381
1382 static void
1383 disassociate(dns_rdataset_t *rdataset) {
1384         dns_dbnode_t *node = rdataset->private5;
1385         dns_sdlznode_t *sdlznode = (dns_sdlznode_t *) node;
1386         dns_db_t *db = (dns_db_t *) sdlznode->sdlz;
1387
1388         detachnode(db, &node);
1389         isc__rdatalist_disassociate(rdataset);
1390 }
1391
1392 static void
1393 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
1394         dns_dbnode_t *node = source->private5;
1395         dns_sdlznode_t *sdlznode = (dns_sdlznode_t *) node;
1396         dns_db_t *db = (dns_db_t *) sdlznode->sdlz;
1397         dns_dbnode_t *tempdb = NULL;
1398
1399         isc__rdatalist_clone(source, target);
1400         attachnode(db, node, &tempdb);
1401         source->private5 = tempdb;
1402 }
1403
1404 static dns_rdatasetmethods_t rdataset_methods = {
1405         disassociate,
1406         isc__rdatalist_first,
1407         isc__rdatalist_next,
1408         isc__rdatalist_current,
1409         rdataset_clone,
1410         isc__rdatalist_count,
1411         isc__rdatalist_addnoqname,
1412         isc__rdatalist_getnoqname,
1413         NULL,
1414         NULL,
1415         NULL,
1416         NULL,
1417         NULL,
1418         NULL,
1419         NULL
1420 };
1421
1422 static void
1423 list_tordataset(dns_rdatalist_t *rdatalist,
1424                 dns_db_t *db, dns_dbnode_t *node,
1425                 dns_rdataset_t *rdataset)
1426 {
1427         /*
1428          * The sdlz rdataset is an rdatalist with some additions.
1429          *      - private1 & private2 are used by the rdatalist.
1430          *      - private3 & private 4 are unused.
1431          *      - private5 is the node.
1432          */
1433
1434         /* This should never fail. */
1435         RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
1436                       ISC_R_SUCCESS);
1437
1438         rdataset->methods = &rdataset_methods;
1439         dns_db_attachnode(db, node, &rdataset->private5);
1440 }
1441
1442 /*
1443  * SDLZ core methods. This is the core of the new DLZ functionality.
1444  */
1445
1446 /*%
1447  * Build a 'bind' database driver structure to be returned by
1448  * either the find zone or the allow zone transfer method.
1449  * This method is only available in this source file, it is
1450  * not made available anywhere else.
1451  */
1452
1453 static isc_result_t
1454 dns_sdlzcreateDBP(isc_mem_t *mctx, void *driverarg, void *dbdata,
1455                   dns_name_t *name, dns_rdataclass_t rdclass, dns_db_t **dbp)
1456 {
1457         isc_result_t result;
1458         dns_sdlz_db_t *sdlzdb;
1459         dns_sdlzimplementation_t *imp;
1460
1461         /* check that things are as we expect */
1462         REQUIRE(dbp != NULL && *dbp == NULL);
1463         REQUIRE(name != NULL);
1464
1465         imp = (dns_sdlzimplementation_t *) driverarg;
1466
1467         /* allocate and zero memory for driver structure */
1468         sdlzdb = isc_mem_get(mctx, sizeof(dns_sdlz_db_t));
1469         if (sdlzdb == NULL)
1470                 return (ISC_R_NOMEMORY);
1471         memset(sdlzdb, 0, sizeof(dns_sdlz_db_t));
1472
1473         /* initialize and set origin */
1474         dns_name_init(&sdlzdb->common.origin, NULL);
1475         result = dns_name_dupwithoffsets(name, mctx, &sdlzdb->common.origin);
1476         if (result != ISC_R_SUCCESS)
1477                 goto mem_cleanup;
1478
1479         /* initialize the reference count mutex */
1480         result = isc_mutex_init(&sdlzdb->refcnt_lock);
1481         if (result != ISC_R_SUCCESS)
1482                 goto name_cleanup;
1483
1484         /* set the rest of the database structure attributes */
1485         sdlzdb->dlzimp = imp;
1486         sdlzdb->common.methods = &sdlzdb_methods;
1487         sdlzdb->common.attributes = 0;
1488         sdlzdb->common.rdclass = rdclass;
1489         sdlzdb->common.mctx = NULL;
1490         sdlzdb->dbdata = dbdata;
1491         sdlzdb->references = 1;
1492
1493         /* attach to the memory context */
1494         isc_mem_attach(mctx, &sdlzdb->common.mctx);
1495
1496         /* mark structure as valid */
1497         sdlzdb->common.magic = DNS_DB_MAGIC;
1498         sdlzdb->common.impmagic = SDLZDB_MAGIC;
1499         *dbp = (dns_db_t *) sdlzdb;
1500
1501         return (result);
1502
1503         /*
1504          * reference count mutex could not be initialized, clean up
1505          * name memory
1506          */
1507  name_cleanup:
1508         dns_name_free(&sdlzdb->common.origin, mctx);
1509  mem_cleanup:
1510         isc_mem_put(mctx, sdlzdb, sizeof(dns_sdlz_db_t));
1511         return (result);
1512 }
1513
1514 static isc_result_t
1515 dns_sdlzallowzonexfr(void *driverarg, void *dbdata, isc_mem_t *mctx,
1516                      dns_rdataclass_t rdclass, dns_name_t *name,
1517                      isc_sockaddr_t *clientaddr, dns_db_t **dbp)
1518 {
1519         isc_buffer_t b;
1520         isc_buffer_t b2;
1521         char namestr[DNS_NAME_MAXTEXT + 1];
1522         char clientstr[(sizeof "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")
1523                        + 1];
1524         isc_netaddr_t netaddr;
1525         isc_result_t result;
1526         dns_sdlzimplementation_t *imp;
1527
1528         /*
1529          * Perform checks to make sure data is as we expect it to be.
1530          */
1531         REQUIRE(driverarg != NULL);
1532         REQUIRE(name != NULL);
1533         REQUIRE(clientaddr != NULL);
1534         REQUIRE(dbp != NULL && *dbp == NULL);
1535
1536         imp = (dns_sdlzimplementation_t *) driverarg;
1537
1538         /* Convert DNS name to ascii text */
1539         isc_buffer_init(&b, namestr, sizeof(namestr));
1540         result = dns_name_totext(name, ISC_TRUE, &b);
1541         if (result != ISC_R_SUCCESS)
1542                 return (result);
1543         isc_buffer_putuint8(&b, 0);
1544
1545         /* convert client address to ascii text */
1546         isc_buffer_init(&b2, clientstr, sizeof(clientstr));
1547         isc_netaddr_fromsockaddr(&netaddr, clientaddr);
1548         result = isc_netaddr_totext(&netaddr, &b2);
1549         if (result != ISC_R_SUCCESS)
1550                 return (result);
1551         isc_buffer_putuint8(&b2, 0);
1552
1553         /* make sure strings are always lowercase */
1554         dns_sdlz_tolower(namestr);
1555         dns_sdlz_tolower(clientstr);
1556
1557         /* Call SDLZ driver's find zone method */
1558         if (imp->methods->allowzonexfr != NULL) {
1559                 MAYBE_LOCK(imp);
1560                 result = imp->methods->allowzonexfr(imp->driverarg, dbdata,
1561                                                     namestr, clientstr);
1562                 MAYBE_UNLOCK(imp);
1563                 /*
1564                  * if zone is supported and transfers allowed build a 'bind'
1565                  * database driver
1566                  */
1567                 if (result == ISC_R_SUCCESS)
1568                         result = dns_sdlzcreateDBP(mctx, driverarg, dbdata,
1569                                                    name, rdclass, dbp);
1570                 return (result);
1571         }
1572
1573         return (ISC_R_NOTIMPLEMENTED);
1574 }
1575
1576 static isc_result_t
1577 dns_sdlzcreate(isc_mem_t *mctx, const char *dlzname, unsigned int argc,
1578                char *argv[], void *driverarg, void **dbdata)
1579 {
1580         dns_sdlzimplementation_t *imp;
1581         isc_result_t result = ISC_R_NOTFOUND;
1582
1583         /* Write debugging message to log */
1584         sdlz_log(ISC_LOG_DEBUG(2), "Loading SDLZ driver.");
1585
1586         /*
1587          * Performs checks to make sure data is as we expect it to be.
1588          */
1589         REQUIRE(driverarg != NULL);
1590         REQUIRE(dlzname != NULL);
1591         REQUIRE(dbdata != NULL);
1592         UNUSED(mctx);
1593
1594         imp = driverarg;
1595
1596         /* If the create method exists, call it. */
1597         if (imp->methods->create != NULL) {
1598                 MAYBE_LOCK(imp);
1599                 result = imp->methods->create(dlzname, argc, argv,
1600                                               imp->driverarg, dbdata);
1601                 MAYBE_UNLOCK(imp);
1602         }
1603
1604         /* Write debugging message to log */
1605         if (result == ISC_R_SUCCESS) {
1606                 sdlz_log(ISC_LOG_DEBUG(2), "SDLZ driver loaded successfully.");
1607         } else {
1608                 sdlz_log(ISC_LOG_ERROR, "SDLZ driver failed to load.");
1609         }
1610
1611         return (result);
1612 }
1613
1614 static void
1615 dns_sdlzdestroy(void *driverdata, void **dbdata)
1616 {
1617
1618         dns_sdlzimplementation_t *imp;
1619
1620         /* Write debugging message to log */
1621         sdlz_log(ISC_LOG_DEBUG(2), "Unloading SDLZ driver.");
1622
1623         imp = driverdata;
1624
1625         /* If the destroy method exists, call it. */
1626         if (imp->methods->destroy != NULL) {
1627                 MAYBE_LOCK(imp);
1628                 imp->methods->destroy(imp->driverarg, dbdata);
1629                 MAYBE_UNLOCK(imp);
1630         }
1631 }
1632
1633 static isc_result_t
1634 dns_sdlzfindzone(void *driverarg, void *dbdata, isc_mem_t *mctx,
1635                  dns_rdataclass_t rdclass, dns_name_t *name, dns_db_t **dbp)
1636 {
1637         isc_buffer_t b;
1638         char namestr[DNS_NAME_MAXTEXT + 1];
1639         isc_result_t result;
1640         dns_sdlzimplementation_t *imp;
1641
1642         /*
1643          * Perform checks to make sure data is as we expect it to be.
1644          */
1645         REQUIRE(driverarg != NULL);
1646         REQUIRE(name != NULL);
1647         REQUIRE(dbp != NULL && *dbp == NULL);
1648
1649         imp = (dns_sdlzimplementation_t *) driverarg;
1650
1651         /* Convert DNS name to ascii text */
1652         isc_buffer_init(&b, namestr, sizeof(namestr));
1653         result = dns_name_totext(name, ISC_TRUE, &b);
1654         if (result != ISC_R_SUCCESS)
1655                 return (result);
1656         isc_buffer_putuint8(&b, 0);
1657
1658         /* make sure strings are always lowercase */
1659         dns_sdlz_tolower(namestr);
1660
1661         /* Call SDLZ driver's find zone method */
1662         MAYBE_LOCK(imp);
1663         result = imp->methods->findzone(imp->driverarg, dbdata, namestr);
1664         MAYBE_UNLOCK(imp);
1665
1666         /*
1667          * if zone is supported build a 'bind' database driver
1668          * structure to return
1669          */
1670         if (result == ISC_R_SUCCESS)
1671                 result = dns_sdlzcreateDBP(mctx, driverarg, dbdata, name,
1672                                            rdclass, dbp);
1673
1674         return (result);
1675 }
1676
1677
1678 static isc_result_t
1679 dns_sdlzconfigure(void *driverarg, void *dbdata, dns_view_t *view)
1680 {
1681         isc_result_t result;
1682         dns_sdlzimplementation_t *imp;
1683
1684         REQUIRE(driverarg != NULL);
1685
1686         imp = (dns_sdlzimplementation_t *) driverarg;
1687
1688         /* Call SDLZ driver's configure method */
1689         if (imp->methods->configure != NULL) {
1690                 MAYBE_LOCK(imp);
1691                 result = imp->methods->configure(view, imp->driverarg, dbdata);
1692                 MAYBE_UNLOCK(imp);
1693         } else {
1694                 result = ISC_R_SUCCESS;
1695         }
1696
1697         return (result);
1698 }
1699
1700 static isc_boolean_t
1701 dns_sdlzssumatch(dns_name_t *signer, dns_name_t *name, isc_netaddr_t *tcpaddr,
1702                  dns_rdatatype_t type, const dst_key_t *key, void *driverarg,
1703                  void *dbdata)
1704 {
1705         dns_sdlzimplementation_t *imp;
1706         char b_signer[DNS_NAME_FORMATSIZE];
1707         char b_name[DNS_NAME_FORMATSIZE];
1708         char b_addr[ISC_NETADDR_FORMATSIZE];
1709         char b_type[DNS_RDATATYPE_FORMATSIZE];
1710         char b_key[DST_KEY_FORMATSIZE];
1711         isc_buffer_t *tkey_token = NULL;
1712         isc_region_t token_region;
1713         isc_uint32_t token_len = 0;
1714         isc_boolean_t ret;
1715
1716         REQUIRE(driverarg != NULL);
1717
1718         imp = (dns_sdlzimplementation_t *) driverarg;
1719         if (imp->methods->ssumatch == NULL)
1720                 return (ISC_FALSE);
1721
1722         /*
1723          * Format the request elements. sdlz operates on strings, not
1724          * structures
1725          */
1726         if (signer != NULL)
1727                 dns_name_format(signer, b_signer, sizeof(b_signer));
1728         else
1729                 b_signer[0] = 0;
1730
1731         dns_name_format(name, b_name, sizeof(b_name));
1732
1733         if (tcpaddr != NULL)
1734                 isc_netaddr_format(tcpaddr, b_addr, sizeof(b_addr));
1735         else
1736                 b_addr[0] = 0;
1737
1738         dns_rdatatype_format(type, b_type, sizeof(b_type));
1739
1740         if (key != NULL) {
1741                 dst_key_format(key, b_key, sizeof(b_key));
1742                 tkey_token = dst_key_tkeytoken(key);
1743         } else
1744                 b_key[0] = 0;
1745
1746         if (tkey_token != NULL) {
1747                 isc_buffer_region(tkey_token, &token_region);
1748                 token_len = token_region.length;
1749         }
1750
1751         MAYBE_LOCK(imp);
1752         ret = imp->methods->ssumatch(b_signer, b_name, b_addr, b_type, b_key,
1753                                      token_len,
1754                                      token_len != 0 ? token_region.base : NULL,
1755                                      imp->driverarg, dbdata);
1756         MAYBE_UNLOCK(imp);
1757         return (ret);
1758 }
1759
1760 static dns_dlzmethods_t sdlzmethods = {
1761         dns_sdlzcreate,
1762         dns_sdlzdestroy,
1763         dns_sdlzfindzone,
1764         dns_sdlzallowzonexfr,
1765         dns_sdlzconfigure,
1766         dns_sdlzssumatch
1767 };
1768
1769 /*
1770  * Public functions.
1771  */
1772
1773 isc_result_t
1774 dns_sdlz_putrr(dns_sdlzlookup_t *lookup, const char *type, dns_ttl_t ttl,
1775                const char *data)
1776 {
1777         dns_rdatalist_t *rdatalist;
1778         dns_rdata_t *rdata;
1779         dns_rdatatype_t typeval;
1780         isc_consttextregion_t r;
1781         isc_buffer_t b;
1782         isc_buffer_t *rdatabuf = NULL;
1783         isc_lex_t *lex;
1784         isc_result_t result;
1785         unsigned int size;
1786         isc_mem_t *mctx;
1787         dns_name_t *origin;
1788
1789         REQUIRE(VALID_SDLZLOOKUP(lookup));
1790         REQUIRE(type != NULL);
1791         REQUIRE(data != NULL);
1792
1793         mctx = lookup->sdlz->common.mctx;
1794
1795         r.base = type;
1796         r.length = strlen(type);
1797         result = dns_rdatatype_fromtext(&typeval, (void *) &r);
1798         if (result != ISC_R_SUCCESS)
1799                 return (result);
1800
1801         rdatalist = ISC_LIST_HEAD(lookup->lists);
1802         while (rdatalist != NULL) {
1803                 if (rdatalist->type == typeval)
1804                         break;
1805                 rdatalist = ISC_LIST_NEXT(rdatalist, link);
1806         }
1807
1808         if (rdatalist == NULL) {
1809                 rdatalist = isc_mem_get(mctx, sizeof(dns_rdatalist_t));
1810                 if (rdatalist == NULL)
1811                         return (ISC_R_NOMEMORY);
1812                 dns_rdatalist_init(rdatalist);
1813                 rdatalist->rdclass = lookup->sdlz->common.rdclass;
1814                 rdatalist->type = typeval;
1815                 rdatalist->ttl = ttl;
1816                 ISC_LIST_APPEND(lookup->lists, rdatalist, link);
1817         } else
1818                 if (rdatalist->ttl > ttl) {
1819                         /*
1820                          * BIND9 doesn't enforce all RRs in an RRset
1821                          * having the same TTL, as per RFC 2136,
1822                          * section 7.12. If a DLZ backend has
1823                          * different TTLs, then the best
1824                          * we can do is return the lowest.
1825                         */
1826                         rdatalist->ttl = ttl;
1827                 }
1828
1829         rdata = isc_mem_get(mctx, sizeof(dns_rdata_t));
1830         if (rdata == NULL)
1831                 return (ISC_R_NOMEMORY);
1832         dns_rdata_init(rdata);
1833
1834         if ((lookup->sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVERDATA) != 0)
1835                 origin = &lookup->sdlz->common.origin;
1836         else
1837                 origin = dns_rootname;
1838
1839         lex = NULL;
1840         result = isc_lex_create(mctx, 64, &lex);
1841         if (result != ISC_R_SUCCESS)
1842                 goto failure;
1843
1844         size = initial_size(data);
1845         do {
1846                 isc_buffer_constinit(&b, data, strlen(data));
1847                 isc_buffer_add(&b, strlen(data));
1848
1849                 result = isc_lex_openbuffer(lex, &b);
1850                 if (result != ISC_R_SUCCESS)
1851                         goto failure;
1852
1853                 rdatabuf = NULL;
1854                 result = isc_buffer_allocate(mctx, &rdatabuf, size);
1855                 if (result != ISC_R_SUCCESS)
1856                         goto failure;
1857
1858                 result = dns_rdata_fromtext(rdata, rdatalist->rdclass,
1859                                             rdatalist->type, lex,
1860                                             origin, ISC_FALSE,
1861                                             mctx, rdatabuf,
1862                                             &lookup->callbacks);
1863                 if (result != ISC_R_SUCCESS)
1864                         isc_buffer_free(&rdatabuf);
1865                 if (size >= 65535)
1866                         break;
1867                 size *= 2;
1868                 if (size >= 65535)
1869                         size = 65535;
1870         } while (result == ISC_R_NOSPACE);
1871
1872         if (result != ISC_R_SUCCESS)
1873                 goto failure;
1874
1875         ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1876         ISC_LIST_APPEND(lookup->buffers, rdatabuf, link);
1877
1878         if (lex != NULL)
1879                 isc_lex_destroy(&lex);
1880
1881         return (ISC_R_SUCCESS);
1882
1883  failure:
1884         if (rdatabuf != NULL)
1885                 isc_buffer_free(&rdatabuf);
1886         if (lex != NULL)
1887                 isc_lex_destroy(&lex);
1888         isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
1889
1890         return (result);
1891 }
1892
1893 isc_result_t
1894 dns_sdlz_putnamedrr(dns_sdlzallnodes_t *allnodes, const char *name,
1895                     const char *type, dns_ttl_t ttl, const char *data)
1896 {
1897         dns_name_t *newname, *origin;
1898         dns_fixedname_t fnewname;
1899         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)allnodes->common.db;
1900         dns_sdlznode_t *sdlznode;
1901         isc_mem_t *mctx = sdlz->common.mctx;
1902         isc_buffer_t b;
1903         isc_result_t result;
1904
1905         dns_fixedname_init(&fnewname);
1906         newname = dns_fixedname_name(&fnewname);
1907
1908         if ((sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVERDATA) != 0)
1909                 origin = &sdlz->common.origin;
1910         else
1911                 origin = dns_rootname;
1912         isc_buffer_constinit(&b, name, strlen(name));
1913         isc_buffer_add(&b, strlen(name));
1914
1915         result = dns_name_fromtext(newname, &b, origin, 0, NULL);
1916         if (result != ISC_R_SUCCESS)
1917                 return (result);
1918
1919         if (allnodes->common.relative_names) {
1920                 /* All names are relative to the root */
1921                 unsigned int nlabels = dns_name_countlabels(newname);
1922                 dns_name_getlabelsequence(newname, 0, nlabels - 1, newname);
1923         }
1924
1925         sdlznode = ISC_LIST_HEAD(allnodes->nodelist);
1926         if (sdlznode == NULL || !dns_name_equal(sdlznode->name, newname)) {
1927                 sdlznode = NULL;
1928                 result = createnode(sdlz, &sdlznode);
1929                 if (result != ISC_R_SUCCESS)
1930                         return (result);
1931                 sdlznode->name = isc_mem_get(mctx, sizeof(dns_name_t));
1932                 if (sdlznode->name == NULL) {
1933                         destroynode(sdlznode);
1934                         return (ISC_R_NOMEMORY);
1935                 }
1936                 dns_name_init(sdlznode->name, NULL);
1937                 result = dns_name_dup(newname, mctx, sdlznode->name);
1938                 if (result != ISC_R_SUCCESS) {
1939                         isc_mem_put(mctx, sdlznode->name, sizeof(dns_name_t));
1940                         destroynode(sdlznode);
1941                         return (result);
1942                 }
1943                 ISC_LIST_PREPEND(allnodes->nodelist, sdlznode, link);
1944                 if (allnodes->origin == NULL &&
1945                     dns_name_equal(newname, &sdlz->common.origin))
1946                         allnodes->origin = sdlznode;
1947         }
1948         return (dns_sdlz_putrr(sdlznode, type, ttl, data));
1949
1950 }
1951
1952 isc_result_t
1953 dns_sdlz_putsoa(dns_sdlzlookup_t *lookup, const char *mname, const char *rname,
1954                 isc_uint32_t serial)
1955 {
1956         char str[2 * DNS_NAME_MAXTEXT + 5 * (sizeof("2147483647")) + 7];
1957         int n;
1958
1959         REQUIRE(mname != NULL);
1960         REQUIRE(rname != NULL);
1961
1962         n = snprintf(str, sizeof str, "%s %s %u %u %u %u %u",
1963                      mname, rname, serial,
1964                      SDLZ_DEFAULT_REFRESH, SDLZ_DEFAULT_RETRY,
1965                      SDLZ_DEFAULT_EXPIRE, SDLZ_DEFAULT_MINIMUM);
1966         if (n >= (int)sizeof(str) || n < 0)
1967                 return (ISC_R_NOSPACE);
1968         return (dns_sdlz_putrr(lookup, "SOA", SDLZ_DEFAULT_TTL, str));
1969 }
1970
1971 isc_result_t
1972 dns_sdlzregister(const char *drivername, const dns_sdlzmethods_t *methods,
1973                  void *driverarg, unsigned int flags, isc_mem_t *mctx,
1974                  dns_sdlzimplementation_t **sdlzimp)
1975 {
1976
1977         dns_sdlzimplementation_t *imp;
1978         isc_result_t result;
1979
1980         /*
1981          * Performs checks to make sure data is as we expect it to be.
1982          */
1983         REQUIRE(drivername != NULL);
1984         REQUIRE(methods != NULL);
1985         REQUIRE(methods->findzone != NULL);
1986         REQUIRE(methods->lookup != NULL);
1987         REQUIRE(mctx != NULL);
1988         REQUIRE(sdlzimp != NULL && *sdlzimp == NULL);
1989         REQUIRE((flags & ~(DNS_SDLZFLAG_RELATIVEOWNER |
1990                            DNS_SDLZFLAG_RELATIVERDATA |
1991                            DNS_SDLZFLAG_THREADSAFE)) == 0);
1992
1993         /* Write debugging message to log */
1994         sdlz_log(ISC_LOG_DEBUG(2), "Registering SDLZ driver '%s'", drivername);
1995
1996         /*
1997          * Allocate memory for a sdlz_implementation object.  Error if
1998          * we cannot.
1999          */
2000         imp = isc_mem_get(mctx, sizeof(dns_sdlzimplementation_t));
2001         if (imp == NULL)
2002                 return (ISC_R_NOMEMORY);
2003
2004         /* Make sure memory region is set to all 0's */
2005         memset(imp, 0, sizeof(dns_sdlzimplementation_t));
2006
2007         /* Store the data passed into this method */
2008         imp->methods = methods;
2009         imp->driverarg = driverarg;
2010         imp->flags = flags;
2011         imp->mctx = NULL;
2012
2013         /* attach the new sdlz_implementation object to a memory context */
2014         isc_mem_attach(mctx, &imp->mctx);
2015
2016         /*
2017          * initialize the driver lock, error if we cannot
2018          * (used if a driver does not support multiple threads)
2019          */
2020         result = isc_mutex_init(&imp->driverlock);
2021         if (result != ISC_R_SUCCESS) {
2022                 UNEXPECTED_ERROR(__FILE__, __LINE__,
2023                                  "isc_mutex_init() failed: %s",
2024                                  isc_result_totext(result));
2025                 goto cleanup_mctx;
2026         }
2027
2028         imp->dlz_imp = NULL;
2029
2030         /*
2031          * register the DLZ driver.  Pass in our "extra" sdlz information as
2032          * a driverarg.  (that's why we stored the passed in driver arg in our
2033          * sdlz_implementation structure)  Also, store the dlz_implementation
2034          * structure in our sdlz_implementation.
2035          */
2036         result = dns_dlzregister(drivername, &sdlzmethods, imp, mctx,
2037                                  &imp->dlz_imp);
2038
2039         /* if registration fails, cleanup and get outta here. */
2040         if (result != ISC_R_SUCCESS)
2041                 goto cleanup_mutex;
2042
2043         *sdlzimp = imp;
2044
2045         return (ISC_R_SUCCESS);
2046
2047  cleanup_mutex:
2048         /* destroy the driver lock, we don't need it anymore */
2049         DESTROYLOCK(&imp->driverlock);
2050
2051  cleanup_mctx:
2052         /*
2053          * return the memory back to the available memory pool and
2054          * remove it from the memory context.
2055          */
2056         isc_mem_put(mctx, imp, sizeof(dns_sdlzimplementation_t));
2057         isc_mem_detach(&mctx);
2058         return (result);
2059 }
2060
2061 void
2062 dns_sdlzunregister(dns_sdlzimplementation_t **sdlzimp) {
2063         dns_sdlzimplementation_t *imp;
2064         isc_mem_t *mctx;
2065
2066         /* Write debugging message to log */
2067         sdlz_log(ISC_LOG_DEBUG(2), "Unregistering SDLZ driver.");
2068
2069         /*
2070          * Performs checks to make sure data is as we expect it to be.
2071          */
2072         REQUIRE(sdlzimp != NULL && *sdlzimp != NULL);
2073
2074         imp = *sdlzimp;
2075
2076         /* Unregister the DLZ driver implementation */
2077         dns_dlzunregister(&imp->dlz_imp);
2078
2079         /* destroy the driver lock, we don't need it anymore */
2080         DESTROYLOCK(&imp->driverlock);
2081
2082         mctx = imp->mctx;
2083
2084         /*
2085          * return the memory back to the available memory pool and
2086          * remove it from the memory context.
2087          */
2088         isc_mem_put(mctx, imp, sizeof(dns_sdlzimplementation_t));
2089         isc_mem_detach(&mctx);
2090
2091         *sdlzimp = NULL;
2092 }
2093
2094
2095 isc_result_t
2096 dns_sdlz_setdb(dns_dlzdb_t *dlzdatabase, dns_rdataclass_t rdclass,
2097                dns_name_t *name, dns_db_t **dbp)
2098 {
2099         isc_result_t result;
2100
2101         result = dns_sdlzcreateDBP(dlzdatabase->mctx,
2102                                    dlzdatabase->implementation->driverarg,
2103                                    dlzdatabase->dbdata, name, rdclass, dbp);
2104         return (result);
2105 }