1999-09-09 03:06:24 +08:00
|
|
|
/* $OpenLDAP$ */
|
2003-11-27 09:17:14 +08:00
|
|
|
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
|
|
|
*
|
2009-01-22 08:40:04 +08:00
|
|
|
* Copyright 1998-2009 The OpenLDAP Foundation.
|
2003-11-27 09:17:14 +08:00
|
|
|
* 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
|
|
|
|
* <http://www.OpenLDAP.org/license.html>.
|
2003-05-25 11:56:57 +08:00
|
|
|
*/
|
2003-11-27 09:17:14 +08:00
|
|
|
|
1999-06-25 01:06:34 +08:00
|
|
|
#include "portable.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "slap.h"
|
|
|
|
|
|
|
|
#ifdef SLAPD_MODULES
|
|
|
|
|
1999-08-07 15:58:11 +08:00
|
|
|
#include <ltdl.h>
|
1999-06-25 01:06:34 +08:00
|
|
|
|
1999-12-08 12:37:59 +08:00
|
|
|
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);
|
|
|
|
|
1999-11-10 05:32:19 +08:00
|
|
|
|
|
|
|
struct module_regtable_t {
|
|
|
|
char *type;
|
1999-12-08 12:37:59 +08:00
|
|
|
MODULE_LOAD_FN proc;
|
1999-11-10 05:32:19 +08:00
|
|
|
} module_regtable[] = {
|
1999-12-08 12:37:59 +08:00
|
|
|
{ "null", load_null_module },
|
1999-11-25 18:07:14 +08:00
|
|
|
#ifdef SLAPD_EXTERNAL_EXTENSIONS
|
1999-12-08 12:37:59 +08:00
|
|
|
{ "extension", load_extop_module },
|
1999-11-25 18:07:14 +08:00
|
|
|
#endif
|
1999-12-08 12:37:59 +08:00
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
1999-11-10 05:32:19 +08:00
|
|
|
|
|
|
|
typedef struct module_loaded_t {
|
|
|
|
struct module_loaded_t *next;
|
2001-12-07 11:18:32 +08:00
|
|
|
lt_dlhandle lib;
|
2007-02-12 07:01:08 +08:00
|
|
|
char name[1];
|
1999-11-10 05:32:19 +08:00
|
|
|
} module_loaded_t;
|
|
|
|
|
|
|
|
module_loaded_t *module_list = NULL;
|
|
|
|
|
2007-02-12 07:01:08 +08:00
|
|
|
static int module_int_unload (module_loaded_t *module);
|
1999-11-10 05:32:19 +08:00
|
|
|
|
2003-06-11 21:37:59 +08:00
|
|
|
#ifdef HAVE_EBCDIC
|
|
|
|
static char ebuf[BUFSIZ];
|
|
|
|
#endif
|
|
|
|
|
1999-11-10 05:32:19 +08:00
|
|
|
int module_init (void)
|
|
|
|
{
|
|
|
|
if (lt_dlinit()) {
|
|
|
|
const char *error = lt_dlerror();
|
2003-06-11 21:37:59 +08:00
|
|
|
#ifdef HAVE_EBCDIC
|
|
|
|
strcpy( ebuf, error );
|
|
|
|
__etoa( ebuf );
|
|
|
|
error = ebuf;
|
|
|
|
#endif
|
1999-11-10 05:32:19 +08:00
|
|
|
Debug(LDAP_DEBUG_ANY, "lt_dlinit failed: %s\n", error, 0, 0);
|
2001-01-16 03:17:29 +08:00
|
|
|
|
1999-11-10 05:32:19 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2007-06-10 01:49:39 +08:00
|
|
|
|
2007-06-11 05:55:39 +08:00
|
|
|
return module_path( LDAP_MODULEDIR );
|
1999-11-10 05:32:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int module_kill (void)
|
|
|
|
{
|
|
|
|
/* unload all modules before shutdown */
|
|
|
|
while (module_list != NULL) {
|
2007-02-12 07:01:08 +08:00
|
|
|
module_int_unload(module_list);
|
1999-11-10 05:32:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (lt_dlexit()) {
|
|
|
|
const char *error = lt_dlerror();
|
2003-06-11 21:37:59 +08:00
|
|
|
#ifdef HAVE_EBCDIC
|
|
|
|
strcpy( ebuf, error );
|
|
|
|
__etoa( ebuf );
|
|
|
|
error = ebuf;
|
|
|
|
#endif
|
1999-11-10 05:32:19 +08:00
|
|
|
Debug(LDAP_DEBUG_ANY, "lt_dlexit failed: %s\n", error, 0, 0);
|
2001-01-16 03:17:29 +08:00
|
|
|
|
1999-11-10 05:32:19 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-02-12 07:01:08 +08:00
|
|
|
void * module_handle( const char *file_name )
|
|
|
|
{
|
|
|
|
module_loaded_t *module;
|
|
|
|
|
|
|
|
for ( module = module_list; module; module= module->next ) {
|
|
|
|
if ( !strcmp( module->name, file_name )) {
|
|
|
|
return module;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int module_unload( const char *file_name )
|
|
|
|
{
|
|
|
|
module_loaded_t *module;
|
|
|
|
|
|
|
|
module = module_handle( file_name );
|
|
|
|
if ( module ) {
|
|
|
|
module_int_unload( module );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -1; /* not found */
|
|
|
|
}
|
|
|
|
|
1999-09-28 17:54:00 +08:00
|
|
|
int module_load(const char* file_name, int argc, char *argv[])
|
|
|
|
{
|
2009-03-23 19:38:24 +08:00
|
|
|
module_loaded_t *module;
|
1999-11-10 05:32:19 +08:00
|
|
|
const char *error;
|
|
|
|
int rc;
|
1999-12-08 12:37:59 +08:00
|
|
|
MODULE_INIT_FN initialize;
|
2003-06-11 21:37:59 +08:00
|
|
|
#ifdef HAVE_EBCDIC
|
|
|
|
#define file ebuf
|
|
|
|
#else
|
|
|
|
#define file file_name
|
|
|
|
#endif
|
1999-11-10 05:32:19 +08:00
|
|
|
|
2009-03-23 19:38:24 +08:00
|
|
|
module = module_handle( file_name );
|
2009-03-24 00:06:00 +08:00
|
|
|
if ( module ) {
|
|
|
|
Debug( LDAP_DEBUG_ANY, "module_load: (%s) already loaded\n",
|
|
|
|
file_name, 0, 0 );
|
|
|
|
return -1;
|
|
|
|
}
|
2009-03-23 19:38:24 +08:00
|
|
|
|
2009-04-03 07:41:41 +08:00
|
|
|
/* If loading a backend, see if we already have it */
|
|
|
|
if ( !strncasecmp( file_name, "back_", 5 )) {
|
|
|
|
char *name = (char *)file_name + 5;
|
|
|
|
char *dot = strchr( name, '.');
|
|
|
|
if (dot) *dot = '\0';
|
|
|
|
rc = backend_info( name ) != NULL;
|
|
|
|
if (dot) *dot = '.';
|
|
|
|
if ( rc ) {
|
|
|
|
Debug( LDAP_DEBUG_CONFIG, "module_load: (%s) already present (static)\n",
|
|
|
|
file_name, 0, 0 );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* check for overlays too */
|
|
|
|
char *dot = strchr( file_name, '.' );
|
|
|
|
if ( dot ) *dot = '\0';
|
|
|
|
rc = overlay_find( file_name ) != NULL;
|
|
|
|
if ( dot ) *dot = '.';
|
|
|
|
if ( rc ) {
|
|
|
|
Debug( LDAP_DEBUG_CONFIG, "module_load: (%s) already present (static)\n",
|
|
|
|
file_name, 0, 0 );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-12 07:01:08 +08:00
|
|
|
module = (module_loaded_t *)ch_calloc(1, sizeof(module_loaded_t) +
|
|
|
|
strlen(file_name));
|
1999-11-10 05:32:19 +08:00
|
|
|
if (module == NULL) {
|
|
|
|
Debug(LDAP_DEBUG_ANY, "module_load failed: (%s) out of memory\n", file_name,
|
|
|
|
0, 0);
|
2001-01-16 03:17:29 +08:00
|
|
|
|
1999-11-10 05:32:19 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2007-02-12 07:01:08 +08:00
|
|
|
strcpy( module->name, file_name );
|
1999-11-10 05:32:19 +08:00
|
|
|
|
2003-06-11 21:37:59 +08:00
|
|
|
#ifdef HAVE_EBCDIC
|
|
|
|
strcpy( file, file_name );
|
|
|
|
__atoe( file );
|
|
|
|
#endif
|
1999-11-10 05:32:19 +08:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2003-06-13 06:21:30 +08:00
|
|
|
if ((module->lib = lt_dlopenext(file)) == NULL) {
|
1999-11-10 05:32:19 +08:00
|
|
|
error = lt_dlerror();
|
2003-06-11 21:37:59 +08:00
|
|
|
#ifdef HAVE_EBCDIC
|
|
|
|
strcpy( ebuf, error );
|
|
|
|
__etoa( ebuf );
|
|
|
|
error = ebuf;
|
|
|
|
#endif
|
2003-06-13 06:21:30 +08:00
|
|
|
Debug(LDAP_DEBUG_ANY, "lt_dlopenext failed: (%s) %s\n", file_name,
|
1999-11-10 05:32:19 +08:00
|
|
|
error, 0);
|
2001-01-16 03:17:29 +08:00
|
|
|
|
1999-11-10 05:32:19 +08:00
|
|
|
ch_free(module);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
Debug(LDAP_DEBUG_CONFIG, "loaded module %s\n", file_name, 0, 0);
|
2001-01-16 03:17:29 +08:00
|
|
|
|
1999-06-25 01:06:34 +08:00
|
|
|
|
2003-06-11 21:37:59 +08:00
|
|
|
#ifdef HAVE_EBCDIC
|
|
|
|
#pragma convlit(suspend)
|
|
|
|
#endif
|
1999-11-10 05:32:19 +08:00
|
|
|
if ((initialize = lt_dlsym(module->lib, "init_module")) == NULL) {
|
2003-06-11 21:37:59 +08:00
|
|
|
#ifdef HAVE_EBCDIC
|
|
|
|
#pragma convlit(resume)
|
|
|
|
#endif
|
1999-11-10 05:32:19 +08:00
|
|
|
Debug(LDAP_DEBUG_CONFIG, "module %s: no init_module() function found\n",
|
|
|
|
file_name, 0, 0);
|
2001-01-16 03:17:29 +08:00
|
|
|
|
1999-11-10 05:32:19 +08:00
|
|
|
lt_dlclose(module->lib);
|
|
|
|
ch_free(module);
|
|
|
|
return -1;
|
|
|
|
}
|
1999-08-17 08:28:01 +08:00
|
|
|
|
1999-11-10 05:32:19 +08:00
|
|
|
/* 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);
|
2001-01-16 03:17:29 +08:00
|
|
|
|
1999-11-10 05:32:19 +08:00
|
|
|
lt_dlclose(module->lib);
|
|
|
|
ch_free(module);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2002-04-11 16:46:34 +08:00
|
|
|
if (rc >= (int)(sizeof(module_regtable) / sizeof(struct module_regtable_t))
|
1999-11-10 05:32:19 +08:00
|
|
|
|| module_regtable[rc].proc == NULL)
|
|
|
|
{
|
|
|
|
Debug(LDAP_DEBUG_CONFIG, "module %s: unknown registration type (%d)\n",
|
|
|
|
file_name, rc, 0);
|
2001-01-16 03:17:29 +08:00
|
|
|
|
2007-02-12 07:01:08 +08:00
|
|
|
module_int_unload(module);
|
1999-11-10 05:32:19 +08:00
|
|
|
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);
|
2001-01-16 03:17:29 +08:00
|
|
|
|
2007-02-12 07:01:08 +08:00
|
|
|
module_int_unload(module);
|
1999-11-10 05:32:19 +08:00
|
|
|
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);
|
2001-01-16 03:17:29 +08:00
|
|
|
|
1999-11-10 05:32:19 +08:00
|
|
|
return 0;
|
1999-06-25 01:06:34 +08:00
|
|
|
}
|
|
|
|
|
1999-09-28 17:54:00 +08:00
|
|
|
int module_path(const char *path)
|
|
|
|
{
|
2003-06-11 21:37:59 +08:00
|
|
|
#ifdef HAVE_EBCDIC
|
|
|
|
strcpy(ebuf, path);
|
|
|
|
__atoe(ebuf);
|
|
|
|
path = ebuf;
|
|
|
|
#endif
|
1999-11-10 05:32:19 +08:00
|
|
|
return lt_dlsetsearchpath( path );
|
|
|
|
}
|
|
|
|
|
|
|
|
void *module_resolve (const void *module, const char *name)
|
|
|
|
{
|
2003-06-11 21:37:59 +08:00
|
|
|
#ifdef HAVE_EBCDIC
|
|
|
|
strcpy(ebuf, name);
|
|
|
|
__atoe(ebuf);
|
|
|
|
name = ebuf;
|
|
|
|
#endif
|
1999-11-10 05:32:19 +08:00
|
|
|
if (module == NULL || name == NULL)
|
|
|
|
return(NULL);
|
|
|
|
return(lt_dlsym(((module_loaded_t *)module)->lib, name));
|
|
|
|
}
|
|
|
|
|
2007-02-12 07:01:08 +08:00
|
|
|
static int module_int_unload (module_loaded_t *module)
|
1999-11-10 05:32:19 +08:00
|
|
|
{
|
|
|
|
module_loaded_t *mod;
|
1999-12-08 12:37:59 +08:00
|
|
|
MODULE_TERM_FN terminate;
|
1999-09-28 17:54:00 +08:00
|
|
|
|
1999-11-10 05:32:19 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-08-17 09:30:09 +08:00
|
|
|
|
1999-11-10 05:32:19 +08:00
|
|
|
/* call module's terminate routine, if present */
|
2003-06-11 21:37:59 +08:00
|
|
|
#ifdef HAVE_EBCDIC
|
|
|
|
#pragma convlit(suspend)
|
|
|
|
#endif
|
2003-01-28 05:51:33 +08:00
|
|
|
if ((terminate = lt_dlsym(module->lib, "term_module"))) {
|
2003-06-11 21:37:59 +08:00
|
|
|
#ifdef HAVE_EBCDIC
|
|
|
|
#pragma convlit(resume)
|
|
|
|
#endif
|
1999-11-10 05:32:19 +08:00
|
|
|
terminate();
|
|
|
|
}
|
1999-08-17 09:30:09 +08:00
|
|
|
|
1999-11-10 05:32:19 +08:00
|
|
|
/* close the library and free the memory */
|
|
|
|
lt_dlclose(module->lib);
|
|
|
|
ch_free(module);
|
|
|
|
}
|
|
|
|
return 0;
|
1999-08-17 09:30:09 +08:00
|
|
|
}
|
1999-11-10 05:32:19 +08:00
|
|
|
|
1999-12-10 06:33:22 +08:00
|
|
|
int load_null_module (const void *module, const char *file_name)
|
1999-11-10 05:32:19 +08:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1999-12-08 12:37:59 +08:00
|
|
|
#ifdef SLAPD_EXTERNAL_EXTENSIONS
|
|
|
|
int
|
|
|
|
load_extop_module (
|
|
|
|
const void *module,
|
|
|
|
const char *file_name
|
|
|
|
)
|
|
|
|
{
|
2002-01-02 19:00:36 +08:00
|
|
|
SLAP_EXTOP_MAIN_FN *ext_main;
|
2003-02-16 14:15:28 +08:00
|
|
|
SLAP_EXTOP_GETOID_FN *ext_getoid;
|
|
|
|
struct berval oid;
|
1999-12-10 06:33:22 +08:00
|
|
|
int rc;
|
|
|
|
|
2002-01-02 19:00:36 +08:00
|
|
|
ext_main = (SLAP_EXTOP_MAIN_FN *)module_resolve(module, "ext_main");
|
1999-12-08 12:37:59 +08:00
|
|
|
if (ext_main == NULL) {
|
|
|
|
return(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
ext_getoid = module_resolve(module, "ext_getoid");
|
|
|
|
if (ext_getoid == NULL) {
|
|
|
|
return(-1);
|
|
|
|
}
|
|
|
|
|
2003-02-16 14:15:28 +08:00
|
|
|
rc = (ext_getoid)(0, &oid, 256);
|
1999-12-10 06:33:22 +08:00
|
|
|
if (rc != 0) {
|
|
|
|
return(rc);
|
|
|
|
}
|
2003-02-16 14:15:28 +08:00
|
|
|
if (oid.bv_val == NULL || oid.bv_len == 0) {
|
1999-12-10 06:33:22 +08:00
|
|
|
return(-1);
|
|
|
|
}
|
|
|
|
|
2006-01-07 01:08:54 +08:00
|
|
|
/* FIXME: this is broken, and no longer needed,
|
|
|
|
* as a module can call load_extop() itself... */
|
2003-02-16 14:15:28 +08:00
|
|
|
rc = load_extop( &oid, ext_main );
|
1999-12-10 06:33:22 +08:00
|
|
|
return rc;
|
1999-12-08 12:37:59 +08:00
|
|
|
}
|
|
|
|
#endif /* SLAPD_EXTERNAL_EXTENSIONS */
|
1999-06-25 01:06:34 +08:00
|
|
|
#endif /* SLAPD_MODULES */
|
|
|
|
|