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