]> git.sur5r.net Git - openldap/blob - servers/slapd/module.c
Suck in HEAD changes since 2.1alpha
[openldap] / servers / slapd / module.c
1 /* $OpenLDAP$ */
2 #include "portable.h"
3 #include <stdio.h>
4 #include "slap.h"
5
6 #ifdef SLAPD_MODULES
7
8 #include <ltdl.h>
9
10 typedef int (*MODULE_INIT_FN)(
11         int argc,
12         char *argv[]);
13 typedef int (*MODULE_LOAD_FN)(
14         const void *module,
15         const char *filename);
16 typedef int (*MODULE_TERM_FN)(void);
17
18
19 struct module_regtable_t {
20         char *type;
21         MODULE_LOAD_FN proc;
22 } module_regtable[] = {
23                 { "null", load_null_module },
24 #ifdef SLAPD_EXTERNAL_EXTENSIONS
25                 { "extension", load_extop_module },
26 #endif
27                 { NULL, NULL }
28 };
29
30 typedef struct module_loaded_t {
31         struct module_loaded_t *next;
32         lt_dlhandle lib;
33 } module_loaded_t;
34
35 module_loaded_t *module_list = NULL;
36
37 static int module_unload (module_loaded_t *module);
38
39 int module_init (void)
40 {
41         if (lt_dlinit()) {
42                 const char *error = lt_dlerror();
43 #ifdef NEW_LOGGING
44                 LDAP_LOG(( "module", LDAP_LEVEL_CRIT,
45                            "module_init: lt_ldinit failed: %s\n", error ));
46 #else
47                 Debug(LDAP_DEBUG_ANY, "lt_dlinit failed: %s\n", error, 0, 0);
48 #endif
49
50                 return -1;
51         }
52         return 0;
53 }
54
55 int module_kill (void)
56 {
57         /* unload all modules before shutdown */
58         while (module_list != NULL) {
59                 module_unload(module_list);
60         }
61
62         if (lt_dlexit()) {
63                 const char *error = lt_dlerror();
64 #ifdef NEW_LOGGING
65                 LDAP_LOG(( "module", LDAP_LEVEL_CRIT,
66                            "module_kill: lt_dlexit failed: %s\n", error ));
67 #else
68                 Debug(LDAP_DEBUG_ANY, "lt_dlexit failed: %s\n", error, 0, 0);
69 #endif
70
71                 return -1;
72         }
73         return 0;
74 }
75
76 int module_load(const char* file_name, int argc, char *argv[])
77 {
78         module_loaded_t *module = NULL;
79         const char *error;
80         int rc;
81         MODULE_INIT_FN initialize;
82
83         module = (module_loaded_t *)ch_calloc(1, sizeof(module_loaded_t));
84         if (module == NULL) {
85 #ifdef NEW_LOGGING
86                 LDAP_LOG(( "module", LDAP_LEVEL_CRIT,
87                            "module_load:  (%s) out of memory.\n", file_name ));
88 #else
89                 Debug(LDAP_DEBUG_ANY, "module_load failed: (%s) out of memory\n", file_name,
90                         0, 0);
91 #endif
92
93                 return -1;
94         }
95
96         /*
97          * The result of lt_dlerror(), when called, must be cached prior
98          * to calling Debug. This is because Debug is a macro that expands
99          * into multiple function calls.
100          */
101         if ((module->lib = lt_dlopen(file_name)) == NULL) {
102                 error = lt_dlerror();
103 #ifdef NEW_LOGGING
104                 LDAP_LOG(( "module", LDAP_LEVEL_CRIT,
105                            "module_load: lt_dlopen failed: (%s) %s.\n",
106                            file_name, error ));
107 #else
108                 Debug(LDAP_DEBUG_ANY, "lt_dlopen failed: (%s) %s\n", file_name,
109                         error, 0);
110 #endif
111
112                 ch_free(module);
113                 return -1;
114         }
115
116 #ifdef NEW_LOGGING
117         LDAP_LOG(( "module", LDAP_LEVEL_INFO,
118                    "module_load: loaded module %s\n", file_name ));
119 #else
120         Debug(LDAP_DEBUG_CONFIG, "loaded module %s\n", file_name, 0, 0);
121 #endif
122
123    
124         if ((initialize = lt_dlsym(module->lib, "init_module")) == NULL) {
125 #ifdef NEW_LOGGING
126                 LDAP_LOG(( "module", LDAP_LEVEL_ERR,
127                            "module_load: module %s : no init_module() function found\n",
128                            file_name ));
129 #else
130                 Debug(LDAP_DEBUG_CONFIG, "module %s: no init_module() function found\n",
131                         file_name, 0, 0);
132 #endif
133
134                 lt_dlclose(module->lib);
135                 ch_free(module);
136                 return -1;
137         }
138
139         /* The imported init_module() routine passes back the type of
140          * module (i.e., which part of slapd it should be hooked into)
141          * or -1 for error.  If it passes back 0, then you get the 
142          * old behavior (i.e., the library is loaded and not hooked
143          * into anything).
144          *
145          * It might be better if the conf file could specify the type
146          * of module.  That way, a single module could support multiple
147          * type of hooks. This could be done by using something like:
148          *
149          *    moduleload extension /usr/local/openldap/whatever.so
150          *
151          * then we'd search through module_regtable for a matching
152          * module type, and hook in there.
153          */
154         rc = initialize(argc, argv);
155         if (rc == -1) {
156 #ifdef NEW_LOGGING
157                 LDAP_LOG(( "module", LDAP_LEVEL_ERR,
158                            "module_load:  module %s init_module() failed\n", file_name));
159 #else
160                 Debug(LDAP_DEBUG_CONFIG, "module %s: init_module() failed\n",
161                         file_name, 0, 0);
162 #endif
163
164                 lt_dlclose(module->lib);
165                 ch_free(module);
166                 return rc;
167         }
168
169         if (rc >= (int)(sizeof(module_regtable) / sizeof(struct module_regtable_t))
170                 || module_regtable[rc].proc == NULL)
171         {
172 #ifdef NEW_LOGGING
173                 LDAP_LOG(( "module", LDAP_LEVEL_ERR,
174                            "module_load: module %s: unknown registration type (%d).\n", file_name));
175 #else
176                 Debug(LDAP_DEBUG_CONFIG, "module %s: unknown registration type (%d)\n",
177                         file_name, rc, 0);
178 #endif
179
180                 module_unload(module);
181                 return -1;
182         }
183
184         rc = (module_regtable[rc].proc)(module, file_name);
185         if (rc != 0) {
186 #ifdef NEW_LOGGING
187                 LDAP_LOG(( "module", LDAP_LEVEL_ERR,
188                            "module_load: module %s:%s could not be registered.\n",
189                            file_name, module_regtable[rc].type ));
190 #else
191                 Debug(LDAP_DEBUG_CONFIG, "module %s: %s module could not be registered\n",
192                         file_name, module_regtable[rc].type, 0);
193 #endif
194
195                 module_unload(module);
196                 return rc;
197         }
198
199         module->next = module_list;
200         module_list = module;
201
202 #ifdef NEW_LOGGING
203         LDAP_LOG(( "module", LDAP_LEVEL_INFO,
204                    "module_load: module %s:%s registered\n", file_name,
205                    module_regtable[rc].type ));
206 #else
207         Debug(LDAP_DEBUG_CONFIG, "module %s: %s module registered\n",
208                 file_name, module_regtable[rc].type, 0);
209 #endif
210
211         return 0;
212 }
213
214 int module_path(const char *path)
215 {
216         return lt_dlsetsearchpath( path );
217 }
218
219 void *module_resolve (const void *module, const char *name)
220 {
221         if (module == NULL || name == NULL)
222                 return(NULL);
223         return(lt_dlsym(((module_loaded_t *)module)->lib, name));
224 }
225
226 static int module_unload (module_loaded_t *module)
227 {
228         module_loaded_t *mod;
229         MODULE_TERM_FN terminate;
230
231         if (module != NULL) {
232                 /* remove module from tracking list */
233                 if (module_list == module) {
234                         module_list = module->next;
235                 } else {
236                         for (mod = module_list; mod; mod = mod->next) {
237                                 if (mod->next == module) {
238                                         mod->next = module->next;
239                                         break;
240                                 }
241                         }
242                 }
243
244                 /* call module's terminate routine, if present */
245                 if (terminate = lt_dlsym(module->lib, "term_module")) {
246                         terminate();
247                 }
248
249                 /* close the library and free the memory */
250                 lt_dlclose(module->lib);
251                 ch_free(module);
252         }
253         return 0;
254 }
255
256 int load_null_module (const void *module, const char *file_name)
257 {
258         return 0;
259 }
260
261 #ifdef SLAPD_EXTERNAL_EXTENSIONS
262 int
263 load_extop_module (
264         const void *module,
265         const char *file_name
266 )
267 {
268         SLAP_EXTOP_MAIN_FN *ext_main;
269         int (*ext_getoid)(int index, char *oid, int blen);
270         char *oid;
271         int rc;
272
273         ext_main = (SLAP_EXTOP_MAIN_FN *)module_resolve(module, "ext_main");
274         if (ext_main == NULL) {
275                 return(-1);
276         }
277
278         ext_getoid = module_resolve(module, "ext_getoid");
279         if (ext_getoid == NULL) {
280                 return(-1);
281         }
282
283         oid = ch_malloc(256);
284         rc = (ext_getoid)(0, oid, 256);
285         if (rc != 0) {
286                 ch_free(oid);
287                 return(rc);
288         }
289         if (*oid == 0) {
290                 free(oid);
291                 return(-1);
292         }
293
294         rc = load_extop( oid, ext_main );
295         free(oid);
296         return rc;
297 }
298 #endif /* SLAPD_EXTERNAL_EXTENSIONS */
299 #endif /* SLAPD_MODULES */
300