BIND: update vendor tree to 9.5.2-P2
[dragonfly.git] / contrib / bind / 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.14.94.6 2009/06/26 06:23:47 marka 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, isc_boolean_t relative_names,
671                dns_dbiterator_t **iteratorp)
672 {
673         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
674         sdlz_dbiterator_t *sdlziter;
675         isc_result_t result;
676         isc_buffer_t b;
677         char zonestr[DNS_NAME_MAXTEXT + 1];
678
679         REQUIRE(VALID_SDLZDB(sdlz));
680
681         if (sdlz->dlzimp->methods->allnodes == NULL)
682                 return (ISC_R_NOTIMPLEMENTED);
683
684         isc_buffer_init(&b, zonestr, sizeof(zonestr));
685         result = dns_name_totext(&sdlz->common.origin, ISC_TRUE, &b);
686         if (result != ISC_R_SUCCESS)
687                 return (result);
688         isc_buffer_putuint8(&b, 0);
689
690         sdlziter = isc_mem_get(sdlz->common.mctx, sizeof(sdlz_dbiterator_t));
691         if (sdlziter == NULL)
692                 return (ISC_R_NOMEMORY);
693
694         sdlziter->common.methods = &dbiterator_methods;
695         sdlziter->common.db = NULL;
696         dns_db_attach(db, &sdlziter->common.db);
697         sdlziter->common.relative_names = relative_names;
698         sdlziter->common.magic = DNS_DBITERATOR_MAGIC;
699         ISC_LIST_INIT(sdlziter->nodelist);
700         sdlziter->current = NULL;
701         sdlziter->origin = NULL;
702
703         /* make sure strings are always lowercase */
704         dns_sdlz_tolower(zonestr);
705
706         MAYBE_LOCK(sdlz->dlzimp);
707         result = sdlz->dlzimp->methods->allnodes(zonestr,
708                                                  sdlz->dlzimp->driverarg,
709                                                  sdlz->dbdata, sdlziter);
710         MAYBE_UNLOCK(sdlz->dlzimp);
711         if (result != ISC_R_SUCCESS) {
712                 dns_dbiterator_t *iter = &sdlziter->common;
713                 dbiterator_destroy(&iter);
714                 return (result);
715         }
716
717         if (sdlziter->origin != NULL) {
718                 ISC_LIST_UNLINK(sdlziter->nodelist, sdlziter->origin, link);
719                 ISC_LIST_PREPEND(sdlziter->nodelist, sdlziter->origin, link);
720         }
721
722         *iteratorp = (dns_dbiterator_t *)sdlziter;
723
724         return (ISC_R_SUCCESS);
725 }
726
727 static isc_result_t
728 findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
729              dns_rdatatype_t type, dns_rdatatype_t covers,
730              isc_stdtime_t now, dns_rdataset_t *rdataset,
731              dns_rdataset_t *sigrdataset)
732 {
733         dns_rdatalist_t *list;
734         dns_sdlznode_t *sdlznode = (dns_sdlznode_t *)node;
735
736         REQUIRE(VALID_SDLZNODE(node));
737
738         UNUSED(db);
739         UNUSED(version);
740         UNUSED(covers);
741         UNUSED(now);
742         UNUSED(sigrdataset);
743
744         if (type == dns_rdatatype_sig || type == dns_rdatatype_rrsig)
745                 return (ISC_R_NOTIMPLEMENTED);
746
747         list = ISC_LIST_HEAD(sdlznode->lists);
748         while (list != NULL) {
749                 if (list->type == type)
750                         break;
751                 list = ISC_LIST_NEXT(list, link);
752         }
753         if (list == NULL)
754                 return (ISC_R_NOTFOUND);
755
756         list_tordataset(list, db, node, rdataset);
757
758         return (ISC_R_SUCCESS);
759 }
760
761 static isc_result_t
762 find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
763      dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
764      dns_dbnode_t **nodep, dns_name_t *foundname,
765      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
766 {
767         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
768         dns_dbnode_t *node = NULL;
769         dns_fixedname_t fname;
770         dns_rdataset_t xrdataset;
771         dns_name_t *xname;
772         unsigned int nlabels, olabels;
773         isc_result_t result;
774         unsigned int i;
775
776         REQUIRE(VALID_SDLZDB(sdlz));
777         REQUIRE(nodep == NULL || *nodep == NULL);
778         REQUIRE(version == NULL || version == (void *) &dummy);
779
780         UNUSED(options);
781         UNUSED(sdlz);
782
783         if (!dns_name_issubdomain(name, &db->origin))
784                 return (DNS_R_NXDOMAIN);
785
786         olabels = dns_name_countlabels(&db->origin);
787         nlabels = dns_name_countlabels(name);
788
789         dns_fixedname_init(&fname);
790         xname = dns_fixedname_name(&fname);
791
792         if (rdataset == NULL) {
793                 dns_rdataset_init(&xrdataset);
794                 rdataset = &xrdataset;
795         }
796
797         result = DNS_R_NXDOMAIN;
798
799         for (i = olabels; i <= nlabels; i++) {
800                 /*
801                  * Unless this is an explicit lookup at the origin, don't
802                  * look at the origin.
803                  */
804                 if (i == olabels && i != nlabels)
805                         continue;
806
807                 /*
808                  * Look up the next label.
809                  */
810                 dns_name_getlabelsequence(name, nlabels - i, i, xname);
811                 result = findnode(db, xname, ISC_FALSE, &node);
812                 if (result != ISC_R_SUCCESS) {
813                         result = DNS_R_NXDOMAIN;
814                         continue;
815                 }
816
817                 /*
818                  * Look for a DNAME at the current label, unless this is
819                  * the qname.
820                  */
821                 if (i < nlabels) {
822                         result = findrdataset(db, node, version,
823                                               dns_rdatatype_dname,
824                                               0, now, rdataset, sigrdataset);
825                         if (result == ISC_R_SUCCESS) {
826                                 result = DNS_R_DNAME;
827                                 break;
828                         }
829                 }
830
831                 /*
832                  * Look for an NS at the current label, unless this is the
833                  * origin or glue is ok.
834                  */
835                 if (i != olabels && (options & DNS_DBFIND_GLUEOK) == 0) {
836                         result = findrdataset(db, node, version,
837                                               dns_rdatatype_ns,
838                                               0, now, rdataset, sigrdataset);
839                         if (result == ISC_R_SUCCESS) {
840                                 if (i == nlabels && type == dns_rdatatype_any)
841                                 {
842                                         result = DNS_R_ZONECUT;
843                                         dns_rdataset_disassociate(rdataset);
844                                         if (sigrdataset != NULL &&
845                                             dns_rdataset_isassociated
846                                                         (sigrdataset)) {
847                                                 dns_rdataset_disassociate
848                                                         (sigrdataset);
849                                         }
850                                 } else
851                                         result = DNS_R_DELEGATION;
852                                 break;
853                         }
854                 }
855
856                 /*
857                  * If the current name is not the qname, add another label
858                  * and try again.
859                  */
860                 if (i < nlabels) {
861                         destroynode(node);
862                         node = NULL;
863                         continue;
864                 }
865
866                 /*
867                  * If we're looking for ANY, we're done.
868                  */
869                 if (type == dns_rdatatype_any) {
870                         result = ISC_R_SUCCESS;
871                         break;
872                 }
873
874                 /*
875                  * Look for the qtype.
876                  */
877                 result = findrdataset(db, node, version, type,
878                                       0, now, rdataset, sigrdataset);
879                 if (result == ISC_R_SUCCESS)
880                         break;
881
882                 /*
883                  * Look for a CNAME
884                  */
885                 if (type != dns_rdatatype_cname) {
886                         result = findrdataset(db, node, version,
887                                               dns_rdatatype_cname,
888                                               0, now, rdataset, sigrdataset);
889                         if (result == ISC_R_SUCCESS) {
890                                 result = DNS_R_CNAME;
891                                 break;
892                         }
893                 }
894
895                 result = DNS_R_NXRRSET;
896                 break;
897         }
898
899         if (rdataset == &xrdataset && dns_rdataset_isassociated(rdataset))
900                 dns_rdataset_disassociate(rdataset);
901
902         if (foundname != NULL) {
903                 isc_result_t xresult;
904
905                 xresult = dns_name_copy(xname, foundname, NULL);
906                 if (xresult != ISC_R_SUCCESS) {
907                         if (node != NULL)
908                                 destroynode(node);
909                         if (dns_rdataset_isassociated(rdataset))
910                                 dns_rdataset_disassociate(rdataset);
911                         return (DNS_R_BADDB);
912                 }
913         }
914
915         if (nodep != NULL)
916                 *nodep = node;
917         else if (node != NULL)
918                 detachnode(db, &node);
919
920         return (result);
921 }
922
923 static isc_result_t
924 allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
925              isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
926 {
927         sdlz_rdatasetiter_t *iterator;
928
929         REQUIRE(version == NULL || version == &dummy);
930
931         UNUSED(version);
932         UNUSED(now);
933
934         iterator = isc_mem_get(db->mctx, sizeof(sdlz_rdatasetiter_t));
935         if (iterator == NULL)
936                 return (ISC_R_NOMEMORY);
937
938         iterator->common.magic = DNS_RDATASETITER_MAGIC;
939         iterator->common.methods = &rdatasetiter_methods;
940         iterator->common.db = db;
941         iterator->common.node = NULL;
942         attachnode(db, node, &iterator->common.node);
943         iterator->common.version = version;
944         iterator->common.now = now;
945
946         *iteratorp = (dns_rdatasetiter_t *)iterator;
947
948         return (ISC_R_SUCCESS);
949 }
950
951 static isc_result_t
952 addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
953             isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
954             dns_rdataset_t *addedrdataset)
955 {
956         UNUSED(db);
957         UNUSED(node);
958         UNUSED(version);
959         UNUSED(now);
960         UNUSED(rdataset);
961         UNUSED(options);
962         UNUSED(addedrdataset);
963
964         return (ISC_R_NOTIMPLEMENTED);
965 }
966
967 static isc_result_t
968 subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
969                  dns_rdataset_t *rdataset, unsigned int options,
970                  dns_rdataset_t *newrdataset)
971 {
972         UNUSED(db);
973         UNUSED(node);
974         UNUSED(version);
975         UNUSED(rdataset);
976         UNUSED(options);
977         UNUSED(newrdataset);
978
979         return (ISC_R_NOTIMPLEMENTED);
980 }
981
982 static isc_result_t
983 deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
984                dns_rdatatype_t type, dns_rdatatype_t covers)
985 {
986         UNUSED(db);
987         UNUSED(node);
988         UNUSED(version);
989         UNUSED(type);
990         UNUSED(covers);
991
992         return (ISC_R_NOTIMPLEMENTED);
993 }
994
995 static isc_boolean_t
996 issecure(dns_db_t *db) {
997         UNUSED(db);
998
999         return (ISC_FALSE);
1000 }
1001
1002 static unsigned int
1003 nodecount(dns_db_t *db) {
1004         UNUSED(db);
1005
1006         return (0);
1007 }
1008
1009 static isc_boolean_t
1010 ispersistent(dns_db_t *db) {
1011         UNUSED(db);
1012         return (ISC_TRUE);
1013 }
1014
1015 static void
1016 overmem(dns_db_t *db, isc_boolean_t overmem) {
1017         UNUSED(db);
1018         UNUSED(overmem);
1019 }
1020
1021 static void
1022 settask(dns_db_t *db, isc_task_t *task) {
1023         UNUSED(db);
1024         UNUSED(task);
1025 }
1026
1027
1028 static dns_dbmethods_t sdlzdb_methods = {
1029         attach,
1030         detach,
1031         beginload,
1032         endload,
1033         dump,
1034         currentversion,
1035         newversion,
1036         attachversion,
1037         closeversion,
1038         findnode,
1039         find,
1040         findzonecut,
1041         attachnode,
1042         detachnode,
1043         expirenode,
1044         printnode,
1045         createiterator,
1046         findrdataset,
1047         allrdatasets,
1048         addrdataset,
1049         subtractrdataset,
1050         deleterdataset,
1051         issecure,
1052         nodecount,
1053         ispersistent,
1054         overmem,
1055         settask,
1056         NULL,
1057         NULL,
1058         NULL
1059 };
1060
1061 /*
1062  * Database Iterator Methods.  These methods were "borrowed" from the SDB
1063  * driver interface.  See the SDB driver interface documentation for more info.
1064  */
1065
1066 static void
1067 dbiterator_destroy(dns_dbiterator_t **iteratorp) {
1068         sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)(*iteratorp);
1069         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)sdlziter->common.db;
1070
1071         while (!ISC_LIST_EMPTY(sdlziter->nodelist)) {
1072                 dns_sdlznode_t *node;
1073                 node = ISC_LIST_HEAD(sdlziter->nodelist);
1074                 ISC_LIST_UNLINK(sdlziter->nodelist, node, link);
1075                 destroynode(node);
1076         }
1077
1078         dns_db_detach(&sdlziter->common.db);
1079         isc_mem_put(sdlz->common.mctx, sdlziter, sizeof(sdlz_dbiterator_t));
1080
1081         *iteratorp = NULL;
1082 }
1083
1084 static isc_result_t
1085 dbiterator_first(dns_dbiterator_t *iterator) {
1086         sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1087
1088         sdlziter->current = ISC_LIST_HEAD(sdlziter->nodelist);
1089         if (sdlziter->current == NULL)
1090                 return (ISC_R_NOMORE);
1091         else
1092                 return (ISC_R_SUCCESS);
1093 }
1094
1095 static isc_result_t
1096 dbiterator_last(dns_dbiterator_t *iterator) {
1097         sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1098
1099         sdlziter->current = ISC_LIST_TAIL(sdlziter->nodelist);
1100         if (sdlziter->current == NULL)
1101                 return (ISC_R_NOMORE);
1102         else
1103                 return (ISC_R_SUCCESS);
1104 }
1105
1106 static isc_result_t
1107 dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
1108         sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1109
1110         sdlziter->current = ISC_LIST_HEAD(sdlziter->nodelist);
1111         while (sdlziter->current != NULL) {
1112                 if (dns_name_equal(sdlziter->current->name, name))
1113                         return (ISC_R_SUCCESS);
1114                 sdlziter->current = ISC_LIST_NEXT(sdlziter->current, link);
1115         }
1116         return (ISC_R_NOTFOUND);
1117 }
1118
1119 static isc_result_t
1120 dbiterator_prev(dns_dbiterator_t *iterator) {
1121         sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1122
1123         sdlziter->current = ISC_LIST_PREV(sdlziter->current, link);
1124         if (sdlziter->current == NULL)
1125                 return (ISC_R_NOMORE);
1126         else
1127                 return (ISC_R_SUCCESS);
1128 }
1129
1130 static isc_result_t
1131 dbiterator_next(dns_dbiterator_t *iterator) {
1132         sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1133
1134         sdlziter->current = ISC_LIST_NEXT(sdlziter->current, link);
1135         if (sdlziter->current == NULL)
1136                 return (ISC_R_NOMORE);
1137         else
1138                 return (ISC_R_SUCCESS);
1139 }
1140
1141 static isc_result_t
1142 dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
1143                    dns_name_t *name)
1144 {
1145         sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1146
1147         attachnode(iterator->db, sdlziter->current, nodep);
1148         if (name != NULL)
1149                 return (dns_name_copy(sdlziter->current->name, name, NULL));
1150         return (ISC_R_SUCCESS);
1151 }
1152
1153 static isc_result_t
1154 dbiterator_pause(dns_dbiterator_t *iterator) {
1155         UNUSED(iterator);
1156         return (ISC_R_SUCCESS);
1157 }
1158
1159 static isc_result_t
1160 dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
1161         UNUSED(iterator);
1162         return (dns_name_copy(dns_rootname, name, NULL));
1163 }
1164
1165 /*
1166  * Rdataset Methods. These methods were "borrowed" from the SDB driver
1167  * interface.  See the SDB driver interface documentation for more info.
1168  */
1169
1170 static void
1171 disassociate(dns_rdataset_t *rdataset) {
1172         dns_dbnode_t *node = rdataset->private5;
1173         dns_sdlznode_t *sdlznode = (dns_sdlznode_t *) node;
1174         dns_db_t *db = (dns_db_t *) sdlznode->sdlz;
1175
1176         detachnode(db, &node);
1177         isc__rdatalist_disassociate(rdataset);
1178 }
1179
1180 static void
1181 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
1182         dns_dbnode_t *node = source->private5;
1183         dns_sdlznode_t *sdlznode = (dns_sdlznode_t *) node;
1184         dns_db_t *db = (dns_db_t *) sdlznode->sdlz;
1185         dns_dbnode_t *tempdb = NULL;
1186
1187         isc__rdatalist_clone(source, target);
1188         attachnode(db, node, &tempdb);
1189         source->private5 = tempdb;
1190 }
1191
1192 static dns_rdatasetmethods_t rdataset_methods = {
1193         disassociate,
1194         isc__rdatalist_first,
1195         isc__rdatalist_next,
1196         isc__rdatalist_current,
1197         rdataset_clone,
1198         isc__rdatalist_count,
1199         isc__rdatalist_addnoqname,
1200         isc__rdatalist_getnoqname,
1201         NULL,
1202         NULL,
1203         NULL
1204 };
1205
1206 static void
1207 list_tordataset(dns_rdatalist_t *rdatalist,
1208                 dns_db_t *db, dns_dbnode_t *node,
1209                 dns_rdataset_t *rdataset)
1210 {
1211         /*
1212          * The sdlz rdataset is an rdatalist with some additions.
1213          *      - private1 & private2 are used by the rdatalist.
1214          *      - private3 & private 4 are unused.
1215          *      - private5 is the node.
1216          */
1217
1218         /* This should never fail. */
1219         RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
1220                       ISC_R_SUCCESS);
1221
1222         rdataset->methods = &rdataset_methods;
1223         dns_db_attachnode(db, node, &rdataset->private5);
1224 }
1225
1226 /*
1227  * SDLZ core methods. This is the core of the new DLZ functionality.
1228  */
1229
1230 /*%
1231  * Build a 'bind' database driver structure to be returned by
1232  * either the find zone or the allow zone transfer method.
1233  * This method is only available in this source file, it is
1234  * not made available anywhere else.
1235  */
1236
1237 static isc_result_t
1238 dns_sdlzcreateDBP(isc_mem_t *mctx, void *driverarg, void *dbdata,
1239                   dns_name_t *name, dns_rdataclass_t rdclass, dns_db_t **dbp)
1240 {
1241         isc_result_t result;
1242         dns_sdlz_db_t *sdlzdb;
1243         dns_sdlzimplementation_t *imp;
1244
1245         /* check that things are as we expect */
1246         REQUIRE(dbp != NULL && *dbp == NULL);
1247         REQUIRE(name != NULL);
1248
1249         imp = (dns_sdlzimplementation_t *) driverarg;
1250
1251         /* allocate and zero memory for driver structure */
1252         sdlzdb = isc_mem_get(mctx, sizeof(dns_sdlz_db_t));
1253         if (sdlzdb == NULL)
1254                 return (ISC_R_NOMEMORY);
1255         memset(sdlzdb, 0, sizeof(dns_sdlz_db_t));
1256
1257         /* initialize and set origin */
1258         dns_name_init(&sdlzdb->common.origin, NULL);
1259         result = dns_name_dupwithoffsets(name, mctx, &sdlzdb->common.origin);
1260         if (result != ISC_R_SUCCESS)
1261                 goto mem_cleanup;
1262
1263         /* initialize the reference count mutex */
1264         result = isc_mutex_init(&sdlzdb->refcnt_lock);
1265         if (result != ISC_R_SUCCESS)
1266                 goto name_cleanup;
1267
1268         /* set the rest of the database structure attributes */
1269         sdlzdb->dlzimp = imp;
1270         sdlzdb->common.methods = &sdlzdb_methods;
1271         sdlzdb->common.attributes = 0;
1272         sdlzdb->common.rdclass = rdclass;
1273         sdlzdb->common.mctx = NULL;
1274         sdlzdb->dbdata = dbdata;
1275         sdlzdb->references = 1;
1276
1277         /* attach to the memory context */
1278         isc_mem_attach(mctx, &sdlzdb->common.mctx);
1279
1280         /* mark structure as valid */
1281         sdlzdb->common.magic = DNS_DB_MAGIC;
1282         sdlzdb->common.impmagic = SDLZDB_MAGIC;
1283         *dbp = (dns_db_t *) sdlzdb;
1284
1285         return (result);
1286
1287         /*
1288          * reference count mutex could not be initialized, clean up
1289          * name memory
1290          */
1291  name_cleanup:
1292         dns_name_free(&sdlzdb->common.origin, mctx);
1293  mem_cleanup:
1294         isc_mem_put(mctx, sdlzdb, sizeof(dns_sdlz_db_t));
1295         return (result);
1296 }
1297
1298 static isc_result_t
1299 dns_sdlzallowzonexfr(void *driverarg, void *dbdata, isc_mem_t *mctx,
1300                      dns_rdataclass_t rdclass, dns_name_t *name,
1301                      isc_sockaddr_t *clientaddr, dns_db_t **dbp)
1302 {
1303         isc_buffer_t b;
1304         isc_buffer_t b2;
1305         char namestr[DNS_NAME_MAXTEXT + 1];
1306         char clientstr[(sizeof "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")
1307                        + 1];
1308         isc_netaddr_t netaddr;
1309         isc_result_t result;
1310         dns_sdlzimplementation_t *imp;
1311
1312         /*
1313          * Perform checks to make sure data is as we expect it to be.
1314          */
1315         REQUIRE(driverarg != NULL);
1316         REQUIRE(name != NULL);
1317         REQUIRE(clientaddr != NULL);
1318         REQUIRE(dbp != NULL && *dbp == NULL);
1319
1320         imp = (dns_sdlzimplementation_t *) driverarg;
1321
1322         /* Convert DNS name to ascii text */
1323         isc_buffer_init(&b, namestr, sizeof(namestr));
1324         result = dns_name_totext(name, ISC_TRUE, &b);
1325         if (result != ISC_R_SUCCESS)
1326                 return (result);
1327         isc_buffer_putuint8(&b, 0);
1328
1329         /* convert client address to ascii text */
1330         isc_buffer_init(&b2, clientstr, sizeof(clientstr));
1331         isc_netaddr_fromsockaddr(&netaddr, clientaddr);
1332         result = isc_netaddr_totext(&netaddr, &b2);
1333         if (result != ISC_R_SUCCESS)
1334                 return (result);
1335         isc_buffer_putuint8(&b2, 0);
1336
1337         /* make sure strings are always lowercase */
1338         dns_sdlz_tolower(namestr);
1339         dns_sdlz_tolower(clientstr);
1340
1341         /* Call SDLZ driver's find zone method */
1342         if (imp->methods->allowzonexfr != NULL) {
1343                 MAYBE_LOCK(imp);
1344                 result = imp->methods->allowzonexfr(imp->driverarg, dbdata,
1345                                                     namestr, clientstr);
1346                 MAYBE_UNLOCK(imp);
1347                 /*
1348                  * if zone is supported and transfers allowed build a 'bind'
1349                  * database driver
1350                  */
1351                 if (result == ISC_R_SUCCESS)
1352                         result = dns_sdlzcreateDBP(mctx, driverarg, dbdata,
1353                                                    name, rdclass, dbp);
1354                 return (result);
1355         }
1356
1357         return (ISC_R_NOTIMPLEMENTED);
1358 }
1359
1360 static isc_result_t
1361 dns_sdlzcreate(isc_mem_t *mctx, const char *dlzname, unsigned int argc,
1362                char *argv[], void *driverarg, void **dbdata)
1363 {
1364         dns_sdlzimplementation_t *imp;
1365         isc_result_t result = ISC_R_NOTFOUND;
1366
1367         /* Write debugging message to log */
1368         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1369                       DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1370                       "Loading SDLZ driver.");
1371
1372         /*
1373          * Performs checks to make sure data is as we expect it to be.
1374          */
1375         REQUIRE(driverarg != NULL);
1376         REQUIRE(dlzname != NULL);
1377         REQUIRE(dbdata != NULL);
1378         UNUSED(mctx);
1379
1380         imp = driverarg;
1381
1382         /* If the create method exists, call it. */
1383         if (imp->methods->create != NULL) {
1384                 MAYBE_LOCK(imp);
1385                 result = imp->methods->create(dlzname, argc, argv,
1386                                               imp->driverarg, dbdata);
1387                 MAYBE_UNLOCK(imp);
1388         }
1389
1390         /* Write debugging message to log */
1391         if (result == ISC_R_SUCCESS) {
1392                 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1393                               DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1394                               "SDLZ driver loaded successfully.");
1395         } else {
1396                 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1397                               DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1398                               "SDLZ driver failed to load.");
1399         }
1400
1401         return (result);
1402 }
1403
1404 static void
1405 dns_sdlzdestroy(void *driverdata, void **dbdata)
1406 {
1407
1408         dns_sdlzimplementation_t *imp;
1409
1410         /* Write debugging message to log */
1411         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1412                       DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1413                       "Unloading SDLZ driver.");
1414
1415         imp = driverdata;
1416
1417         /* If the destroy method exists, call it. */
1418         if (imp->methods->destroy != NULL) {
1419                 MAYBE_LOCK(imp);
1420                 imp->methods->destroy(imp->driverarg, dbdata);
1421                 MAYBE_UNLOCK(imp);
1422         }
1423 }
1424
1425 static isc_result_t
1426 dns_sdlzfindzone(void *driverarg, void *dbdata, isc_mem_t *mctx,
1427                  dns_rdataclass_t rdclass, dns_name_t *name, dns_db_t **dbp)
1428 {
1429         isc_buffer_t b;
1430         char namestr[DNS_NAME_MAXTEXT + 1];
1431         isc_result_t result;
1432         dns_sdlzimplementation_t *imp;
1433
1434         /*
1435          * Perform checks to make sure data is as we expect it to be.
1436          */
1437         REQUIRE(driverarg != NULL);
1438         REQUIRE(name != NULL);
1439         REQUIRE(dbp != NULL && *dbp == NULL);
1440
1441         imp = (dns_sdlzimplementation_t *) driverarg;
1442
1443         /* Convert DNS name to ascii text */
1444         isc_buffer_init(&b, namestr, sizeof(namestr));
1445         result = dns_name_totext(name, ISC_TRUE, &b);
1446         if (result != ISC_R_SUCCESS)
1447                 return (result);
1448         isc_buffer_putuint8(&b, 0);
1449
1450         /* make sure strings are always lowercase */
1451         dns_sdlz_tolower(namestr);
1452
1453         /* Call SDLZ driver's find zone method */
1454         MAYBE_LOCK(imp);
1455         result = imp->methods->findzone(imp->driverarg, dbdata, namestr);
1456         MAYBE_UNLOCK(imp);
1457
1458         /*
1459          * if zone is supported build a 'bind' database driver
1460          * structure to return
1461          */
1462         if (result == ISC_R_SUCCESS)
1463                 result = dns_sdlzcreateDBP(mctx, driverarg, dbdata, name,
1464                                            rdclass, dbp);
1465
1466         return (result);
1467 }
1468
1469 static dns_dlzmethods_t sdlzmethods = {
1470         dns_sdlzcreate,
1471         dns_sdlzdestroy,
1472         dns_sdlzfindzone,
1473         dns_sdlzallowzonexfr
1474 };
1475
1476 /*
1477  * Public functions.
1478  */
1479
1480 isc_result_t
1481 dns_sdlz_putrr(dns_sdlzlookup_t *lookup, const char *type, dns_ttl_t ttl,
1482                const char *data)
1483 {
1484         dns_rdatalist_t *rdatalist;
1485         dns_rdata_t *rdata;
1486         dns_rdatatype_t typeval;
1487         isc_consttextregion_t r;
1488         isc_buffer_t b;
1489         isc_buffer_t *rdatabuf = NULL;
1490         isc_lex_t *lex;
1491         isc_result_t result;
1492         unsigned int size;
1493         isc_mem_t *mctx;
1494         dns_name_t *origin;
1495
1496         REQUIRE(VALID_SDLZLOOKUP(lookup));
1497         REQUIRE(type != NULL);
1498         REQUIRE(data != NULL);
1499
1500         mctx = lookup->sdlz->common.mctx;
1501
1502         r.base = type;
1503         r.length = strlen(type);
1504         result = dns_rdatatype_fromtext(&typeval, (void *) &r);
1505         if (result != ISC_R_SUCCESS)
1506                 return (result);
1507
1508         rdatalist = ISC_LIST_HEAD(lookup->lists);
1509         while (rdatalist != NULL) {
1510                 if (rdatalist->type == typeval)
1511                         break;
1512                 rdatalist = ISC_LIST_NEXT(rdatalist, link);
1513         }
1514
1515         if (rdatalist == NULL) {
1516                 rdatalist = isc_mem_get(mctx, sizeof(dns_rdatalist_t));
1517                 if (rdatalist == NULL)
1518                         return (ISC_R_NOMEMORY);
1519                 rdatalist->rdclass = lookup->sdlz->common.rdclass;
1520                 rdatalist->type = typeval;
1521                 rdatalist->covers = 0;
1522                 rdatalist->ttl = ttl;
1523                 ISC_LIST_INIT(rdatalist->rdata);
1524                 ISC_LINK_INIT(rdatalist, link);
1525                 ISC_LIST_APPEND(lookup->lists, rdatalist, link);
1526         } else
1527                 if (rdatalist->ttl != ttl)
1528                         return (DNS_R_BADTTL);
1529
1530         rdata = isc_mem_get(mctx, sizeof(dns_rdata_t));
1531         if (rdata == NULL)
1532                 return (ISC_R_NOMEMORY);
1533         dns_rdata_init(rdata);
1534
1535         if ((lookup->sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVERDATA) != 0)
1536                 origin = &lookup->sdlz->common.origin;
1537         else
1538                 origin = dns_rootname;
1539
1540         lex = NULL;
1541         result = isc_lex_create(mctx, 64, &lex);
1542         if (result != ISC_R_SUCCESS)
1543                 goto failure;
1544
1545         size = initial_size(data);
1546         do {
1547                 isc_buffer_init(&b, data, strlen(data));
1548                 isc_buffer_add(&b, strlen(data));
1549
1550                 result = isc_lex_openbuffer(lex, &b);
1551                 if (result != ISC_R_SUCCESS)
1552                         goto failure;
1553
1554                 rdatabuf = NULL;
1555                 result = isc_buffer_allocate(mctx, &rdatabuf, size);
1556                 if (result != ISC_R_SUCCESS)
1557                         goto failure;
1558
1559                 result = dns_rdata_fromtext(rdata, rdatalist->rdclass,
1560                                             rdatalist->type, lex,
1561                                             origin, ISC_FALSE,
1562                                             mctx, rdatabuf,
1563                                             &lookup->callbacks);
1564                 if (result != ISC_R_SUCCESS)
1565                         isc_buffer_free(&rdatabuf);
1566                 size *= 2;
1567         } while (result == ISC_R_NOSPACE);
1568
1569         if (result != ISC_R_SUCCESS)
1570                 goto failure;
1571
1572         ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1573         ISC_LIST_APPEND(lookup->buffers, rdatabuf, link);
1574
1575         if (lex != NULL)
1576                 isc_lex_destroy(&lex);
1577
1578         return (ISC_R_SUCCESS);
1579
1580  failure:
1581         if (rdatabuf != NULL)
1582                 isc_buffer_free(&rdatabuf);
1583         if (lex != NULL)
1584                 isc_lex_destroy(&lex);
1585         isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
1586
1587         return (result);
1588 }
1589
1590 isc_result_t
1591 dns_sdlz_putnamedrr(dns_sdlzallnodes_t *allnodes, const char *name,
1592                     const char *type, dns_ttl_t ttl, const char *data)
1593 {
1594         dns_name_t *newname, *origin;
1595         dns_fixedname_t fnewname;
1596         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)allnodes->common.db;
1597         dns_sdlznode_t *sdlznode;
1598         isc_mem_t *mctx = sdlz->common.mctx;
1599         isc_buffer_t b;
1600         isc_result_t result;
1601
1602         dns_fixedname_init(&fnewname);
1603         newname = dns_fixedname_name(&fnewname);
1604
1605         if ((sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVERDATA) != 0)
1606                 origin = &sdlz->common.origin;
1607         else
1608                 origin = dns_rootname;
1609         isc_buffer_init(&b, name, strlen(name));
1610         isc_buffer_add(&b, strlen(name));
1611
1612         result = dns_name_fromtext(newname, &b, origin, ISC_FALSE, NULL);
1613         if (result != ISC_R_SUCCESS)
1614                 return (result);
1615
1616         if (allnodes->common.relative_names) {
1617                 /* All names are relative to the root */
1618                 unsigned int nlabels = dns_name_countlabels(newname);
1619                 dns_name_getlabelsequence(newname, 0, nlabels - 1, newname);
1620         }
1621
1622         sdlznode = ISC_LIST_HEAD(allnodes->nodelist);
1623         if (sdlznode == NULL || !dns_name_equal(sdlznode->name, newname)) {
1624                 sdlznode = NULL;
1625                 result = createnode(sdlz, &sdlznode);
1626                 if (result != ISC_R_SUCCESS)
1627                         return (result);
1628                 sdlznode->name = isc_mem_get(mctx, sizeof(dns_name_t));
1629                 if (sdlznode->name == NULL) {
1630                         destroynode(sdlznode);
1631                         return (ISC_R_NOMEMORY);
1632                 }
1633                 dns_name_init(sdlznode->name, NULL);
1634                 result = dns_name_dup(newname, mctx, sdlznode->name);
1635                 if (result != ISC_R_SUCCESS) {
1636                         isc_mem_put(mctx, sdlznode->name, sizeof(dns_name_t));
1637                         destroynode(sdlznode);
1638                         return (result);
1639                 }
1640                 ISC_LIST_PREPEND(allnodes->nodelist, sdlznode, link);
1641                 if (allnodes->origin == NULL &&
1642                     dns_name_equal(newname, &sdlz->common.origin))
1643                         allnodes->origin = sdlznode;
1644         }
1645         return (dns_sdlz_putrr(sdlznode, type, ttl, data));
1646
1647 }
1648
1649 isc_result_t
1650 dns_sdlz_putsoa(dns_sdlzlookup_t *lookup, const char *mname, const char *rname,
1651                 isc_uint32_t serial)
1652 {
1653         char str[2 * DNS_NAME_MAXTEXT + 5 * (sizeof("2147483647")) + 7];
1654         int n;
1655
1656         REQUIRE(mname != NULL);
1657         REQUIRE(rname != NULL);
1658
1659         n = snprintf(str, sizeof str, "%s %s %u %u %u %u %u",
1660                      mname, rname, serial,
1661                      SDLZ_DEFAULT_REFRESH, SDLZ_DEFAULT_RETRY,
1662                      SDLZ_DEFAULT_EXPIRE, SDLZ_DEFAULT_MINIMUM);
1663         if (n >= (int)sizeof(str) || n < 0)
1664                 return (ISC_R_NOSPACE);
1665         return (dns_sdlz_putrr(lookup, "SOA", SDLZ_DEFAULT_TTL, str));
1666 }
1667
1668 isc_result_t
1669 dns_sdlzregister(const char *drivername, const dns_sdlzmethods_t *methods,
1670                  void *driverarg, unsigned int flags, isc_mem_t *mctx,
1671                  dns_sdlzimplementation_t **sdlzimp)
1672 {
1673
1674         dns_sdlzimplementation_t *imp;
1675         isc_result_t result;
1676
1677         /*
1678          * Performs checks to make sure data is as we expect it to be.
1679          */
1680         REQUIRE(drivername != NULL);
1681         REQUIRE(methods != NULL);
1682         REQUIRE(methods->findzone != NULL);
1683         REQUIRE(methods->lookup != NULL);
1684         REQUIRE(mctx != NULL);
1685         REQUIRE(sdlzimp != NULL && *sdlzimp == NULL);
1686         REQUIRE((flags & ~(DNS_SDLZFLAG_RELATIVEOWNER |
1687                            DNS_SDLZFLAG_RELATIVERDATA |
1688                            DNS_SDLZFLAG_THREADSAFE)) == 0);
1689
1690         /* Write debugging message to log */
1691         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1692                       DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1693                       "Registering SDLZ driver '%s'", drivername);
1694
1695         /*
1696          * Allocate memory for a sdlz_implementation object.  Error if
1697          * we cannot.
1698          */
1699         imp = isc_mem_get(mctx, sizeof(dns_sdlzimplementation_t));
1700         if (imp == NULL)
1701                 return (ISC_R_NOMEMORY);
1702
1703         /* Make sure memory region is set to all 0's */
1704         memset(imp, 0, sizeof(dns_sdlzimplementation_t));
1705
1706         /* Store the data passed into this method */
1707         imp->methods = methods;
1708         imp->driverarg = driverarg;
1709         imp->flags = flags;
1710         imp->mctx = NULL;
1711
1712         /* attach the new sdlz_implementation object to a memory context */
1713         isc_mem_attach(mctx, &imp->mctx);
1714
1715         /*
1716          * initialize the driver lock, error if we cannot
1717          * (used if a driver does not support multiple threads)
1718          */
1719         result = isc_mutex_init(&imp->driverlock);
1720         if (result != ISC_R_SUCCESS) {
1721                 UNEXPECTED_ERROR(__FILE__, __LINE__,
1722                                  "isc_mutex_init() failed: %s",
1723                                  isc_result_totext(result));
1724                 goto cleanup_mctx;
1725         }
1726
1727         imp->dlz_imp = NULL;
1728
1729         /*
1730          * register the DLZ driver.  Pass in our "extra" sdlz information as
1731          * a driverarg.  (that's why we stored the passed in driver arg in our
1732          * sdlz_implementation structure)  Also, store the dlz_implementation
1733          * structure in our sdlz_implementation.
1734          */
1735         result = dns_dlzregister(drivername, &sdlzmethods, imp, mctx,
1736                                  &imp->dlz_imp);
1737
1738         /* if registration fails, cleanup and get outta here. */
1739         if (result != ISC_R_SUCCESS)
1740                 goto cleanup_mutex;
1741
1742         *sdlzimp = imp;
1743
1744         return (ISC_R_SUCCESS);
1745
1746  cleanup_mutex:
1747         /* destroy the driver lock, we don't need it anymore */
1748         DESTROYLOCK(&imp->driverlock);
1749
1750  cleanup_mctx:
1751         /*
1752          * return the memory back to the available memory pool and
1753          * remove it from the memory context.
1754          */
1755         isc_mem_put(mctx, imp, sizeof(dns_sdlzimplementation_t));
1756         isc_mem_detach(&mctx);
1757         return (result);
1758 }
1759
1760 void
1761 dns_sdlzunregister(dns_sdlzimplementation_t **sdlzimp) {
1762         dns_sdlzimplementation_t *imp;
1763         isc_mem_t *mctx;
1764
1765         /* Write debugging message to log */
1766         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1767                       DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1768                       "Unregistering SDLZ driver.");
1769
1770         /*
1771          * Performs checks to make sure data is as we expect it to be.
1772          */
1773         REQUIRE(sdlzimp != NULL && *sdlzimp != NULL);
1774
1775         imp = *sdlzimp;
1776
1777         /* Unregister the DLZ driver implementation */
1778         dns_dlzunregister(&imp->dlz_imp);
1779
1780         /* destroy the driver lock, we don't need it anymore */
1781         DESTROYLOCK(&imp->driverlock);
1782
1783         mctx = imp->mctx;
1784
1785         /*
1786          * return the memory back to the available memory pool and
1787          * remove it from the memory context.
1788          */
1789         isc_mem_put(mctx, imp, sizeof(dns_sdlzimplementation_t));
1790         isc_mem_detach(&mctx);
1791
1792         *sdlzimp = NULL;
1793 }