]> CyberLeo.Net >> Repos - FreeBSD/releng/8.0.git/blob - contrib/bind9/lib/dns/sdlz.c
Adjust to reflect 8.0-RELEASE.
[FreeBSD/releng/8.0.git] / contrib / bind9 / lib / dns / sdlz.c
1 /*
2  * Portions Copyright (C) 2005-2009  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: sdlz.c,v 1.18.50.2 2009/04/21 23:47:18 tbox Exp $ */
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 };
112
113 struct dns_sdlzlookup {
114         /* Unlocked */
115         unsigned int                    magic;
116         dns_sdlz_db_t                   *sdlz;
117         ISC_LIST(dns_rdatalist_t)       lists;
118         ISC_LIST(isc_buffer_t)          buffers;
119         dns_name_t                      *name;
120         ISC_LINK(dns_sdlzlookup_t)      link;
121         isc_mutex_t                     lock;
122         dns_rdatacallbacks_t            callbacks;
123         /* Locked */
124         unsigned int                    references;
125 };
126
127 typedef struct dns_sdlzlookup dns_sdlznode_t;
128
129 struct dns_sdlzallnodes {
130         dns_dbiterator_t                common;
131         ISC_LIST(dns_sdlznode_t)        nodelist;
132         dns_sdlznode_t                  *current;
133         dns_sdlznode_t                  *origin;
134 };
135
136 typedef dns_sdlzallnodes_t sdlz_dbiterator_t;
137
138 typedef struct sdlz_rdatasetiter {
139         dns_rdatasetiter_t              common;
140         dns_rdatalist_t                 *current;
141 } sdlz_rdatasetiter_t;
142
143
144 #define SDLZDB_MAGIC            ISC_MAGIC('D', 'L', 'Z', 'S')
145
146 /*
147  * Note that "impmagic" is not the first four bytes of the struct, so
148  * ISC_MAGIC_VALID cannot be used.
149  */
150
151 #define VALID_SDLZDB(sdlzdb)    ((sdlzdb) != NULL && \
152                                  (sdlzdb)->common.impmagic == SDLZDB_MAGIC)
153
154 #define SDLZLOOKUP_MAGIC        ISC_MAGIC('D','L','Z','L')
155 #define VALID_SDLZLOOKUP(sdlzl) ISC_MAGIC_VALID(sdlzl, SDLZLOOKUP_MAGIC)
156 #define VALID_SDLZNODE(sdlzn)   VALID_SDLZLOOKUP(sdlzn)
157
158 /* These values are taken from RFC 1537 */
159 #define SDLZ_DEFAULT_REFRESH    (60 * 60 * 8)
160 #define SDLZ_DEFAULT_RETRY      (60 * 60 * 2)
161 #define SDLZ_DEFAULT_EXPIRE     (60 * 60 * 24 * 7)
162 #define SDLZ_DEFAULT_MINIMUM    (60 * 60 * 24)
163
164 /* This is a reasonable value */
165 #define SDLZ_DEFAULT_TTL        (60 * 60 * 24)
166
167 static int dummy;
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 /*% Converts the input string to lowercase, in place. */
229
230 static void
231 dns_sdlz_tolower(char *str) {
232
233         unsigned int len = strlen(str);
234         unsigned int i;
235
236         for (i = 0; i < len; i++) {
237                 if (str[i] >= 'A' && str[i] <= 'Z')
238                         str[i] += 32;
239         }
240
241 }
242
243 static inline unsigned int
244 initial_size(const char *data) {
245         unsigned int len = (strlen(data) / 64) + 1;
246         return (len * 64 + 64);
247 }
248
249 /*
250  * Rdataset Iterator Methods. These methods were "borrowed" from the SDB
251  * driver interface.  See the SDB driver interface documentation for more info.
252  */
253
254 static void
255 rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
256         sdlz_rdatasetiter_t *sdlziterator =
257                 (sdlz_rdatasetiter_t *)(*iteratorp);
258
259         detachnode(sdlziterator->common.db, &sdlziterator->common.node);
260         isc_mem_put(sdlziterator->common.db->mctx, sdlziterator,
261                     sizeof(sdlz_rdatasetiter_t));
262         *iteratorp = NULL;
263 }
264
265 static isc_result_t
266 rdatasetiter_first(dns_rdatasetiter_t *iterator) {
267         sdlz_rdatasetiter_t *sdlziterator = (sdlz_rdatasetiter_t *)iterator;
268         dns_sdlznode_t *sdlznode = (dns_sdlznode_t *)iterator->node;
269
270         if (ISC_LIST_EMPTY(sdlznode->lists))
271                 return (ISC_R_NOMORE);
272         sdlziterator->current = ISC_LIST_HEAD(sdlznode->lists);
273         return (ISC_R_SUCCESS);
274 }
275
276 static isc_result_t
277 rdatasetiter_next(dns_rdatasetiter_t *iterator) {
278         sdlz_rdatasetiter_t *sdlziterator = (sdlz_rdatasetiter_t *)iterator;
279
280         sdlziterator->current = ISC_LIST_NEXT(sdlziterator->current, link);
281         if (sdlziterator->current == NULL)
282                 return (ISC_R_NOMORE);
283         else
284                 return (ISC_R_SUCCESS);
285 }
286
287 static void
288 rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
289         sdlz_rdatasetiter_t *sdlziterator = (sdlz_rdatasetiter_t *)iterator;
290
291         list_tordataset(sdlziterator->current, iterator->db, iterator->node,
292                         rdataset);
293 }
294
295 static dns_rdatasetitermethods_t rdatasetiter_methods = {
296         rdatasetiter_destroy,
297         rdatasetiter_first,
298         rdatasetiter_next,
299         rdatasetiter_current
300 };
301
302 /*
303  * DB routines. These methods were "borrowed" from the SDB driver interface.
304  * See the SDB driver interface documentation for more info.
305  */
306
307 static void
308 attach(dns_db_t *source, dns_db_t **targetp) {
309         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *) source;
310
311         REQUIRE(VALID_SDLZDB(sdlz));
312
313         LOCK(&sdlz->refcnt_lock);
314         REQUIRE(sdlz->references > 0);
315         sdlz->references++;
316         UNLOCK(&sdlz->refcnt_lock);
317
318         *targetp = source;
319 }
320
321 static void
322 destroy(dns_sdlz_db_t *sdlz) {
323         isc_mem_t *mctx;
324         mctx = sdlz->common.mctx;
325
326         sdlz->common.magic = 0;
327         sdlz->common.impmagic = 0;
328
329         isc_mutex_destroy(&sdlz->refcnt_lock);
330
331         dns_name_free(&sdlz->common.origin, mctx);
332
333         isc_mem_put(mctx, sdlz, sizeof(dns_sdlz_db_t));
334         isc_mem_detach(&mctx);
335 }
336
337 static void
338 detach(dns_db_t **dbp) {
339         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)(*dbp);
340         isc_boolean_t need_destroy = ISC_FALSE;
341
342         REQUIRE(VALID_SDLZDB(sdlz));
343         LOCK(&sdlz->refcnt_lock);
344         REQUIRE(sdlz->references > 0);
345         sdlz->references--;
346         if (sdlz->references == 0)
347                 need_destroy = ISC_TRUE;
348         UNLOCK(&sdlz->refcnt_lock);
349
350         if (need_destroy)
351                 destroy(sdlz);
352
353         *dbp = NULL;
354 }
355
356 static isc_result_t
357 beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, dns_dbload_t **dbloadp) {
358         UNUSED(db);
359         UNUSED(addp);
360         UNUSED(dbloadp);
361         return (ISC_R_NOTIMPLEMENTED);
362 }
363
364 static isc_result_t
365 endload(dns_db_t *db, dns_dbload_t **dbloadp) {
366         UNUSED(db);
367         UNUSED(dbloadp);
368         return (ISC_R_NOTIMPLEMENTED);
369 }
370
371 static isc_result_t
372 dump(dns_db_t *db, dns_dbversion_t *version, const char *filename,
373      dns_masterformat_t masterformat)
374 {
375         UNUSED(db);
376         UNUSED(version);
377         UNUSED(filename);
378         UNUSED(masterformat);
379         return (ISC_R_NOTIMPLEMENTED);
380 }
381
382 static void
383 currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
384         REQUIRE(versionp != NULL && *versionp == NULL);
385
386         UNUSED(db);
387
388         *versionp = (void *) &dummy;
389         return;
390 }
391
392 static isc_result_t
393 newversion(dns_db_t *db, dns_dbversion_t **versionp) {
394         UNUSED(db);
395         UNUSED(versionp);
396
397         return (ISC_R_NOTIMPLEMENTED);
398 }
399
400 static void
401 attachversion(dns_db_t *db, dns_dbversion_t *source,
402               dns_dbversion_t **targetp)
403 {
404         REQUIRE(source != NULL && source == (void *) &dummy);
405
406         UNUSED(db);
407         UNUSED(source);
408         UNUSED(targetp);
409         *targetp = source;
410 }
411
412 static void
413 closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
414         REQUIRE(versionp != NULL && *versionp == (void *) &dummy);
415         REQUIRE(commit == ISC_FALSE);
416
417         UNUSED(db);
418         UNUSED(commit);
419
420         *versionp = NULL;
421 }
422
423 static isc_result_t
424 createnode(dns_sdlz_db_t *sdlz, dns_sdlznode_t **nodep) {
425         dns_sdlznode_t *node;
426         isc_result_t result;
427
428         node = isc_mem_get(sdlz->common.mctx, sizeof(dns_sdlznode_t));
429         if (node == NULL)
430                 return (ISC_R_NOMEMORY);
431
432         node->sdlz = NULL;
433         attach((dns_db_t *)sdlz, (dns_db_t **)&node->sdlz);
434         ISC_LIST_INIT(node->lists);
435         ISC_LIST_INIT(node->buffers);
436         ISC_LINK_INIT(node, link);
437         node->name = NULL;
438         result = isc_mutex_init(&node->lock);
439         if (result != ISC_R_SUCCESS) {
440                 UNEXPECTED_ERROR(__FILE__, __LINE__,
441                                  "isc_mutex_init() failed: %s",
442                                  isc_result_totext(result));
443                 isc_mem_put(sdlz->common.mctx, node, sizeof(dns_sdlznode_t));
444                 return (ISC_R_UNEXPECTED);
445         }
446         dns_rdatacallbacks_init(&node->callbacks);
447         node->references = 1;
448         node->magic = SDLZLOOKUP_MAGIC;
449
450         *nodep = node;
451         return (ISC_R_SUCCESS);
452 }
453
454 static void
455 destroynode(dns_sdlznode_t *node) {
456         dns_rdatalist_t *list;
457         dns_rdata_t *rdata;
458         isc_buffer_t *b;
459         dns_sdlz_db_t *sdlz;
460         dns_db_t *db;
461         isc_mem_t *mctx;
462
463         sdlz = node->sdlz;
464         mctx = sdlz->common.mctx;
465
466         while (!ISC_LIST_EMPTY(node->lists)) {
467                 list = ISC_LIST_HEAD(node->lists);
468                 while (!ISC_LIST_EMPTY(list->rdata)) {
469                         rdata = ISC_LIST_HEAD(list->rdata);
470                         ISC_LIST_UNLINK(list->rdata, rdata, link);
471                         isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
472                 }
473                 ISC_LIST_UNLINK(node->lists, list, link);
474                 isc_mem_put(mctx, list, sizeof(dns_rdatalist_t));
475         }
476
477         while (!ISC_LIST_EMPTY(node->buffers)) {
478                 b = ISC_LIST_HEAD(node->buffers);
479                 ISC_LIST_UNLINK(node->buffers, b, link);
480                 isc_buffer_free(&b);
481         }
482
483         if (node->name != NULL) {
484                 dns_name_free(node->name, mctx);
485                 isc_mem_put(mctx, node->name, sizeof(dns_name_t));
486         }
487         DESTROYLOCK(&node->lock);
488         node->magic = 0;
489         isc_mem_put(mctx, node, sizeof(dns_sdlznode_t));
490         db = &sdlz->common;
491         detach(&db);
492 }
493
494 static isc_result_t
495 findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
496          dns_dbnode_t **nodep)
497 {
498         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
499         dns_sdlznode_t *node = NULL;
500         isc_result_t result;
501         isc_buffer_t b;
502         char namestr[DNS_NAME_MAXTEXT + 1];
503         isc_buffer_t b2;
504         char zonestr[DNS_NAME_MAXTEXT + 1];
505         isc_boolean_t isorigin;
506         dns_sdlzauthorityfunc_t authority;
507
508         REQUIRE(VALID_SDLZDB(sdlz));
509         REQUIRE(create == ISC_FALSE);
510         REQUIRE(nodep != NULL && *nodep == NULL);
511
512         UNUSED(name);
513         UNUSED(create);
514
515         isc_buffer_init(&b, namestr, sizeof(namestr));
516         if ((sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVEOWNER) != 0) {
517                 dns_name_t relname;
518                 unsigned int labels;
519
520                 labels = dns_name_countlabels(name) -
521                          dns_name_countlabels(&db->origin);
522                 dns_name_init(&relname, NULL);
523                 dns_name_getlabelsequence(name, 0, labels, &relname);
524                 result = dns_name_totext(&relname, ISC_TRUE, &b);
525                 if (result != ISC_R_SUCCESS)
526                         return (result);
527         } else {
528                 result = dns_name_totext(name, ISC_TRUE, &b);
529                 if (result != ISC_R_SUCCESS)
530                         return (result);
531         }
532         isc_buffer_putuint8(&b, 0);
533
534         isc_buffer_init(&b2, zonestr, sizeof(zonestr));
535         result = dns_name_totext(&sdlz->common.origin, ISC_TRUE, &b2);
536         if (result != ISC_R_SUCCESS)
537                 return (result);
538         isc_buffer_putuint8(&b2, 0);
539
540         result = createnode(sdlz, &node);
541         if (result != ISC_R_SUCCESS)
542                 return (result);
543
544         isorigin = dns_name_equal(name, &sdlz->common.origin);
545
546         /* make sure strings are always lowercase */
547         dns_sdlz_tolower(zonestr);
548         dns_sdlz_tolower(namestr);
549
550         MAYBE_LOCK(sdlz->dlzimp);
551
552         /* try to lookup the host (namestr) */
553         result = sdlz->dlzimp->methods->lookup(zonestr, namestr,
554                                                sdlz->dlzimp->driverarg,
555                                                sdlz->dbdata, node);
556
557         /*
558          * if the host (namestr) was not found, try to lookup a
559          * "wildcard" host.
560          */
561         if (result != ISC_R_SUCCESS) {
562                 result = sdlz->dlzimp->methods->lookup(zonestr, "*",
563                                                        sdlz->dlzimp->driverarg,
564                                                        sdlz->dbdata, node);
565         }
566
567         MAYBE_UNLOCK(sdlz->dlzimp);
568
569         if (result != ISC_R_SUCCESS && !isorigin) {
570                 destroynode(node);
571                 return (result);
572         }
573
574         if (isorigin && sdlz->dlzimp->methods->authority != NULL) {
575                 MAYBE_LOCK(sdlz->dlzimp);
576                 authority = sdlz->dlzimp->methods->authority;
577                 result = (*authority)(zonestr, sdlz->dlzimp->driverarg,
578                                       sdlz->dbdata, node);
579                 MAYBE_UNLOCK(sdlz->dlzimp);
580                 if (result != ISC_R_SUCCESS &&
581                     result != ISC_R_NOTIMPLEMENTED) {
582                         destroynode(node);
583                         return (result);
584                 }
585         }
586
587         *nodep = node;
588         return (ISC_R_SUCCESS);
589 }
590
591 static isc_result_t
592 findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
593             isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
594             dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
595 {
596         UNUSED(db);
597         UNUSED(name);
598         UNUSED(options);
599         UNUSED(now);
600         UNUSED(nodep);
601         UNUSED(foundname);
602         UNUSED(rdataset);
603         UNUSED(sigrdataset);
604
605         return (ISC_R_NOTIMPLEMENTED);
606 }
607
608 static void
609 attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
610         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
611         dns_sdlznode_t *node = (dns_sdlznode_t *)source;
612
613         REQUIRE(VALID_SDLZDB(sdlz));
614
615         UNUSED(sdlz);
616
617         LOCK(&node->lock);
618         INSIST(node->references > 0);
619         node->references++;
620         INSIST(node->references != 0);          /* Catch overflow. */
621         UNLOCK(&node->lock);
622
623         *targetp = source;
624 }
625
626 static void
627 detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
628         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
629         dns_sdlznode_t *node;
630         isc_boolean_t need_destroy = ISC_FALSE;
631
632         REQUIRE(VALID_SDLZDB(sdlz));
633         REQUIRE(targetp != NULL && *targetp != NULL);
634
635         UNUSED(sdlz);
636
637         node = (dns_sdlznode_t *)(*targetp);
638
639         LOCK(&node->lock);
640         INSIST(node->references > 0);
641         node->references--;
642         if (node->references == 0)
643                 need_destroy = ISC_TRUE;
644         UNLOCK(&node->lock);
645
646         if (need_destroy)
647                 destroynode(node);
648
649         *targetp = NULL;
650 }
651
652 static isc_result_t
653 expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
654         UNUSED(db);
655         UNUSED(node);
656         UNUSED(now);
657         INSIST(0);
658         return (ISC_R_UNEXPECTED);
659 }
660
661 static void
662 printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
663         UNUSED(db);
664         UNUSED(node);
665         UNUSED(out);
666         return;
667 }
668
669 static isc_result_t
670 createiterator(dns_db_t *db, unsigned int options, dns_dbiterator_t **iteratorp)
671 {
672         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
673         sdlz_dbiterator_t *sdlziter;
674         isc_result_t result;
675         isc_buffer_t b;
676         char zonestr[DNS_NAME_MAXTEXT + 1];
677
678         REQUIRE(VALID_SDLZDB(sdlz));
679
680         if (sdlz->dlzimp->methods->allnodes == NULL)
681                 return (ISC_R_NOTIMPLEMENTED);
682
683         if ((options & DNS_DB_NSEC3ONLY) != 0 ||
684             (options & DNS_DB_NONSEC3) != 0)
685                  return (ISC_R_NOTIMPLEMENTED);
686
687         isc_buffer_init(&b, zonestr, sizeof(zonestr));
688         result = dns_name_totext(&sdlz->common.origin, ISC_TRUE, &b);
689         if (result != ISC_R_SUCCESS)
690                 return (result);
691         isc_buffer_putuint8(&b, 0);
692
693         sdlziter = isc_mem_get(sdlz->common.mctx, sizeof(sdlz_dbiterator_t));
694         if (sdlziter == NULL)
695                 return (ISC_R_NOMEMORY);
696
697         sdlziter->common.methods = &dbiterator_methods;
698         sdlziter->common.db = NULL;
699         dns_db_attach(db, &sdlziter->common.db);
700         sdlziter->common.relative_names = ISC_TF(options & DNS_DB_RELATIVENAMES);
701         sdlziter->common.magic = DNS_DBITERATOR_MAGIC;
702         ISC_LIST_INIT(sdlziter->nodelist);
703         sdlziter->current = NULL;
704         sdlziter->origin = NULL;
705
706         /* make sure strings are always lowercase */
707         dns_sdlz_tolower(zonestr);
708
709         MAYBE_LOCK(sdlz->dlzimp);
710         result = sdlz->dlzimp->methods->allnodes(zonestr,
711                                                  sdlz->dlzimp->driverarg,
712                                                  sdlz->dbdata, sdlziter);
713         MAYBE_UNLOCK(sdlz->dlzimp);
714         if (result != ISC_R_SUCCESS) {
715                 dns_dbiterator_t *iter = &sdlziter->common;
716                 dbiterator_destroy(&iter);
717                 return (result);
718         }
719
720         if (sdlziter->origin != NULL) {
721                 ISC_LIST_UNLINK(sdlziter->nodelist, sdlziter->origin, link);
722                 ISC_LIST_PREPEND(sdlziter->nodelist, sdlziter->origin, link);
723         }
724
725         *iteratorp = (dns_dbiterator_t *)sdlziter;
726
727         return (ISC_R_SUCCESS);
728 }
729
730 static isc_result_t
731 findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
732              dns_rdatatype_t type, dns_rdatatype_t covers,
733              isc_stdtime_t now, dns_rdataset_t *rdataset,
734              dns_rdataset_t *sigrdataset)
735 {
736         dns_rdatalist_t *list;
737         dns_sdlznode_t *sdlznode = (dns_sdlznode_t *)node;
738
739         REQUIRE(VALID_SDLZNODE(node));
740
741         UNUSED(db);
742         UNUSED(version);
743         UNUSED(covers);
744         UNUSED(now);
745         UNUSED(sigrdataset);
746
747         if (type == dns_rdatatype_sig || type == dns_rdatatype_rrsig)
748                 return (ISC_R_NOTIMPLEMENTED);
749
750         list = ISC_LIST_HEAD(sdlznode->lists);
751         while (list != NULL) {
752                 if (list->type == type)
753                         break;
754                 list = ISC_LIST_NEXT(list, link);
755         }
756         if (list == NULL)
757                 return (ISC_R_NOTFOUND);
758
759         list_tordataset(list, db, node, rdataset);
760
761         return (ISC_R_SUCCESS);
762 }
763
764 static isc_result_t
765 find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
766      dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
767      dns_dbnode_t **nodep, dns_name_t *foundname,
768      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
769 {
770         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
771         dns_dbnode_t *node = NULL;
772         dns_fixedname_t fname;
773         dns_rdataset_t xrdataset;
774         dns_name_t *xname;
775         unsigned int nlabels, olabels;
776         isc_result_t result;
777         unsigned int i;
778
779         REQUIRE(VALID_SDLZDB(sdlz));
780         REQUIRE(nodep == NULL || *nodep == NULL);
781         REQUIRE(version == NULL || version == (void *) &dummy);
782
783         UNUSED(options);
784         UNUSED(sdlz);
785
786         if (!dns_name_issubdomain(name, &db->origin))
787                 return (DNS_R_NXDOMAIN);
788
789         olabels = dns_name_countlabels(&db->origin);
790         nlabels = dns_name_countlabels(name);
791
792         dns_fixedname_init(&fname);
793         xname = dns_fixedname_name(&fname);
794
795         if (rdataset == NULL) {
796                 dns_rdataset_init(&xrdataset);
797                 rdataset = &xrdataset;
798         }
799
800         result = DNS_R_NXDOMAIN;
801
802         for (i = olabels; i <= nlabels; i++) {
803                 /*
804                  * Unless this is an explicit lookup at the origin, don't
805                  * look at the origin.
806                  */
807                 if (i == olabels && i != nlabels)
808                         continue;
809
810                 /*
811                  * Look up the next label.
812                  */
813                 dns_name_getlabelsequence(name, nlabels - i, i, xname);
814                 result = findnode(db, xname, ISC_FALSE, &node);
815                 if (result != ISC_R_SUCCESS) {
816                         result = DNS_R_NXDOMAIN;
817                         continue;
818                 }
819
820                 /*
821                  * Look for a DNAME at the current label, unless this is
822                  * the qname.
823                  */
824                 if (i < nlabels) {
825                         result = findrdataset(db, node, version,
826                                               dns_rdatatype_dname,
827                                               0, now, rdataset, sigrdataset);
828                         if (result == ISC_R_SUCCESS) {
829                                 result = DNS_R_DNAME;
830                                 break;
831                         }
832                 }
833
834                 /*
835                  * Look for an NS at the current label, unless this is the
836                  * origin or glue is ok.
837                  */
838                 if (i != olabels && (options & DNS_DBFIND_GLUEOK) == 0) {
839                         result = findrdataset(db, node, version,
840                                               dns_rdatatype_ns,
841                                               0, now, rdataset, sigrdataset);
842                         if (result == ISC_R_SUCCESS) {
843                                 if (i == nlabels && type == dns_rdatatype_any)
844                                 {
845                                         result = DNS_R_ZONECUT;
846                                         dns_rdataset_disassociate(rdataset);
847                                         if (sigrdataset != NULL &&
848                                             dns_rdataset_isassociated
849                                                         (sigrdataset)) {
850                                                 dns_rdataset_disassociate
851                                                         (sigrdataset);
852                                         }
853                                 } else
854                                         result = DNS_R_DELEGATION;
855                                 break;
856                         }
857                 }
858
859                 /*
860                  * If the current name is not the qname, add another label
861                  * and try again.
862                  */
863                 if (i < nlabels) {
864                         destroynode(node);
865                         node = NULL;
866                         continue;
867                 }
868
869                 /*
870                  * If we're looking for ANY, we're done.
871                  */
872                 if (type == dns_rdatatype_any) {
873                         result = ISC_R_SUCCESS;
874                         break;
875                 }
876
877                 /*
878                  * Look for the qtype.
879                  */
880                 result = findrdataset(db, node, version, type,
881                                       0, now, rdataset, sigrdataset);
882                 if (result == ISC_R_SUCCESS)
883                         break;
884
885                 /*
886                  * Look for a CNAME
887                  */
888                 if (type != dns_rdatatype_cname) {
889                         result = findrdataset(db, node, version,
890                                               dns_rdatatype_cname,
891                                               0, now, rdataset, sigrdataset);
892                         if (result == ISC_R_SUCCESS) {
893                                 result = DNS_R_CNAME;
894                                 break;
895                         }
896                 }
897
898                 result = DNS_R_NXRRSET;
899                 break;
900         }
901
902         if (rdataset == &xrdataset && dns_rdataset_isassociated(rdataset))
903                 dns_rdataset_disassociate(rdataset);
904
905         if (foundname != NULL) {
906                 isc_result_t xresult;
907
908                 xresult = dns_name_copy(xname, foundname, NULL);
909                 if (xresult != ISC_R_SUCCESS) {
910                         if (node != NULL)
911                                 destroynode(node);
912                         if (dns_rdataset_isassociated(rdataset))
913                                 dns_rdataset_disassociate(rdataset);
914                         return (DNS_R_BADDB);
915                 }
916         }
917
918         if (nodep != NULL)
919                 *nodep = node;
920         else if (node != NULL)
921                 detachnode(db, &node);
922
923         return (result);
924 }
925
926 static isc_result_t
927 allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
928              isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
929 {
930         sdlz_rdatasetiter_t *iterator;
931
932         REQUIRE(version == NULL || version == &dummy);
933
934         UNUSED(version);
935         UNUSED(now);
936
937         iterator = isc_mem_get(db->mctx, sizeof(sdlz_rdatasetiter_t));
938         if (iterator == NULL)
939                 return (ISC_R_NOMEMORY);
940
941         iterator->common.magic = DNS_RDATASETITER_MAGIC;
942         iterator->common.methods = &rdatasetiter_methods;
943         iterator->common.db = db;
944         iterator->common.node = NULL;
945         attachnode(db, node, &iterator->common.node);
946         iterator->common.version = version;
947         iterator->common.now = now;
948
949         *iteratorp = (dns_rdatasetiter_t *)iterator;
950
951         return (ISC_R_SUCCESS);
952 }
953
954 static isc_result_t
955 addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
956             isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
957             dns_rdataset_t *addedrdataset)
958 {
959         UNUSED(db);
960         UNUSED(node);
961         UNUSED(version);
962         UNUSED(now);
963         UNUSED(rdataset);
964         UNUSED(options);
965         UNUSED(addedrdataset);
966
967         return (ISC_R_NOTIMPLEMENTED);
968 }
969
970 static isc_result_t
971 subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
972                  dns_rdataset_t *rdataset, unsigned int options,
973                  dns_rdataset_t *newrdataset)
974 {
975         UNUSED(db);
976         UNUSED(node);
977         UNUSED(version);
978         UNUSED(rdataset);
979         UNUSED(options);
980         UNUSED(newrdataset);
981
982         return (ISC_R_NOTIMPLEMENTED);
983 }
984
985 static isc_result_t
986 deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
987                dns_rdatatype_t type, dns_rdatatype_t covers)
988 {
989         UNUSED(db);
990         UNUSED(node);
991         UNUSED(version);
992         UNUSED(type);
993         UNUSED(covers);
994
995         return (ISC_R_NOTIMPLEMENTED);
996 }
997
998 static isc_boolean_t
999 issecure(dns_db_t *db) {
1000         UNUSED(db);
1001
1002         return (ISC_FALSE);
1003 }
1004
1005 static unsigned int
1006 nodecount(dns_db_t *db) {
1007         UNUSED(db);
1008
1009         return (0);
1010 }
1011
1012 static isc_boolean_t
1013 ispersistent(dns_db_t *db) {
1014         UNUSED(db);
1015         return (ISC_TRUE);
1016 }
1017
1018 static void
1019 overmem(dns_db_t *db, isc_boolean_t overmem) {
1020         UNUSED(db);
1021         UNUSED(overmem);
1022 }
1023
1024 static void
1025 settask(dns_db_t *db, isc_task_t *task) {
1026         UNUSED(db);
1027         UNUSED(task);
1028 }
1029
1030
1031 static dns_dbmethods_t sdlzdb_methods = {
1032         attach,
1033         detach,
1034         beginload,
1035         endload,
1036         dump,
1037         currentversion,
1038         newversion,
1039         attachversion,
1040         closeversion,
1041         findnode,
1042         find,
1043         findzonecut,
1044         attachnode,
1045         detachnode,
1046         expirenode,
1047         printnode,
1048         createiterator,
1049         findrdataset,
1050         allrdatasets,
1051         addrdataset,
1052         subtractrdataset,
1053         deleterdataset,
1054         issecure,
1055         nodecount,
1056         ispersistent,
1057         overmem,
1058         settask,
1059         NULL,
1060         NULL,
1061         NULL,
1062         NULL,
1063         NULL,
1064         NULL,
1065         NULL,
1066         NULL,
1067         NULL
1068 };
1069
1070 /*
1071  * Database Iterator Methods.  These methods were "borrowed" from the SDB
1072  * driver interface.  See the SDB driver interface documentation for more info.
1073  */
1074
1075 static void
1076 dbiterator_destroy(dns_dbiterator_t **iteratorp) {
1077         sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)(*iteratorp);
1078         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)sdlziter->common.db;
1079
1080         while (!ISC_LIST_EMPTY(sdlziter->nodelist)) {
1081                 dns_sdlznode_t *node;
1082                 node = ISC_LIST_HEAD(sdlziter->nodelist);
1083                 ISC_LIST_UNLINK(sdlziter->nodelist, node, link);
1084                 destroynode(node);
1085         }
1086
1087         dns_db_detach(&sdlziter->common.db);
1088         isc_mem_put(sdlz->common.mctx, sdlziter, sizeof(sdlz_dbiterator_t));
1089
1090         *iteratorp = NULL;
1091 }
1092
1093 static isc_result_t
1094 dbiterator_first(dns_dbiterator_t *iterator) {
1095         sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1096
1097         sdlziter->current = ISC_LIST_HEAD(sdlziter->nodelist);
1098         if (sdlziter->current == NULL)
1099                 return (ISC_R_NOMORE);
1100         else
1101                 return (ISC_R_SUCCESS);
1102 }
1103
1104 static isc_result_t
1105 dbiterator_last(dns_dbiterator_t *iterator) {
1106         sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1107
1108         sdlziter->current = ISC_LIST_TAIL(sdlziter->nodelist);
1109         if (sdlziter->current == NULL)
1110                 return (ISC_R_NOMORE);
1111         else
1112                 return (ISC_R_SUCCESS);
1113 }
1114
1115 static isc_result_t
1116 dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
1117         sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1118
1119         sdlziter->current = ISC_LIST_HEAD(sdlziter->nodelist);
1120         while (sdlziter->current != NULL)
1121                 if (dns_name_equal(sdlziter->current->name, name))
1122                         return (ISC_R_SUCCESS);
1123         return (ISC_R_NOTFOUND);
1124 }
1125
1126 static isc_result_t
1127 dbiterator_prev(dns_dbiterator_t *iterator) {
1128         sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1129
1130         sdlziter->current = ISC_LIST_PREV(sdlziter->current, link);
1131         if (sdlziter->current == NULL)
1132                 return (ISC_R_NOMORE);
1133         else
1134                 return (ISC_R_SUCCESS);
1135 }
1136
1137 static isc_result_t
1138 dbiterator_next(dns_dbiterator_t *iterator) {
1139         sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1140
1141         sdlziter->current = ISC_LIST_NEXT(sdlziter->current, link);
1142         if (sdlziter->current == NULL)
1143                 return (ISC_R_NOMORE);
1144         else
1145                 return (ISC_R_SUCCESS);
1146 }
1147
1148 static isc_result_t
1149 dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
1150                    dns_name_t *name)
1151 {
1152         sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1153
1154         attachnode(iterator->db, sdlziter->current, nodep);
1155         if (name != NULL)
1156                 return (dns_name_copy(sdlziter->current->name, name, NULL));
1157         return (ISC_R_SUCCESS);
1158 }
1159
1160 static isc_result_t
1161 dbiterator_pause(dns_dbiterator_t *iterator) {
1162         UNUSED(iterator);
1163         return (ISC_R_SUCCESS);
1164 }
1165
1166 static isc_result_t
1167 dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
1168         UNUSED(iterator);
1169         return (dns_name_copy(dns_rootname, name, NULL));
1170 }
1171
1172 /*
1173  * Rdataset Methods. These methods were "borrowed" from the SDB driver
1174  * interface.  See the SDB driver interface documentation for more info.
1175  */
1176
1177 static void
1178 disassociate(dns_rdataset_t *rdataset) {
1179         dns_dbnode_t *node = rdataset->private5;
1180         dns_sdlznode_t *sdlznode = (dns_sdlznode_t *) node;
1181         dns_db_t *db = (dns_db_t *) sdlznode->sdlz;
1182
1183         detachnode(db, &node);
1184         isc__rdatalist_disassociate(rdataset);
1185 }
1186
1187 static void
1188 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
1189         dns_dbnode_t *node = source->private5;
1190         dns_sdlznode_t *sdlznode = (dns_sdlznode_t *) node;
1191         dns_db_t *db = (dns_db_t *) sdlznode->sdlz;
1192         dns_dbnode_t *tempdb = NULL;
1193
1194         isc__rdatalist_clone(source, target);
1195         attachnode(db, node, &tempdb);
1196         source->private5 = tempdb;
1197 }
1198
1199 static dns_rdatasetmethods_t rdataset_methods = {
1200         disassociate,
1201         isc__rdatalist_first,
1202         isc__rdatalist_next,
1203         isc__rdatalist_current,
1204         rdataset_clone,
1205         isc__rdatalist_count,
1206         isc__rdatalist_addnoqname,
1207         isc__rdatalist_getnoqname,
1208         NULL,
1209         NULL,
1210         NULL,
1211         NULL,
1212         NULL
1213 };
1214
1215 static void
1216 list_tordataset(dns_rdatalist_t *rdatalist,
1217                 dns_db_t *db, dns_dbnode_t *node,
1218                 dns_rdataset_t *rdataset)
1219 {
1220         /*
1221          * The sdlz rdataset is an rdatalist with some additions.
1222          *      - private1 & private2 are used by the rdatalist.
1223          *      - private3 & private 4 are unused.
1224          *      - private5 is the node.
1225          */
1226
1227         /* This should never fail. */
1228         RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
1229                       ISC_R_SUCCESS);
1230
1231         rdataset->methods = &rdataset_methods;
1232         dns_db_attachnode(db, node, &rdataset->private5);
1233 }
1234
1235 /*
1236  * SDLZ core methods. This is the core of the new DLZ functionality.
1237  */
1238
1239 /*%
1240  * Build a 'bind' database driver structure to be returned by
1241  * either the find zone or the allow zone transfer method.
1242  * This method is only available in this source file, it is
1243  * not made available anywhere else.
1244  */
1245
1246 static isc_result_t
1247 dns_sdlzcreateDBP(isc_mem_t *mctx, void *driverarg, void *dbdata,
1248                   dns_name_t *name, dns_rdataclass_t rdclass, dns_db_t **dbp)
1249 {
1250         isc_result_t result;
1251         dns_sdlz_db_t *sdlzdb;
1252         dns_sdlzimplementation_t *imp;
1253
1254         /* check that things are as we expect */
1255         REQUIRE(dbp != NULL && *dbp == NULL);
1256         REQUIRE(name != NULL);
1257
1258         imp = (dns_sdlzimplementation_t *) driverarg;
1259
1260         /* allocate and zero memory for driver structure */
1261         sdlzdb = isc_mem_get(mctx, sizeof(dns_sdlz_db_t));
1262         if (sdlzdb == NULL)
1263                 return (ISC_R_NOMEMORY);
1264         memset(sdlzdb, 0, sizeof(dns_sdlz_db_t));
1265
1266         /* initialize and set origin */
1267         dns_name_init(&sdlzdb->common.origin, NULL);
1268         result = dns_name_dupwithoffsets(name, mctx, &sdlzdb->common.origin);
1269         if (result != ISC_R_SUCCESS)
1270                 goto mem_cleanup;
1271
1272         /* initialize the reference count mutex */
1273         result = isc_mutex_init(&sdlzdb->refcnt_lock);
1274         if (result != ISC_R_SUCCESS)
1275                 goto name_cleanup;
1276
1277         /* set the rest of the database structure attributes */
1278         sdlzdb->dlzimp = imp;
1279         sdlzdb->common.methods = &sdlzdb_methods;
1280         sdlzdb->common.attributes = 0;
1281         sdlzdb->common.rdclass = rdclass;
1282         sdlzdb->common.mctx = NULL;
1283         sdlzdb->dbdata = dbdata;
1284         sdlzdb->references = 1;
1285
1286         /* attach to the memory context */
1287         isc_mem_attach(mctx, &sdlzdb->common.mctx);
1288
1289         /* mark structure as valid */
1290         sdlzdb->common.magic = DNS_DB_MAGIC;
1291         sdlzdb->common.impmagic = SDLZDB_MAGIC;
1292         *dbp = (dns_db_t *) sdlzdb;
1293
1294         return (result);
1295
1296         /*
1297          * reference count mutex could not be initialized, clean up
1298          * name memory
1299          */
1300  name_cleanup:
1301         dns_name_free(&sdlzdb->common.origin, mctx);
1302  mem_cleanup:
1303         isc_mem_put(mctx, sdlzdb, sizeof(dns_sdlz_db_t));
1304         return (result);
1305 }
1306
1307 static isc_result_t
1308 dns_sdlzallowzonexfr(void *driverarg, void *dbdata, isc_mem_t *mctx,
1309                      dns_rdataclass_t rdclass, dns_name_t *name,
1310                      isc_sockaddr_t *clientaddr, dns_db_t **dbp)
1311 {
1312         isc_buffer_t b;
1313         isc_buffer_t b2;
1314         char namestr[DNS_NAME_MAXTEXT + 1];
1315         char clientstr[(sizeof "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")
1316                        + 1];
1317         isc_netaddr_t netaddr;
1318         isc_result_t result;
1319         dns_sdlzimplementation_t *imp;
1320
1321         /*
1322          * Perform checks to make sure data is as we expect it to be.
1323          */
1324         REQUIRE(driverarg != NULL);
1325         REQUIRE(name != NULL);
1326         REQUIRE(clientaddr != NULL);
1327         REQUIRE(dbp != NULL && *dbp == NULL);
1328
1329         imp = (dns_sdlzimplementation_t *) driverarg;
1330
1331         /* Convert DNS name to ascii text */
1332         isc_buffer_init(&b, namestr, sizeof(namestr));
1333         result = dns_name_totext(name, ISC_TRUE, &b);
1334         if (result != ISC_R_SUCCESS)
1335                 return (result);
1336         isc_buffer_putuint8(&b, 0);
1337
1338         /* convert client address to ascii text */
1339         isc_buffer_init(&b2, clientstr, sizeof(clientstr));
1340         isc_netaddr_fromsockaddr(&netaddr, clientaddr);
1341         result = isc_netaddr_totext(&netaddr, &b2);
1342         if (result != ISC_R_SUCCESS)
1343                 return (result);
1344         isc_buffer_putuint8(&b2, 0);
1345
1346         /* make sure strings are always lowercase */
1347         dns_sdlz_tolower(namestr);
1348         dns_sdlz_tolower(clientstr);
1349
1350         /* Call SDLZ driver's find zone method */
1351         if (imp->methods->allowzonexfr != NULL) {
1352                 MAYBE_LOCK(imp);
1353                 result = imp->methods->allowzonexfr(imp->driverarg, dbdata,
1354                                                     namestr, clientstr);
1355                 MAYBE_UNLOCK(imp);
1356                 /*
1357                  * if zone is supported and transfers allowed build a 'bind'
1358                  * database driver
1359                  */
1360                 if (result == ISC_R_SUCCESS)
1361                         result = dns_sdlzcreateDBP(mctx, driverarg, dbdata,
1362                                                    name, rdclass, dbp);
1363                 return (result);
1364         }
1365
1366         return (ISC_R_NOTIMPLEMENTED);
1367 }
1368
1369 static isc_result_t
1370 dns_sdlzcreate(isc_mem_t *mctx, const char *dlzname, unsigned int argc,
1371                char *argv[], void *driverarg, void **dbdata)
1372 {
1373         dns_sdlzimplementation_t *imp;
1374         isc_result_t result = ISC_R_NOTFOUND;
1375
1376         /* Write debugging message to log */
1377         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1378                       DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1379                       "Loading SDLZ driver.");
1380
1381         /*
1382          * Performs checks to make sure data is as we expect it to be.
1383          */
1384         REQUIRE(driverarg != NULL);
1385         REQUIRE(dlzname != NULL);
1386         REQUIRE(dbdata != NULL);
1387         UNUSED(mctx);
1388
1389         imp = driverarg;
1390
1391         /* If the create method exists, call it. */
1392         if (imp->methods->create != NULL) {
1393                 MAYBE_LOCK(imp);
1394                 result = imp->methods->create(dlzname, argc, argv,
1395                                               imp->driverarg, dbdata);
1396                 MAYBE_UNLOCK(imp);
1397         }
1398
1399         /* Write debugging message to log */
1400         if (result == ISC_R_SUCCESS) {
1401                 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1402                               DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1403                               "SDLZ driver loaded successfully.");
1404         } else {
1405                 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1406                               DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1407                               "SDLZ driver failed to load.");
1408         }
1409
1410         return (result);
1411 }
1412
1413 static void
1414 dns_sdlzdestroy(void *driverdata, void **dbdata)
1415 {
1416
1417         dns_sdlzimplementation_t *imp;
1418
1419         /* Write debugging message to log */
1420         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1421                       DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1422                       "Unloading SDLZ driver.");
1423
1424         imp = driverdata;
1425
1426         /* If the destroy method exists, call it. */
1427         if (imp->methods->destroy != NULL) {
1428                 MAYBE_LOCK(imp);
1429                 imp->methods->destroy(imp->driverarg, dbdata);
1430                 MAYBE_UNLOCK(imp);
1431         }
1432 }
1433
1434 static isc_result_t
1435 dns_sdlzfindzone(void *driverarg, void *dbdata, isc_mem_t *mctx,
1436                  dns_rdataclass_t rdclass, dns_name_t *name, dns_db_t **dbp)
1437 {
1438         isc_buffer_t b;
1439         char namestr[DNS_NAME_MAXTEXT + 1];
1440         isc_result_t result;
1441         dns_sdlzimplementation_t *imp;
1442
1443         /*
1444          * Perform checks to make sure data is as we expect it to be.
1445          */
1446         REQUIRE(driverarg != NULL);
1447         REQUIRE(name != NULL);
1448         REQUIRE(dbp != NULL && *dbp == NULL);
1449
1450         imp = (dns_sdlzimplementation_t *) driverarg;
1451
1452         /* Convert DNS name to ascii text */
1453         isc_buffer_init(&b, namestr, sizeof(namestr));
1454         result = dns_name_totext(name, ISC_TRUE, &b);
1455         if (result != ISC_R_SUCCESS)
1456                 return (result);
1457         isc_buffer_putuint8(&b, 0);
1458
1459         /* make sure strings are always lowercase */
1460         dns_sdlz_tolower(namestr);
1461
1462         /* Call SDLZ driver's find zone method */
1463         MAYBE_LOCK(imp);
1464         result = imp->methods->findzone(imp->driverarg, dbdata, namestr);
1465         MAYBE_UNLOCK(imp);
1466
1467         /*
1468          * if zone is supported build a 'bind' database driver
1469          * structure to return
1470          */
1471         if (result == ISC_R_SUCCESS)
1472                 result = dns_sdlzcreateDBP(mctx, driverarg, dbdata, name,
1473                                            rdclass, dbp);
1474
1475         return (result);
1476 }
1477
1478 static dns_dlzmethods_t sdlzmethods = {
1479         dns_sdlzcreate,
1480         dns_sdlzdestroy,
1481         dns_sdlzfindzone,
1482         dns_sdlzallowzonexfr
1483 };
1484
1485 /*
1486  * Public functions.
1487  */
1488
1489 isc_result_t
1490 dns_sdlz_putrr(dns_sdlzlookup_t *lookup, const char *type, dns_ttl_t ttl,
1491                const char *data)
1492 {
1493         dns_rdatalist_t *rdatalist;
1494         dns_rdata_t *rdata;
1495         dns_rdatatype_t typeval;
1496         isc_consttextregion_t r;
1497         isc_buffer_t b;
1498         isc_buffer_t *rdatabuf = NULL;
1499         isc_lex_t *lex;
1500         isc_result_t result;
1501         unsigned int size;
1502         isc_mem_t *mctx;
1503         dns_name_t *origin;
1504
1505         REQUIRE(VALID_SDLZLOOKUP(lookup));
1506         REQUIRE(type != NULL);
1507         REQUIRE(data != NULL);
1508
1509         mctx = lookup->sdlz->common.mctx;
1510
1511         r.base = type;
1512         r.length = strlen(type);
1513         result = dns_rdatatype_fromtext(&typeval, (void *) &r);
1514         if (result != ISC_R_SUCCESS)
1515                 return (result);
1516
1517         rdatalist = ISC_LIST_HEAD(lookup->lists);
1518         while (rdatalist != NULL) {
1519                 if (rdatalist->type == typeval)
1520                         break;
1521                 rdatalist = ISC_LIST_NEXT(rdatalist, link);
1522         }
1523
1524         if (rdatalist == NULL) {
1525                 rdatalist = isc_mem_get(mctx, sizeof(dns_rdatalist_t));
1526                 if (rdatalist == NULL)
1527                         return (ISC_R_NOMEMORY);
1528                 rdatalist->rdclass = lookup->sdlz->common.rdclass;
1529                 rdatalist->type = typeval;
1530                 rdatalist->covers = 0;
1531                 rdatalist->ttl = ttl;
1532                 ISC_LIST_INIT(rdatalist->rdata);
1533                 ISC_LINK_INIT(rdatalist, link);
1534                 ISC_LIST_APPEND(lookup->lists, rdatalist, link);
1535         } else
1536                 if (rdatalist->ttl != ttl)
1537                         return (DNS_R_BADTTL);
1538
1539         rdata = isc_mem_get(mctx, sizeof(dns_rdata_t));
1540         if (rdata == NULL)
1541                 return (ISC_R_NOMEMORY);
1542         dns_rdata_init(rdata);
1543
1544         if ((lookup->sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVERDATA) != 0)
1545                 origin = &lookup->sdlz->common.origin;
1546         else
1547                 origin = dns_rootname;
1548
1549         lex = NULL;
1550         result = isc_lex_create(mctx, 64, &lex);
1551         if (result != ISC_R_SUCCESS)
1552                 goto failure;
1553
1554         size = initial_size(data);
1555         do {
1556                 isc_buffer_init(&b, data, strlen(data));
1557                 isc_buffer_add(&b, strlen(data));
1558
1559                 result = isc_lex_openbuffer(lex, &b);
1560                 if (result != ISC_R_SUCCESS)
1561                         goto failure;
1562
1563                 rdatabuf = NULL;
1564                 result = isc_buffer_allocate(mctx, &rdatabuf, size);
1565                 if (result != ISC_R_SUCCESS)
1566                         goto failure;
1567
1568                 result = dns_rdata_fromtext(rdata, rdatalist->rdclass,
1569                                             rdatalist->type, lex,
1570                                             origin, ISC_FALSE,
1571                                             mctx, rdatabuf,
1572                                             &lookup->callbacks);
1573                 if (result != ISC_R_SUCCESS)
1574                         isc_buffer_free(&rdatabuf);
1575                 size *= 2;
1576         } while (result == ISC_R_NOSPACE);
1577
1578         if (result != ISC_R_SUCCESS)
1579                 goto failure;
1580
1581         ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1582         ISC_LIST_APPEND(lookup->buffers, rdatabuf, link);
1583
1584         if (lex != NULL)
1585                 isc_lex_destroy(&lex);
1586
1587         return (ISC_R_SUCCESS);
1588
1589  failure:
1590         if (rdatabuf != NULL)
1591                 isc_buffer_free(&rdatabuf);
1592         if (lex != NULL)
1593                 isc_lex_destroy(&lex);
1594         isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
1595
1596         return (result);
1597 }
1598
1599 isc_result_t
1600 dns_sdlz_putnamedrr(dns_sdlzallnodes_t *allnodes, const char *name,
1601                     const char *type, dns_ttl_t ttl, const char *data)
1602 {
1603         dns_name_t *newname, *origin;
1604         dns_fixedname_t fnewname;
1605         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)allnodes->common.db;
1606         dns_sdlznode_t *sdlznode;
1607         isc_mem_t *mctx = sdlz->common.mctx;
1608         isc_buffer_t b;
1609         isc_result_t result;
1610
1611         dns_fixedname_init(&fnewname);
1612         newname = dns_fixedname_name(&fnewname);
1613
1614         if ((sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVERDATA) != 0)
1615                 origin = &sdlz->common.origin;
1616         else
1617                 origin = dns_rootname;
1618         isc_buffer_init(&b, name, strlen(name));
1619         isc_buffer_add(&b, strlen(name));
1620
1621         result = dns_name_fromtext(newname, &b, origin, ISC_FALSE, NULL);
1622         if (result != ISC_R_SUCCESS)
1623                 return (result);
1624
1625         if (allnodes->common.relative_names) {
1626                 /* All names are relative to the root */
1627                 unsigned int nlabels = dns_name_countlabels(newname);
1628                 dns_name_getlabelsequence(newname, 0, nlabels - 1, newname);
1629         }
1630
1631         sdlznode = ISC_LIST_HEAD(allnodes->nodelist);
1632         if (sdlznode == NULL || !dns_name_equal(sdlznode->name, newname)) {
1633                 sdlznode = NULL;
1634                 result = createnode(sdlz, &sdlznode);
1635                 if (result != ISC_R_SUCCESS)
1636                         return (result);
1637                 sdlznode->name = isc_mem_get(mctx, sizeof(dns_name_t));
1638                 if (sdlznode->name == NULL) {
1639                         destroynode(sdlznode);
1640                         return (ISC_R_NOMEMORY);
1641                 }
1642                 dns_name_init(sdlznode->name, NULL);
1643                 result = dns_name_dup(newname, mctx, sdlznode->name);
1644                 if (result != ISC_R_SUCCESS) {
1645                         isc_mem_put(mctx, sdlznode->name, sizeof(dns_name_t));
1646                         destroynode(sdlznode);
1647                         return (result);
1648                 }
1649                 ISC_LIST_PREPEND(allnodes->nodelist, sdlznode, link);
1650                 if (allnodes->origin == NULL &&
1651                     dns_name_equal(newname, &sdlz->common.origin))
1652                         allnodes->origin = sdlznode;
1653         }
1654         return (dns_sdlz_putrr(sdlznode, type, ttl, data));
1655
1656 }
1657
1658 isc_result_t
1659 dns_sdlz_putsoa(dns_sdlzlookup_t *lookup, const char *mname, const char *rname,
1660                 isc_uint32_t serial)
1661 {
1662         char str[2 * DNS_NAME_MAXTEXT + 5 * (sizeof("2147483647")) + 7];
1663         int n;
1664
1665         REQUIRE(mname != NULL);
1666         REQUIRE(rname != NULL);
1667
1668         n = snprintf(str, sizeof str, "%s %s %u %u %u %u %u",
1669                      mname, rname, serial,
1670                      SDLZ_DEFAULT_REFRESH, SDLZ_DEFAULT_RETRY,
1671                      SDLZ_DEFAULT_EXPIRE, SDLZ_DEFAULT_MINIMUM);
1672         if (n >= (int)sizeof(str) || n < 0)
1673                 return (ISC_R_NOSPACE);
1674         return (dns_sdlz_putrr(lookup, "SOA", SDLZ_DEFAULT_TTL, str));
1675 }
1676
1677 isc_result_t
1678 dns_sdlzregister(const char *drivername, const dns_sdlzmethods_t *methods,
1679                  void *driverarg, unsigned int flags, isc_mem_t *mctx,
1680                  dns_sdlzimplementation_t **sdlzimp)
1681 {
1682
1683         dns_sdlzimplementation_t *imp;
1684         isc_result_t result;
1685
1686         /*
1687          * Performs checks to make sure data is as we expect it to be.
1688          */
1689         REQUIRE(drivername != NULL);
1690         REQUIRE(methods != NULL);
1691         REQUIRE(methods->findzone != NULL);
1692         REQUIRE(methods->lookup != NULL);
1693         REQUIRE(mctx != NULL);
1694         REQUIRE(sdlzimp != NULL && *sdlzimp == NULL);
1695         REQUIRE((flags & ~(DNS_SDLZFLAG_RELATIVEOWNER |
1696                            DNS_SDLZFLAG_RELATIVERDATA |
1697                            DNS_SDLZFLAG_THREADSAFE)) == 0);
1698
1699         /* Write debugging message to log */
1700         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1701                       DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1702                       "Registering SDLZ driver '%s'", drivername);
1703
1704         /*
1705          * Allocate memory for a sdlz_implementation object.  Error if
1706          * we cannot.
1707          */
1708         imp = isc_mem_get(mctx, sizeof(dns_sdlzimplementation_t));
1709         if (imp == NULL)
1710                 return (ISC_R_NOMEMORY);
1711
1712         /* Make sure memory region is set to all 0's */
1713         memset(imp, 0, sizeof(dns_sdlzimplementation_t));
1714
1715         /* Store the data passed into this method */
1716         imp->methods = methods;
1717         imp->driverarg = driverarg;
1718         imp->flags = flags;
1719         imp->mctx = NULL;
1720
1721         /* attach the new sdlz_implementation object to a memory context */
1722         isc_mem_attach(mctx, &imp->mctx);
1723
1724         /*
1725          * initialize the driver lock, error if we cannot
1726          * (used if a driver does not support multiple threads)
1727          */
1728         result = isc_mutex_init(&imp->driverlock);
1729         if (result != ISC_R_SUCCESS) {
1730                 UNEXPECTED_ERROR(__FILE__, __LINE__,
1731                                  "isc_mutex_init() failed: %s",
1732                                  isc_result_totext(result));
1733                 goto cleanup_mctx;
1734         }
1735
1736         imp->dlz_imp = NULL;
1737
1738         /*
1739          * register the DLZ driver.  Pass in our "extra" sdlz information as
1740          * a driverarg.  (that's why we stored the passed in driver arg in our
1741          * sdlz_implementation structure)  Also, store the dlz_implementation
1742          * structure in our sdlz_implementation.
1743          */
1744         result = dns_dlzregister(drivername, &sdlzmethods, imp, mctx,
1745                                  &imp->dlz_imp);
1746
1747         /* if registration fails, cleanup and get outta here. */
1748         if (result != ISC_R_SUCCESS)
1749                 goto cleanup_mutex;
1750
1751         *sdlzimp = imp;
1752
1753         return (ISC_R_SUCCESS);
1754
1755  cleanup_mutex:
1756         /* destroy the driver lock, we don't need it anymore */
1757         DESTROYLOCK(&imp->driverlock);
1758
1759  cleanup_mctx:
1760         /*
1761          * return the memory back to the available memory pool and
1762          * remove it from the memory context.
1763          */
1764         isc_mem_put(mctx, imp, sizeof(dns_sdlzimplementation_t));
1765         isc_mem_detach(&mctx);
1766         return (result);
1767 }
1768
1769 void
1770 dns_sdlzunregister(dns_sdlzimplementation_t **sdlzimp) {
1771         dns_sdlzimplementation_t *imp;
1772         isc_mem_t *mctx;
1773
1774         /* Write debugging message to log */
1775         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1776                       DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1777                       "Unregistering SDLZ driver.");
1778
1779         /*
1780          * Performs checks to make sure data is as we expect it to be.
1781          */
1782         REQUIRE(sdlzimp != NULL && *sdlzimp != NULL);
1783
1784         imp = *sdlzimp;
1785
1786         /* Unregister the DLZ driver implementation */
1787         dns_dlzunregister(&imp->dlz_imp);
1788
1789         /* destroy the driver lock, we don't need it anymore */
1790         DESTROYLOCK(&imp->driverlock);
1791
1792         mctx = imp->mctx;
1793
1794         /*
1795          * return the memory back to the available memory pool and
1796          * remove it from the memory context.
1797          */
1798         isc_mem_put(mctx, imp, sizeof(dns_sdlzimplementation_t));
1799         isc_mem_detach(&mctx);
1800
1801         *sdlzimp = NULL;
1802 }