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