Import bind 9.5.2 vendor sources.
[dragonfly.git] / contrib / bind-9.5.2 / lib / dns / dlz.c
blob528cf02faa4f4344e559b02e3a6840f06ef94779
1 /*
2 * Portions Copyright (C) 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC")
3 * Portions Copyright (C) 1999-2001 Internet Software Consortium.
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.
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.
19 * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
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.
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.
35 * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
36 * conceived and contributed by Rob Butler.
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.
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.
53 /* $Id: dlz.c,v 1.5.128.2 2009/01/19 23:47:02 tbox Exp $ */
55 /*! \file */
57 /***
58 *** Imports
59 ***/
61 #include <config.h>
63 #include <dns/fixedname.h>
64 #include <dns/log.h>
65 #include <dns/master.h>
66 #include <dns/dlz.h>
69 #include <isc/buffer.h>
70 #include <isc/magic.h>
71 #include <isc/mem.h>
72 #include <isc/once.h>
73 #include <isc/rwlock.h>
74 #include <isc/string.h>
75 #include <isc/util.h>
77 /***
78 *** Supported DLZ DB Implementations Registry
79 ***/
81 static ISC_LIST(dns_dlzimplementation_t) dlz_implementations;
82 static isc_rwlock_t dlz_implock;
83 static isc_once_t once = ISC_ONCE_INIT;
85 static void
86 dlz_initialize(void) {
87 RUNTIME_CHECK(isc_rwlock_init(&dlz_implock, 0, 0) == ISC_R_SUCCESS);
88 ISC_LIST_INIT(dlz_implementations);
91 /*%
92 * Searches the dlz_implementations list for a driver matching name.
94 static inline dns_dlzimplementation_t *
95 dlz_impfind(const char *name) {
96 dns_dlzimplementation_t *imp;
98 for (imp = ISC_LIST_HEAD(dlz_implementations);
99 imp != NULL;
100 imp = ISC_LIST_NEXT(imp, link))
101 if (strcasecmp(name, imp->name) == 0)
102 return (imp);
103 return (NULL);
106 /***
107 *** Basic DLZ Methods
108 ***/
110 isc_result_t
111 dns_dlzallowzonexfr(dns_view_t *view, dns_name_t *name,
112 isc_sockaddr_t *clientaddr, dns_db_t **dbp)
114 isc_result_t result;
115 dns_dlzallowzonexfr_t allowzonexfr;
116 dns_dlzdb_t *dlzdatabase;
119 * Performs checks to make sure data is as we expect it to be.
121 REQUIRE(DNS_DLZ_VALID(view->dlzdatabase));
122 REQUIRE(name != NULL);
123 REQUIRE(dbp != NULL && *dbp == NULL);
125 /* ask driver if the zone is supported */
126 dlzdatabase = view->dlzdatabase;
127 allowzonexfr = dlzdatabase->implementation->methods->allowzonexfr;
128 result = (*allowzonexfr)(dlzdatabase->implementation->driverarg,
129 dlzdatabase->dbdata, dlzdatabase->mctx,
130 view->rdclass, name, clientaddr, dbp);
132 if (result == ISC_R_NOTIMPLEMENTED)
133 return (ISC_R_NOTFOUND);
134 return (result);
137 isc_result_t
138 dns_dlzcreate(isc_mem_t *mctx, const char *dlzname, const char *drivername,
139 unsigned int argc, char *argv[], dns_dlzdb_t **dbp)
141 dns_dlzimplementation_t *impinfo;
142 isc_result_t result;
145 * initialize the dlz_implementations list, this is guaranteed
146 * to only really happen once.
148 RUNTIME_CHECK(isc_once_do(&once, dlz_initialize) == ISC_R_SUCCESS);
151 * Performs checks to make sure data is as we expect it to be.
153 REQUIRE(dbp != NULL && *dbp == NULL);
154 REQUIRE(dlzname != NULL);
155 REQUIRE(drivername != NULL);
156 REQUIRE(mctx != NULL);
158 /* write log message */
159 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
160 DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
161 "Loading '%s' using driver %s", dlzname, drivername);
163 /* lock the dlz_implementations list so we can search it. */
164 RWLOCK(&dlz_implock, isc_rwlocktype_read);
166 /* search for the driver implementation */
167 impinfo = dlz_impfind(drivername);
168 if (impinfo == NULL) {
169 RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
171 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
172 DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
173 "unsupported DLZ database driver '%s'."
174 " %s not loaded.",
175 drivername, dlzname);
177 return (ISC_R_NOTFOUND);
180 /* Allocate memory to hold the DLZ database driver */
181 (*dbp) = isc_mem_get(mctx, sizeof(dns_dlzdb_t));
182 if ((*dbp) == NULL) {
183 RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
184 return (ISC_R_NOMEMORY);
187 /* Make sure memory region is set to all 0's */
188 memset((*dbp), 0, sizeof(dns_dlzdb_t));
190 (*dbp)->implementation = impinfo;
192 /* Create a new database using implementation 'drivername'. */
193 result = ((impinfo->methods->create)(mctx, dlzname, argc, argv,
194 impinfo->driverarg,
195 &(*dbp)->dbdata));
197 /* mark the DLZ driver as valid */
198 if (result == ISC_R_SUCCESS) {
199 RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
200 (*dbp)->magic = DNS_DLZ_MAGIC;
201 isc_mem_attach(mctx, &(*dbp)->mctx);
202 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
203 DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
204 "DLZ driver loaded successfully.");
205 return (ISC_R_SUCCESS);
206 } else {
207 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
208 DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
209 "DLZ driver failed to load.");
212 /* impinfo->methods->create failed. */
213 RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
214 isc_mem_put(mctx, (*dbp), sizeof(dns_dlzdb_t));
215 return (result);
218 void
219 dns_dlzdestroy(dns_dlzdb_t **dbp) {
220 isc_mem_t *mctx;
221 dns_dlzdestroy_t destroy;
223 /* Write debugging message to log */
224 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
225 DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
226 "Unloading DLZ driver.");
229 * Perform checks to make sure data is as we expect it to be.
231 REQUIRE(dbp != NULL && DNS_DLZ_VALID(*dbp));
233 /* call the drivers destroy method */
234 if ((*dbp) != NULL) {
235 mctx = (*dbp)->mctx;
236 destroy = (*dbp)->implementation->methods->destroy;
237 (*destroy)((*dbp)->implementation->driverarg,(*dbp)->dbdata);
238 /* return memory */
239 isc_mem_put(mctx, (*dbp), sizeof(dns_dlzdb_t));
240 isc_mem_detach(&mctx);
243 *dbp = NULL;
247 isc_result_t
248 dns_dlzfindzone(dns_view_t *view, dns_name_t *name, unsigned int minlabels,
249 dns_db_t **dbp)
251 dns_fixedname_t fname;
252 dns_name_t *zonename;
253 unsigned int namelabels;
254 unsigned int i;
255 isc_result_t result;
256 dns_dlzfindzone_t findzone;
257 dns_dlzdb_t *dlzdatabase;
260 * Performs checks to make sure data is as we expect it to be.
262 REQUIRE(DNS_DLZ_VALID(view->dlzdatabase));
263 REQUIRE(name != NULL);
264 REQUIRE(dbp != NULL && *dbp == NULL);
266 /* setup a "fixed" dns name */
267 dns_fixedname_init(&fname);
268 zonename = dns_fixedname_name(&fname);
270 /* count the number of labels in the name */
271 namelabels = dns_name_countlabels(name);
274 * loop through starting with the longest domain name and
275 * trying shorter names portions of the name until we find a
276 * match, have an error, or are below the 'minlabels'
277 * threshold. minlabels is 0, if the standard database didn't
278 * have a zone name match. Otherwise minlabels is the number
279 * of labels in that name. We need to beat that for a
280 * "better" match for the DLZ database to be authoritative
281 * instead of the standard database.
283 for (i = namelabels; i > minlabels && i > 1; i--) {
284 if (i == namelabels) {
285 result = dns_name_copy(name, zonename, NULL);
286 if (result != ISC_R_SUCCESS)
287 return (result);
288 } else
289 dns_name_split(name, i, NULL, zonename);
291 /* ask SDLZ driver if the zone is supported */
292 dlzdatabase = view->dlzdatabase;
293 findzone = dlzdatabase->implementation->methods->findzone;
294 result = (*findzone)(dlzdatabase->implementation->driverarg,
295 dlzdatabase->dbdata, dlzdatabase->mctx,
296 view->rdclass, zonename, dbp);
297 if (result != ISC_R_NOTFOUND)
298 return (result);
300 return (ISC_R_NOTFOUND);
304 * Registers a DLZ driver. This basically just adds the dlz
305 * driver to the list of available drivers in the dlz_implementations list.
307 isc_result_t
308 dns_dlzregister(const char *drivername, const dns_dlzmethods_t *methods,
309 void *driverarg, isc_mem_t *mctx,
310 dns_dlzimplementation_t **dlzimp)
313 dns_dlzimplementation_t *dlz_imp;
315 /* Write debugging message to log */
316 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
317 DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
318 "Registering DLZ driver '%s'", drivername);
321 * Performs checks to make sure data is as we expect it to be.
323 REQUIRE(drivername != NULL);
324 REQUIRE(methods != NULL);
325 REQUIRE(methods->create != NULL);
326 REQUIRE(methods->destroy != NULL);
327 REQUIRE(methods->findzone != NULL);
328 REQUIRE(mctx != NULL);
329 REQUIRE(dlzimp != NULL && *dlzimp == NULL);
332 * initialize the dlz_implementations list, this is guaranteed
333 * to only really happen once.
335 RUNTIME_CHECK(isc_once_do(&once, dlz_initialize) == ISC_R_SUCCESS);
337 /* lock the dlz_implementations list so we can modify it. */
338 RWLOCK(&dlz_implock, isc_rwlocktype_write);
341 * check that another already registered driver isn't using
342 * the same name
344 dlz_imp = dlz_impfind(drivername);
345 if (dlz_imp != NULL) {
346 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
347 DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
348 "DLZ Driver '%s' already registered",
349 drivername);
350 RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
351 return (ISC_R_EXISTS);
355 * Allocate memory for a dlz_implementation object. Error if
356 * we cannot.
358 dlz_imp = isc_mem_get(mctx, sizeof(dns_dlzimplementation_t));
359 if (dlz_imp == NULL) {
360 RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
361 return (ISC_R_NOMEMORY);
364 /* Make sure memory region is set to all 0's */
365 memset(dlz_imp, 0, sizeof(dns_dlzimplementation_t));
367 /* Store the data passed into this method */
368 dlz_imp->name = drivername;
369 dlz_imp->methods = methods;
370 dlz_imp->mctx = NULL;
371 dlz_imp->driverarg = driverarg;
373 /* attach the new dlz_implementation object to a memory context */
374 isc_mem_attach(mctx, &dlz_imp->mctx);
377 * prepare the dlz_implementation object to be put in a list,
378 * and append it to the list
380 ISC_LINK_INIT(dlz_imp, link);
381 ISC_LIST_APPEND(dlz_implementations, dlz_imp, link);
383 /* Unlock the dlz_implementations list. */
384 RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
386 /* Pass back the dlz_implementation that we created. */
387 *dlzimp = dlz_imp;
389 return (ISC_R_SUCCESS);
393 * Helper function for dns_dlzstrtoargv().
394 * Pardon the gratuitous recursion.
396 static isc_result_t
397 dns_dlzstrtoargvsub(isc_mem_t *mctx, char *s, unsigned int *argcp,
398 char ***argvp, unsigned int n)
400 isc_result_t result;
402 restart:
403 /* Discard leading whitespace. */
404 while (*s == ' ' || *s == '\t')
405 s++;
407 if (*s == '\0') {
408 /* We have reached the end of the string. */
409 *argcp = n;
410 *argvp = isc_mem_get(mctx, n * sizeof(char *));
411 if (*argvp == NULL)
412 return (ISC_R_NOMEMORY);
413 } else {
414 char *p = s;
415 while (*p != ' ' && *p != '\t' && *p != '\0' && *p != '{') {
416 if (*p == '\n') {
417 *p = ' ';
418 goto restart;
420 p++;
423 /* do "grouping", items between { and } are one arg */
424 if (*p == '{') {
425 char *t = p;
427 * shift all characters to left by 1 to get rid of '{'
429 while (*t != '\0') {
430 t++;
431 *(t-1) = *t;
433 while (*p != '\0' && *p != '}') {
434 p++;
436 /* get rid of '}' character */
437 if (*p == '}') {
438 *p = '\0';
439 p++;
441 /* normal case, no "grouping" */
442 } else if (*p != '\0')
443 *p++ = '\0';
445 result = dns_dlzstrtoargvsub(mctx, p, argcp, argvp, n + 1);
446 if (result != ISC_R_SUCCESS)
447 return (result);
448 (*argvp)[n] = s;
450 return (ISC_R_SUCCESS);
454 * Tokenize the string "s" into whitespace-separated words,
455 * return the number of words in '*argcp' and an array
456 * of pointers to the words in '*argvp'. The caller
457 * must free the array using isc_mem_put(). The string
458 * is modified in-place.
460 isc_result_t
461 dns_dlzstrtoargv(isc_mem_t *mctx, char *s,
462 unsigned int *argcp, char ***argvp)
464 return(dns_dlzstrtoargvsub(mctx, s, argcp, argvp, 0));
468 * Unregisters a DLZ driver. This basically just removes the dlz
469 * driver from the list of available drivers in the dlz_implementations list.
471 void
472 dns_dlzunregister(dns_dlzimplementation_t **dlzimp) {
473 dns_dlzimplementation_t *dlz_imp;
474 isc_mem_t *mctx;
476 /* Write debugging message to log */
477 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
478 DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
479 "Unregistering DLZ driver.");
482 * Performs checks to make sure data is as we expect it to be.
484 REQUIRE(dlzimp != NULL && *dlzimp != NULL);
487 * initialize the dlz_implementations list, this is guaranteed
488 * to only really happen once.
490 RUNTIME_CHECK(isc_once_do(&once, dlz_initialize) == ISC_R_SUCCESS);
492 dlz_imp = *dlzimp;
494 /* lock the dlz_implementations list so we can modify it. */
495 RWLOCK(&dlz_implock, isc_rwlocktype_write);
497 /* remove the dlz_implementation object from the list */
498 ISC_LIST_UNLINK(dlz_implementations, dlz_imp, link);
499 mctx = dlz_imp->mctx;
502 * return the memory back to the available memory pool and
503 * remove it from the memory context.
505 isc_mem_put(mctx, dlz_imp, sizeof(dns_dlzimplementation_t));
506 isc_mem_detach(&mctx);
508 /* Unlock the dlz_implementations list. */
509 RWUNLOCK(&dlz_implock, isc_rwlocktype_write);