X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fmodule.c;h=4559be0e0cf556c6b4b240de504e9a2a75544fbd;hb=a5ee438c9394a19a241716d3d922299c20b0365d;hp=b99d718e40f1af136490244a2954a156a96defb4;hpb=5a470f89594d1d8ca986801376f3b88671fdde20;p=openldap diff --git a/servers/slapd/module.c b/servers/slapd/module.c index b99d718e40..4559be0e0c 100644 --- a/servers/slapd/module.c +++ b/servers/slapd/module.c @@ -1,37 +1,236 @@ +/* $OpenLDAP$ */ #include "portable.h" #include #include "slap.h" #ifdef SLAPD_MODULES -#include -#include +#include -int load_module(const char* file_name, int argc, char *argv[]) { - GModule* module = NULL; - void (*initialize) LDAP_P((int argc, char *argv[])); +typedef int (*MODULE_INIT_FN)( + int argc, + char *argv[]); +typedef int (*MODULE_LOAD_FN)( + const void *module, + const char *filename); +typedef int (*MODULE_TERM_FN)(void); - if (!g_module_supported()) { - Debug(LDAP_DEBUG_ANY, "loadable modules not supported on this platform\n", 0, 0, 0); - return FALSE; - } - - if ((module = g_module_open(file_name, G_MODULE_BIND_LAZY)) == NULL) { - Debug(LDAP_DEBUG_ANY, "failed to load module %s: %s\n", file_name, g_module_error(), 0); - return FALSE; - } - Debug(LDAP_DEBUG_CONFIG, "loaded module %s\n", file_name, 0, 0); +struct module_regtable_t { + char *type; + MODULE_LOAD_FN proc; +} module_regtable[] = { + { "null", load_null_module }, +#ifdef SLAPD_EXTERNAL_EXTENSIONS + { "extension", load_extop_module }, +#endif + { NULL, NULL } +}; + +typedef struct module_loaded_t { + struct module_loaded_t *next; + lt_dlhandle *lib; +} module_loaded_t; + +module_loaded_t *module_list = NULL; + +static int module_unload (module_loaded_t *module); + +int module_init (void) +{ + if (lt_dlinit()) { + const char *error = lt_dlerror(); + Debug(LDAP_DEBUG_ANY, "lt_dlinit failed: %s\n", error, 0, 0); + return -1; + } + return 0; +} + +int module_kill (void) +{ + /* unload all modules before shutdown */ + while (module_list != NULL) { + module_unload(module_list); + } + + if (lt_dlexit()) { + const char *error = lt_dlerror(); + Debug(LDAP_DEBUG_ANY, "lt_dlexit failed: %s\n", error, 0, 0); + return -1; + } + return 0; +} + +int module_load(const char* file_name, int argc, char *argv[]) +{ + module_loaded_t *module = NULL; + const char *error; + int rc; + MODULE_INIT_FN initialize; + + module = (module_loaded_t *)ch_calloc(1, sizeof(module_loaded_t)); + if (module == NULL) { + Debug(LDAP_DEBUG_ANY, "module_load failed: (%s) out of memory\n", file_name, + 0, 0); + return -1; + } + + /* + * The result of lt_dlerror(), when called, must be cached prior + * to calling Debug. This is because Debug is a macro that expands + * into multiple function calls. + */ + if ((module->lib = lt_dlopen(file_name)) == NULL) { + error = lt_dlerror(); + Debug(LDAP_DEBUG_ANY, "lt_dlopen failed: (%s) %s\n", file_name, + error, 0); + ch_free(module); + return -1; + } + + Debug(LDAP_DEBUG_CONFIG, "loaded module %s\n", file_name, 0, 0); - if (g_module_symbol(module, "init_module", (gpointer *) &initialize)) { - initialize(argc, argv); - } else { - Debug(LDAP_DEBUG_CONFIG, "module %s: no init_module() function found\n", file_name, 0, 0); - return FALSE; - } + if ((initialize = lt_dlsym(module->lib, "init_module")) == NULL) { + Debug(LDAP_DEBUG_CONFIG, "module %s: no init_module() function found\n", + file_name, 0, 0); + lt_dlclose(module->lib); + ch_free(module); + return -1; + } + + /* The imported init_module() routine passes back the type of + * module (i.e., which part of slapd it should be hooked into) + * or -1 for error. If it passes back 0, then you get the + * old behavior (i.e., the library is loaded and not hooked + * into anything). + * + * It might be better if the conf file could specify the type + * of module. That way, a single module could support multiple + * type of hooks. This could be done by using something like: + * + * moduleload extension /usr/local/openldap/whatever.so + * + * then we'd search through module_regtable for a matching + * module type, and hook in there. + */ + rc = initialize(argc, argv); + if (rc == -1) { + Debug(LDAP_DEBUG_CONFIG, "module %s: init_module() failed\n", + file_name, 0, 0); + lt_dlclose(module->lib); + ch_free(module); + return rc; + } + + if (rc >= (sizeof(module_regtable) / sizeof(struct module_regtable_t)) + || module_regtable[rc].proc == NULL) + { + Debug(LDAP_DEBUG_CONFIG, "module %s: unknown registration type (%d)\n", + file_name, rc, 0); + module_unload(module); + return -1; + } + + rc = (module_regtable[rc].proc)(module, file_name); + if (rc != 0) { + Debug(LDAP_DEBUG_CONFIG, "module %s: %s module could not be registered\n", + file_name, module_regtable[rc].type, 0); + module_unload(module); + return rc; + } + + module->next = module_list; + module_list = module; - return TRUE; + Debug(LDAP_DEBUG_CONFIG, "module %s: %s module registered\n", + file_name, module_regtable[rc].type, 0); + return 0; } +int module_path(const char *path) +{ + return lt_dlsetsearchpath( path ); +} + +void *module_resolve (const void *module, const char *name) +{ + if (module == NULL || name == NULL) + return(NULL); + return(lt_dlsym(((module_loaded_t *)module)->lib, name)); +} + +static int module_unload (module_loaded_t *module) +{ + module_loaded_t *mod; + MODULE_TERM_FN terminate; + + if (module != NULL) { + /* remove module from tracking list */ + if (module_list == module) { + module_list = module->next; + } else { + for (mod = module_list; mod; mod = mod->next) { + if (mod->next == module) { + mod->next = module->next; + break; + } + } + } + + /* call module's terminate routine, if present */ + if (terminate = lt_dlsym(module->lib, "term_module")) { + terminate(); + } + + /* close the library and free the memory */ + lt_dlclose(module->lib); + ch_free(module); + } + return 0; +} + +int load_null_module (const void *module, const char *file_name) +{ + return 0; +} + +#ifdef SLAPD_EXTERNAL_EXTENSIONS +int +load_extop_module ( + const void *module, + const char *file_name +) +{ + SLAP_EXTOP_MAIN_FN ext_main; + int (*ext_getoid)(int index, char *oid, int blen); + char *oid; + int rc; + + ext_main = (SLAP_EXTOP_MAIN_FN)module_resolve(module, "ext_main"); + if (ext_main == NULL) { + return(-1); + } + + ext_getoid = module_resolve(module, "ext_getoid"); + if (ext_getoid == NULL) { + return(-1); + } + + oid = ch_malloc(256); + rc = (ext_getoid)(0, oid, 256); + if (rc != 0) { + ch_free(oid); + return(rc); + } + if (*oid == 0) { + free(oid); + return(-1); + } + + rc = load_extop( oid, ext_main ); + free(oid); + return rc; +} +#endif /* SLAPD_EXTERNAL_EXTENSIONS */ #endif /* SLAPD_MODULES */