]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bind9/lib/dns/sdlz.c
Integrate OpenBSD rev 1.5 of x86emu.c.
[FreeBSD/FreeBSD.git] / contrib / bind9 / lib / dns / sdlz.c
1 /*
2  * Portions Copyright (C) 2005-2009  Internet Systems Consortium, Inc. ("ISC")
3  * Portions Copyright (C) 1999-2001  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /*
19  * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
20  *
21  * Permission to use, copy, modify, and distribute this software for any
22  * purpose with or without fee is hereby granted, provided that the
23  * above copyright notice and this permission notice appear in all
24  * copies.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
27  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
29  * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
30  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
31  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
32  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
33  * USE OR PERFORMANCE OF THIS SOFTWARE.
34  *
35  * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
36  * conceived and contributed by Rob Butler.
37  *
38  * Permission to use, copy, modify, and distribute this software for any
39  * purpose with or without fee is hereby granted, provided that the
40  * above copyright notice and this permission notice appear in all
41  * copies.
42  *
43  * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
44  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
45  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
46  * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
47  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
48  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
49  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
50  * USE OR PERFORMANCE OF THIS SOFTWARE.
51  */
52
53 /* $Id: sdlz.c,v 1.18.50.3 2009/06/26 06:25:44 marka Exp $ */
54
55 /*! \file */
56
57 #include <config.h>
58 #include <string.h>
59
60 #include <isc/buffer.h>
61 #include <isc/lex.h>
62 #include <isc/log.h>
63 #include <isc/rwlock.h>
64 #include <isc/string.h>
65 #include <isc/util.h>
66 #include <isc/magic.h>
67 #include <isc/mem.h>
68 #include <isc/once.h>
69 #include <isc/print.h>
70 #include <isc/region.h>
71
72 #include <dns/callbacks.h>
73 #include <dns/db.h>
74 #include <dns/dbiterator.h>
75 #include <dns/dlz.h>
76 #include <dns/fixedname.h>
77 #include <dns/log.h>
78 #include <dns/rdata.h>
79 #include <dns/rdatalist.h>
80 #include <dns/rdataset.h>
81 #include <dns/rdatasetiter.h>
82 #include <dns/rdatatype.h>
83 #include <dns/result.h>
84 #include <dns/master.h>
85 #include <dns/sdlz.h>
86 #include <dns/types.h>
87
88 #include "rdatalist_p.h"
89
90 /*
91  * Private Types
92  */
93
94 struct dns_sdlzimplementation {
95         const dns_sdlzmethods_t         *methods;
96         isc_mem_t                       *mctx;
97         void                            *driverarg;
98         unsigned int                    flags;
99         isc_mutex_t                     driverlock;
100         dns_dlzimplementation_t         *dlz_imp;
101 };
102
103 struct dns_sdlz_db {
104         /* Unlocked */
105         dns_db_t                        common;
106         void                            *dbdata;
107         dns_sdlzimplementation_t        *dlzimp;
108         isc_mutex_t                     refcnt_lock;
109         /* Locked */
110         unsigned int                    references;
111 };
112
113 struct dns_sdlzlookup {
114         /* Unlocked */
115         unsigned int                    magic;
116         dns_sdlz_db_t                   *sdlz;
117         ISC_LIST(dns_rdatalist_t)       lists;
118         ISC_LIST(isc_buffer_t)          buffers;
119         dns_name_t                      *name;
120         ISC_LINK(dns_sdlzlookup_t)      link;
121         isc_mutex_t                     lock;
122         dns_rdatacallbacks_t            callbacks;
123         /* Locked */
124         unsigned int                    references;
125 };
126
127 typedef struct dns_sdlzlookup dns_sdlznode_t;
128
129 struct dns_sdlzallnodes {
130         dns_dbiterator_t                common;
131         ISC_LIST(dns_sdlznode_t)        nodelist;
132         dns_sdlznode_t                  *current;
133         dns_sdlznode_t                  *origin;
134 };
135
136 typedef dns_sdlzallnodes_t sdlz_dbiterator_t;
137
138 typedef struct sdlz_rdatasetiter {
139         dns_rdatasetiter_t              common;
140         dns_rdatalist_t                 *current;
141 } sdlz_rdatasetiter_t;
142
143
144 #define SDLZDB_MAGIC            ISC_MAGIC('D', 'L', 'Z', 'S')
145
146 /*
147  * Note that "impmagic" is not the first four bytes of the struct, so
148  * ISC_MAGIC_VALID cannot be used.
149  */
150
151 #define VALID_SDLZDB(sdlzdb)    ((sdlzdb) != NULL && \
152                                  (sdlzdb)->common.impmagic == SDLZDB_MAGIC)
153
154 #define SDLZLOOKUP_MAGIC        ISC_MAGIC('D','L','Z','L')
155 #define VALID_SDLZLOOKUP(sdlzl) ISC_MAGIC_VALID(sdlzl, SDLZLOOKUP_MAGIC)
156 #define VALID_SDLZNODE(sdlzn)   VALID_SDLZLOOKUP(sdlzn)
157
158 /* These values are taken from RFC 1537 */
159 #define SDLZ_DEFAULT_REFRESH    (60 * 60 * 8)
160 #define SDLZ_DEFAULT_RETRY      (60 * 60 * 2)
161 #define SDLZ_DEFAULT_EXPIRE     (60 * 60 * 24 * 7)
162 #define SDLZ_DEFAULT_MINIMUM    (60 * 60 * 24)
163
164 /* This is a reasonable value */
165 #define SDLZ_DEFAULT_TTL        (60 * 60 * 24)
166
167 static int dummy;
168
169 #ifdef __COVERITY__
170 #define MAYBE_LOCK(imp) LOCK(&imp->driverlock)
171 #define MAYBE_UNLOCK(imp) UNLOCK(&imp->driverlock)
172 #else
173 #define MAYBE_LOCK(imp) \
174         do { \
175                 unsigned int flags = imp->flags; \
176                 if ((flags & DNS_SDLZFLAG_THREADSAFE) == 0) \
177                         LOCK(&imp->driverlock); \
178         } while (0)
179
180 #define MAYBE_UNLOCK(imp) \
181         do { \
182                 unsigned int flags = imp->flags; \
183                 if ((flags & DNS_SDLZFLAG_THREADSAFE) == 0) \
184                         UNLOCK(&imp->driverlock); \
185         } while (0)
186 #endif
187
188 /*
189  * Forward references.  Try to keep these to a minimum.
190  */
191
192 static void list_tordataset(dns_rdatalist_t *rdatalist,
193                             dns_db_t *db, dns_dbnode_t *node,
194                             dns_rdataset_t *rdataset);
195
196 static void detachnode(dns_db_t *db, dns_dbnode_t **targetp);
197
198 static void             dbiterator_destroy(dns_dbiterator_t **iteratorp);
199 static isc_result_t     dbiterator_first(dns_dbiterator_t *iterator);
200 static isc_result_t     dbiterator_last(dns_dbiterator_t *iterator);
201 static isc_result_t     dbiterator_seek(dns_dbiterator_t *iterator,
202                                         dns_name_t *name);
203 static isc_result_t     dbiterator_prev(dns_dbiterator_t *iterator);
204 static isc_result_t     dbiterator_next(dns_dbiterator_t *iterator);
205 static isc_result_t     dbiterator_current(dns_dbiterator_t *iterator,
206                                            dns_dbnode_t **nodep,
207                                            dns_name_t *name);
208 static isc_result_t     dbiterator_pause(dns_dbiterator_t *iterator);
209 static isc_result_t     dbiterator_origin(dns_dbiterator_t *iterator,
210                                           dns_name_t *name);
211
212 static dns_dbiteratormethods_t dbiterator_methods = {
213         dbiterator_destroy,
214         dbiterator_first,
215         dbiterator_last,
216         dbiterator_seek,
217         dbiterator_prev,
218         dbiterator_next,
219         dbiterator_current,
220         dbiterator_pause,
221         dbiterator_origin
222 };
223
224 /*
225  * Utility functions
226  */
227
228 /*% Converts the input string to lowercase, in place. */
229
230 static void
231 dns_sdlz_tolower(char *str) {
232
233         unsigned int len = strlen(str);
234         unsigned int i;
235
236         for (i = 0; i < len; i++) {
237                 if (str[i] >= 'A' && str[i] <= 'Z')
238                         str[i] += 32;
239         }
240
241 }
242
243 static inline unsigned int
244 initial_size(const char *data) {
245         unsigned int len = (strlen(data) / 64) + 1;
246         return (len * 64 + 64);
247 }
248
249 /*
250  * Rdataset Iterator Methods. These methods were "borrowed" from the SDB
251  * driver interface.  See the SDB driver interface documentation for more info.
252  */
253
254 static void
255 rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
256         sdlz_rdatasetiter_t *sdlziterator =
257                 (sdlz_rdatasetiter_t *)(*iteratorp);
258
259         detachnode(sdlziterator->common.db, &sdlziterator->common.node);
260         isc_mem_put(sdlziterator->common.db->mctx, sdlziterator,
261                     sizeof(sdlz_rdatasetiter_t));
262         *iteratorp = NULL;
263 }
264
265 static isc_result_t
266 rdatasetiter_first(dns_rdatasetiter_t *iterator) {
267         sdlz_rdatasetiter_t *sdlziterator = (sdlz_rdatasetiter_t *)iterator;
268         dns_sdlznode_t *sdlznode = (dns_sdlznode_t *)iterator->node;
269
270         if (ISC_LIST_EMPTY(sdlznode->lists))
271                 return (ISC_R_NOMORE);
272         sdlziterator->current = ISC_LIST_HEAD(sdlznode->lists);
273         return (ISC_R_SUCCESS);
274 }
275
276 static isc_result_t
277 rdatasetiter_next(dns_rdatasetiter_t *iterator) {
278         sdlz_rdatasetiter_t *sdlziterator = (sdlz_rdatasetiter_t *)iterator;
279
280         sdlziterator->current = ISC_LIST_NEXT(sdlziterator->current, link);
281         if (sdlziterator->current == NULL)
282                 return (ISC_R_NOMORE);
283         else
284                 return (ISC_R_SUCCESS);
285 }
286
287 static void
288 rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
289         sdlz_rdatasetiter_t *sdlziterator = (sdlz_rdatasetiter_t *)iterator;
290
291         list_tordataset(sdlziterator->current, iterator->db, iterator->node,
292                         rdataset);
293 }
294
295 static dns_rdatasetitermethods_t rdatasetiter_methods = {
296         rdatasetiter_destroy,
297         rdatasetiter_first,
298         rdatasetiter_next,
299         rdatasetiter_current
300 };
301
302 /*
303  * DB routines. These methods were "borrowed" from the SDB driver interface.
304  * See the SDB driver interface documentation for more info.
305  */
306
307 static void
308 attach(dns_db_t *source, dns_db_t **targetp) {
309         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *) source;
310
311         REQUIRE(VALID_SDLZDB(sdlz));
312
313         LOCK(&sdlz->refcnt_lock);
314         REQUIRE(sdlz->references > 0);
315         sdlz->references++;
316         UNLOCK(&sdlz->refcnt_lock);
317
318         *targetp = source;
319 }
320
321 static void
322 destroy(dns_sdlz_db_t *sdlz) {
323         isc_mem_t *mctx;
324         mctx = sdlz->common.mctx;
325
326         sdlz->common.magic = 0;
327         sdlz->common.impmagic = 0;
328
329         isc_mutex_destroy(&sdlz->refcnt_lock);
330
331         dns_name_free(&sdlz->common.origin, mctx);
332
333         isc_mem_put(mctx, sdlz, sizeof(dns_sdlz_db_t));
334         isc_mem_detach(&mctx);
335 }
336
337 static void
338 detach(dns_db_t **dbp) {
339         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)(*dbp);
340         isc_boolean_t need_destroy = ISC_FALSE;
341
342         REQUIRE(VALID_SDLZDB(sdlz));
343         LOCK(&sdlz->refcnt_lock);
344         REQUIRE(sdlz->references > 0);
345         sdlz->references--;
346         if (sdlz->references == 0)
347                 need_destroy = ISC_TRUE;
348         UNLOCK(&sdlz->refcnt_lock);
349
350         if (need_destroy)
351                 destroy(sdlz);
352
353         *dbp = NULL;
354 }
355
356 static isc_result_t
357 beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, dns_dbload_t **dbloadp) {
358         UNUSED(db);
359         UNUSED(addp);
360         UNUSED(dbloadp);
361         return (ISC_R_NOTIMPLEMENTED);
362 }
363
364 static isc_result_t
365 endload(dns_db_t *db, dns_dbload_t **dbloadp) {
366         UNUSED(db);
367         UNUSED(dbloadp);
368         return (ISC_R_NOTIMPLEMENTED);
369 }
370
371 static isc_result_t
372 dump(dns_db_t *db, dns_dbversion_t *version, const char *filename,
373      dns_masterformat_t masterformat)
374 {
375         UNUSED(db);
376         UNUSED(version);
377         UNUSED(filename);
378         UNUSED(masterformat);
379         return (ISC_R_NOTIMPLEMENTED);
380 }
381
382 static void
383 currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
384         REQUIRE(versionp != NULL && *versionp == NULL);
385
386         UNUSED(db);
387
388         *versionp = (void *) &dummy;
389         return;
390 }
391
392 static isc_result_t
393 newversion(dns_db_t *db, dns_dbversion_t **versionp) {
394         UNUSED(db);
395         UNUSED(versionp);
396
397         return (ISC_R_NOTIMPLEMENTED);
398 }
399
400 static void
401 attachversion(dns_db_t *db, dns_dbversion_t *source,
402               dns_dbversion_t **targetp)
403 {
404         REQUIRE(source != NULL && source == (void *) &dummy);
405
406         UNUSED(db);
407         UNUSED(source);
408         UNUSED(targetp);
409         *targetp = source;
410 }
411
412 static void
413 closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
414         REQUIRE(versionp != NULL && *versionp == (void *) &dummy);
415         REQUIRE(commit == ISC_FALSE);
416
417         UNUSED(db);
418         UNUSED(commit);
419
420         *versionp = NULL;
421 }
422
423 static isc_result_t
424 createnode(dns_sdlz_db_t *sdlz, dns_sdlznode_t **nodep) {
425         dns_sdlznode_t *node;
426         isc_result_t result;
427
428         node = isc_mem_get(sdlz->common.mctx, sizeof(dns_sdlznode_t));
429         if (node == NULL)
430                 return (ISC_R_NOMEMORY);
431
432         node->sdlz = NULL;
433         attach((dns_db_t *)sdlz, (dns_db_t **)&node->sdlz);
434         ISC_LIST_INIT(node->lists);
435         ISC_LIST_INIT(node->buffers);
436         ISC_LINK_INIT(node, link);
437         node->name = NULL;
438         result = isc_mutex_init(&node->lock);
439         if (result != ISC_R_SUCCESS) {
440                 UNEXPECTED_ERROR(__FILE__, __LINE__,
441                                  "isc_mutex_init() failed: %s",
442                                  isc_result_totext(result));
443                 isc_mem_put(sdlz->common.mctx, node, sizeof(dns_sdlznode_t));
444                 return (ISC_R_UNEXPECTED);
445         }
446         dns_rdatacallbacks_init(&node->callbacks);
447         node->references = 1;
448         node->magic = SDLZLOOKUP_MAGIC;
449
450         *nodep = node;
451         return (ISC_R_SUCCESS);
452 }
453
454 static void
455 destroynode(dns_sdlznode_t *node) {
456         dns_rdatalist_t *list;
457         dns_rdata_t *rdata;
458         isc_buffer_t *b;
459         dns_sdlz_db_t *sdlz;
460         dns_db_t *db;
461         isc_mem_t *mctx;
462
463         sdlz = node->sdlz;
464         mctx = sdlz->common.mctx;
465
466         while (!ISC_LIST_EMPTY(node->lists)) {
467                 list = ISC_LIST_HEAD(node->lists);
468                 while (!ISC_LIST_EMPTY(list->rdata)) {
469                         rdata = ISC_LIST_HEAD(list->rdata);
470                         ISC_LIST_UNLINK(list->rdata, rdata, link);
471                         isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
472                 }
473                 ISC_LIST_UNLINK(node->lists, list, link);
474                 isc_mem_put(mctx, list, sizeof(dns_rdatalist_t));
475         }
476
477         while (!ISC_LIST_EMPTY(node->buffers)) {
478                 b = ISC_LIST_HEAD(node->buffers);
479                 ISC_LIST_UNLINK(node->buffers, b, link);
480                 isc_buffer_free(&b);
481         }
482
483         if (node->name != NULL) {
484                 dns_name_free(node->name, mctx);
485                 isc_mem_put(mctx, node->name, sizeof(dns_name_t));
486         }
487         DESTROYLOCK(&node->lock);
488         node->magic = 0;
489         isc_mem_put(mctx, node, sizeof(dns_sdlznode_t));
490         db = &sdlz->common;
491         detach(&db);
492 }
493
494 static isc_result_t
495 findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
496          dns_dbnode_t **nodep)
497 {
498         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
499         dns_sdlznode_t *node = NULL;
500         isc_result_t result;
501         isc_buffer_t b;
502         char namestr[DNS_NAME_MAXTEXT + 1];
503         isc_buffer_t b2;
504         char zonestr[DNS_NAME_MAXTEXT + 1];
505         isc_boolean_t isorigin;
506         dns_sdlzauthorityfunc_t authority;
507
508         REQUIRE(VALID_SDLZDB(sdlz));
509         REQUIRE(create == ISC_FALSE);
510         REQUIRE(nodep != NULL && *nodep == NULL);
511
512         UNUSED(name);
513         UNUSED(create);
514
515         isc_buffer_init(&b, namestr, sizeof(namestr));
516         if ((sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVEOWNER) != 0) {
517                 dns_name_t relname;
518                 unsigned int labels;
519
520                 labels = dns_name_countlabels(name) -
521                          dns_name_countlabels(&db->origin);
522                 dns_name_init(&relname, NULL);
523                 dns_name_getlabelsequence(name, 0, labels, &relname);
524                 result = dns_name_totext(&relname, ISC_TRUE, &b);
525                 if (result != ISC_R_SUCCESS)
526                         return (result);
527         } else {
528                 result = dns_name_totext(name, ISC_TRUE, &b);
529                 if (result != ISC_R_SUCCESS)
530                         return (result);
531         }
532         isc_buffer_putuint8(&b, 0);
533
534         isc_buffer_init(&b2, zonestr, sizeof(zonestr));
535         result = dns_name_totext(&sdlz->common.origin, ISC_TRUE, &b2);
536         if (result != ISC_R_SUCCESS)
537                 return (result);
538         isc_buffer_putuint8(&b2, 0);
539
540         result = createnode(sdlz, &node);
541         if (result != ISC_R_SUCCESS)
542                 return (result);
543
544         isorigin = dns_name_equal(name, &sdlz->common.origin);
545
546         /* make sure strings are always lowercase */
547         dns_sdlz_tolower(zonestr);
548         dns_sdlz_tolower(namestr);
549
550         MAYBE_LOCK(sdlz->dlzimp);
551
552         /* try to lookup the host (namestr) */
553         result = sdlz->dlzimp->methods->lookup(zonestr, namestr,
554                                                sdlz->dlzimp->driverarg,
555                                                sdlz->dbdata, node);
556
557         /*
558          * if the host (namestr) was not found, try to lookup a
559          * "wildcard" host.
560          */
561         if (result != ISC_R_SUCCESS) {
562                 result = sdlz->dlzimp->methods->lookup(zonestr, "*",
563                                                        sdlz->dlzimp->driverarg,
564                                                        sdlz->dbdata, node);
565         }
566
567         MAYBE_UNLOCK(sdlz->dlzimp);
568
569         if (result != ISC_R_SUCCESS && !isorigin) {
570                 destroynode(node);
571                 return (result);
572         }
573
574         if (isorigin && sdlz->dlzimp->methods->authority != NULL) {
575                 MAYBE_LOCK(sdlz->dlzimp);
576                 authority = sdlz->dlzimp->methods->authority;
577                 result = (*authority)(zonestr, sdlz->dlzimp->driverarg,
578                                       sdlz->dbdata, node);
579                 MAYBE_UNLOCK(sdlz->dlzimp);
580                 if (result != ISC_R_SUCCESS &&
581                     result != ISC_R_NOTIMPLEMENTED) {
582                         destroynode(node);
583                         return (result);
584                 }
585         }
586
587         *nodep = node;
588         return (ISC_R_SUCCESS);
589 }
590
591 static isc_result_t
592 findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
593             isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
594             dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
595 {
596         UNUSED(db);
597         UNUSED(name);
598         UNUSED(options);
599         UNUSED(now);
600         UNUSED(nodep);
601         UNUSED(foundname);
602         UNUSED(rdataset);
603         UNUSED(sigrdataset);
604
605         return (ISC_R_NOTIMPLEMENTED);
606 }
607
608 static void
609 attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
610         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
611         dns_sdlznode_t *node = (dns_sdlznode_t *)source;
612
613         REQUIRE(VALID_SDLZDB(sdlz));
614
615         UNUSED(sdlz);
616
617         LOCK(&node->lock);
618         INSIST(node->references > 0);
619         node->references++;
620         INSIST(node->references != 0);          /* Catch overflow. */
621         UNLOCK(&node->lock);
622
623         *targetp = source;
624 }
625
626 static void
627 detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
628         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
629         dns_sdlznode_t *node;
630         isc_boolean_t need_destroy = ISC_FALSE;
631
632         REQUIRE(VALID_SDLZDB(sdlz));
633         REQUIRE(targetp != NULL && *targetp != NULL);
634
635         UNUSED(sdlz);
636
637         node = (dns_sdlznode_t *)(*targetp);
638
639         LOCK(&node->lock);
640         INSIST(node->references > 0);
641         node->references--;
642         if (node->references == 0)
643                 need_destroy = ISC_TRUE;
644         UNLOCK(&node->lock);
645
646         if (need_destroy)
647                 destroynode(node);
648
649         *targetp = NULL;
650 }
651
652 static isc_result_t
653 expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
654         UNUSED(db);
655         UNUSED(node);
656         UNUSED(now);
657         INSIST(0);
658         return (ISC_R_UNEXPECTED);
659 }
660
661 static void
662 printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
663         UNUSED(db);
664         UNUSED(node);
665         UNUSED(out);
666         return;
667 }
668
669 static isc_result_t
670 createiterator(dns_db_t *db, 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 };
1216
1217 static void
1218 list_tordataset(dns_rdatalist_t *rdatalist,
1219                 dns_db_t *db, dns_dbnode_t *node,
1220                 dns_rdataset_t *rdataset)
1221 {
1222         /*
1223          * The sdlz rdataset is an rdatalist with some additions.
1224          *      - private1 & private2 are used by the rdatalist.
1225          *      - private3 & private 4 are unused.
1226          *      - private5 is the node.
1227          */
1228
1229         /* This should never fail. */
1230         RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
1231                       ISC_R_SUCCESS);
1232
1233         rdataset->methods = &rdataset_methods;
1234         dns_db_attachnode(db, node, &rdataset->private5);
1235 }
1236
1237 /*
1238  * SDLZ core methods. This is the core of the new DLZ functionality.
1239  */
1240
1241 /*%
1242  * Build a 'bind' database driver structure to be returned by
1243  * either the find zone or the allow zone transfer method.
1244  * This method is only available in this source file, it is
1245  * not made available anywhere else.
1246  */
1247
1248 static isc_result_t
1249 dns_sdlzcreateDBP(isc_mem_t *mctx, void *driverarg, void *dbdata,
1250                   dns_name_t *name, dns_rdataclass_t rdclass, dns_db_t **dbp)
1251 {
1252         isc_result_t result;
1253         dns_sdlz_db_t *sdlzdb;
1254         dns_sdlzimplementation_t *imp;
1255
1256         /* check that things are as we expect */
1257         REQUIRE(dbp != NULL && *dbp == NULL);
1258         REQUIRE(name != NULL);
1259
1260         imp = (dns_sdlzimplementation_t *) driverarg;
1261
1262         /* allocate and zero memory for driver structure */
1263         sdlzdb = isc_mem_get(mctx, sizeof(dns_sdlz_db_t));
1264         if (sdlzdb == NULL)
1265                 return (ISC_R_NOMEMORY);
1266         memset(sdlzdb, 0, sizeof(dns_sdlz_db_t));
1267
1268         /* initialize and set origin */
1269         dns_name_init(&sdlzdb->common.origin, NULL);
1270         result = dns_name_dupwithoffsets(name, mctx, &sdlzdb->common.origin);
1271         if (result != ISC_R_SUCCESS)
1272                 goto mem_cleanup;
1273
1274         /* initialize the reference count mutex */
1275         result = isc_mutex_init(&sdlzdb->refcnt_lock);
1276         if (result != ISC_R_SUCCESS)
1277                 goto name_cleanup;
1278
1279         /* set the rest of the database structure attributes */
1280         sdlzdb->dlzimp = imp;
1281         sdlzdb->common.methods = &sdlzdb_methods;
1282         sdlzdb->common.attributes = 0;
1283         sdlzdb->common.rdclass = rdclass;
1284         sdlzdb->common.mctx = NULL;
1285         sdlzdb->dbdata = dbdata;
1286         sdlzdb->references = 1;
1287
1288         /* attach to the memory context */
1289         isc_mem_attach(mctx, &sdlzdb->common.mctx);
1290
1291         /* mark structure as valid */
1292         sdlzdb->common.magic = DNS_DB_MAGIC;
1293         sdlzdb->common.impmagic = SDLZDB_MAGIC;
1294         *dbp = (dns_db_t *) sdlzdb;
1295
1296         return (result);
1297
1298         /*
1299          * reference count mutex could not be initialized, clean up
1300          * name memory
1301          */
1302  name_cleanup:
1303         dns_name_free(&sdlzdb->common.origin, mctx);
1304  mem_cleanup:
1305         isc_mem_put(mctx, sdlzdb, sizeof(dns_sdlz_db_t));
1306         return (result);
1307 }
1308
1309 static isc_result_t
1310 dns_sdlzallowzonexfr(void *driverarg, void *dbdata, isc_mem_t *mctx,
1311                      dns_rdataclass_t rdclass, dns_name_t *name,
1312                      isc_sockaddr_t *clientaddr, dns_db_t **dbp)
1313 {
1314         isc_buffer_t b;
1315         isc_buffer_t b2;
1316         char namestr[DNS_NAME_MAXTEXT + 1];
1317         char clientstr[(sizeof "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")
1318                        + 1];
1319         isc_netaddr_t netaddr;
1320         isc_result_t result;
1321         dns_sdlzimplementation_t *imp;
1322
1323         /*
1324          * Perform checks to make sure data is as we expect it to be.
1325          */
1326         REQUIRE(driverarg != NULL);
1327         REQUIRE(name != NULL);
1328         REQUIRE(clientaddr != NULL);
1329         REQUIRE(dbp != NULL && *dbp == NULL);
1330
1331         imp = (dns_sdlzimplementation_t *) driverarg;
1332
1333         /* Convert DNS name to ascii text */
1334         isc_buffer_init(&b, namestr, sizeof(namestr));
1335         result = dns_name_totext(name, ISC_TRUE, &b);
1336         if (result != ISC_R_SUCCESS)
1337                 return (result);
1338         isc_buffer_putuint8(&b, 0);
1339
1340         /* convert client address to ascii text */
1341         isc_buffer_init(&b2, clientstr, sizeof(clientstr));
1342         isc_netaddr_fromsockaddr(&netaddr, clientaddr);
1343         result = isc_netaddr_totext(&netaddr, &b2);
1344         if (result != ISC_R_SUCCESS)
1345                 return (result);
1346         isc_buffer_putuint8(&b2, 0);
1347
1348         /* make sure strings are always lowercase */
1349         dns_sdlz_tolower(namestr);
1350         dns_sdlz_tolower(clientstr);
1351
1352         /* Call SDLZ driver's find zone method */
1353         if (imp->methods->allowzonexfr != NULL) {
1354                 MAYBE_LOCK(imp);
1355                 result = imp->methods->allowzonexfr(imp->driverarg, dbdata,
1356                                                     namestr, clientstr);
1357                 MAYBE_UNLOCK(imp);
1358                 /*
1359                  * if zone is supported and transfers allowed build a 'bind'
1360                  * database driver
1361                  */
1362                 if (result == ISC_R_SUCCESS)
1363                         result = dns_sdlzcreateDBP(mctx, driverarg, dbdata,
1364                                                    name, rdclass, dbp);
1365                 return (result);
1366         }
1367
1368         return (ISC_R_NOTIMPLEMENTED);
1369 }
1370
1371 static isc_result_t
1372 dns_sdlzcreate(isc_mem_t *mctx, const char *dlzname, unsigned int argc,
1373                char *argv[], void *driverarg, void **dbdata)
1374 {
1375         dns_sdlzimplementation_t *imp;
1376         isc_result_t result = ISC_R_NOTFOUND;
1377
1378         /* Write debugging message to log */
1379         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1380                       DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1381                       "Loading SDLZ driver.");
1382
1383         /*
1384          * Performs checks to make sure data is as we expect it to be.
1385          */
1386         REQUIRE(driverarg != NULL);
1387         REQUIRE(dlzname != NULL);
1388         REQUIRE(dbdata != NULL);
1389         UNUSED(mctx);
1390
1391         imp = driverarg;
1392
1393         /* If the create method exists, call it. */
1394         if (imp->methods->create != NULL) {
1395                 MAYBE_LOCK(imp);
1396                 result = imp->methods->create(dlzname, argc, argv,
1397                                               imp->driverarg, dbdata);
1398                 MAYBE_UNLOCK(imp);
1399         }
1400
1401         /* Write debugging message to log */
1402         if (result == ISC_R_SUCCESS) {
1403                 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1404                               DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1405                               "SDLZ driver loaded successfully.");
1406         } else {
1407                 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1408                               DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1409                               "SDLZ driver failed to load.");
1410         }
1411
1412         return (result);
1413 }
1414
1415 static void
1416 dns_sdlzdestroy(void *driverdata, void **dbdata)
1417 {
1418
1419         dns_sdlzimplementation_t *imp;
1420
1421         /* Write debugging message to log */
1422         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1423                       DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1424                       "Unloading SDLZ driver.");
1425
1426         imp = driverdata;
1427
1428         /* If the destroy method exists, call it. */
1429         if (imp->methods->destroy != NULL) {
1430                 MAYBE_LOCK(imp);
1431                 imp->methods->destroy(imp->driverarg, dbdata);
1432                 MAYBE_UNLOCK(imp);
1433         }
1434 }
1435
1436 static isc_result_t
1437 dns_sdlzfindzone(void *driverarg, void *dbdata, isc_mem_t *mctx,
1438                  dns_rdataclass_t rdclass, dns_name_t *name, dns_db_t **dbp)
1439 {
1440         isc_buffer_t b;
1441         char namestr[DNS_NAME_MAXTEXT + 1];
1442         isc_result_t result;
1443         dns_sdlzimplementation_t *imp;
1444
1445         /*
1446          * Perform checks to make sure data is as we expect it to be.
1447          */
1448         REQUIRE(driverarg != NULL);
1449         REQUIRE(name != NULL);
1450         REQUIRE(dbp != NULL && *dbp == NULL);
1451
1452         imp = (dns_sdlzimplementation_t *) driverarg;
1453
1454         /* Convert DNS name to ascii text */
1455         isc_buffer_init(&b, namestr, sizeof(namestr));
1456         result = dns_name_totext(name, ISC_TRUE, &b);
1457         if (result != ISC_R_SUCCESS)
1458                 return (result);
1459         isc_buffer_putuint8(&b, 0);
1460
1461         /* make sure strings are always lowercase */
1462         dns_sdlz_tolower(namestr);
1463
1464         /* Call SDLZ driver's find zone method */
1465         MAYBE_LOCK(imp);
1466         result = imp->methods->findzone(imp->driverarg, dbdata, namestr);
1467         MAYBE_UNLOCK(imp);
1468
1469         /*
1470          * if zone is supported build a 'bind' database driver
1471          * structure to return
1472          */
1473         if (result == ISC_R_SUCCESS)
1474                 result = dns_sdlzcreateDBP(mctx, driverarg, dbdata, name,
1475                                            rdclass, dbp);
1476
1477         return (result);
1478 }
1479
1480 static dns_dlzmethods_t sdlzmethods = {
1481         dns_sdlzcreate,
1482         dns_sdlzdestroy,
1483         dns_sdlzfindzone,
1484         dns_sdlzallowzonexfr
1485 };
1486
1487 /*
1488  * Public functions.
1489  */
1490
1491 isc_result_t
1492 dns_sdlz_putrr(dns_sdlzlookup_t *lookup, const char *type, dns_ttl_t ttl,
1493                const char *data)
1494 {
1495         dns_rdatalist_t *rdatalist;
1496         dns_rdata_t *rdata;
1497         dns_rdatatype_t typeval;
1498         isc_consttextregion_t r;
1499         isc_buffer_t b;
1500         isc_buffer_t *rdatabuf = NULL;
1501         isc_lex_t *lex;
1502         isc_result_t result;
1503         unsigned int size;
1504         isc_mem_t *mctx;
1505         dns_name_t *origin;
1506
1507         REQUIRE(VALID_SDLZLOOKUP(lookup));
1508         REQUIRE(type != NULL);
1509         REQUIRE(data != NULL);
1510
1511         mctx = lookup->sdlz->common.mctx;
1512
1513         r.base = type;
1514         r.length = strlen(type);
1515         result = dns_rdatatype_fromtext(&typeval, (void *) &r);
1516         if (result != ISC_R_SUCCESS)
1517                 return (result);
1518
1519         rdatalist = ISC_LIST_HEAD(lookup->lists);
1520         while (rdatalist != NULL) {
1521                 if (rdatalist->type == typeval)
1522                         break;
1523                 rdatalist = ISC_LIST_NEXT(rdatalist, link);
1524         }
1525
1526         if (rdatalist == NULL) {
1527                 rdatalist = isc_mem_get(mctx, sizeof(dns_rdatalist_t));
1528                 if (rdatalist == NULL)
1529                         return (ISC_R_NOMEMORY);
1530                 rdatalist->rdclass = lookup->sdlz->common.rdclass;
1531                 rdatalist->type = typeval;
1532                 rdatalist->covers = 0;
1533                 rdatalist->ttl = ttl;
1534                 ISC_LIST_INIT(rdatalist->rdata);
1535                 ISC_LINK_INIT(rdatalist, link);
1536                 ISC_LIST_APPEND(lookup->lists, rdatalist, link);
1537         } else
1538                 if (rdatalist->ttl != ttl)
1539                         return (DNS_R_BADTTL);
1540
1541         rdata = isc_mem_get(mctx, sizeof(dns_rdata_t));
1542         if (rdata == NULL)
1543                 return (ISC_R_NOMEMORY);
1544         dns_rdata_init(rdata);
1545
1546         if ((lookup->sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVERDATA) != 0)
1547                 origin = &lookup->sdlz->common.origin;
1548         else
1549                 origin = dns_rootname;
1550
1551         lex = NULL;
1552         result = isc_lex_create(mctx, 64, &lex);
1553         if (result != ISC_R_SUCCESS)
1554                 goto failure;
1555
1556         size = initial_size(data);
1557         do {
1558                 isc_buffer_init(&b, data, strlen(data));
1559                 isc_buffer_add(&b, strlen(data));
1560
1561                 result = isc_lex_openbuffer(lex, &b);
1562                 if (result != ISC_R_SUCCESS)
1563                         goto failure;
1564
1565                 rdatabuf = NULL;
1566                 result = isc_buffer_allocate(mctx, &rdatabuf, size);
1567                 if (result != ISC_R_SUCCESS)
1568                         goto failure;
1569
1570                 result = dns_rdata_fromtext(rdata, rdatalist->rdclass,
1571                                             rdatalist->type, lex,
1572                                             origin, ISC_FALSE,
1573                                             mctx, rdatabuf,
1574                                             &lookup->callbacks);
1575                 if (result != ISC_R_SUCCESS)
1576                         isc_buffer_free(&rdatabuf);
1577                 size *= 2;
1578         } while (result == ISC_R_NOSPACE);
1579
1580         if (result != ISC_R_SUCCESS)
1581                 goto failure;
1582
1583         ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1584         ISC_LIST_APPEND(lookup->buffers, rdatabuf, link);
1585
1586         if (lex != NULL)
1587                 isc_lex_destroy(&lex);
1588
1589         return (ISC_R_SUCCESS);
1590
1591  failure:
1592         if (rdatabuf != NULL)
1593                 isc_buffer_free(&rdatabuf);
1594         if (lex != NULL)
1595                 isc_lex_destroy(&lex);
1596         isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
1597
1598         return (result);
1599 }
1600
1601 isc_result_t
1602 dns_sdlz_putnamedrr(dns_sdlzallnodes_t *allnodes, const char *name,
1603                     const char *type, dns_ttl_t ttl, const char *data)
1604 {
1605         dns_name_t *newname, *origin;
1606         dns_fixedname_t fnewname;
1607         dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)allnodes->common.db;
1608         dns_sdlznode_t *sdlznode;
1609         isc_mem_t *mctx = sdlz->common.mctx;
1610         isc_buffer_t b;
1611         isc_result_t result;
1612
1613         dns_fixedname_init(&fnewname);
1614         newname = dns_fixedname_name(&fnewname);
1615
1616         if ((sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVERDATA) != 0)
1617                 origin = &sdlz->common.origin;
1618         else
1619                 origin = dns_rootname;
1620         isc_buffer_init(&b, name, strlen(name));
1621         isc_buffer_add(&b, strlen(name));
1622
1623         result = dns_name_fromtext(newname, &b, origin, ISC_FALSE, NULL);
1624         if (result != ISC_R_SUCCESS)
1625                 return (result);
1626
1627         if (allnodes->common.relative_names) {
1628                 /* All names are relative to the root */
1629                 unsigned int nlabels = dns_name_countlabels(newname);
1630                 dns_name_getlabelsequence(newname, 0, nlabels - 1, newname);
1631         }
1632
1633         sdlznode = ISC_LIST_HEAD(allnodes->nodelist);
1634         if (sdlznode == NULL || !dns_name_equal(sdlznode->name, newname)) {
1635                 sdlznode = NULL;
1636                 result = createnode(sdlz, &sdlznode);
1637                 if (result != ISC_R_SUCCESS)
1638                         return (result);
1639                 sdlznode->name = isc_mem_get(mctx, sizeof(dns_name_t));
1640                 if (sdlznode->name == NULL) {
1641                         destroynode(sdlznode);
1642                         return (ISC_R_NOMEMORY);
1643                 }
1644                 dns_name_init(sdlznode->name, NULL);
1645                 result = dns_name_dup(newname, mctx, sdlznode->name);
1646                 if (result != ISC_R_SUCCESS) {
1647                         isc_mem_put(mctx, sdlznode->name, sizeof(dns_name_t));
1648                         destroynode(sdlznode);
1649                         return (result);
1650                 }
1651                 ISC_LIST_PREPEND(allnodes->nodelist, sdlznode, link);
1652                 if (allnodes->origin == NULL &&
1653                     dns_name_equal(newname, &sdlz->common.origin))
1654                         allnodes->origin = sdlznode;
1655         }
1656         return (dns_sdlz_putrr(sdlznode, type, ttl, data));
1657
1658 }
1659
1660 isc_result_t
1661 dns_sdlz_putsoa(dns_sdlzlookup_t *lookup, const char *mname, const char *rname,
1662                 isc_uint32_t serial)
1663 {
1664         char str[2 * DNS_NAME_MAXTEXT + 5 * (sizeof("2147483647")) + 7];
1665         int n;
1666
1667         REQUIRE(mname != NULL);
1668         REQUIRE(rname != NULL);
1669
1670         n = snprintf(str, sizeof str, "%s %s %u %u %u %u %u",
1671                      mname, rname, serial,
1672                      SDLZ_DEFAULT_REFRESH, SDLZ_DEFAULT_RETRY,
1673                      SDLZ_DEFAULT_EXPIRE, SDLZ_DEFAULT_MINIMUM);
1674         if (n >= (int)sizeof(str) || n < 0)
1675                 return (ISC_R_NOSPACE);
1676         return (dns_sdlz_putrr(lookup, "SOA", SDLZ_DEFAULT_TTL, str));
1677 }
1678
1679 isc_result_t
1680 dns_sdlzregister(const char *drivername, const dns_sdlzmethods_t *methods,
1681                  void *driverarg, unsigned int flags, isc_mem_t *mctx,
1682                  dns_sdlzimplementation_t **sdlzimp)
1683 {
1684
1685         dns_sdlzimplementation_t *imp;
1686         isc_result_t result;
1687
1688         /*
1689          * Performs checks to make sure data is as we expect it to be.
1690          */
1691         REQUIRE(drivername != NULL);
1692         REQUIRE(methods != NULL);
1693         REQUIRE(methods->findzone != NULL);
1694         REQUIRE(methods->lookup != NULL);
1695         REQUIRE(mctx != NULL);
1696         REQUIRE(sdlzimp != NULL && *sdlzimp == NULL);
1697         REQUIRE((flags & ~(DNS_SDLZFLAG_RELATIVEOWNER |
1698                            DNS_SDLZFLAG_RELATIVERDATA |
1699                            DNS_SDLZFLAG_THREADSAFE)) == 0);
1700
1701         /* Write debugging message to log */
1702         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1703                       DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1704                       "Registering SDLZ driver '%s'", drivername);
1705
1706         /*
1707          * Allocate memory for a sdlz_implementation object.  Error if
1708          * we cannot.
1709          */
1710         imp = isc_mem_get(mctx, sizeof(dns_sdlzimplementation_t));
1711         if (imp == NULL)
1712                 return (ISC_R_NOMEMORY);
1713
1714         /* Make sure memory region is set to all 0's */
1715         memset(imp, 0, sizeof(dns_sdlzimplementation_t));
1716
1717         /* Store the data passed into this method */
1718         imp->methods = methods;
1719         imp->driverarg = driverarg;
1720         imp->flags = flags;
1721         imp->mctx = NULL;
1722
1723         /* attach the new sdlz_implementation object to a memory context */
1724         isc_mem_attach(mctx, &imp->mctx);
1725
1726         /*
1727          * initialize the driver lock, error if we cannot
1728          * (used if a driver does not support multiple threads)
1729          */
1730         result = isc_mutex_init(&imp->driverlock);
1731         if (result != ISC_R_SUCCESS) {
1732                 UNEXPECTED_ERROR(__FILE__, __LINE__,
1733                                  "isc_mutex_init() failed: %s",
1734                                  isc_result_totext(result));
1735                 goto cleanup_mctx;
1736         }
1737
1738         imp->dlz_imp = NULL;
1739
1740         /*
1741          * register the DLZ driver.  Pass in our "extra" sdlz information as
1742          * a driverarg.  (that's why we stored the passed in driver arg in our
1743          * sdlz_implementation structure)  Also, store the dlz_implementation
1744          * structure in our sdlz_implementation.
1745          */
1746         result = dns_dlzregister(drivername, &sdlzmethods, imp, mctx,
1747                                  &imp->dlz_imp);
1748
1749         /* if registration fails, cleanup and get outta here. */
1750         if (result != ISC_R_SUCCESS)
1751                 goto cleanup_mutex;
1752
1753         *sdlzimp = imp;
1754
1755         return (ISC_R_SUCCESS);
1756
1757  cleanup_mutex:
1758         /* destroy the driver lock, we don't need it anymore */
1759         DESTROYLOCK(&imp->driverlock);
1760
1761  cleanup_mctx:
1762         /*
1763          * return the memory back to the available memory pool and
1764          * remove it from the memory context.
1765          */
1766         isc_mem_put(mctx, imp, sizeof(dns_sdlzimplementation_t));
1767         isc_mem_detach(&mctx);
1768         return (result);
1769 }
1770
1771 void
1772 dns_sdlzunregister(dns_sdlzimplementation_t **sdlzimp) {
1773         dns_sdlzimplementation_t *imp;
1774         isc_mem_t *mctx;
1775
1776         /* Write debugging message to log */
1777         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1778                       DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1779                       "Unregistering SDLZ driver.");
1780
1781         /*
1782          * Performs checks to make sure data is as we expect it to be.
1783          */
1784         REQUIRE(sdlzimp != NULL && *sdlzimp != NULL);
1785
1786         imp = *sdlzimp;
1787
1788         /* Unregister the DLZ driver implementation */
1789         dns_dlzunregister(&imp->dlz_imp);
1790
1791         /* destroy the driver lock, we don't need it anymore */
1792         DESTROYLOCK(&imp->driverlock);
1793
1794         mctx = imp->mctx;
1795
1796         /*
1797          * return the memory back to the available memory pool and
1798          * remove it from the memory context.
1799          */
1800         isc_mem_put(mctx, imp, sizeof(dns_sdlzimplementation_t));
1801         isc_mem_detach(&mctx);
1802
1803         *sdlzimp = NULL;
1804 }