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