1/* $OpenLDAP$ */ 2/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 1998-2011 The OpenLDAP Foundation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted only as authorized by the OpenLDAP 9 * Public License. 10 * 11 * A copy of this license is available in the file LICENSE in the 12 * top-level directory of the distribution or, alternatively, at 13 * <http://www.OpenLDAP.org/license.html>. 14 */ 15 16#include "portable.h" 17#include <stdio.h> 18#include "slap.h" 19 20#ifdef SLAPD_MODULES 21 22#include <ltdl.h> 23 24typedef int (*MODULE_INIT_FN)( 25 int argc, 26 char *argv[]); 27typedef int (*MODULE_LOAD_FN)( 28 const void *module, 29 const char *filename); 30typedef int (*MODULE_TERM_FN)(void); 31 32 33struct module_regtable_t { 34 char *type; 35 MODULE_LOAD_FN proc; 36} module_regtable[] = { 37 { "null", load_null_module }, 38#ifdef SLAPD_EXTERNAL_EXTENSIONS 39 { "extension", load_extop_module }, 40#endif 41 { NULL, NULL } 42}; 43 44typedef struct module_loaded_t { 45 struct module_loaded_t *next; 46 lt_dlhandle lib; 47 char name[1]; 48} module_loaded_t; 49 50module_loaded_t *module_list = NULL; 51 52static int module_int_unload (module_loaded_t *module); 53 54#ifdef HAVE_EBCDIC 55static char ebuf[BUFSIZ]; 56#endif 57 58int module_init (void) 59{ 60 if (lt_dlinit()) { 61 const char *error = lt_dlerror(); 62#ifdef HAVE_EBCDIC 63 strcpy( ebuf, error ); 64 __etoa( ebuf ); 65 error = ebuf; 66#endif 67 Debug(LDAP_DEBUG_ANY, "lt_dlinit failed: %s\n", error, 0, 0); 68 69 return -1; 70 } 71 72 return module_path( LDAP_MODULEDIR ); 73} 74 75int module_kill (void) 76{ 77 /* unload all modules before shutdown */ 78 while (module_list != NULL) { 79 module_int_unload(module_list); 80 } 81 82 if (lt_dlexit()) { 83 const char *error = lt_dlerror(); 84#ifdef HAVE_EBCDIC 85 strcpy( ebuf, error ); 86 __etoa( ebuf ); 87 error = ebuf; 88#endif 89 Debug(LDAP_DEBUG_ANY, "lt_dlexit failed: %s\n", error, 0, 0); 90 91 return -1; 92 } 93 return 0; 94} 95 96void * module_handle( const char *file_name ) 97{ 98 module_loaded_t *module; 99 100 for ( module = module_list; module; module= module->next ) { 101 if ( !strcmp( module->name, file_name )) { 102 return module; 103 } 104 } 105 return NULL; 106} 107 108int module_unload( const char *file_name ) 109{ 110 module_loaded_t *module; 111 112 module = module_handle( file_name ); 113 if ( module ) { 114 module_int_unload( module ); 115 return 0; 116 } 117 return -1; /* not found */ 118} 119 120int module_load(const char* file_name, int argc, char *argv[]) 121{ 122 module_loaded_t *module; 123 const char *error; 124 int rc; 125 MODULE_INIT_FN initialize; 126#ifdef HAVE_EBCDIC 127#define file ebuf 128#else 129#define file file_name 130#endif 131 132 module = module_handle( file_name ); 133 if ( module ) { 134 Debug( LDAP_DEBUG_ANY, "module_load: (%s) already loaded\n", 135 file_name, 0, 0 ); 136 return -1; 137 } 138 139 /* If loading a backend, see if we already have it */ 140 if ( !strncasecmp( file_name, "back_", 5 )) { 141 char *name = (char *)file_name + 5; 142 char *dot = strchr( name, '.'); 143 if (dot) *dot = '\0'; 144 rc = backend_info( name ) != NULL; 145 if (dot) *dot = '.'; 146 if ( rc ) { 147 Debug( LDAP_DEBUG_CONFIG, "module_load: (%s) already present (static)\n", 148 file_name, 0, 0 ); 149 return 0; 150 } 151 } else { 152 /* check for overlays too */ 153 char *dot = strchr( file_name, '.' ); 154 if ( dot ) *dot = '\0'; 155 rc = overlay_find( file_name ) != NULL; 156 if ( dot ) *dot = '.'; 157 if ( rc ) { 158 Debug( LDAP_DEBUG_CONFIG, "module_load: (%s) already present (static)\n", 159 file_name, 0, 0 ); 160 return 0; 161 } 162 } 163 164 module = (module_loaded_t *)ch_calloc(1, sizeof(module_loaded_t) + 165 strlen(file_name)); 166 if (module == NULL) { 167 Debug(LDAP_DEBUG_ANY, "module_load failed: (%s) out of memory\n", file_name, 168 0, 0); 169 170 return -1; 171 } 172 strcpy( module->name, file_name ); 173 174#ifdef HAVE_EBCDIC 175 strcpy( file, file_name ); 176 __atoe( file ); 177#endif 178 /* 179 * The result of lt_dlerror(), when called, must be cached prior 180 * to calling Debug. This is because Debug is a macro that expands 181 * into multiple function calls. 182 */ 183 if ((module->lib = lt_dlopenext(file)) == NULL) { 184 error = lt_dlerror(); 185#ifdef HAVE_EBCDIC 186 strcpy( ebuf, error ); 187 __etoa( ebuf ); 188 error = ebuf; 189#endif 190 Debug(LDAP_DEBUG_ANY, "lt_dlopenext failed: (%s) %s\n", file_name, 191 error, 0); 192 193 ch_free(module); 194 return -1; 195 } 196 197 Debug(LDAP_DEBUG_CONFIG, "loaded module %s\n", file_name, 0, 0); 198 199 200#ifdef HAVE_EBCDIC 201#pragma convlit(suspend) 202#endif 203 if ((initialize = lt_dlsym(module->lib, "init_module")) == NULL) { 204#ifdef HAVE_EBCDIC 205#pragma convlit(resume) 206#endif 207 Debug(LDAP_DEBUG_CONFIG, "module %s: no init_module() function found\n", 208 file_name, 0, 0); 209 210 lt_dlclose(module->lib); 211 ch_free(module); 212 return -1; 213 } 214 215 /* The imported init_module() routine passes back the type of 216 * module (i.e., which part of slapd it should be hooked into) 217 * or -1 for error. If it passes back 0, then you get the 218 * old behavior (i.e., the library is loaded and not hooked 219 * into anything). 220 * 221 * It might be better if the conf file could specify the type 222 * of module. That way, a single module could support multiple 223 * type of hooks. This could be done by using something like: 224 * 225 * moduleload extension /usr/local/openldap/whatever.so 226 * 227 * then we'd search through module_regtable for a matching 228 * module type, and hook in there. 229 */ 230 rc = initialize(argc, argv); 231 if (rc == -1) { 232 Debug(LDAP_DEBUG_CONFIG, "module %s: init_module() failed\n", 233 file_name, 0, 0); 234 235 lt_dlclose(module->lib); 236 ch_free(module); 237 return rc; 238 } 239 240 if (rc >= (int)(sizeof(module_regtable) / sizeof(struct module_regtable_t)) 241 || module_regtable[rc].proc == NULL) 242 { 243 Debug(LDAP_DEBUG_CONFIG, "module %s: unknown registration type (%d)\n", 244 file_name, rc, 0); 245 246 module_int_unload(module); 247 return -1; 248 } 249 250 rc = (module_regtable[rc].proc)(module, file_name); 251 if (rc != 0) { 252 Debug(LDAP_DEBUG_CONFIG, "module %s: %s module could not be registered\n", 253 file_name, module_regtable[rc].type, 0); 254 255 module_int_unload(module); 256 return rc; 257 } 258 259 module->next = module_list; 260 module_list = module; 261 262 Debug(LDAP_DEBUG_CONFIG, "module %s: %s module registered\n", 263 file_name, module_regtable[rc].type, 0); 264 265 return 0; 266} 267 268int module_path(const char *path) 269{ 270#ifdef HAVE_EBCDIC 271 strcpy(ebuf, path); 272 __atoe(ebuf); 273 path = ebuf; 274#endif 275 return lt_dlsetsearchpath( path ); 276} 277 278void *module_resolve (const void *module, const char *name) 279{ 280#ifdef HAVE_EBCDIC 281 strcpy(ebuf, name); 282 __atoe(ebuf); 283 name = ebuf; 284#endif 285 if (module == NULL || name == NULL) 286 return(NULL); 287 return(lt_dlsym(((module_loaded_t *)module)->lib, name)); 288} 289 290static int module_int_unload (module_loaded_t *module) 291{ 292 module_loaded_t *mod; 293 MODULE_TERM_FN terminate; 294 295 if (module != NULL) { 296 /* remove module from tracking list */ 297 if (module_list == module) { 298 module_list = module->next; 299 } else { 300 for (mod = module_list; mod; mod = mod->next) { 301 if (mod->next == module) { 302 mod->next = module->next; 303 break; 304 } 305 } 306 } 307 308 /* call module's terminate routine, if present */ 309#ifdef HAVE_EBCDIC 310#pragma convlit(suspend) 311#endif 312 if ((terminate = lt_dlsym(module->lib, "term_module"))) { 313#ifdef HAVE_EBCDIC 314#pragma convlit(resume) 315#endif 316 terminate(); 317 } 318 319 /* close the library and free the memory */ 320 lt_dlclose(module->lib); 321 ch_free(module); 322 } 323 return 0; 324} 325 326int load_null_module (const void *module, const char *file_name) 327{ 328 return 0; 329} 330 331#ifdef SLAPD_EXTERNAL_EXTENSIONS 332int 333load_extop_module ( 334 const void *module, 335 const char *file_name 336) 337{ 338 SLAP_EXTOP_MAIN_FN *ext_main; 339 SLAP_EXTOP_GETOID_FN *ext_getoid; 340 struct berval oid; 341 int rc; 342 343 ext_main = (SLAP_EXTOP_MAIN_FN *)module_resolve(module, "ext_main"); 344 if (ext_main == NULL) { 345 return(-1); 346 } 347 348 ext_getoid = module_resolve(module, "ext_getoid"); 349 if (ext_getoid == NULL) { 350 return(-1); 351 } 352 353 rc = (ext_getoid)(0, &oid, 256); 354 if (rc != 0) { 355 return(rc); 356 } 357 if (oid.bv_val == NULL || oid.bv_len == 0) { 358 return(-1); 359 } 360 361 /* FIXME: this is broken, and no longer needed, 362 * as a module can call load_extop() itself... */ 363 rc = load_extop( &oid, ext_main ); 364 return rc; 365} 366#endif /* SLAPD_EXTERNAL_EXTENSIONS */ 367#endif /* SLAPD_MODULES */ 368 369