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