Home | History | Annotate | Line # | Download | only in ns
hooks.c revision 1.1.1.5
      1      1.1  christos /*	$NetBSD: hooks.c,v 1.1.1.5 2021/02/19 16:37:18 christos Exp $	*/
      2      1.1  christos 
      3      1.1  christos /*
      4      1.1  christos  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5      1.1  christos  *
      6      1.1  christos  * This Source Code Form is subject to the terms of the Mozilla Public
      7      1.1  christos  * License, v. 2.0. If a copy of the MPL was not distributed with this
      8  1.1.1.5  christos  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
      9      1.1  christos  *
     10      1.1  christos  * See the COPYRIGHT file distributed with this work for additional
     11      1.1  christos  * information regarding copyright ownership.
     12      1.1  christos  */
     13      1.1  christos 
     14      1.1  christos /*! \file */
     15      1.1  christos 
     16  1.1.1.3  christos #include <errno.h>
     17  1.1.1.3  christos #include <stdio.h>
     18      1.1  christos #include <string.h>
     19      1.1  christos 
     20      1.1  christos #if HAVE_DLFCN_H
     21      1.1  christos #include <dlfcn.h>
     22      1.1  christos #elif _WIN32
     23      1.1  christos #include <windows.h>
     24  1.1.1.4  christos #endif /* if HAVE_DLFCN_H */
     25      1.1  christos 
     26  1.1.1.3  christos #include <isc/errno.h>
     27      1.1  christos #include <isc/list.h>
     28      1.1  christos #include <isc/log.h>
     29      1.1  christos #include <isc/mem.h>
     30      1.1  christos #include <isc/mutex.h>
     31  1.1.1.4  christos #include <isc/platform.h>
     32  1.1.1.3  christos #include <isc/print.h>
     33      1.1  christos #include <isc/result.h>
     34      1.1  christos #include <isc/types.h>
     35  1.1.1.4  christos #include <isc/util.h>
     36      1.1  christos 
     37      1.1  christos #include <dns/view.h>
     38      1.1  christos 
     39      1.1  christos #include <ns/hooks.h>
     40      1.1  christos #include <ns/log.h>
     41      1.1  christos #include <ns/query.h>
     42      1.1  christos 
     43  1.1.1.4  christos #define CHECK(op)                              \
     44  1.1.1.4  christos 	do {                                   \
     45  1.1.1.4  christos 		result = (op);                 \
     46  1.1.1.4  christos 		if (result != ISC_R_SUCCESS) { \
     47  1.1.1.4  christos 			goto cleanup;          \
     48  1.1.1.4  christos 		}                              \
     49      1.1  christos 	} while (0)
     50      1.1  christos 
     51      1.1  christos struct ns_plugin {
     52  1.1.1.4  christos 	isc_mem_t *mctx;
     53  1.1.1.4  christos 	void *handle;
     54  1.1.1.4  christos 	void *inst;
     55  1.1.1.4  christos 	char *modpath;
     56  1.1.1.4  christos 	ns_plugin_check_t *check_func;
     57  1.1.1.4  christos 	ns_plugin_register_t *register_func;
     58  1.1.1.4  christos 	ns_plugin_destroy_t *destroy_func;
     59  1.1.1.4  christos 	LINK(ns_plugin_t) link;
     60      1.1  christos };
     61      1.1  christos 
     62      1.1  christos static ns_hooklist_t default_hooktable[NS_HOOKPOINTS_COUNT];
     63      1.1  christos LIBNS_EXTERNAL_DATA ns_hooktable_t *ns__hook_table = &default_hooktable;
     64      1.1  christos 
     65  1.1.1.3  christos isc_result_t
     66  1.1.1.3  christos ns_plugin_expandpath(const char *src, char *dst, size_t dstsize) {
     67  1.1.1.3  christos 	int result;
     68  1.1.1.3  christos 
     69  1.1.1.3  christos #ifndef WIN32
     70  1.1.1.3  christos 	/*
     71  1.1.1.3  christos 	 * On Unix systems, differentiate between paths and filenames.
     72  1.1.1.3  christos 	 */
     73  1.1.1.3  christos 	if (strchr(src, '/') != NULL) {
     74  1.1.1.3  christos 		/*
     75  1.1.1.3  christos 		 * 'src' is an absolute or relative path.  Copy it verbatim.
     76  1.1.1.3  christos 		 */
     77  1.1.1.3  christos 		result = snprintf(dst, dstsize, "%s", src);
     78  1.1.1.3  christos 	} else {
     79  1.1.1.3  christos 		/*
     80  1.1.1.3  christos 		 * 'src' is a filename.  Prepend default plugin directory path.
     81  1.1.1.3  christos 		 */
     82  1.1.1.3  christos 		result = snprintf(dst, dstsize, "%s/%s", NAMED_PLUGINDIR, src);
     83  1.1.1.3  christos 	}
     84  1.1.1.4  christos #else  /* ifndef WIN32 */
     85  1.1.1.3  christos 	/*
     86  1.1.1.3  christos 	 * On Windows, always copy 'src' do 'dst'.
     87  1.1.1.3  christos 	 */
     88  1.1.1.3  christos 	result = snprintf(dst, dstsize, "%s", src);
     89  1.1.1.4  christos #endif /* ifndef WIN32 */
     90  1.1.1.3  christos 
     91  1.1.1.3  christos 	if (result < 0) {
     92  1.1.1.3  christos 		return (isc_errno_toresult(errno));
     93  1.1.1.3  christos 	} else if ((size_t)result >= dstsize) {
     94  1.1.1.3  christos 		return (ISC_R_NOSPACE);
     95  1.1.1.3  christos 	} else {
     96  1.1.1.3  christos 		return (ISC_R_SUCCESS);
     97  1.1.1.3  christos 	}
     98  1.1.1.3  christos }
     99  1.1.1.3  christos 
    100      1.1  christos #if HAVE_DLFCN_H && HAVE_DLOPEN
    101      1.1  christos static isc_result_t
    102  1.1.1.4  christos load_symbol(void *handle, const char *modpath, const char *symbol_name,
    103  1.1.1.4  christos 	    void **symbolp) {
    104      1.1  christos 	void *symbol = NULL;
    105      1.1  christos 
    106      1.1  christos 	REQUIRE(handle != NULL);
    107      1.1  christos 	REQUIRE(symbolp != NULL && *symbolp == NULL);
    108      1.1  christos 
    109      1.1  christos 	/*
    110      1.1  christos 	 * Clear any pre-existing error conditions before running dlsym().
    111      1.1  christos 	 * (In this case, we expect dlsym() to return non-NULL values
    112      1.1  christos 	 * and will always return an error if it returns NULL, but
    113      1.1  christos 	 * this ensures that we'll report the correct error condition
    114      1.1  christos 	 * if there is one.)
    115      1.1  christos 	 */
    116      1.1  christos 	dlerror();
    117      1.1  christos 	symbol = dlsym(handle, symbol_name);
    118      1.1  christos 	if (symbol == NULL) {
    119      1.1  christos 		const char *errmsg = dlerror();
    120      1.1  christos 		if (errmsg == NULL) {
    121      1.1  christos 			errmsg = "returned function pointer is NULL";
    122      1.1  christos 		}
    123      1.1  christos 		isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
    124      1.1  christos 			      NS_LOGMODULE_HOOKS, ISC_LOG_ERROR,
    125      1.1  christos 			      "failed to look up symbol %s in "
    126      1.1  christos 			      "plugin '%s': %s",
    127      1.1  christos 			      symbol_name, modpath, errmsg);
    128      1.1  christos 		return (ISC_R_FAILURE);
    129      1.1  christos 	}
    130      1.1  christos 
    131      1.1  christos 	*symbolp = symbol;
    132      1.1  christos 
    133      1.1  christos 	return (ISC_R_SUCCESS);
    134      1.1  christos }
    135      1.1  christos 
    136      1.1  christos static isc_result_t
    137      1.1  christos load_plugin(isc_mem_t *mctx, const char *modpath, ns_plugin_t **pluginp) {
    138      1.1  christos 	isc_result_t result;
    139      1.1  christos 	void *handle = NULL;
    140      1.1  christos 	ns_plugin_t *plugin = NULL;
    141      1.1  christos 	ns_plugin_check_t *check_func = NULL;
    142      1.1  christos 	ns_plugin_register_t *register_func = NULL;
    143      1.1  christos 	ns_plugin_destroy_t *destroy_func = NULL;
    144      1.1  christos 	ns_plugin_version_t *version_func = NULL;
    145      1.1  christos 	int version, flags;
    146      1.1  christos 
    147      1.1  christos 	REQUIRE(pluginp != NULL && *pluginp == NULL);
    148      1.1  christos 
    149      1.1  christos 	flags = RTLD_LAZY | RTLD_LOCAL;
    150  1.1.1.2  christos #if defined(RTLD_DEEPBIND) && !__SANITIZE_ADDRESS__
    151      1.1  christos 	flags |= RTLD_DEEPBIND;
    152  1.1.1.4  christos #endif /* if defined(RTLD_DEEPBIND) && !__SANITIZE_ADDRESS__ */
    153      1.1  christos 
    154      1.1  christos 	handle = dlopen(modpath, flags);
    155      1.1  christos 	if (handle == NULL) {
    156      1.1  christos 		const char *errmsg = dlerror();
    157      1.1  christos 		if (errmsg == NULL) {
    158      1.1  christos 			errmsg = "unknown error";
    159      1.1  christos 		}
    160      1.1  christos 		isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
    161      1.1  christos 			      NS_LOGMODULE_HOOKS, ISC_LOG_ERROR,
    162  1.1.1.4  christos 			      "failed to dlopen() plugin '%s': %s", modpath,
    163  1.1.1.4  christos 			      errmsg);
    164      1.1  christos 		return (ISC_R_FAILURE);
    165      1.1  christos 	}
    166      1.1  christos 
    167      1.1  christos 	CHECK(load_symbol(handle, modpath, "plugin_version",
    168      1.1  christos 			  (void **)&version_func));
    169      1.1  christos 
    170      1.1  christos 	version = version_func();
    171      1.1  christos 	if (version < (NS_PLUGIN_VERSION - NS_PLUGIN_AGE) ||
    172      1.1  christos 	    version > NS_PLUGIN_VERSION)
    173      1.1  christos 	{
    174      1.1  christos 		isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
    175      1.1  christos 			      NS_LOGMODULE_HOOKS, ISC_LOG_ERROR,
    176  1.1.1.4  christos 			      "plugin API version mismatch: %d/%d", version,
    177  1.1.1.4  christos 			      NS_PLUGIN_VERSION);
    178      1.1  christos 		CHECK(ISC_R_FAILURE);
    179      1.1  christos 	}
    180      1.1  christos 
    181      1.1  christos 	CHECK(load_symbol(handle, modpath, "plugin_check",
    182      1.1  christos 			  (void **)&check_func));
    183      1.1  christos 	CHECK(load_symbol(handle, modpath, "plugin_register",
    184      1.1  christos 			  (void **)&register_func));
    185      1.1  christos 	CHECK(load_symbol(handle, modpath, "plugin_destroy",
    186      1.1  christos 			  (void **)&destroy_func));
    187      1.1  christos 
    188      1.1  christos 	plugin = isc_mem_get(mctx, sizeof(*plugin));
    189      1.1  christos 	memset(plugin, 0, sizeof(*plugin));
    190      1.1  christos 	isc_mem_attach(mctx, &plugin->mctx);
    191      1.1  christos 	plugin->handle = handle;
    192      1.1  christos 	plugin->modpath = isc_mem_strdup(plugin->mctx, modpath);
    193      1.1  christos 	plugin->check_func = check_func;
    194      1.1  christos 	plugin->register_func = register_func;
    195      1.1  christos 	plugin->destroy_func = destroy_func;
    196      1.1  christos 
    197      1.1  christos 	ISC_LINK_INIT(plugin, link);
    198      1.1  christos 
    199      1.1  christos 	*pluginp = plugin;
    200      1.1  christos 	plugin = NULL;
    201      1.1  christos 
    202      1.1  christos cleanup:
    203      1.1  christos 	if (result != ISC_R_SUCCESS) {
    204      1.1  christos 		isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
    205      1.1  christos 			      NS_LOGMODULE_HOOKS, ISC_LOG_ERROR,
    206      1.1  christos 			      "failed to dynamically load "
    207  1.1.1.4  christos 			      "plugin '%s': %s",
    208  1.1.1.4  christos 			      modpath, isc_result_totext(result));
    209      1.1  christos 
    210      1.1  christos 		if (plugin != NULL) {
    211      1.1  christos 			isc_mem_putanddetach(&plugin->mctx, plugin,
    212      1.1  christos 					     sizeof(*plugin));
    213      1.1  christos 		}
    214      1.1  christos 
    215  1.1.1.4  christos 		(void)dlclose(handle);
    216      1.1  christos 	}
    217      1.1  christos 
    218      1.1  christos 	return (result);
    219      1.1  christos }
    220      1.1  christos 
    221      1.1  christos static void
    222      1.1  christos unload_plugin(ns_plugin_t **pluginp) {
    223      1.1  christos 	ns_plugin_t *plugin = NULL;
    224      1.1  christos 
    225      1.1  christos 	REQUIRE(pluginp != NULL && *pluginp != NULL);
    226      1.1  christos 
    227      1.1  christos 	plugin = *pluginp;
    228      1.1  christos 	*pluginp = NULL;
    229      1.1  christos 
    230  1.1.1.4  christos 	isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS,
    231  1.1.1.4  christos 		      ISC_LOG_DEBUG(1), "unloading plugin '%s'",
    232  1.1.1.4  christos 		      plugin->modpath);
    233      1.1  christos 
    234      1.1  christos 	if (plugin->inst != NULL) {
    235      1.1  christos 		plugin->destroy_func(&plugin->inst);
    236      1.1  christos 	}
    237      1.1  christos 	if (plugin->handle != NULL) {
    238  1.1.1.4  christos 		(void)dlclose(plugin->handle);
    239      1.1  christos 	}
    240      1.1  christos 	if (plugin->modpath != NULL) {
    241      1.1  christos 		isc_mem_free(plugin->mctx, plugin->modpath);
    242      1.1  christos 	}
    243      1.1  christos 
    244      1.1  christos 	isc_mem_putanddetach(&plugin->mctx, plugin, sizeof(*plugin));
    245      1.1  christos }
    246      1.1  christos #elif _WIN32
    247      1.1  christos static isc_result_t
    248  1.1.1.4  christos load_symbol(HMODULE handle, const char *modpath, const char *symbol_name,
    249  1.1.1.4  christos 	    void **symbolp) {
    250      1.1  christos 	void *symbol = NULL;
    251      1.1  christos 
    252      1.1  christos 	REQUIRE(handle != NULL);
    253      1.1  christos 	REQUIRE(symbolp != NULL && *symbolp == NULL);
    254      1.1  christos 
    255      1.1  christos 	symbol = GetProcAddress(handle, symbol_name);
    256      1.1  christos 	if (symbol == NULL) {
    257      1.1  christos 		int errstatus = GetLastError();
    258      1.1  christos 		isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
    259      1.1  christos 			      NS_LOGMODULE_HOOKS, ISC_LOG_ERROR,
    260      1.1  christos 			      "failed to look up symbol %s in "
    261      1.1  christos 			      "plugin '%s': %d",
    262      1.1  christos 			      symbol_name, modpath, errstatus);
    263      1.1  christos 		return (ISC_R_FAILURE);
    264      1.1  christos 	}
    265      1.1  christos 
    266      1.1  christos 	*symbolp = symbol;
    267      1.1  christos 
    268      1.1  christos 	return (ISC_R_SUCCESS);
    269      1.1  christos }
    270      1.1  christos 
    271      1.1  christos static isc_result_t
    272      1.1  christos load_plugin(isc_mem_t *mctx, const char *modpath, ns_plugin_t **pluginp) {
    273      1.1  christos 	isc_result_t result;
    274      1.1  christos 	HMODULE handle;
    275      1.1  christos 	ns_plugin_t *plugin = NULL;
    276      1.1  christos 	ns_plugin_register_t *register_func = NULL;
    277      1.1  christos 	ns_plugin_destroy_t *destroy_func = NULL;
    278      1.1  christos 	ns_plugin_version_t *version_func = NULL;
    279      1.1  christos 	int version;
    280      1.1  christos 
    281      1.1  christos 	REQUIRE(pluginp != NULL && *pluginp == NULL);
    282      1.1  christos 
    283      1.1  christos 	handle = LoadLibraryA(modpath);
    284      1.1  christos 	if (handle == NULL) {
    285      1.1  christos 		CHECK(ISC_R_FAILURE);
    286      1.1  christos 	}
    287      1.1  christos 
    288      1.1  christos 	CHECK(load_symbol(handle, modpath, "plugin_version",
    289      1.1  christos 			  (void **)&version_func));
    290      1.1  christos 
    291  1.1.1.3  christos 	version = version_func();
    292      1.1  christos 	if (version < (NS_PLUGIN_VERSION - NS_PLUGIN_AGE) ||
    293      1.1  christos 	    version > NS_PLUGIN_VERSION)
    294      1.1  christos 	{
    295      1.1  christos 		isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
    296      1.1  christos 			      NS_LOGMODULE_HOOKS, ISC_LOG_ERROR,
    297  1.1.1.4  christos 			      "plugin API version mismatch: %d/%d", version,
    298  1.1.1.4  christos 			      NS_PLUGIN_VERSION);
    299      1.1  christos 		CHECK(ISC_R_FAILURE);
    300      1.1  christos 	}
    301      1.1  christos 
    302      1.1  christos 	CHECK(load_symbol(handle, modpath, "plugin_register",
    303      1.1  christos 			  (void **)&register_func));
    304      1.1  christos 	CHECK(load_symbol(handle, modpath, "plugin_destroy",
    305      1.1  christos 			  (void **)&destroy_func));
    306      1.1  christos 
    307      1.1  christos 	plugin = isc_mem_get(mctx, sizeof(*plugin));
    308      1.1  christos 	memset(plugin, 0, sizeof(*plugin));
    309      1.1  christos 	isc_mem_attach(mctx, &plugin->mctx);
    310      1.1  christos 	plugin->handle = handle;
    311      1.1  christos 	plugin->modpath = isc_mem_strdup(plugin->mctx, modpath);
    312      1.1  christos 	plugin->register_func = register_func;
    313      1.1  christos 	plugin->destroy_func = destroy_func;
    314      1.1  christos 
    315      1.1  christos 	ISC_LINK_INIT(plugin, link);
    316      1.1  christos 
    317      1.1  christos 	*pluginp = plugin;
    318      1.1  christos 	plugin = NULL;
    319      1.1  christos 
    320      1.1  christos cleanup:
    321      1.1  christos 	if (result != ISC_R_SUCCESS) {
    322      1.1  christos 		isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
    323      1.1  christos 			      NS_LOGMODULE_HOOKS, ISC_LOG_ERROR,
    324      1.1  christos 			      "failed to dynamically load "
    325  1.1.1.4  christos 			      "plugin '%s': %d (%s)",
    326  1.1.1.4  christos 			      modpath, GetLastError(),
    327  1.1.1.4  christos 			      isc_result_totext(result));
    328      1.1  christos 
    329      1.1  christos 		if (plugin != NULL) {
    330      1.1  christos 			isc_mem_putanddetach(&plugin->mctx, plugin,
    331      1.1  christos 					     sizeof(*plugin));
    332      1.1  christos 		}
    333      1.1  christos 
    334      1.1  christos 		if (handle != NULL) {
    335      1.1  christos 			FreeLibrary(handle);
    336      1.1  christos 		}
    337      1.1  christos 	}
    338      1.1  christos 
    339      1.1  christos 	return (result);
    340      1.1  christos }
    341      1.1  christos 
    342      1.1  christos static void
    343      1.1  christos unload_plugin(ns_plugin_t **pluginp) {
    344      1.1  christos 	ns_plugin_t *plugin = NULL;
    345      1.1  christos 
    346      1.1  christos 	REQUIRE(pluginp != NULL && *pluginp != NULL);
    347      1.1  christos 
    348      1.1  christos 	plugin = *pluginp;
    349      1.1  christos 	*pluginp = NULL;
    350      1.1  christos 
    351  1.1.1.4  christos 	isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS,
    352  1.1.1.4  christos 		      ISC_LOG_DEBUG(1), "unloading plugin '%s'",
    353  1.1.1.4  christos 		      plugin->modpath);
    354      1.1  christos 
    355      1.1  christos 	if (plugin->inst != NULL) {
    356      1.1  christos 		plugin->destroy_func(&plugin->inst);
    357      1.1  christos 	}
    358      1.1  christos 	if (plugin->handle != NULL) {
    359      1.1  christos 		FreeLibrary(plugin->handle);
    360      1.1  christos 	}
    361      1.1  christos 
    362      1.1  christos 	if (plugin->modpath != NULL) {
    363      1.1  christos 		isc_mem_free(plugin->mctx, plugin->modpath);
    364      1.1  christos 	}
    365      1.1  christos 
    366      1.1  christos 	isc_mem_putanddetach(&plugin->mctx, plugin, sizeof(*plugin));
    367      1.1  christos }
    368  1.1.1.4  christos #else  /* HAVE_DLFCN_H || _WIN32 */
    369      1.1  christos static isc_result_t
    370      1.1  christos load_plugin(isc_mem_t *mctx, const char *modpath, ns_plugin_t **pluginp) {
    371      1.1  christos 	UNUSED(mctx);
    372      1.1  christos 	UNUSED(modpath);
    373      1.1  christos 	UNUSED(pluginp);
    374      1.1  christos 
    375  1.1.1.4  christos 	isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS,
    376  1.1.1.4  christos 		      ISC_LOG_ERROR, "plugin support is not implemented");
    377      1.1  christos 
    378      1.1  christos 	return (ISC_R_NOTIMPLEMENTED);
    379      1.1  christos }
    380      1.1  christos 
    381      1.1  christos static void
    382      1.1  christos unload_plugin(ns_plugin_t **pluginp) {
    383      1.1  christos 	UNUSED(pluginp);
    384      1.1  christos }
    385  1.1.1.4  christos #endif /* HAVE_DLFCN_H */
    386      1.1  christos 
    387      1.1  christos isc_result_t
    388  1.1.1.4  christos ns_plugin_register(const char *modpath, const char *parameters, const void *cfg,
    389  1.1.1.4  christos 		   const char *cfg_file, unsigned long cfg_line,
    390      1.1  christos 		   isc_mem_t *mctx, isc_log_t *lctx, void *actx,
    391  1.1.1.4  christos 		   dns_view_t *view) {
    392      1.1  christos 	isc_result_t result;
    393      1.1  christos 	ns_plugin_t *plugin = NULL;
    394      1.1  christos 
    395      1.1  christos 	REQUIRE(mctx != NULL);
    396      1.1  christos 	REQUIRE(lctx != NULL);
    397      1.1  christos 	REQUIRE(view != NULL);
    398      1.1  christos 
    399  1.1.1.4  christos 	isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS,
    400  1.1.1.4  christos 		      ISC_LOG_INFO, "loading plugin '%s'", modpath);
    401      1.1  christos 
    402      1.1  christos 	CHECK(load_plugin(mctx, modpath, &plugin));
    403      1.1  christos 
    404  1.1.1.4  christos 	isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS,
    405  1.1.1.4  christos 		      ISC_LOG_INFO, "registering plugin '%s'", modpath);
    406      1.1  christos 
    407  1.1.1.4  christos 	CHECK(plugin->register_func(parameters, cfg, cfg_file, cfg_line, mctx,
    408  1.1.1.4  christos 				    lctx, actx, view->hooktable,
    409      1.1  christos 				    &plugin->inst));
    410      1.1  christos 
    411      1.1  christos 	ISC_LIST_APPEND(*(ns_plugins_t *)view->plugins, plugin, link);
    412      1.1  christos 
    413      1.1  christos cleanup:
    414      1.1  christos 	if (result != ISC_R_SUCCESS && plugin != NULL) {
    415      1.1  christos 		unload_plugin(&plugin);
    416      1.1  christos 	}
    417      1.1  christos 
    418      1.1  christos 	return (result);
    419      1.1  christos }
    420      1.1  christos 
    421      1.1  christos isc_result_t
    422  1.1.1.4  christos ns_plugin_check(const char *modpath, const char *parameters, const void *cfg,
    423  1.1.1.4  christos 		const char *cfg_file, unsigned long cfg_line, isc_mem_t *mctx,
    424  1.1.1.4  christos 		isc_log_t *lctx, void *actx) {
    425      1.1  christos 	isc_result_t result;
    426      1.1  christos 	ns_plugin_t *plugin = NULL;
    427      1.1  christos 
    428      1.1  christos 	CHECK(load_plugin(mctx, modpath, &plugin));
    429      1.1  christos 
    430  1.1.1.4  christos 	result = plugin->check_func(parameters, cfg, cfg_file, cfg_line, mctx,
    431  1.1.1.4  christos 				    lctx, actx);
    432      1.1  christos 
    433      1.1  christos cleanup:
    434      1.1  christos 	if (plugin != NULL) {
    435      1.1  christos 		unload_plugin(&plugin);
    436      1.1  christos 	}
    437      1.1  christos 
    438      1.1  christos 	return (result);
    439      1.1  christos }
    440      1.1  christos 
    441      1.1  christos void
    442      1.1  christos ns_hooktable_init(ns_hooktable_t *hooktable) {
    443      1.1  christos 	int i;
    444      1.1  christos 
    445      1.1  christos 	for (i = 0; i < NS_HOOKPOINTS_COUNT; i++) {
    446      1.1  christos 		ISC_LIST_INIT((*hooktable)[i]);
    447      1.1  christos 	}
    448      1.1  christos }
    449      1.1  christos 
    450      1.1  christos isc_result_t
    451      1.1  christos ns_hooktable_create(isc_mem_t *mctx, ns_hooktable_t **tablep) {
    452      1.1  christos 	ns_hooktable_t *hooktable = NULL;
    453      1.1  christos 
    454      1.1  christos 	REQUIRE(tablep != NULL && *tablep == NULL);
    455      1.1  christos 
    456      1.1  christos 	hooktable = isc_mem_get(mctx, sizeof(*hooktable));
    457      1.1  christos 
    458      1.1  christos 	ns_hooktable_init(hooktable);
    459      1.1  christos 
    460      1.1  christos 	*tablep = hooktable;
    461      1.1  christos 
    462      1.1  christos 	return (ISC_R_SUCCESS);
    463      1.1  christos }
    464      1.1  christos 
    465      1.1  christos void
    466      1.1  christos ns_hooktable_free(isc_mem_t *mctx, void **tablep) {
    467      1.1  christos 	ns_hooktable_t *table = NULL;
    468      1.1  christos 	ns_hook_t *hook = NULL, *next = NULL;
    469      1.1  christos 	int i = 0;
    470      1.1  christos 
    471      1.1  christos 	REQUIRE(tablep != NULL && *tablep != NULL);
    472      1.1  christos 
    473      1.1  christos 	table = *tablep;
    474      1.1  christos 	*tablep = NULL;
    475      1.1  christos 
    476      1.1  christos 	for (i = 0; i < NS_HOOKPOINTS_COUNT; i++) {
    477  1.1.1.4  christos 		for (hook = ISC_LIST_HEAD((*table)[i]); hook != NULL;
    478  1.1.1.4  christos 		     hook = next) {
    479      1.1  christos 			next = ISC_LIST_NEXT(hook, link);
    480      1.1  christos 			ISC_LIST_UNLINK((*table)[i], hook, link);
    481      1.1  christos 			if (hook->mctx != NULL) {
    482  1.1.1.4  christos 				isc_mem_putanddetach(&hook->mctx, hook,
    483  1.1.1.4  christos 						     sizeof(*hook));
    484      1.1  christos 			}
    485      1.1  christos 		}
    486      1.1  christos 	}
    487      1.1  christos 
    488      1.1  christos 	isc_mem_put(mctx, table, sizeof(*table));
    489      1.1  christos }
    490      1.1  christos 
    491      1.1  christos void
    492      1.1  christos ns_hook_add(ns_hooktable_t *hooktable, isc_mem_t *mctx,
    493  1.1.1.4  christos 	    ns_hookpoint_t hookpoint, const ns_hook_t *hook) {
    494      1.1  christos 	ns_hook_t *copy = NULL;
    495      1.1  christos 
    496      1.1  christos 	REQUIRE(hooktable != NULL);
    497      1.1  christos 	REQUIRE(mctx != NULL);
    498      1.1  christos 	REQUIRE(hookpoint < NS_HOOKPOINTS_COUNT);
    499      1.1  christos 	REQUIRE(hook != NULL);
    500      1.1  christos 
    501      1.1  christos 	copy = isc_mem_get(mctx, sizeof(*copy));
    502      1.1  christos 	memset(copy, 0, sizeof(*copy));
    503      1.1  christos 
    504      1.1  christos 	copy->action = hook->action;
    505      1.1  christos 	copy->action_data = hook->action_data;
    506      1.1  christos 	isc_mem_attach(mctx, &copy->mctx);
    507      1.1  christos 
    508      1.1  christos 	ISC_LINK_INIT(copy, link);
    509      1.1  christos 	ISC_LIST_APPEND((*hooktable)[hookpoint], copy, link);
    510      1.1  christos }
    511      1.1  christos 
    512      1.1  christos void
    513      1.1  christos ns_plugins_create(isc_mem_t *mctx, ns_plugins_t **listp) {
    514      1.1  christos 	ns_plugins_t *plugins = NULL;
    515      1.1  christos 
    516      1.1  christos 	REQUIRE(listp != NULL && *listp == NULL);
    517      1.1  christos 
    518      1.1  christos 	plugins = isc_mem_get(mctx, sizeof(*plugins));
    519      1.1  christos 	memset(plugins, 0, sizeof(*plugins));
    520      1.1  christos 	ISC_LIST_INIT(*plugins);
    521      1.1  christos 
    522      1.1  christos 	*listp = plugins;
    523      1.1  christos }
    524      1.1  christos 
    525      1.1  christos void
    526      1.1  christos ns_plugins_free(isc_mem_t *mctx, void **listp) {
    527      1.1  christos 	ns_plugins_t *list = NULL;
    528      1.1  christos 	ns_plugin_t *plugin = NULL, *next = NULL;
    529      1.1  christos 
    530      1.1  christos 	REQUIRE(listp != NULL && *listp != NULL);
    531      1.1  christos 
    532      1.1  christos 	list = *listp;
    533      1.1  christos 	*listp = NULL;
    534      1.1  christos 
    535  1.1.1.4  christos 	for (plugin = ISC_LIST_HEAD(*list); plugin != NULL; plugin = next) {
    536      1.1  christos 		next = ISC_LIST_NEXT(plugin, link);
    537      1.1  christos 		ISC_LIST_UNLINK(*list, plugin, link);
    538      1.1  christos 		unload_plugin(&plugin);
    539      1.1  christos 	}
    540      1.1  christos 
    541      1.1  christos 	isc_mem_put(mctx, list, sizeof(*list));
    542      1.1  christos }
    543