1 /* $OpenLDAP: pkg/ldap/servers/slapd/module.c,v 1.29.2.3 2008/02/11 23:26:44 kurt Exp $ */ 2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 1998-2008 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 24 typedef int (*MODULE_INIT_FN)( 25 int argc, 26 char *argv[]); 27 typedef int (*MODULE_LOAD_FN)( 28 const void *module, 29 const char *filename); 30 typedef int (*MODULE_TERM_FN)(void); 31 32 33 struct 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 44 typedef struct module_loaded_t { 45 struct module_loaded_t *next; 46 lt_dlhandle lib; 47 char name[1]; 48 } module_loaded_t; 49 50 module_loaded_t *module_list = NULL; 51 52 static int module_int_unload (module_loaded_t *module); 53 54 #ifdef HAVE_EBCDIC 55 static char ebuf[BUFSIZ]; 56 #endif 57 58 int 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 75 int 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 96 void * 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 108 int 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 120 int module_load(const char* file_name, int argc, char *argv[]) 121 { 122 module_loaded_t *module = NULL; 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_loaded_t *)ch_calloc(1, sizeof(module_loaded_t) + 133 strlen(file_name)); 134 if (module == NULL) { 135 Debug(LDAP_DEBUG_ANY, "module_load failed: (%s) out of memory\n", file_name, 136 0, 0); 137 138 return -1; 139 } 140 strcpy( module->name, file_name ); 141 142 #ifdef HAVE_EBCDIC 143 strcpy( file, file_name ); 144 __atoe( file ); 145 #endif 146 /* 147 * The result of lt_dlerror(), when called, must be cached prior 148 * to calling Debug. This is because Debug is a macro that expands 149 * into multiple function calls. 150 */ 151 if ((module->lib = lt_dlopenext(file)) == NULL) { 152 error = lt_dlerror(); 153 #ifdef HAVE_EBCDIC 154 strcpy( ebuf, error ); 155 __etoa( ebuf ); 156 error = ebuf; 157 #endif 158 Debug(LDAP_DEBUG_ANY, "lt_dlopenext failed: (%s) %s\n", file_name, 159 error, 0); 160 161 ch_free(module); 162 return -1; 163 } 164 165 Debug(LDAP_DEBUG_CONFIG, "loaded module %s\n", file_name, 0, 0); 166 167 168 #ifdef HAVE_EBCDIC 169 #pragma convlit(suspend) 170 #endif 171 if ((initialize = lt_dlsym(module->lib, "init_module")) == NULL) { 172 #ifdef HAVE_EBCDIC 173 #pragma convlit(resume) 174 #endif 175 Debug(LDAP_DEBUG_CONFIG, "module %s: no init_module() function found\n", 176 file_name, 0, 0); 177 178 lt_dlclose(module->lib); 179 ch_free(module); 180 return -1; 181 } 182 183 /* The imported init_module() routine passes back the type of 184 * module (i.e., which part of slapd it should be hooked into) 185 * or -1 for error. If it passes back 0, then you get the 186 * old behavior (i.e., the library is loaded and not hooked 187 * into anything). 188 * 189 * It might be better if the conf file could specify the type 190 * of module. That way, a single module could support multiple 191 * type of hooks. This could be done by using something like: 192 * 193 * moduleload extension /usr/local/openldap/whatever.so 194 * 195 * then we'd search through module_regtable for a matching 196 * module type, and hook in there. 197 */ 198 rc = initialize(argc, argv); 199 if (rc == -1) { 200 Debug(LDAP_DEBUG_CONFIG, "module %s: init_module() failed\n", 201 file_name, 0, 0); 202 203 lt_dlclose(module->lib); 204 ch_free(module); 205 return rc; 206 } 207 208 if (rc >= (int)(sizeof(module_regtable) / sizeof(struct module_regtable_t)) 209 || module_regtable[rc].proc == NULL) 210 { 211 Debug(LDAP_DEBUG_CONFIG, "module %s: unknown registration type (%d)\n", 212 file_name, rc, 0); 213 214 module_int_unload(module); 215 return -1; 216 } 217 218 rc = (module_regtable[rc].proc)(module, file_name); 219 if (rc != 0) { 220 Debug(LDAP_DEBUG_CONFIG, "module %s: %s module could not be registered\n", 221 file_name, module_regtable[rc].type, 0); 222 223 module_int_unload(module); 224 return rc; 225 } 226 227 module->next = module_list; 228 module_list = module; 229 230 Debug(LDAP_DEBUG_CONFIG, "module %s: %s module registered\n", 231 file_name, module_regtable[rc].type, 0); 232 233 return 0; 234 } 235 236 int module_path(const char *path) 237 { 238 #ifdef HAVE_EBCDIC 239 strcpy(ebuf, path); 240 __atoe(ebuf); 241 path = ebuf; 242 #endif 243 return lt_dlsetsearchpath( path ); 244 } 245 246 void *module_resolve (const void *module, const char *name) 247 { 248 #ifdef HAVE_EBCDIC 249 strcpy(ebuf, name); 250 __atoe(ebuf); 251 name = ebuf; 252 #endif 253 if (module == NULL || name == NULL) 254 return(NULL); 255 return(lt_dlsym(((module_loaded_t *)module)->lib, name)); 256 } 257 258 static int module_int_unload (module_loaded_t *module) 259 { 260 module_loaded_t *mod; 261 MODULE_TERM_FN terminate; 262 263 if (module != NULL) { 264 /* remove module from tracking list */ 265 if (module_list == module) { 266 module_list = module->next; 267 } else { 268 for (mod = module_list; mod; mod = mod->next) { 269 if (mod->next == module) { 270 mod->next = module->next; 271 break; 272 } 273 } 274 } 275 276 /* call module's terminate routine, if present */ 277 #ifdef HAVE_EBCDIC 278 #pragma convlit(suspend) 279 #endif 280 if ((terminate = lt_dlsym(module->lib, "term_module"))) { 281 #ifdef HAVE_EBCDIC 282 #pragma convlit(resume) 283 #endif 284 terminate(); 285 } 286 287 /* close the library and free the memory */ 288 lt_dlclose(module->lib); 289 ch_free(module); 290 } 291 return 0; 292 } 293 294 int load_null_module (const void *module, const char *file_name) 295 { 296 return 0; 297 } 298 299 #ifdef SLAPD_EXTERNAL_EXTENSIONS 300 int 301 load_extop_module ( 302 const void *module, 303 const char *file_name 304 ) 305 { 306 SLAP_EXTOP_MAIN_FN *ext_main; 307 SLAP_EXTOP_GETOID_FN *ext_getoid; 308 struct berval oid; 309 int rc; 310 311 ext_main = (SLAP_EXTOP_MAIN_FN *)module_resolve(module, "ext_main"); 312 if (ext_main == NULL) { 313 return(-1); 314 } 315 316 ext_getoid = module_resolve(module, "ext_getoid"); 317 if (ext_getoid == NULL) { 318 return(-1); 319 } 320 321 rc = (ext_getoid)(0, &oid, 256); 322 if (rc != 0) { 323 return(rc); 324 } 325 if (oid.bv_val == NULL || oid.bv_len == 0) { 326 return(-1); 327 } 328 329 /* FIXME: this is broken, and no longer needed, 330 * as a module can call load_extop() itself... */ 331 rc = load_extop( &oid, ext_main ); 332 return rc; 333 } 334 #endif /* SLAPD_EXTERNAL_EXTENSIONS */ 335 #endif /* SLAPD_MODULES */ 336 337