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