]> git.sur5r.net Git - openldap/blob - servers/slapd/module.c
Sync with HEAD
[openldap] / servers / slapd / module.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2003 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 } module_loaded_t;
48
49 module_loaded_t *module_list = NULL;
50
51 static int module_unload (module_loaded_t *module);
52
53 #ifdef HAVE_EBCDIC
54 static char ebuf[BUFSIZ];
55 #endif
56
57 int module_init (void)
58 {
59         if (lt_dlinit()) {
60                 const char *error = lt_dlerror();
61 #ifdef HAVE_EBCDIC
62                 strcpy( ebuf, error );
63                 __etoa( ebuf );
64                 error = ebuf;
65 #endif
66 #ifdef NEW_LOGGING
67                 LDAP_LOG( SLAPD, CRIT, 
68                         "module_init: lt_dlinit failed: %s\n", error, 0, 0 );
69 #else
70                 Debug(LDAP_DEBUG_ANY, "lt_dlinit failed: %s\n", error, 0, 0);
71 #endif
72
73                 return -1;
74         }
75         return 0;
76 }
77
78 int module_kill (void)
79 {
80         /* unload all modules before shutdown */
81         while (module_list != NULL) {
82                 module_unload(module_list);
83         }
84
85         if (lt_dlexit()) {
86                 const char *error = lt_dlerror();
87 #ifdef HAVE_EBCDIC
88                 strcpy( ebuf, error );
89                 __etoa( ebuf );
90                 error = ebuf;
91 #endif
92 #ifdef NEW_LOGGING
93                 LDAP_LOG( SLAPD, CRIT, "module_kill: lt_dlexit failed: %s\n", 
94                         error, 0, 0 );
95 #else
96                 Debug(LDAP_DEBUG_ANY, "lt_dlexit failed: %s\n", error, 0, 0);
97 #endif
98
99                 return -1;
100         }
101         return 0;
102 }
103
104 int module_load(const char* file_name, int argc, char *argv[])
105 {
106         module_loaded_t *module = NULL;
107         const char *error;
108         int rc;
109         MODULE_INIT_FN initialize;
110 #ifdef HAVE_EBCDIC
111 #define file    ebuf
112 #else
113 #define file    file_name
114 #endif
115
116         module = (module_loaded_t *)ch_calloc(1, sizeof(module_loaded_t));
117         if (module == NULL) {
118 #ifdef NEW_LOGGING
119                 LDAP_LOG( SLAPD, CRIT, 
120                         "module_load:  (%s) out of memory.\n", file_name, 0, 0 );
121 #else
122                 Debug(LDAP_DEBUG_ANY, "module_load failed: (%s) out of memory\n", file_name,
123                         0, 0);
124 #endif
125
126                 return -1;
127         }
128
129 #ifdef HAVE_EBCDIC
130         strcpy( file, file_name );
131         __atoe( file );
132 #endif
133         /*
134          * The result of lt_dlerror(), when called, must be cached prior
135          * to calling Debug. This is because Debug is a macro that expands
136          * into multiple function calls.
137          */
138         if ((module->lib = lt_dlopenext(file)) == NULL) {
139                 error = lt_dlerror();
140 #ifdef HAVE_EBCDIC
141                 strcpy( ebuf, error );
142                 __etoa( ebuf );
143                 error = ebuf;
144 #endif
145 #ifdef NEW_LOGGING
146                 LDAP_LOG( SLAPD, CRIT, 
147                         "module_load: lt_dlopenext failed: (%s) %s.\n", 
148                         file_name, error, 0 );
149 #else
150                 Debug(LDAP_DEBUG_ANY, "lt_dlopenext failed: (%s) %s\n", file_name,
151                         error, 0);
152 #endif
153
154                 ch_free(module);
155                 return -1;
156         }
157
158 #ifdef NEW_LOGGING
159         LDAP_LOG( SLAPD, INFO, "module_load: loaded module %s\n", file_name, 0, 0 );
160 #else
161         Debug(LDAP_DEBUG_CONFIG, "loaded module %s\n", file_name, 0, 0);
162 #endif
163
164    
165 #ifdef HAVE_EBCDIC
166 #pragma convlit(suspend)
167 #endif
168         if ((initialize = lt_dlsym(module->lib, "init_module")) == NULL) {
169 #ifdef HAVE_EBCDIC
170 #pragma convlit(resume)
171 #endif
172 #ifdef NEW_LOGGING
173                 LDAP_LOG( SLAPD, ERR, 
174                         "module_load: module %s : no init_module() function found\n",
175                     file_name, 0, 0 );
176 #else
177                 Debug(LDAP_DEBUG_CONFIG, "module %s: no init_module() function found\n",
178                         file_name, 0, 0);
179 #endif
180
181                 lt_dlclose(module->lib);
182                 ch_free(module);
183                 return -1;
184         }
185
186         /* The imported init_module() routine passes back the type of
187          * module (i.e., which part of slapd it should be hooked into)
188          * or -1 for error.  If it passes back 0, then you get the 
189          * old behavior (i.e., the library is loaded and not hooked
190          * into anything).
191          *
192          * It might be better if the conf file could specify the type
193          * of module.  That way, a single module could support multiple
194          * type of hooks. This could be done by using something like:
195          *
196          *    moduleload extension /usr/local/openldap/whatever.so
197          *
198          * then we'd search through module_regtable for a matching
199          * module type, and hook in there.
200          */
201         rc = initialize(argc, argv);
202         if (rc == -1) {
203 #ifdef NEW_LOGGING
204                 LDAP_LOG( SLAPD, ERR, 
205                         "module_load:  module %s init_module() failed\n", file_name, 0, 0);
206 #else
207                 Debug(LDAP_DEBUG_CONFIG, "module %s: init_module() failed\n",
208                         file_name, 0, 0);
209 #endif
210
211                 lt_dlclose(module->lib);
212                 ch_free(module);
213                 return rc;
214         }
215
216         if (rc >= (int)(sizeof(module_regtable) / sizeof(struct module_regtable_t))
217                 || module_regtable[rc].proc == NULL)
218         {
219 #ifdef NEW_LOGGING
220                 LDAP_LOG( SLAPD, ERR, 
221                         "module_load: module %s: unknown registration type (%d).\n", 
222                         file_name, rc, 0);
223 #else
224                 Debug(LDAP_DEBUG_CONFIG, "module %s: unknown registration type (%d)\n",
225                         file_name, rc, 0);
226 #endif
227
228                 module_unload(module);
229                 return -1;
230         }
231
232         rc = (module_regtable[rc].proc)(module, file_name);
233         if (rc != 0) {
234 #ifdef NEW_LOGGING
235                 LDAP_LOG( SLAPD, ERR, 
236                         "module_load: module %s:%s could not be registered.\n",
237                         file_name, module_regtable[rc].type, 0 );
238 #else
239                 Debug(LDAP_DEBUG_CONFIG, "module %s: %s module could not be registered\n",
240                         file_name, module_regtable[rc].type, 0);
241 #endif
242
243                 module_unload(module);
244                 return rc;
245         }
246
247         module->next = module_list;
248         module_list = module;
249
250 #ifdef NEW_LOGGING
251         LDAP_LOG( SLAPD, INFO, 
252                 "module_load: module %s:%s registered\n", file_name,
253                 module_regtable[rc].type, 0 );
254 #else
255         Debug(LDAP_DEBUG_CONFIG, "module %s: %s module registered\n",
256                 file_name, module_regtable[rc].type, 0);
257 #endif
258
259         return 0;
260 }
261
262 int module_path(const char *path)
263 {
264 #ifdef HAVE_EBCDIC
265         strcpy(ebuf, path);
266         __atoe(ebuf);
267         path = ebuf;
268 #endif
269         return lt_dlsetsearchpath( path );
270 }
271
272 void *module_resolve (const void *module, const char *name)
273 {
274 #ifdef HAVE_EBCDIC
275         strcpy(ebuf, name);
276         __atoe(ebuf);
277         name = ebuf;
278 #endif
279         if (module == NULL || name == NULL)
280                 return(NULL);
281         return(lt_dlsym(((module_loaded_t *)module)->lib, name));
282 }
283
284 static int module_unload (module_loaded_t *module)
285 {
286         module_loaded_t *mod;
287         MODULE_TERM_FN terminate;
288
289         if (module != NULL) {
290                 /* remove module from tracking list */
291                 if (module_list == module) {
292                         module_list = module->next;
293                 } else {
294                         for (mod = module_list; mod; mod = mod->next) {
295                                 if (mod->next == module) {
296                                         mod->next = module->next;
297                                         break;
298                                 }
299                         }
300                 }
301
302                 /* call module's terminate routine, if present */
303 #ifdef HAVE_EBCDIC
304 #pragma convlit(suspend)
305 #endif
306                 if ((terminate = lt_dlsym(module->lib, "term_module"))) {
307 #ifdef HAVE_EBCDIC
308 #pragma convlit(resume)
309 #endif
310                         terminate();
311                 }
312
313                 /* close the library and free the memory */
314                 lt_dlclose(module->lib);
315                 ch_free(module);
316         }
317         return 0;
318 }
319
320 int load_null_module (const void *module, const char *file_name)
321 {
322         return 0;
323 }
324
325 #ifdef SLAPD_EXTERNAL_EXTENSIONS
326 int
327 load_extop_module (
328         const void *module,
329         const char *file_name
330 )
331 {
332         SLAP_EXTOP_MAIN_FN *ext_main;
333         SLAP_EXTOP_GETOID_FN *ext_getoid;
334         struct berval oid;
335         int rc;
336
337         ext_main = (SLAP_EXTOP_MAIN_FN *)module_resolve(module, "ext_main");
338         if (ext_main == NULL) {
339                 return(-1);
340         }
341
342         ext_getoid = module_resolve(module, "ext_getoid");
343         if (ext_getoid == NULL) {
344                 return(-1);
345         }
346
347         rc = (ext_getoid)(0, &oid, 256);
348         if (rc != 0) {
349                 return(rc);
350         }
351         if (oid.bv_val == NULL || oid.bv_len == 0) {
352                 return(-1);
353         }
354
355         rc = load_extop( &oid, ext_main );
356         return rc;
357 }
358 #endif /* SLAPD_EXTERNAL_EXTENSIONS */
359 #endif /* SLAPD_MODULES */
360