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