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