1/* $NetBSD: module.c,v 1.3 2021/08/14 16:14:58 christos Exp $ */ 2 3/* $OpenLDAP$ */ 4/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1998-2021 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.3 2021/08/14 16:14:58 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 29typedef int (*MODULE_INIT_FN)( 30 int argc, 31 char *argv[]); 32typedef int (*MODULE_LOAD_FN)( 33 const void *module, 34 const char *filename); 35typedef int (*MODULE_TERM_FN)(void); 36 37 38struct 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 49typedef struct module_loaded_t { 50 struct module_loaded_t *next; 51 lt_dlhandle lib; 52 char name[1]; 53} module_loaded_t; 54 55module_loaded_t *module_list = NULL; 56 57static int module_int_unload (module_loaded_t *module); 58 59#ifdef HAVE_EBCDIC 60static char ebuf[BUFSIZ]; 61#endif 62 63int 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 ); 73 74 return -1; 75 } 76 77 return module_path( LDAP_MODULEDIR ); 78} 79 80int 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 ); 95 96 return -1; 97 } 98 return 0; 99} 100 101void * 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 113int 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 125int 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 ); 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 ); 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 ); 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 174 return -1; 175 } 176 strcpy( module->name, file_name ); 177 178#ifdef HAVE_EBCDIC 179 strcpy( file, file_name ); 180 __atoe( file ); 181#endif 182 /* 183 * The result of lt_dlerror(), when called, must be cached prior 184 * to calling Debug. This is because Debug is a macro that expands 185 * into multiple function calls. 186 */ 187 if ((module->lib = lt_dlopenext(file)) == NULL) { 188 error = lt_dlerror(); 189#ifdef HAVE_EBCDIC 190 strcpy( ebuf, error ); 191 __etoa( ebuf ); 192 error = ebuf; 193#endif 194 Debug(LDAP_DEBUG_ANY, "lt_dlopenext failed: (%s) %s\n", file_name, 195 error ); 196 197 ch_free(module); 198 return -1; 199 } 200 201 Debug(LDAP_DEBUG_CONFIG, "loaded module %s\n", file_name ); 202 203 204#ifdef HAVE_EBCDIC 205#pragma convlit(suspend) 206#endif 207 if ((initialize = lt_dlsym(module->lib, "init_module")) == NULL) { 208#ifdef HAVE_EBCDIC 209#pragma convlit(resume) 210#endif 211 Debug(LDAP_DEBUG_CONFIG, "module %s: no init_module() function found\n", 212 file_name ); 213 214 lt_dlclose(module->lib); 215 ch_free(module); 216 return -1; 217 } 218 219 /* The imported init_module() routine passes back the type of 220 * module (i.e., which part of slapd it should be hooked into) 221 * or -1 for error. If it passes back 0, then you get the 222 * old behavior (i.e., the library is loaded and not hooked 223 * into anything). 224 * 225 * It might be better if the conf file could specify the type 226 * of module. That way, a single module could support multiple 227 * type of hooks. This could be done by using something like: 228 * 229 * moduleload extension /usr/local/openldap/whatever.so 230 * 231 * then we'd search through module_regtable for a matching 232 * module type, and hook in there. 233 */ 234 rc = initialize(argc, argv); 235 if (rc == -1) { 236 Debug(LDAP_DEBUG_CONFIG, "module %s: init_module() failed\n", 237 file_name ); 238 239 lt_dlclose(module->lib); 240 ch_free(module); 241 return rc; 242 } 243 244 if (rc >= (int)(sizeof(module_regtable) / sizeof(struct module_regtable_t)) 245 || module_regtable[rc].proc == NULL) 246 { 247 Debug(LDAP_DEBUG_CONFIG, "module %s: unknown registration type (%d)\n", 248 file_name, rc ); 249 250 module_int_unload(module); 251 return -1; 252 } 253 254 rc = (module_regtable[rc].proc)(module, file_name); 255 if (rc != 0) { 256 Debug(LDAP_DEBUG_CONFIG, "module %s: %s module could not be registered\n", 257 file_name, module_regtable[rc].type ); 258 259 module_int_unload(module); 260 return rc; 261 } 262 263 module->next = module_list; 264 module_list = module; 265 266 Debug(LDAP_DEBUG_CONFIG, "module %s: %s module registered\n", 267 file_name, module_regtable[rc].type ); 268 269 return 0; 270} 271 272int module_path(const char *path) 273{ 274#ifdef HAVE_EBCDIC 275 strcpy(ebuf, path); 276 __atoe(ebuf); 277 path = ebuf; 278#endif 279 return lt_dlsetsearchpath( path ); 280} 281 282void *module_resolve (const void *module, const char *name) 283{ 284#ifdef HAVE_EBCDIC 285 strcpy(ebuf, name); 286 __atoe(ebuf); 287 name = ebuf; 288#endif 289 if (module == NULL || name == NULL) 290 return(NULL); 291 return(lt_dlsym(((module_loaded_t *)module)->lib, name)); 292} 293 294static int module_int_unload (module_loaded_t *module) 295{ 296 module_loaded_t *mod; 297 MODULE_TERM_FN terminate; 298 299 if (module != NULL) { 300 /* remove module from tracking list */ 301 if (module_list == module) { 302 module_list = module->next; 303 } else { 304 for (mod = module_list; mod; mod = mod->next) { 305 if (mod->next == module) { 306 mod->next = module->next; 307 break; 308 } 309 } 310 } 311 312 /* call module's terminate routine, if present */ 313#ifdef HAVE_EBCDIC 314#pragma convlit(suspend) 315#endif 316 if ((terminate = lt_dlsym(module->lib, "term_module"))) { 317#ifdef HAVE_EBCDIC 318#pragma convlit(resume) 319#endif 320 terminate(); 321 } 322 323 /* close the library and free the memory */ 324 lt_dlclose(module->lib); 325 ch_free(module); 326 } 327 return 0; 328} 329 330int load_null_module (const void *module, const char *file_name) 331{ 332 return 0; 333} 334 335#ifdef SLAPD_EXTERNAL_EXTENSIONS 336int 337load_extop_module ( 338 const void *module, 339 const char *file_name 340) 341{ 342 SLAP_EXTOP_MAIN_FN *ext_main; 343 SLAP_EXTOP_GETOID_FN *ext_getoid; 344 struct berval oid; 345 int rc; 346 347 ext_main = (SLAP_EXTOP_MAIN_FN *)module_resolve(module, "ext_main"); 348 if (ext_main == NULL) { 349 return(-1); 350 } 351 352 ext_getoid = module_resolve(module, "ext_getoid"); 353 if (ext_getoid == NULL) { 354 return(-1); 355 } 356 357 rc = (ext_getoid)(0, &oid, 256); 358 if (rc != 0) { 359 return(rc); 360 } 361 if (oid.bv_val == NULL || oid.bv_len == 0) { 362 return(-1); 363 } 364 365 /* FIXME: this is broken, and no longer needed, 366 * as a module can call load_extop() itself... */ 367 rc = load_extop( &oid, ext_main ); 368 return rc; 369} 370#endif /* SLAPD_EXTERNAL_EXTENSIONS */ 371#endif /* SLAPD_MODULES */ 372 373