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