xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/module.c (revision 3816d47b2c42fcd6e549e3407f842a5b1a1d23ad)
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