]> git.sur5r.net Git - openldap/blob - servers/slapd/module.c
Update copyright for next release
[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 = 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