X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fmodule.c;h=67175aaf2ebcf16c40f99a976e4f00dd4be199ee;hb=f38e72b26c4a245dc0aa43c0f6310f20ae3fd9cc;hp=3768f38b7cf52aab7f04efc1a9b3144e8ea1909f;hpb=22ad6bd6d4f37f2a5906448019f32c3bbdaca23f;p=openldap diff --git a/servers/slapd/module.c b/servers/slapd/module.c index 3768f38b7c..67175aaf2e 100644 --- a/servers/slapd/module.c +++ b/servers/slapd/module.c @@ -1,3 +1,18 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 1998-2005 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ + #include "portable.h" #include #include "slap.h" @@ -6,39 +21,286 @@ #include -int module_load(const char* file_name, int argc, char *argv[]) { - lt_dlhandle* module = NULL; - int (*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); + + +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); + +#ifdef HAVE_EBCDIC +static char ebuf[BUFSIZ]; +#endif + +int module_init (void) +{ + if (lt_dlinit()) { + const char *error = lt_dlerror(); +#ifdef HAVE_EBCDIC + strcpy( ebuf, error ); + __etoa( ebuf ); + error = ebuf; +#endif + 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(); +#ifdef HAVE_EBCDIC + strcpy( ebuf, error ); + __etoa( ebuf ); + error = ebuf; +#endif + 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; +#ifdef HAVE_EBCDIC +#define file ebuf +#else +#define file file_name +#endif - if (lt_dlinit()) { - Debug(LDAP_DEBUG_ANY, "lt_dlinit failed: %s\n", lt_dlerror(), 0, 0); - return -1; - } + 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); - if ((module = lt_dlopen(file_name)) == NULL) { - Debug(LDAP_DEBUG_ANY, "lt_dlopen failed: (%s) %s\n", file_name, - lt_dlerror(), 0); - return -1; - } + return -1; + } + +#ifdef HAVE_EBCDIC + strcpy( file, file_name ); + __atoe( file ); +#endif + /* + * 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_dlopenext(file)) == NULL) { + error = lt_dlerror(); +#ifdef HAVE_EBCDIC + strcpy( ebuf, error ); + __etoa( ebuf ); + error = ebuf; +#endif + Debug(LDAP_DEBUG_ANY, "lt_dlopenext 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); - Debug(LDAP_DEBUG_CONFIG, "loaded module %s\n", file_name, 0, 0); - if ((initialize = lt_dlsym(module, "init_module"))) - return initialize(argc, argv); +#ifdef HAVE_EBCDIC +#pragma convlit(suspend) +#endif + if ((initialize = lt_dlsym(module->lib, "init_module")) == NULL) { +#ifdef HAVE_EBCDIC +#pragma convlit(resume) +#endif + 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); - Debug(LDAP_DEBUG_CONFIG, "module %s: no init_module() function found\n", - file_name, 0, 0); - return -1; + lt_dlclose(module->lib); + ch_free(module); + return rc; + } + + if (rc >= (int)(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; + + 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) +{ +#ifdef HAVE_EBCDIC + strcpy(ebuf, path); + __atoe(ebuf); + path = ebuf; +#endif + return lt_dlsetsearchpath( path ); +} + +void *module_resolve (const void *module, const char *name) +{ +#ifdef HAVE_EBCDIC + strcpy(ebuf, name); + __atoe(ebuf); + name = ebuf; +#endif + 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 */ +#ifdef HAVE_EBCDIC +#pragma convlit(suspend) +#endif + if ((terminate = lt_dlsym(module->lib, "term_module"))) { +#ifdef HAVE_EBCDIC +#pragma convlit(resume) +#endif + 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; } -int module_path(const char *path) { +#ifdef SLAPD_EXTERNAL_EXTENSIONS +int +load_extop_module ( + const void *module, + const char *file_name +) +{ + SLAP_EXTOP_MAIN_FN *ext_main; + SLAP_EXTOP_GETOID_FN *ext_getoid; + struct berval 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); + } - if (lt_dlinit()) { - Debug(LDAP_DEBUG_ANY, "lt_dlinit failed: %s\n", lt_dlerror(), 0, 0); - return -1; - } + rc = (ext_getoid)(0, &oid, 256); + if (rc != 0) { + return(rc); + } + if (oid.bv_val == NULL || oid.bv_len == 0) { + return(-1); + } - return lt_dlsetsearchpath( path ); + rc = load_extop( &oid, ext_main ); + return rc; } +#endif /* SLAPD_EXTERNAL_EXTENSIONS */ #endif /* SLAPD_MODULES */