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