]> git.sur5r.net Git - openldap/blob - servers/slapd/module.c
a09da6a8b6dd530ad28515b9326384a5f1dfe991
[openldap] / servers / slapd / module.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2009 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;
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_handle( file_name );
133         if ( module ) {
134                 Debug( LDAP_DEBUG_ANY, "module_load: (%s) already loaded\n",
135                         file_name, 0, 0 );
136                 return -1;
137         }
138
139         module = (module_loaded_t *)ch_calloc(1, sizeof(module_loaded_t) +
140                 strlen(file_name));
141         if (module == NULL) {
142                 Debug(LDAP_DEBUG_ANY, "module_load failed: (%s) out of memory\n", file_name,
143                         0, 0);
144
145                 return -1;
146         }
147         strcpy( module->name, file_name );
148
149 #ifdef HAVE_EBCDIC
150         strcpy( file, file_name );
151         __atoe( file );
152 #endif
153         /*
154          * The result of lt_dlerror(), when called, must be cached prior
155          * to calling Debug. This is because Debug is a macro that expands
156          * into multiple function calls.
157          */
158         if ((module->lib = lt_dlopenext(file)) == NULL) {
159                 error = lt_dlerror();
160 #ifdef HAVE_EBCDIC
161                 strcpy( ebuf, error );
162                 __etoa( ebuf );
163                 error = ebuf;
164 #endif
165                 Debug(LDAP_DEBUG_ANY, "lt_dlopenext failed: (%s) %s\n", file_name,
166                         error, 0);
167
168                 ch_free(module);
169                 return -1;
170         }
171
172         Debug(LDAP_DEBUG_CONFIG, "loaded module %s\n", file_name, 0, 0);
173
174    
175 #ifdef HAVE_EBCDIC
176 #pragma convlit(suspend)
177 #endif
178         if ((initialize = lt_dlsym(module->lib, "init_module")) == NULL) {
179 #ifdef HAVE_EBCDIC
180 #pragma convlit(resume)
181 #endif
182                 Debug(LDAP_DEBUG_CONFIG, "module %s: no init_module() function found\n",
183                         file_name, 0, 0);
184
185                 lt_dlclose(module->lib);
186                 ch_free(module);
187                 return -1;
188         }
189
190         /* The imported init_module() routine passes back the type of
191          * module (i.e., which part of slapd it should be hooked into)
192          * or -1 for error.  If it passes back 0, then you get the 
193          * old behavior (i.e., the library is loaded and not hooked
194          * into anything).
195          *
196          * It might be better if the conf file could specify the type
197          * of module.  That way, a single module could support multiple
198          * type of hooks. This could be done by using something like:
199          *
200          *    moduleload extension /usr/local/openldap/whatever.so
201          *
202          * then we'd search through module_regtable for a matching
203          * module type, and hook in there.
204          */
205         rc = initialize(argc, argv);
206         if (rc == -1) {
207                 Debug(LDAP_DEBUG_CONFIG, "module %s: init_module() failed\n",
208                         file_name, 0, 0);
209
210                 lt_dlclose(module->lib);
211                 ch_free(module);
212                 return rc;
213         }
214
215         if (rc >= (int)(sizeof(module_regtable) / sizeof(struct module_regtable_t))
216                 || module_regtable[rc].proc == NULL)
217         {
218                 Debug(LDAP_DEBUG_CONFIG, "module %s: unknown registration type (%d)\n",
219                         file_name, rc, 0);
220
221                 module_int_unload(module);
222                 return -1;
223         }
224
225         rc = (module_regtable[rc].proc)(module, file_name);
226         if (rc != 0) {
227                 Debug(LDAP_DEBUG_CONFIG, "module %s: %s module could not be registered\n",
228                         file_name, module_regtable[rc].type, 0);
229
230                 module_int_unload(module);
231                 return rc;
232         }
233
234         module->next = module_list;
235         module_list = module;
236
237         Debug(LDAP_DEBUG_CONFIG, "module %s: %s module registered\n",
238                 file_name, module_regtable[rc].type, 0);
239
240         return 0;
241 }
242
243 int module_path(const char *path)
244 {
245 #ifdef HAVE_EBCDIC
246         strcpy(ebuf, path);
247         __atoe(ebuf);
248         path = ebuf;
249 #endif
250         return lt_dlsetsearchpath( path );
251 }
252
253 void *module_resolve (const void *module, const char *name)
254 {
255 #ifdef HAVE_EBCDIC
256         strcpy(ebuf, name);
257         __atoe(ebuf);
258         name = ebuf;
259 #endif
260         if (module == NULL || name == NULL)
261                 return(NULL);
262         return(lt_dlsym(((module_loaded_t *)module)->lib, name));
263 }
264
265 static int module_int_unload (module_loaded_t *module)
266 {
267         module_loaded_t *mod;
268         MODULE_TERM_FN terminate;
269
270         if (module != NULL) {
271                 /* remove module from tracking list */
272                 if (module_list == module) {
273                         module_list = module->next;
274                 } else {
275                         for (mod = module_list; mod; mod = mod->next) {
276                                 if (mod->next == module) {
277                                         mod->next = module->next;
278                                         break;
279                                 }
280                         }
281                 }
282
283                 /* call module's terminate routine, if present */
284 #ifdef HAVE_EBCDIC
285 #pragma convlit(suspend)
286 #endif
287                 if ((terminate = lt_dlsym(module->lib, "term_module"))) {
288 #ifdef HAVE_EBCDIC
289 #pragma convlit(resume)
290 #endif
291                         terminate();
292                 }
293
294                 /* close the library and free the memory */
295                 lt_dlclose(module->lib);
296                 ch_free(module);
297         }
298         return 0;
299 }
300
301 int load_null_module (const void *module, const char *file_name)
302 {
303         return 0;
304 }
305
306 #ifdef SLAPD_EXTERNAL_EXTENSIONS
307 int
308 load_extop_module (
309         const void *module,
310         const char *file_name
311 )
312 {
313         SLAP_EXTOP_MAIN_FN *ext_main;
314         SLAP_EXTOP_GETOID_FN *ext_getoid;
315         struct berval oid;
316         int rc;
317
318         ext_main = (SLAP_EXTOP_MAIN_FN *)module_resolve(module, "ext_main");
319         if (ext_main == NULL) {
320                 return(-1);
321         }
322
323         ext_getoid = module_resolve(module, "ext_getoid");
324         if (ext_getoid == NULL) {
325                 return(-1);
326         }
327
328         rc = (ext_getoid)(0, &oid, 256);
329         if (rc != 0) {
330                 return(rc);
331         }
332         if (oid.bv_val == NULL || oid.bv_len == 0) {
333                 return(-1);
334         }
335
336         /* FIXME: this is broken, and no longer needed, 
337          * as a module can call load_extop() itself... */
338         rc = load_extop( &oid, ext_main );
339         return rc;
340 }
341 #endif /* SLAPD_EXTERNAL_EXTENSIONS */
342 #endif /* SLAPD_MODULES */
343