1 /*
2  * Copyright (C) 2011-2014  Internet Systems Consortium, Inc. ("ISC")
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14  * PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /* $Id$ */
18 
19 #include <config.h>
20 
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <dlfcn.h>
25 
26 #include <dns/log.h>
27 #include <dns/result.h>
28 #include <dns/dlz_dlopen.h>
29 
30 #include <isc/mem.h>
31 #include <isc/print.h>
32 #include <isc/result.h>
33 #include <isc/util.h>
34 
35 #include <named/globals.h>
36 
37 #include <dlz/dlz_dlopen_driver.h>
38 
39 #ifdef ISC_DLZ_DLOPEN
40 static dns_sdlzimplementation_t *dlz_dlopen = NULL;
41 
42 
43 typedef struct dlopen_data {
44 	isc_mem_t *mctx;
45 	char *dl_path;
46 	char *dlzname;
47 	void *dl_handle;
48 	void *dbdata;
49 	unsigned int flags;
50 	isc_mutex_t lock;
51 	int version;
52 	isc_boolean_t in_configure;
53 
54 	dlz_dlopen_version_t *dlz_version;
55 	dlz_dlopen_create_t *dlz_create;
56 	dlz_dlopen_findzonedb_t *dlz_findzonedb;
57 	dlz_dlopen_lookup_t *dlz_lookup;
58 	dlz_dlopen_authority_t *dlz_authority;
59 	dlz_dlopen_allnodes_t *dlz_allnodes;
60 	dlz_dlopen_allowzonexfr_t *dlz_allowzonexfr;
61 	dlz_dlopen_newversion_t *dlz_newversion;
62 	dlz_dlopen_closeversion_t *dlz_closeversion;
63 	dlz_dlopen_configure_t *dlz_configure;
64 	dlz_dlopen_ssumatch_t *dlz_ssumatch;
65 	dlz_dlopen_addrdataset_t *dlz_addrdataset;
66 	dlz_dlopen_subrdataset_t *dlz_subrdataset;
67 	dlz_dlopen_delrdataset_t *dlz_delrdataset;
68 	dlz_dlopen_destroy_t *dlz_destroy;
69 } dlopen_data_t;
70 
71 /* Modules can choose whether they are lock-safe or not. */
72 #define MAYBE_LOCK(cd) \
73 	do { \
74 		if ((cd->flags & DNS_SDLZFLAG_THREADSAFE) == 0 && \
75 		    cd->in_configure == ISC_FALSE) \
76 			LOCK(&cd->lock); \
77 	} while (0)
78 
79 #define MAYBE_UNLOCK(cd) \
80 	do { \
81 		if ((cd->flags & DNS_SDLZFLAG_THREADSAFE) == 0 && \
82 		    cd->in_configure == ISC_FALSE) \
83 			UNLOCK(&cd->lock); \
84 	} while (0)
85 
86 /*
87  * Log a message at the given level.
88  */
dlopen_log(int level,const char * fmt,...)89 static void dlopen_log(int level, const char *fmt, ...)
90 {
91 	va_list ap;
92 	va_start(ap, fmt);
93 	isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_DATABASE,
94 		       DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(level),
95 		       fmt, ap);
96 	va_end(ap);
97 }
98 
99 /*
100  * SDLZ methods
101  */
102 
103 static isc_result_t
dlopen_dlz_allnodes(const char * zone,void * driverarg,void * dbdata,dns_sdlzallnodes_t * allnodes)104 dlopen_dlz_allnodes(const char *zone, void *driverarg, void *dbdata,
105 		    dns_sdlzallnodes_t *allnodes)
106 {
107 	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
108 	isc_result_t result;
109 
110 
111 	UNUSED(driverarg);
112 
113 	if (cd->dlz_allnodes == NULL) {
114 		return (ISC_R_NOPERM);
115 	}
116 
117 	MAYBE_LOCK(cd);
118 	result = cd->dlz_allnodes(zone, cd->dbdata, allnodes);
119 	MAYBE_UNLOCK(cd);
120 	return (result);
121 }
122 
123 
124 static isc_result_t
dlopen_dlz_allowzonexfr(void * driverarg,void * dbdata,const char * name,const char * client)125 dlopen_dlz_allowzonexfr(void *driverarg, void *dbdata, const char *name,
126 			const char *client)
127 {
128 	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
129 	isc_result_t result;
130 
131 	UNUSED(driverarg);
132 
133 
134 	if (cd->dlz_allowzonexfr == NULL) {
135 		return (ISC_R_NOPERM);
136 	}
137 
138 	MAYBE_LOCK(cd);
139 	result = cd->dlz_allowzonexfr(cd->dbdata, name, client);
140 	MAYBE_UNLOCK(cd);
141 	return (result);
142 }
143 
144 static isc_result_t
dlopen_dlz_authority(const char * zone,void * driverarg,void * dbdata,dns_sdlzlookup_t * lookup)145 dlopen_dlz_authority(const char *zone, void *driverarg, void *dbdata,
146 		     dns_sdlzlookup_t *lookup)
147 {
148 	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
149 	isc_result_t result;
150 
151 	UNUSED(driverarg);
152 
153 	if (cd->dlz_authority == NULL) {
154 		return (ISC_R_NOTIMPLEMENTED);
155 	}
156 
157 	MAYBE_LOCK(cd);
158 	result = cd->dlz_authority(zone, cd->dbdata, lookup);
159 	MAYBE_UNLOCK(cd);
160 	return (result);
161 }
162 
163 static isc_result_t
dlopen_dlz_findzonedb(void * driverarg,void * dbdata,const char * name)164 dlopen_dlz_findzonedb(void *driverarg, void *dbdata, const char *name)
165 {
166 	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
167 	isc_result_t result;
168 
169 	UNUSED(driverarg);
170 
171 	MAYBE_LOCK(cd);
172 	result = cd->dlz_findzonedb(cd->dbdata, name);
173 	MAYBE_UNLOCK(cd);
174 	return (result);
175 }
176 
177 
178 static isc_result_t
dlopen_dlz_lookup(const char * zone,const char * name,void * driverarg,void * dbdata,dns_sdlzlookup_t * lookup,dns_clientinfomethods_t * methods,dns_clientinfo_t * clientinfo)179 dlopen_dlz_lookup(const char *zone, const char *name, void *driverarg,
180 		  void *dbdata, dns_sdlzlookup_t *lookup,
181 		  dns_clientinfomethods_t *methods,
182 		  dns_clientinfo_t *clientinfo)
183 {
184 	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
185 	isc_result_t result;
186 
187 	UNUSED(driverarg);
188 
189 	MAYBE_LOCK(cd);
190 	result = cd->dlz_lookup(zone, name, cd->dbdata, lookup,
191 				methods, clientinfo);
192 	MAYBE_UNLOCK(cd);
193 	return (result);
194 }
195 
196 /*
197  * Load a symbol from the library
198  */
199 static void *
dl_load_symbol(dlopen_data_t * cd,const char * symbol,isc_boolean_t mandatory)200 dl_load_symbol(dlopen_data_t *cd, const char *symbol, isc_boolean_t mandatory) {
201 	void *ptr = dlsym(cd->dl_handle, symbol);
202 	if (ptr == NULL && mandatory) {
203 		dlopen_log(ISC_LOG_ERROR,
204 			   "dlz_dlopen: library '%s' is missing "
205 			   "required symbol '%s'", cd->dl_path, symbol);
206 	}
207 	return (ptr);
208 }
209 
210 /*
211  * Called at startup for each dlopen zone in named.conf
212  */
213 static isc_result_t
dlopen_dlz_create(const char * dlzname,unsigned int argc,char * argv[],void * driverarg,void ** dbdata)214 dlopen_dlz_create(const char *dlzname, unsigned int argc, char *argv[],
215 		  void *driverarg, void **dbdata)
216 {
217 	dlopen_data_t *cd;
218 	isc_mem_t *mctx = NULL;
219 	isc_result_t result = ISC_R_FAILURE;
220 	int dlopen_flags = 0;
221 
222 	UNUSED(driverarg);
223 
224 	if (argc < 2) {
225 		dlopen_log(ISC_LOG_ERROR,
226 			   "dlz_dlopen driver for '%s' needs a path to "
227 			   "the shared library", dlzname);
228 		return (ISC_R_FAILURE);
229 	}
230 
231 	result = isc_mem_create(0, 0, &mctx);
232 	if (result != ISC_R_SUCCESS)
233 		return (result);
234 
235 	cd = isc_mem_get(mctx, sizeof(*cd));
236 	if (cd == NULL) {
237 		isc_mem_destroy(&mctx);
238 		return (ISC_R_NOMEMORY);
239 	}
240 	memset(cd, 0, sizeof(*cd));
241 
242 	cd->mctx = mctx;
243 
244 	cd->dl_path = isc_mem_strdup(cd->mctx, argv[1]);
245 	if (cd->dl_path == NULL) {
246 		result = ISC_R_NOMEMORY;
247 		goto failed;
248 	}
249 
250 	cd->dlzname = isc_mem_strdup(cd->mctx, dlzname);
251 	if (cd->dlzname == NULL) {
252 		result = ISC_R_NOMEMORY;
253 		goto failed;
254 	}
255 
256 	/* Initialize the lock */
257 	result = isc_mutex_init(&cd->lock);
258 	if (result != ISC_R_SUCCESS)
259 		goto failed;
260 
261 	/* Open the library */
262 	dlopen_flags = RTLD_NOW|RTLD_GLOBAL;
263 
264 #ifdef RTLD_DEEPBIND
265 	/*
266 	 * If RTLD_DEEPBIND is available then use it. This can avoid
267 	 * issues with a module using a different version of a system
268 	 * library than one that bind9 uses. For example, bind9 may link
269 	 * to MIT kerberos, but the module may use Heimdal. If we don't
270 	 * use RTLD_DEEPBIND then we could end up with Heimdal functions
271 	 * calling MIT functions, which leads to bizarre results (usually
272 	 * a segfault).
273 	 */
274 	dlopen_flags |= RTLD_DEEPBIND;
275 #endif
276 
277 	cd->dl_handle = dlopen(cd->dl_path, dlopen_flags);
278 	if (cd->dl_handle == NULL) {
279 		dlopen_log(ISC_LOG_ERROR,
280 			   "dlz_dlopen failed to open library '%s' - %s",
281 			   cd->dl_path, dlerror());
282 		result = ISC_R_FAILURE;
283 		goto failed;
284 	}
285 
286 	/* Find the symbols */
287 	cd->dlz_version = (dlz_dlopen_version_t *)
288 		dl_load_symbol(cd, "dlz_version", ISC_TRUE);
289 	cd->dlz_create = (dlz_dlopen_create_t *)
290 		dl_load_symbol(cd, "dlz_create", ISC_TRUE);
291 	cd->dlz_lookup = (dlz_dlopen_lookup_t *)
292 		dl_load_symbol(cd, "dlz_lookup", ISC_TRUE);
293 	cd->dlz_findzonedb = (dlz_dlopen_findzonedb_t *)
294 		dl_load_symbol(cd, "dlz_findzonedb", ISC_TRUE);
295 
296 	if (cd->dlz_create == NULL ||
297 	    cd->dlz_lookup == NULL ||
298 	    cd->dlz_findzonedb == NULL)
299 	{
300 		/* We're missing a required symbol */
301 		result = ISC_R_FAILURE;
302 		goto failed;
303 	}
304 
305 	cd->dlz_allowzonexfr = (dlz_dlopen_allowzonexfr_t *)
306 		dl_load_symbol(cd, "dlz_allowzonexfr", ISC_FALSE);
307 	cd->dlz_allnodes = (dlz_dlopen_allnodes_t *)
308 		dl_load_symbol(cd, "dlz_allnodes",
309 			       ISC_TF(cd->dlz_allowzonexfr != NULL));
310 	cd->dlz_authority = (dlz_dlopen_authority_t *)
311 		dl_load_symbol(cd, "dlz_authority", ISC_FALSE);
312 	cd->dlz_newversion = (dlz_dlopen_newversion_t *)
313 		dl_load_symbol(cd, "dlz_newversion", ISC_FALSE);
314 	cd->dlz_closeversion = (dlz_dlopen_closeversion_t *)
315 		dl_load_symbol(cd, "dlz_closeversion",
316 			       ISC_TF(cd->dlz_newversion != NULL));
317 	cd->dlz_configure = (dlz_dlopen_configure_t *)
318 		dl_load_symbol(cd, "dlz_configure", ISC_FALSE);
319 	cd->dlz_ssumatch = (dlz_dlopen_ssumatch_t *)
320 		dl_load_symbol(cd, "dlz_ssumatch", ISC_FALSE);
321 	cd->dlz_addrdataset = (dlz_dlopen_addrdataset_t *)
322 		dl_load_symbol(cd, "dlz_addrdataset", ISC_FALSE);
323 	cd->dlz_subrdataset = (dlz_dlopen_subrdataset_t *)
324 		dl_load_symbol(cd, "dlz_subrdataset", ISC_FALSE);
325 	cd->dlz_delrdataset = (dlz_dlopen_delrdataset_t *)
326 		dl_load_symbol(cd, "dlz_delrdataset", ISC_FALSE);
327 	cd->dlz_destroy = (dlz_dlopen_destroy_t *)
328 		dl_load_symbol(cd, "dlz_destroy", ISC_FALSE);
329 
330 	/* Check the version of the API is the same */
331 	cd->version = cd->dlz_version(&cd->flags);
332 	if (cd->version != DLZ_DLOPEN_VERSION) {
333 		dlopen_log(ISC_LOG_ERROR,
334 			   "dlz_dlopen: incorrect version %d "
335 			   "should be %d in '%s'",
336 			   cd->version, DLZ_DLOPEN_VERSION, cd->dl_path);
337 		result = ISC_R_FAILURE;
338 		goto failed;
339 	}
340 
341 	/*
342 	 * Call the library's create function. Note that this is an
343 	 * extended version of dlz create, with the addition of
344 	 * named function pointers for helper functions that the
345 	 * driver will need. This avoids the need for the backend to
346 	 * link the BIND9 libraries
347 	 */
348 	MAYBE_LOCK(cd);
349 	result = cd->dlz_create(dlzname, argc-1, argv+1,
350 				&cd->dbdata,
351 				"log", dlopen_log,
352 				"putrr", dns_sdlz_putrr,
353 				"putnamedrr", dns_sdlz_putnamedrr,
354 				"writeable_zone", dns_dlz_writeablezone,
355 				NULL);
356 	MAYBE_UNLOCK(cd);
357 	if (result != ISC_R_SUCCESS)
358 		goto failed;
359 
360 	*dbdata = cd;
361 
362 	return (ISC_R_SUCCESS);
363 
364 failed:
365 	dlopen_log(ISC_LOG_ERROR, "dlz_dlopen of '%s' failed", dlzname);
366 	if (cd->dl_path != NULL)
367 		isc_mem_free(mctx, cd->dl_path);
368 	if (cd->dlzname != NULL)
369 		isc_mem_free(mctx, cd->dlzname);
370 	if (dlopen_flags != 0)
371 		(void) isc_mutex_destroy(&cd->lock);
372 #ifdef HAVE_DLCLOSE
373 	if (cd->dl_handle)
374 		dlclose(cd->dl_handle);
375 #endif
376 	isc_mem_put(mctx, cd, sizeof(*cd));
377 	isc_mem_destroy(&mctx);
378 	return (result);
379 }
380 
381 /*
382  * Called when bind is shutting down
383  */
384 static void
dlopen_dlz_destroy(void * driverarg,void * dbdata)385 dlopen_dlz_destroy(void *driverarg, void *dbdata) {
386 	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
387 	isc_mem_t *mctx;
388 
389 	UNUSED(driverarg);
390 
391 	if (cd->dlz_destroy) {
392 		MAYBE_LOCK(cd);
393 		cd->dlz_destroy(cd->dbdata);
394 		MAYBE_UNLOCK(cd);
395 	}
396 
397 	if (cd->dl_path)
398 		isc_mem_free(cd->mctx, cd->dl_path);
399 	if (cd->dlzname)
400 		isc_mem_free(cd->mctx, cd->dlzname);
401 
402 #ifdef HAVE_DLCLOSE
403 	if (cd->dl_handle)
404 		dlclose(cd->dl_handle);
405 #endif
406 
407 	(void) isc_mutex_destroy(&cd->lock);
408 
409 	mctx = cd->mctx;
410 	isc_mem_put(mctx, cd, sizeof(*cd));
411 	isc_mem_destroy(&mctx);
412 }
413 
414 /*
415  * Called to start a transaction
416  */
417 static isc_result_t
dlopen_dlz_newversion(const char * zone,void * driverarg,void * dbdata,void ** versionp)418 dlopen_dlz_newversion(const char *zone, void *driverarg, void *dbdata,
419 		      void **versionp)
420 {
421 	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
422 	isc_result_t result;
423 
424 	UNUSED(driverarg);
425 
426 	if (cd->dlz_newversion == NULL)
427 		return (ISC_R_NOTIMPLEMENTED);
428 
429 	MAYBE_LOCK(cd);
430 	result = cd->dlz_newversion(zone, cd->dbdata, versionp);
431 	MAYBE_UNLOCK(cd);
432 	return (result);
433 }
434 
435 /*
436  * Called to end a transaction
437  */
438 static void
dlopen_dlz_closeversion(const char * zone,isc_boolean_t commit,void * driverarg,void * dbdata,void ** versionp)439 dlopen_dlz_closeversion(const char *zone, isc_boolean_t commit,
440 			void *driverarg, void *dbdata, void **versionp)
441 {
442 	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
443 
444 	UNUSED(driverarg);
445 
446 	if (cd->dlz_newversion == NULL) {
447 		*versionp = NULL;
448 		return;
449 	}
450 
451 	MAYBE_LOCK(cd);
452 	cd->dlz_closeversion(zone, commit, cd->dbdata, versionp);
453 	MAYBE_UNLOCK(cd);
454 }
455 
456 /*
457  * Called on startup to configure any writeable zones
458  */
459 static isc_result_t
dlopen_dlz_configure(dns_view_t * view,void * driverarg,void * dbdata)460 dlopen_dlz_configure(dns_view_t *view, void *driverarg, void *dbdata) {
461 	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
462 	isc_result_t result;
463 
464 	UNUSED(driverarg);
465 
466 	if (cd->dlz_configure == NULL)
467 		return (ISC_R_SUCCESS);
468 
469 	MAYBE_LOCK(cd);
470 	cd->in_configure = ISC_TRUE;
471 	result = cd->dlz_configure(view, cd->dbdata);
472 	cd->in_configure = ISC_FALSE;
473 	MAYBE_UNLOCK(cd);
474 
475 	return (result);
476 }
477 
478 
479 /*
480  * Check for authority to change a name
481  */
482 static isc_boolean_t
dlopen_dlz_ssumatch(const char * signer,const char * name,const char * tcpaddr,const char * type,const char * key,isc_uint32_t keydatalen,unsigned char * keydata,void * driverarg,void * dbdata)483 dlopen_dlz_ssumatch(const char *signer, const char *name, const char *tcpaddr,
484 		    const char *type, const char *key, isc_uint32_t keydatalen,
485 		    unsigned char *keydata, void *driverarg, void *dbdata)
486 {
487 	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
488 	isc_boolean_t ret;
489 
490 	UNUSED(driverarg);
491 
492 	if (cd->dlz_ssumatch == NULL)
493 		return (ISC_FALSE);
494 
495 	MAYBE_LOCK(cd);
496 	ret = cd->dlz_ssumatch(signer, name, tcpaddr, type, key, keydatalen,
497 			       keydata, cd->dbdata);
498 	MAYBE_UNLOCK(cd);
499 
500 	return (ret);
501 }
502 
503 
504 /*
505  * Add an rdataset
506  */
507 static isc_result_t
dlopen_dlz_addrdataset(const char * name,const char * rdatastr,void * driverarg,void * dbdata,void * version)508 dlopen_dlz_addrdataset(const char *name, const char *rdatastr,
509 		       void *driverarg, void *dbdata, void *version)
510 {
511 	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
512 	isc_result_t result;
513 
514 	UNUSED(driverarg);
515 
516 	if (cd->dlz_addrdataset == NULL)
517 		return (ISC_R_NOTIMPLEMENTED);
518 
519 	MAYBE_LOCK(cd);
520 	result = cd->dlz_addrdataset(name, rdatastr, cd->dbdata, version);
521 	MAYBE_UNLOCK(cd);
522 
523 	return (result);
524 }
525 
526 /*
527  * Subtract an rdataset
528  */
529 static isc_result_t
dlopen_dlz_subrdataset(const char * name,const char * rdatastr,void * driverarg,void * dbdata,void * version)530 dlopen_dlz_subrdataset(const char *name, const char *rdatastr,
531 		       void *driverarg, void *dbdata, void *version)
532 {
533 	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
534 	isc_result_t result;
535 
536 	UNUSED(driverarg);
537 
538 	if (cd->dlz_subrdataset == NULL)
539 		return (ISC_R_NOTIMPLEMENTED);
540 
541 	MAYBE_LOCK(cd);
542 	result = cd->dlz_subrdataset(name, rdatastr, cd->dbdata, version);
543 	MAYBE_UNLOCK(cd);
544 
545 	return (result);
546 }
547 
548 /*
549   delete a rdataset
550  */
551 static isc_result_t
dlopen_dlz_delrdataset(const char * name,const char * type,void * driverarg,void * dbdata,void * version)552 dlopen_dlz_delrdataset(const char *name, const char *type,
553 		       void *driverarg, void *dbdata, void *version)
554 {
555 	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
556 	isc_result_t result;
557 
558 	UNUSED(driverarg);
559 
560 	if (cd->dlz_delrdataset == NULL)
561 		return (ISC_R_NOTIMPLEMENTED);
562 
563 	MAYBE_LOCK(cd);
564 	result = cd->dlz_delrdataset(name, type, cd->dbdata, version);
565 	MAYBE_UNLOCK(cd);
566 
567 	return (result);
568 }
569 
570 
571 static dns_sdlzmethods_t dlz_dlopen_methods = {
572 	dlopen_dlz_create,
573 	dlopen_dlz_destroy,
574 	dlopen_dlz_findzonedb,
575 	dlopen_dlz_lookup,
576 	dlopen_dlz_authority,
577 	dlopen_dlz_allnodes,
578 	dlopen_dlz_allowzonexfr,
579 	dlopen_dlz_newversion,
580 	dlopen_dlz_closeversion,
581 	dlopen_dlz_configure,
582 	dlopen_dlz_ssumatch,
583 	dlopen_dlz_addrdataset,
584 	dlopen_dlz_subrdataset,
585 	dlopen_dlz_delrdataset
586 };
587 #endif
588 
589 /*
590  * Register driver with BIND
591  */
592 isc_result_t
dlz_dlopen_init(isc_mem_t * mctx)593 dlz_dlopen_init(isc_mem_t *mctx) {
594 #ifndef ISC_DLZ_DLOPEN
595 	UNUSED(mctx);
596 	return (ISC_R_NOTIMPLEMENTED);
597 #else
598 	isc_result_t result;
599 
600 	dlopen_log(2, "Registering DLZ_dlopen driver");
601 
602 	result = dns_sdlzregister("dlopen", &dlz_dlopen_methods, NULL,
603 				  DNS_SDLZFLAG_RELATIVEOWNER |
604 				  DNS_SDLZFLAG_THREADSAFE,
605 				  mctx, &dlz_dlopen);
606 
607 	if (result != ISC_R_SUCCESS) {
608 		UNEXPECTED_ERROR(__FILE__, __LINE__,
609 				 "dns_sdlzregister() failed: %s",
610 				 isc_result_totext(result));
611 		result = ISC_R_UNEXPECTED;
612 	}
613 
614 	return (result);
615 #endif
616 }
617 
618 
619 /*
620  * Unregister the driver
621  */
622 void
dlz_dlopen_clear(void)623 dlz_dlopen_clear(void) {
624 #ifdef ISC_DLZ_DLOPEN
625 	dlopen_log(2, "Unregistering DLZ_dlopen driver");
626 	if (dlz_dlopen != NULL)
627 		dns_sdlzunregister(&dlz_dlopen);
628 #endif
629 }
630