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