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