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