Back to index

openldap  2.4.31
module.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1998-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in the file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 
00016 #include "portable.h"
00017 #include <stdio.h>
00018 #include "slap.h"
00019 
00020 #ifdef SLAPD_MODULES
00021 
00022 #include <ltdl.h>
00023 
00024 typedef int (*MODULE_INIT_FN)(
00025        int argc,
00026        char *argv[]);
00027 typedef int (*MODULE_LOAD_FN)(
00028        const void *module,
00029        const char *filename);
00030 typedef int (*MODULE_TERM_FN)(void);
00031 
00032 
00033 struct module_regtable_t {
00034        char *type;
00035        MODULE_LOAD_FN proc;
00036 } module_regtable[] = {
00037               { "null", load_null_module },
00038 #ifdef SLAPD_EXTERNAL_EXTENSIONS
00039               { "extension", load_extop_module },
00040 #endif
00041               { NULL, NULL }
00042 };
00043 
00044 typedef struct module_loaded_t {
00045        struct module_loaded_t *next;
00046        lt_dlhandle lib;
00047        char name[1];
00048 } module_loaded_t;
00049 
00050 module_loaded_t *module_list = NULL;
00051 
00052 static int module_int_unload (module_loaded_t *module);
00053 
00054 #ifdef HAVE_EBCDIC
00055 static char ebuf[BUFSIZ];
00056 #endif
00057 
00058 int module_init (void)
00059 {
00060        if (lt_dlinit()) {
00061               const char *error = lt_dlerror();
00062 #ifdef HAVE_EBCDIC
00063               strcpy( ebuf, error );
00064               __etoa( ebuf );
00065               error = ebuf;
00066 #endif
00067               Debug(LDAP_DEBUG_ANY, "lt_dlinit failed: %s\n", error, 0, 0);
00068 
00069               return -1;
00070        }
00071 
00072        return module_path( LDAP_MODULEDIR );
00073 }
00074 
00075 int module_kill (void)
00076 {
00077        /* unload all modules before shutdown */
00078        while (module_list != NULL) {
00079               module_int_unload(module_list);
00080        }
00081 
00082        if (lt_dlexit()) {
00083               const char *error = lt_dlerror();
00084 #ifdef HAVE_EBCDIC
00085               strcpy( ebuf, error );
00086               __etoa( ebuf );
00087               error = ebuf;
00088 #endif
00089               Debug(LDAP_DEBUG_ANY, "lt_dlexit failed: %s\n", error, 0, 0);
00090 
00091               return -1;
00092        }
00093        return 0;
00094 }
00095 
00096 void * module_handle( const char *file_name )
00097 {
00098        module_loaded_t *module;
00099 
00100        for ( module = module_list; module; module= module->next ) {
00101               if ( !strcmp( module->name, file_name )) {
00102                      return module;
00103               }
00104        }
00105        return NULL;
00106 }
00107 
00108 int module_unload( const char *file_name )
00109 {
00110        module_loaded_t *module;
00111 
00112        module = module_handle( file_name );
00113        if ( module ) {
00114               module_int_unload( module );
00115               return 0;
00116        }
00117        return -1;    /* not found */
00118 }
00119 
00120 int module_load(const char* file_name, int argc, char *argv[])
00121 {
00122        module_loaded_t *module;
00123        const char *error;
00124        int rc;
00125        MODULE_INIT_FN initialize;
00126 #ifdef HAVE_EBCDIC
00127 #define       file   ebuf
00128 #else
00129 #define       file   file_name
00130 #endif
00131 
00132        module = module_handle( file_name );
00133        if ( module ) {
00134               Debug( LDAP_DEBUG_ANY, "module_load: (%s) already loaded\n",
00135                      file_name, 0, 0 );
00136               return -1;
00137        }
00138 
00139        /* If loading a backend, see if we already have it */
00140        if ( !strncasecmp( file_name, "back_", 5 )) {
00141               char *name = (char *)file_name + 5;
00142               char *dot = strchr( name, '.');
00143               if (dot) *dot = '\0';
00144               rc = backend_info( name ) != NULL;
00145               if (dot) *dot = '.';
00146               if ( rc ) {
00147                      Debug( LDAP_DEBUG_CONFIG, "module_load: (%s) already present (static)\n",
00148                             file_name, 0, 0 );
00149                      return 0;
00150               }
00151        } else {
00152               /* check for overlays too */
00153               char *dot = strchr( file_name, '.' );
00154               if ( dot ) *dot = '\0';
00155               rc = overlay_find( file_name ) != NULL;
00156               if ( dot ) *dot = '.';
00157               if ( rc ) {
00158                      Debug( LDAP_DEBUG_CONFIG, "module_load: (%s) already present (static)\n",
00159                             file_name, 0, 0 );
00160                      return 0;
00161               }
00162        }
00163 
00164        module = (module_loaded_t *)ch_calloc(1, sizeof(module_loaded_t) +
00165               strlen(file_name));
00166        if (module == NULL) {
00167               Debug(LDAP_DEBUG_ANY, "module_load failed: (%s) out of memory\n", file_name,
00168                      0, 0);
00169 
00170               return -1;
00171        }
00172        strcpy( module->name, file_name );
00173 
00174 #ifdef HAVE_EBCDIC
00175        strcpy( file, file_name );
00176        __atoe( file );
00177 #endif
00178        /*
00179         * The result of lt_dlerror(), when called, must be cached prior
00180         * to calling Debug. This is because Debug is a macro that expands
00181         * into multiple function calls.
00182         */
00183        if ((module->lib = lt_dlopenext(file)) == NULL) {
00184               error = lt_dlerror();
00185 #ifdef HAVE_EBCDIC
00186               strcpy( ebuf, error );
00187               __etoa( ebuf );
00188               error = ebuf;
00189 #endif
00190               Debug(LDAP_DEBUG_ANY, "lt_dlopenext failed: (%s) %s\n", file_name,
00191                      error, 0);
00192 
00193               ch_free(module);
00194               return -1;
00195        }
00196 
00197        Debug(LDAP_DEBUG_CONFIG, "loaded module %s\n", file_name, 0, 0);
00198 
00199    
00200 #ifdef HAVE_EBCDIC
00201 #pragma convlit(suspend)
00202 #endif
00203        if ((initialize = lt_dlsym(module->lib, "init_module")) == NULL) {
00204 #ifdef HAVE_EBCDIC
00205 #pragma convlit(resume)
00206 #endif
00207               Debug(LDAP_DEBUG_CONFIG, "module %s: no init_module() function found\n",
00208                      file_name, 0, 0);
00209 
00210               lt_dlclose(module->lib);
00211               ch_free(module);
00212               return -1;
00213        }
00214 
00215        /* The imported init_module() routine passes back the type of
00216         * module (i.e., which part of slapd it should be hooked into)
00217         * or -1 for error.  If it passes back 0, then you get the 
00218         * old behavior (i.e., the library is loaded and not hooked
00219         * into anything).
00220         *
00221         * It might be better if the conf file could specify the type
00222         * of module.  That way, a single module could support multiple
00223         * type of hooks. This could be done by using something like:
00224         *
00225         *    moduleload extension /usr/local/openldap/whatever.so
00226         *
00227         * then we'd search through module_regtable for a matching
00228         * module type, and hook in there.
00229         */
00230        rc = initialize(argc, argv);
00231        if (rc == -1) {
00232               Debug(LDAP_DEBUG_CONFIG, "module %s: init_module() failed\n",
00233                      file_name, 0, 0);
00234 
00235               lt_dlclose(module->lib);
00236               ch_free(module);
00237               return rc;
00238        }
00239 
00240        if (rc >= (int)(sizeof(module_regtable) / sizeof(struct module_regtable_t))
00241               || module_regtable[rc].proc == NULL)
00242        {
00243               Debug(LDAP_DEBUG_CONFIG, "module %s: unknown registration type (%d)\n",
00244                      file_name, rc, 0);
00245 
00246               module_int_unload(module);
00247               return -1;
00248        }
00249 
00250        rc = (module_regtable[rc].proc)(module, file_name);
00251        if (rc != 0) {
00252               Debug(LDAP_DEBUG_CONFIG, "module %s: %s module could not be registered\n",
00253                      file_name, module_regtable[rc].type, 0);
00254 
00255               module_int_unload(module);
00256               return rc;
00257        }
00258 
00259        module->next = module_list;
00260        module_list = module;
00261 
00262        Debug(LDAP_DEBUG_CONFIG, "module %s: %s module registered\n",
00263               file_name, module_regtable[rc].type, 0);
00264 
00265        return 0;
00266 }
00267 
00268 int module_path(const char *path)
00269 {
00270 #ifdef HAVE_EBCDIC
00271        strcpy(ebuf, path);
00272        __atoe(ebuf);
00273        path = ebuf;
00274 #endif
00275        return lt_dlsetsearchpath( path );
00276 }
00277 
00278 void *module_resolve (const void *module, const char *name)
00279 {
00280 #ifdef HAVE_EBCDIC
00281        strcpy(ebuf, name);
00282        __atoe(ebuf);
00283        name = ebuf;
00284 #endif
00285        if (module == NULL || name == NULL)
00286               return(NULL);
00287        return(lt_dlsym(((module_loaded_t *)module)->lib, name));
00288 }
00289 
00290 static int module_int_unload (module_loaded_t *module)
00291 {
00292        module_loaded_t *mod;
00293        MODULE_TERM_FN terminate;
00294 
00295        if (module != NULL) {
00296               /* remove module from tracking list */
00297               if (module_list == module) {
00298                      module_list = module->next;
00299               } else {
00300                      for (mod = module_list; mod; mod = mod->next) {
00301                             if (mod->next == module) {
00302                                    mod->next = module->next;
00303                                    break;
00304                             }
00305                      }
00306               }
00307 
00308               /* call module's terminate routine, if present */
00309 #ifdef HAVE_EBCDIC
00310 #pragma convlit(suspend)
00311 #endif
00312               if ((terminate = lt_dlsym(module->lib, "term_module"))) {
00313 #ifdef HAVE_EBCDIC
00314 #pragma convlit(resume)
00315 #endif
00316                      terminate();
00317               }
00318 
00319               /* close the library and free the memory */
00320               lt_dlclose(module->lib);
00321               ch_free(module);
00322        }
00323        return 0;
00324 }
00325 
00326 int load_null_module (const void *module, const char *file_name)
00327 {
00328        return 0;
00329 }
00330 
00331 #ifdef SLAPD_EXTERNAL_EXTENSIONS
00332 int
00333 load_extop_module (
00334        const void *module,
00335        const char *file_name
00336 )
00337 {
00338        SLAP_EXTOP_MAIN_FN *ext_main;
00339        SLAP_EXTOP_GETOID_FN *ext_getoid;
00340        struct berval oid;
00341        int rc;
00342 
00343        ext_main = (SLAP_EXTOP_MAIN_FN *)module_resolve(module, "ext_main");
00344        if (ext_main == NULL) {
00345               return(-1);
00346        }
00347 
00348        ext_getoid = module_resolve(module, "ext_getoid");
00349        if (ext_getoid == NULL) {
00350               return(-1);
00351        }
00352 
00353        rc = (ext_getoid)(0, &oid, 256);
00354        if (rc != 0) {
00355               return(rc);
00356        }
00357        if (oid.bv_val == NULL || oid.bv_len == 0) {
00358               return(-1);
00359        }
00360 
00361        /* FIXME: this is broken, and no longer needed, 
00362         * as a module can call load_extop() itself... */
00363        rc = load_extop( &oid, ext_main );
00364        return rc;
00365 }
00366 #endif /* SLAPD_EXTERNAL_EXTENSIONS */
00367 #endif /* SLAPD_MODULES */
00368