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 
26 typedef int (*MODULE_INIT_FN)(
27 	int argc,
28 	char *argv[]);
29 typedef int (*MODULE_LOAD_FN)(
30 	const void *module,
31 	const char *filename);
32 typedef int (*MODULE_TERM_FN)(void);
33 
34 
35 struct 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 
46 typedef struct module_loaded_t {
47 	struct module_loaded_t *next;
48 	lt_dlhandle lib;
49 	char name[1];
50 } module_loaded_t;
51 
52 module_loaded_t *module_list = NULL;
53 
54 static int module_int_unload (module_loaded_t *module);
55 
56 #ifdef HAVE_EBCDIC
57 static char ebuf[BUFSIZ];
58 #endif
59 
60 int 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 
77 int 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 
98 void * 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 
110 int 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 
122 int 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 
270 int 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 
280 void *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 
292 static 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 
328 int load_null_module (const void *module, const char *file_name)
329 {
330 	return 0;
331 }
332 
333 #ifdef SLAPD_EXTERNAL_EXTENSIONS
334 int
335 load_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