1 /* $NetBSD: dlz_dlopen_driver.c,v 1.4 2015/07/08 17:28:55 christos Exp $ */
4 * Copyright (C) 2011-2014 Internet Systems Consortium, Inc. ("ISC")
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
19 /* Id: dlz_dlopen_driver.c,v 1.5 2011/10/14 00:52:32 marka Exp */
30 #include <dns/result.h>
31 #include <dns/dlz_dlopen.h>
34 #include <isc/print.h>
35 #include <isc/result.h>
38 #include <named/globals.h>
40 #include <dlz/dlz_dlopen_driver.h>
43 static dns_sdlzimplementation_t
*dlz_dlopen
= NULL
;
46 typedef struct dlopen_data
{
55 isc_boolean_t in_configure
;
57 dlz_dlopen_version_t
*dlz_version
;
58 dlz_dlopen_create_t
*dlz_create
;
59 dlz_dlopen_findzonedb_t
*dlz_findzonedb
;
60 dlz_dlopen_lookup_t
*dlz_lookup
;
61 dlz_dlopen_authority_t
*dlz_authority
;
62 dlz_dlopen_allnodes_t
*dlz_allnodes
;
63 dlz_dlopen_allowzonexfr_t
*dlz_allowzonexfr
;
64 dlz_dlopen_newversion_t
*dlz_newversion
;
65 dlz_dlopen_closeversion_t
*dlz_closeversion
;
66 dlz_dlopen_configure_t
*dlz_configure
;
67 dlz_dlopen_ssumatch_t
*dlz_ssumatch
;
68 dlz_dlopen_addrdataset_t
*dlz_addrdataset
;
69 dlz_dlopen_subrdataset_t
*dlz_subrdataset
;
70 dlz_dlopen_delrdataset_t
*dlz_delrdataset
;
71 dlz_dlopen_destroy_t
*dlz_destroy
;
74 /* Modules can choose whether they are lock-safe or not. */
75 #define MAYBE_LOCK(cd) \
77 if ((cd->flags & DNS_SDLZFLAG_THREADSAFE) == 0 && \
78 cd->in_configure == ISC_FALSE) \
80 } while (/*CONSTCOND*/0)
82 #define MAYBE_UNLOCK(cd) \
84 if ((cd->flags & DNS_SDLZFLAG_THREADSAFE) == 0 && \
85 cd->in_configure == ISC_FALSE) \
87 } while (/*CONSTCOND*/0)
90 * Log a message at the given level.
92 static void dlopen_log(int level
, const char *fmt
, ...)
96 isc_log_vwrite(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
97 DNS_LOGMODULE_DLZ
, ISC_LOG_DEBUG(level
),
107 dlopen_dlz_allnodes(const char *zone
, void *driverarg
, void *dbdata
,
108 dns_sdlzallnodes_t
*allnodes
)
110 dlopen_data_t
*cd
= (dlopen_data_t
*) dbdata
;
116 if (cd
->dlz_allnodes
== NULL
) {
117 return (ISC_R_NOPERM
);
121 result
= cd
->dlz_allnodes(zone
, cd
->dbdata
, allnodes
);
128 dlopen_dlz_allowzonexfr(void *driverarg
, void *dbdata
, const char *name
,
131 dlopen_data_t
*cd
= (dlopen_data_t
*) dbdata
;
137 if (cd
->dlz_allowzonexfr
== NULL
) {
138 return (ISC_R_NOPERM
);
142 result
= cd
->dlz_allowzonexfr(cd
->dbdata
, name
, client
);
148 dlopen_dlz_authority(const char *zone
, void *driverarg
, void *dbdata
,
149 dns_sdlzlookup_t
*lookup
)
151 dlopen_data_t
*cd
= (dlopen_data_t
*) dbdata
;
156 if (cd
->dlz_authority
== NULL
) {
157 return (ISC_R_NOTIMPLEMENTED
);
161 result
= cd
->dlz_authority(zone
, cd
->dbdata
, lookup
);
167 dlopen_dlz_findzonedb(void *driverarg
, void *dbdata
, const char *name
,
168 dns_clientinfomethods_t
*methods
,
169 dns_clientinfo_t
*clientinfo
)
171 dlopen_data_t
*cd
= (dlopen_data_t
*) dbdata
;
177 result
= cd
->dlz_findzonedb(cd
->dbdata
, name
, methods
, clientinfo
);
184 dlopen_dlz_lookup(const char *zone
, const char *name
, void *driverarg
,
185 void *dbdata
, dns_sdlzlookup_t
*lookup
,
186 dns_clientinfomethods_t
*methods
,
187 dns_clientinfo_t
*clientinfo
)
189 dlopen_data_t
*cd
= (dlopen_data_t
*) dbdata
;
195 result
= cd
->dlz_lookup(zone
, name
, cd
->dbdata
, lookup
,
196 methods
, clientinfo
);
202 * Load a symbol from the library
205 dl_load_symbol(dlopen_data_t
*cd
, const char *symbol
, isc_boolean_t mandatory
) {
206 void *ptr
= GetProcAddress(cd
->dl_handle
, symbol
);
207 if (ptr
== NULL
&& mandatory
) {
208 dlopen_log(ISC_LOG_ERROR
,
209 "dlz_dlopen: library '%s' is missing "
210 "required symbol '%s'", cd
->dl_path
, symbol
);
216 * Called at startup for each dlopen zone in named.conf
219 dlopen_dlz_create(const char *dlzname
, unsigned int argc
, char *argv
[],
220 void *driverarg
, void **dbdata
)
223 isc_mem_t
*mctx
= NULL
;
224 isc_result_t result
= ISC_R_FAILURE
;
225 isc_boolean_t triedload
= ISC_FALSE
;
230 dlopen_log(ISC_LOG_ERROR
,
231 "dlz_dlopen driver for '%s' needs a path to "
232 "the shared library", dlzname
);
233 return (ISC_R_FAILURE
);
236 isc_mem_create(0, 0, &mctx
);
238 cd
= isc_mem_get(mctx
, sizeof(*cd
));
240 isc_mem_destroy(&mctx
);
241 return (ISC_R_NOMEMORY
);
243 memset(cd
, 0, sizeof(*cd
));
247 cd
->dl_path
= isc_mem_strdup(cd
->mctx
, argv
[1]);
248 if (cd
->dl_path
== NULL
) {
249 result
= ISC_R_NOMEMORY
;
253 cd
->dlzname
= isc_mem_strdup(cd
->mctx
, dlzname
);
254 if (cd
->dlzname
== NULL
) {
255 result
= ISC_R_NOMEMORY
;
259 triedload
= ISC_TRUE
;
261 /* Initialize the lock */
262 result
= isc_mutex_init(&cd
->lock
);
263 if (result
!= ISC_R_SUCCESS
)
266 /* Open the library */
267 cd
->dl_handle
= LoadLibraryA(cd
->dl_path
);
268 if (cd
->dl_handle
== NULL
) {
269 unsigned int error
= GetLastError();
271 dlopen_log(ISC_LOG_ERROR
,
272 "dlz_dlopen failed to open library '%s' - %u",
274 result
= ISC_R_FAILURE
;
278 /* Find the symbols */
279 cd
->dlz_version
= (dlz_dlopen_version_t
*)
280 dl_load_symbol(cd
, "dlz_version", ISC_TRUE
);
281 cd
->dlz_create
= (dlz_dlopen_create_t
*)
282 dl_load_symbol(cd
, "dlz_create", ISC_TRUE
);
283 cd
->dlz_lookup
= (dlz_dlopen_lookup_t
*)
284 dl_load_symbol(cd
, "dlz_lookup", ISC_TRUE
);
285 cd
->dlz_findzonedb
= (dlz_dlopen_findzonedb_t
*)
286 dl_load_symbol(cd
, "dlz_findzonedb", ISC_TRUE
);
288 if (cd
->dlz_create
== NULL
||
289 cd
->dlz_version
== NULL
||
290 cd
->dlz_lookup
== NULL
||
291 cd
->dlz_findzonedb
== NULL
)
293 /* We're missing a required symbol */
294 result
= ISC_R_FAILURE
;
298 cd
->dlz_allowzonexfr
= (dlz_dlopen_allowzonexfr_t
*)
299 dl_load_symbol(cd
, "dlz_allowzonexfr", ISC_FALSE
);
300 cd
->dlz_allnodes
= (dlz_dlopen_allnodes_t
*)
301 dl_load_symbol(cd
, "dlz_allnodes",
302 ISC_TF(cd
->dlz_allowzonexfr
!= NULL
));
303 cd
->dlz_authority
= (dlz_dlopen_authority_t
*)
304 dl_load_symbol(cd
, "dlz_authority", ISC_FALSE
);
305 cd
->dlz_newversion
= (dlz_dlopen_newversion_t
*)
306 dl_load_symbol(cd
, "dlz_newversion", ISC_FALSE
);
307 cd
->dlz_closeversion
= (dlz_dlopen_closeversion_t
*)
308 dl_load_symbol(cd
, "dlz_closeversion",
309 ISC_TF(cd
->dlz_newversion
!= NULL
));
310 cd
->dlz_configure
= (dlz_dlopen_configure_t
*)
311 dl_load_symbol(cd
, "dlz_configure", ISC_FALSE
);
312 cd
->dlz_ssumatch
= (dlz_dlopen_ssumatch_t
*)
313 dl_load_symbol(cd
, "dlz_ssumatch", ISC_FALSE
);
314 cd
->dlz_addrdataset
= (dlz_dlopen_addrdataset_t
*)
315 dl_load_symbol(cd
, "dlz_addrdataset", ISC_FALSE
);
316 cd
->dlz_subrdataset
= (dlz_dlopen_subrdataset_t
*)
317 dl_load_symbol(cd
, "dlz_subrdataset", ISC_FALSE
);
318 cd
->dlz_delrdataset
= (dlz_dlopen_delrdataset_t
*)
319 dl_load_symbol(cd
, "dlz_delrdataset", ISC_FALSE
);
321 /* Check the version of the API is the same */
322 cd
->version
= cd
->dlz_version(&cd
->flags
);
323 if (cd
->version
< (DLZ_DLOPEN_VERSION
- DLZ_DLOPEN_AGE
) ||
324 cd
->version
> DLZ_DLOPEN_VERSION
)
326 dlopen_log(ISC_LOG_ERROR
,
327 "dlz_dlopen: %s: incorrect driver API version %d, "
329 cd
->dl_path
, cd
->version
, DLZ_DLOPEN_VERSION
);
330 result
= ISC_R_FAILURE
;
335 * Call the library's create function. Note that this is an
336 * extended version of dlz create, with the addition of
337 * named function pointers for helper functions that the
338 * driver will need. This avoids the need for the backend to
339 * link the BIND9 libraries
342 result
= cd
->dlz_create(dlzname
, argc
-1, argv
+1,
345 "putrr", dns_sdlz_putrr
,
346 "putnamedrr", dns_sdlz_putnamedrr
,
347 "writeable_zone", dns_dlz_writeablezone
,
350 if (result
!= ISC_R_SUCCESS
)
355 return (ISC_R_SUCCESS
);
358 DESTROYLOCK(&cd
->lock
);
360 dlopen_log(ISC_LOG_ERROR
, "dlz_dlopen of '%s' failed", dlzname
);
362 isc_mem_free(mctx
, cd
->dl_path
);
364 isc_mem_free(mctx
, cd
->dlzname
);
366 (void) isc_mutex_destroy(&cd
->lock
);
368 FreeLibrary(cd
->dl_handle
);
369 isc_mem_put(mctx
, cd
, sizeof(*cd
));
370 isc_mem_destroy(&mctx
);
376 * Called when bind is shutting down
379 dlopen_dlz_destroy(void *driverarg
, void *dbdata
) {
380 dlopen_data_t
*cd
= (dlopen_data_t
*) dbdata
;
385 if (cd
->dlz_destroy
) {
387 cd
->dlz_destroy(cd
->dbdata
);
392 isc_mem_free(cd
->mctx
, cd
->dl_path
);
394 isc_mem_free(cd
->mctx
, cd
->dlzname
);
397 FreeLibrary(cd
->dl_handle
);
399 DESTROYLOCK(&cd
->lock
);
402 isc_mem_put(mctx
, cd
, sizeof(*cd
));
403 isc_mem_destroy(&mctx
);
407 * Called to start a transaction
410 dlopen_dlz_newversion(const char *zone
, void *driverarg
, void *dbdata
,
413 dlopen_data_t
*cd
= (dlopen_data_t
*) dbdata
;
418 if (cd
->dlz_newversion
== NULL
)
419 return (ISC_R_NOTIMPLEMENTED
);
422 result
= cd
->dlz_newversion(zone
, cd
->dbdata
, versionp
);
428 * Called to end a transaction
431 dlopen_dlz_closeversion(const char *zone
, isc_boolean_t commit
,
432 void *driverarg
, void *dbdata
, void **versionp
)
434 dlopen_data_t
*cd
= (dlopen_data_t
*) dbdata
;
438 if (cd
->dlz_newversion
== NULL
) {
444 cd
->dlz_closeversion(zone
, commit
, cd
->dbdata
, versionp
);
449 * Called on startup to configure any writeable zones
452 dlopen_dlz_configure(dns_view_t
*view
, dns_dlzdb_t
*dlzdb
,
453 void *driverarg
, void *dbdata
)
455 dlopen_data_t
*cd
= (dlopen_data_t
*) dbdata
;
460 if (cd
->dlz_configure
== NULL
)
461 return (ISC_R_SUCCESS
);
464 cd
->in_configure
= ISC_TRUE
;
465 result
= cd
->dlz_configure(view
, dlzdb
, cd
->dbdata
);
466 cd
->in_configure
= ISC_FALSE
;
474 * Check for authority to change a name
477 dlopen_dlz_ssumatch(const char *signer
, const char *name
, const char *tcpaddr
,
478 const char *type
, const char *key
, isc_uint32_t keydatalen
,
479 unsigned char *keydata
, void *driverarg
, void *dbdata
)
481 dlopen_data_t
*cd
= (dlopen_data_t
*) dbdata
;
486 if (cd
->dlz_ssumatch
== NULL
)
490 ret
= cd
->dlz_ssumatch(signer
, name
, tcpaddr
, type
, key
, keydatalen
,
491 keydata
, cd
->dbdata
);
502 dlopen_dlz_addrdataset(const char *name
, const char *rdatastr
,
503 void *driverarg
, void *dbdata
, void *version
)
505 dlopen_data_t
*cd
= (dlopen_data_t
*) dbdata
;
510 if (cd
->dlz_addrdataset
== NULL
)
511 return (ISC_R_NOTIMPLEMENTED
);
514 result
= cd
->dlz_addrdataset(name
, rdatastr
, cd
->dbdata
, version
);
521 * Subtract an rdataset
524 dlopen_dlz_subrdataset(const char *name
, const char *rdatastr
,
525 void *driverarg
, void *dbdata
, void *version
)
527 dlopen_data_t
*cd
= (dlopen_data_t
*) dbdata
;
532 if (cd
->dlz_subrdataset
== NULL
)
533 return (ISC_R_NOTIMPLEMENTED
);
536 result
= cd
->dlz_subrdataset(name
, rdatastr
, cd
->dbdata
, version
);
546 dlopen_dlz_delrdataset(const char *name
, const char *type
,
547 void *driverarg
, void *dbdata
, void *version
)
549 dlopen_data_t
*cd
= (dlopen_data_t
*) dbdata
;
554 if (cd
->dlz_delrdataset
== NULL
)
555 return (ISC_R_NOTIMPLEMENTED
);
558 result
= cd
->dlz_delrdataset(name
, type
, cd
->dbdata
, version
);
565 static dns_sdlzmethods_t dlz_dlopen_methods
= {
568 dlopen_dlz_findzonedb
,
570 dlopen_dlz_authority
,
572 dlopen_dlz_allowzonexfr
,
573 dlopen_dlz_newversion
,
574 dlopen_dlz_closeversion
,
575 dlopen_dlz_configure
,
577 dlopen_dlz_addrdataset
,
578 dlopen_dlz_subrdataset
,
579 dlopen_dlz_delrdataset
584 * Register driver with BIND
587 dlz_dlopen_init(isc_mem_t
*mctx
) {
588 #ifndef ISC_DLZ_DLOPEN
590 return (ISC_R_NOTIMPLEMENTED
);
594 dlopen_log(2, "Registering DLZ_dlopen driver");
596 result
= dns_sdlzregister("dlopen", &dlz_dlopen_methods
, NULL
,
597 DNS_SDLZFLAG_RELATIVEOWNER
|
598 DNS_SDLZFLAG_RELATIVERDATA
|
599 DNS_SDLZFLAG_THREADSAFE
,
602 if (result
!= ISC_R_SUCCESS
) {
603 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
604 "dns_sdlzregister() failed: %s",
605 isc_result_totext(result
));
606 result
= ISC_R_UNEXPECTED
;
615 * Unregister the driver
618 dlz_dlopen_clear(void) {
619 #ifdef ISC_DLZ_DLOPEN
620 dlopen_log(2, "Unregistering DLZ_dlopen driver");
621 if (dlz_dlopen
!= NULL
)
622 dns_sdlzunregister(&dlz_dlopen
);