Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / lib / dns / dlz.c
blob953a669bb70cf7add200fe77158fd8027c3cf48b
1 /* $NetBSD: dlz.c,v 1.7 2014/12/10 04:37:58 christos Exp $ */
3 /*
4 * Portions Copyright (C) 2005, 2007, 2009-2013 Internet Systems Consortium, Inc. ("ISC")
5 * Portions Copyright (C) 1999-2001 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
21 * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
23 * Permission to use, copy, modify, and distribute this software for any
24 * purpose with or without fee is hereby granted, provided that the
25 * above copyright notice and this permission notice appear in all
26 * copies.
28 * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
29 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
31 * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
32 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
33 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
34 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
35 * USE OR PERFORMANCE OF THIS SOFTWARE.
37 * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
38 * conceived and contributed by Rob Butler.
40 * Permission to use, copy, modify, and distribute this software for any
41 * purpose with or without fee is hereby granted, provided that the
42 * above copyright notice and this permission notice appear in all
43 * copies.
45 * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
46 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
48 * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
49 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
50 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
51 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
52 * USE OR PERFORMANCE OF THIS SOFTWARE.
55 /* Id */
57 /*! \file */
59 /***
60 *** Imports
61 ***/
63 #include <config.h>
65 #include <dns/db.h>
66 #include <dns/dlz.h>
67 #include <dns/fixedname.h>
68 #include <dns/log.h>
69 #include <dns/master.h>
70 #include <dns/ssu.h>
71 #include <dns/zone.h>
74 #include <isc/buffer.h>
75 #include <isc/magic.h>
76 #include <isc/mem.h>
77 #include <isc/once.h>
78 #include <isc/rwlock.h>
79 #include <isc/string.h>
80 #include <isc/util.h>
82 /***
83 *** Supported DLZ DB Implementations Registry
84 ***/
86 static ISC_LIST(dns_dlzimplementation_t) dlz_implementations;
87 static isc_rwlock_t dlz_implock;
88 static isc_once_t once = ISC_ONCE_INIT;
90 static void
91 dlz_initialize(void) {
92 RUNTIME_CHECK(isc_rwlock_init(&dlz_implock, 0, 0) == ISC_R_SUCCESS);
93 ISC_LIST_INIT(dlz_implementations);
96 /*%
97 * Searches the dlz_implementations list for a driver matching name.
99 static inline dns_dlzimplementation_t *
100 dlz_impfind(const char *name) {
101 dns_dlzimplementation_t *imp;
103 for (imp = ISC_LIST_HEAD(dlz_implementations);
104 imp != NULL;
105 imp = ISC_LIST_NEXT(imp, link))
106 if (strcasecmp(name, imp->name) == 0)
107 return (imp);
108 return (NULL);
111 /***
112 *** Basic DLZ Methods
113 ***/
115 isc_result_t
116 dns_dlzallowzonexfr(dns_view_t *view, dns_name_t *name,
117 isc_sockaddr_t *clientaddr, dns_db_t **dbp)
119 isc_result_t result = ISC_R_NOTFOUND;
120 dns_dlzallowzonexfr_t allowzonexfr;
121 dns_dlzdb_t *dlzdb;
124 * Performs checks to make sure data is as we expect it to be.
126 REQUIRE(name != NULL);
127 REQUIRE(dbp != NULL && *dbp == NULL);
130 * Find a driver in which the zone exists and transfer is supported
132 for (dlzdb = ISC_LIST_HEAD(view->dlz_searched);
133 dlzdb != NULL;
134 dlzdb = ISC_LIST_NEXT(dlzdb, link))
136 REQUIRE(DNS_DLZ_VALID(dlzdb));
138 allowzonexfr = dlzdb->implementation->methods->allowzonexfr;
139 result = (*allowzonexfr)(dlzdb->implementation->driverarg,
140 dlzdb->dbdata, dlzdb->mctx,
141 view->rdclass, name, clientaddr, dbp);
144 * if ISC_R_NOPERM, we found the right database but
145 * the zone may not transfer.
147 if (result == ISC_R_SUCCESS || result == ISC_R_NOPERM)
148 return (result);
151 if (result == ISC_R_NOTIMPLEMENTED)
152 result = ISC_R_NOTFOUND;
154 return (result);
157 isc_result_t
158 dns_dlzcreate(isc_mem_t *mctx, const char *dlzname, const char *drivername,
159 unsigned int argc, char *argv[], dns_dlzdb_t **dbp)
161 dns_dlzimplementation_t *impinfo;
162 isc_result_t result;
163 dns_dlzdb_t *db = NULL;
166 * initialize the dlz_implementations list, this is guaranteed
167 * to only really happen once.
169 RUNTIME_CHECK(isc_once_do(&once, dlz_initialize) == ISC_R_SUCCESS);
172 * Performs checks to make sure data is as we expect it to be.
174 REQUIRE(dbp != NULL && *dbp == NULL);
175 REQUIRE(dlzname != NULL);
176 REQUIRE(drivername != NULL);
177 REQUIRE(mctx != NULL);
179 /* write log message */
180 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
181 DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
182 "Loading '%s' using driver %s", dlzname, drivername);
184 /* lock the dlz_implementations list so we can search it. */
185 RWLOCK(&dlz_implock, isc_rwlocktype_read);
187 /* search for the driver implementation */
188 impinfo = dlz_impfind(drivername);
189 if (impinfo == NULL) {
190 RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
192 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
193 DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
194 "unsupported DLZ database driver '%s'."
195 " %s not loaded.",
196 drivername, dlzname);
198 return (ISC_R_NOTFOUND);
201 /* Allocate memory to hold the DLZ database driver */
202 db = isc_mem_get(mctx, sizeof(dns_dlzdb_t));
203 if (db == NULL) {
204 RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
205 return (ISC_R_NOMEMORY);
208 /* Make sure memory region is set to all 0's */
209 memset(db, 0, sizeof(dns_dlzdb_t));
211 ISC_LINK_INIT(db, link);
212 db->implementation = impinfo;
213 if (dlzname != NULL)
214 db->dlzname = isc_mem_strdup(mctx, dlzname);
216 /* Create a new database using implementation 'drivername'. */
217 result = ((impinfo->methods->create)(mctx, dlzname, argc, argv,
218 impinfo->driverarg,
219 &db->dbdata));
221 /* mark the DLZ driver as valid */
222 if (result == ISC_R_SUCCESS) {
223 RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
224 db->magic = DNS_DLZ_MAGIC;
225 isc_mem_attach(mctx, &db->mctx);
226 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
227 DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
228 "DLZ driver loaded successfully.");
229 *dbp = db;
230 return (ISC_R_SUCCESS);
231 } else {
232 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
233 DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
234 "DLZ driver failed to load.");
237 /* impinfo->methods->create failed. */
238 RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
239 isc_mem_put(mctx, db, sizeof(dns_dlzdb_t));
240 return (result);
243 void
244 dns_dlzdestroy(dns_dlzdb_t **dbp) {
245 isc_mem_t *mctx;
246 dns_dlzdestroy_t destroy;
248 /* Write debugging message to log */
249 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
250 DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
251 "Unloading DLZ driver.");
254 * Perform checks to make sure data is as we expect it to be.
256 REQUIRE(dbp != NULL && DNS_DLZ_VALID(*dbp));
258 if ((*dbp)->ssutable != NULL) {
259 dns_ssutable_detach(&(*dbp)->ssutable);
262 /* call the drivers destroy method */
263 if ((*dbp) != NULL) {
264 mctx = (*dbp)->mctx;
265 if ((*dbp)->dlzname != NULL)
266 isc_mem_free(mctx, (*dbp)->dlzname);
267 destroy = (*dbp)->implementation->methods->destroy;
268 (*destroy)((*dbp)->implementation->driverarg,(*dbp)->dbdata);
269 /* return memory */
270 isc_mem_put(mctx, (*dbp), sizeof(dns_dlzdb_t));
271 isc_mem_detach(&mctx);
274 *dbp = NULL;
278 * Registers a DLZ driver. This basically just adds the dlz
279 * driver to the list of available drivers in the dlz_implementations list.
281 isc_result_t
282 dns_dlzregister(const char *drivername, const dns_dlzmethods_t *methods,
283 void *driverarg, isc_mem_t *mctx,
284 dns_dlzimplementation_t **dlzimp)
287 dns_dlzimplementation_t *dlz_imp;
289 /* Write debugging message to log */
290 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
291 DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
292 "Registering DLZ driver '%s'", drivername);
295 * Performs checks to make sure data is as we expect it to be.
297 REQUIRE(drivername != NULL);
298 REQUIRE(methods != NULL);
299 REQUIRE(methods->create != NULL);
300 REQUIRE(methods->destroy != NULL);
301 REQUIRE(methods->findzone != NULL);
302 REQUIRE(mctx != NULL);
303 REQUIRE(dlzimp != NULL && *dlzimp == NULL);
306 * initialize the dlz_implementations list, this is guaranteed
307 * to only really happen once.
309 RUNTIME_CHECK(isc_once_do(&once, dlz_initialize) == ISC_R_SUCCESS);
311 /* lock the dlz_implementations list so we can modify it. */
312 RWLOCK(&dlz_implock, isc_rwlocktype_write);
315 * check that another already registered driver isn't using
316 * the same name
318 dlz_imp = dlz_impfind(drivername);
319 if (dlz_imp != NULL) {
320 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
321 DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
322 "DLZ Driver '%s' already registered",
323 drivername);
324 RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
325 return (ISC_R_EXISTS);
329 * Allocate memory for a dlz_implementation object. Error if
330 * we cannot.
332 dlz_imp = isc_mem_get(mctx, sizeof(dns_dlzimplementation_t));
333 if (dlz_imp == NULL) {
334 RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
335 return (ISC_R_NOMEMORY);
338 /* Make sure memory region is set to all 0's */
339 memset(dlz_imp, 0, sizeof(dns_dlzimplementation_t));
341 /* Store the data passed into this method */
342 dlz_imp->name = drivername;
343 dlz_imp->methods = methods;
344 dlz_imp->mctx = NULL;
345 dlz_imp->driverarg = driverarg;
347 /* attach the new dlz_implementation object to a memory context */
348 isc_mem_attach(mctx, &dlz_imp->mctx);
351 * prepare the dlz_implementation object to be put in a list,
352 * and append it to the list
354 ISC_LINK_INIT(dlz_imp, link);
355 ISC_LIST_APPEND(dlz_implementations, dlz_imp, link);
357 /* Unlock the dlz_implementations list. */
358 RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
360 /* Pass back the dlz_implementation that we created. */
361 *dlzimp = dlz_imp;
363 return (ISC_R_SUCCESS);
367 * Helper function for dns_dlzstrtoargv().
368 * Pardon the gratuitous recursion.
370 static isc_result_t
371 dns_dlzstrtoargvsub(isc_mem_t *mctx, char *s, unsigned int *argcp,
372 char ***argvp, unsigned int n)
374 isc_result_t result;
376 restart:
377 /* Discard leading whitespace. */
378 while (*s == ' ' || *s == '\t')
379 s++;
381 if (*s == '\0') {
382 /* We have reached the end of the string. */
383 *argcp = n;
384 *argvp = isc_mem_get(mctx, n * sizeof(char *));
385 if (*argvp == NULL)
386 return (ISC_R_NOMEMORY);
387 } else {
388 char *p = s;
389 while (*p != ' ' && *p != '\t' && *p != '\0' && *p != '{') {
390 if (*p == '\n') {
391 *p = ' ';
392 goto restart;
394 p++;
397 /* do "grouping", items between { and } are one arg */
398 if (*p == '{') {
399 char *t = p;
401 * shift all characters to left by 1 to get rid of '{'
403 while (*t != '\0') {
404 t++;
405 *(t-1) = *t;
407 while (*p != '\0' && *p != '}') {
408 p++;
410 /* get rid of '}' character */
411 if (*p == '}') {
412 *p = '\0';
413 p++;
415 /* normal case, no "grouping" */
416 } else if (*p != '\0')
417 *p++ = '\0';
419 result = dns_dlzstrtoargvsub(mctx, p, argcp, argvp, n + 1);
420 if (result != ISC_R_SUCCESS)
421 return (result);
422 (*argvp)[n] = s;
424 return (ISC_R_SUCCESS);
428 * Tokenize the string "s" into whitespace-separated words,
429 * return the number of words in '*argcp' and an array
430 * of pointers to the words in '*argvp'. The caller
431 * must free the array using isc_mem_put(). The string
432 * is modified in-place.
434 isc_result_t
435 dns_dlzstrtoargv(isc_mem_t *mctx, char *s,
436 unsigned int *argcp, char ***argvp)
438 return(dns_dlzstrtoargvsub(mctx, s, argcp, argvp, 0));
442 * Unregisters a DLZ driver. This basically just removes the dlz
443 * driver from the list of available drivers in the dlz_implementations list.
445 void
446 dns_dlzunregister(dns_dlzimplementation_t **dlzimp) {
447 dns_dlzimplementation_t *dlz_imp;
448 isc_mem_t *mctx;
450 /* Write debugging message to log */
451 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
452 DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
453 "Unregistering DLZ driver.");
456 * Performs checks to make sure data is as we expect it to be.
458 REQUIRE(dlzimp != NULL && *dlzimp != NULL);
461 * initialize the dlz_implementations list, this is guaranteed
462 * to only really happen once.
464 RUNTIME_CHECK(isc_once_do(&once, dlz_initialize) == ISC_R_SUCCESS);
466 dlz_imp = *dlzimp;
468 /* lock the dlz_implementations list so we can modify it. */
469 RWLOCK(&dlz_implock, isc_rwlocktype_write);
471 /* remove the dlz_implementation object from the list */
472 ISC_LIST_UNLINK(dlz_implementations, dlz_imp, link);
473 mctx = dlz_imp->mctx;
476 * Return the memory back to the available memory pool and
477 * remove it from the memory context.
479 isc_mem_put(mctx, dlz_imp, sizeof(dns_dlzimplementation_t));
480 isc_mem_detach(&mctx);
482 /* Unlock the dlz_implementations list. */
483 RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
487 * Create a writeable DLZ zone. This can be called by DLZ drivers
488 * during configure() to create a zone that can be updated. The zone
489 * type is set to dns_zone_dlz, which is equivalent to a master zone
491 * This function uses a callback setup in dns_dlzconfigure() to call
492 * into the server zone code to setup the remaining pieces of server
493 * specific functionality on the zone
495 isc_result_t
496 dns_dlz_writeablezone(dns_view_t *view, dns_dlzdb_t *dlzdb,
497 const char *zone_name)
499 dns_zone_t *zone = NULL;
500 dns_zone_t *dupzone = NULL;
501 isc_result_t result;
502 isc_buffer_t buffer;
503 dns_fixedname_t fixorigin;
504 dns_name_t *origin;
506 REQUIRE(DNS_DLZ_VALID(dlzdb));
508 REQUIRE(dlzdb->configure_callback != NULL);
510 isc_buffer_constinit(&buffer, zone_name, strlen(zone_name));
511 isc_buffer_add(&buffer, strlen(zone_name));
512 dns_fixedname_init(&fixorigin);
513 result = dns_name_fromtext(dns_fixedname_name(&fixorigin),
514 &buffer, dns_rootname, 0, NULL);
515 if (result != ISC_R_SUCCESS)
516 goto cleanup;
517 origin = dns_fixedname_name(&fixorigin);
519 if (!dlzdb->search) {
520 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
521 DNS_LOGMODULE_DLZ, ISC_LOG_WARNING,
522 "DLZ %s has 'search no;', but attempted to "
523 "register writeable zone %s.",
524 dlzdb->dlzname, zone_name);
525 result = ISC_R_SUCCESS;
526 goto cleanup;
529 /* See if the zone already exists */
530 result = dns_view_findzone(view, origin, &dupzone);
531 if (result == ISC_R_SUCCESS) {
532 dns_zone_detach(&dupzone);
533 result = ISC_R_EXISTS;
534 goto cleanup;
536 INSIST(dupzone == NULL);
538 /* Create it */
539 result = dns_zone_create(&zone, view->mctx);
540 if (result != ISC_R_SUCCESS)
541 goto cleanup;
542 result = dns_zone_setorigin(zone, origin);
543 if (result != ISC_R_SUCCESS)
544 goto cleanup;
545 dns_zone_setview(zone, view);
547 dns_zone_setadded(zone, ISC_TRUE);
549 if (dlzdb->ssutable == NULL) {
550 result = dns_ssutable_createdlz(dlzdb->mctx,
551 &dlzdb->ssutable, dlzdb);
552 if (result != ISC_R_SUCCESS)
553 goto cleanup;
555 dns_zone_setssutable(zone, dlzdb->ssutable);
557 result = dlzdb->configure_callback(view, dlzdb, zone);
558 if (result != ISC_R_SUCCESS)
559 goto cleanup;
561 result = dns_view_addzone(view, zone);
564 cleanup:
565 if (zone != NULL)
566 dns_zone_detach(&zone);
568 return (result);
572 * Configure a DLZ driver. This is optional, and if supplied gives
573 * the backend an opportunity to configure parameters related to DLZ.
575 isc_result_t
576 dns_dlzconfigure(dns_view_t *view, dns_dlzdb_t *dlzdb,
577 dlzconfigure_callback_t callback)
579 dns_dlzimplementation_t *impl;
580 isc_result_t result;
582 REQUIRE(DNS_DLZ_VALID(dlzdb));
583 REQUIRE(dlzdb->implementation != NULL);
585 impl = dlzdb->implementation;
587 if (impl->methods->configure == NULL)
588 return (ISC_R_SUCCESS);
590 dlzdb->configure_callback = callback;
592 result = impl->methods->configure(impl->driverarg, dlzdb->dbdata,
593 view, dlzdb);
594 return (result);
597 isc_boolean_t
598 dns_dlz_ssumatch(dns_dlzdb_t *dlzdatabase, dns_name_t *signer,
599 dns_name_t *name, isc_netaddr_t *tcpaddr,
600 dns_rdatatype_t type, const dst_key_t *key)
602 dns_dlzimplementation_t *impl;
603 isc_boolean_t r;
605 REQUIRE(dlzdatabase != NULL);
606 REQUIRE(dlzdatabase->implementation != NULL);
607 REQUIRE(dlzdatabase->implementation->methods != NULL);
608 impl = dlzdatabase->implementation;
610 if (impl->methods->ssumatch == NULL) {
611 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
612 DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
613 "No ssumatch method for DLZ database");
614 return (ISC_FALSE);
617 r = impl->methods->ssumatch(signer, name, tcpaddr, type, key,
618 impl->driverarg, dlzdatabase->dbdata);
619 return (r);