]> git.sur5r.net Git - openldap/blob - servers/slapd/module.c
Use "uri" directive (instead of "server") to specify server. Add "bin
[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                 Debug(LDAP_DEBUG_ANY, "lt_dlinit failed: %s\n", error, 0, 0);
44                 return -1;
45         }
46         return 0;
47 }
48
49 int module_kill (void)
50 {
51         /* unload all modules before shutdown */
52         while (module_list != NULL) {
53                 module_unload(module_list);
54         }
55
56         if (lt_dlexit()) {
57                 const char *error = lt_dlerror();
58                 Debug(LDAP_DEBUG_ANY, "lt_dlexit failed: %s\n", error, 0, 0);
59                 return -1;
60         }
61         return 0;
62 }
63
64 int module_load(const char* file_name, int argc, char *argv[])
65 {
66         module_loaded_t *module = NULL;
67         const char *error;
68         int rc;
69         MODULE_INIT_FN initialize;
70
71         module = (module_loaded_t *)ch_calloc(1, sizeof(module_loaded_t));
72         if (module == NULL) {
73                 Debug(LDAP_DEBUG_ANY, "module_load failed: (%s) out of memory\n", file_name,
74                         0, 0);
75                 return -1;
76         }
77
78         /*
79          * The result of lt_dlerror(), when called, must be cached prior
80          * to calling Debug. This is because Debug is a macro that expands
81          * into multiple function calls.
82          */
83         if ((module->lib = lt_dlopen(file_name)) == NULL) {
84                 error = lt_dlerror();
85                 Debug(LDAP_DEBUG_ANY, "lt_dlopen failed: (%s) %s\n", file_name,
86                         error, 0);
87                 ch_free(module);
88                 return -1;
89         }
90
91         Debug(LDAP_DEBUG_CONFIG, "loaded module %s\n", file_name, 0, 0);
92    
93         if ((initialize = lt_dlsym(module->lib, "init_module")) == NULL) {
94                 Debug(LDAP_DEBUG_CONFIG, "module %s: no init_module() function found\n",
95                         file_name, 0, 0);
96                 lt_dlclose(module->lib);
97                 ch_free(module);
98                 return -1;
99         }
100
101         /* The imported init_module() routine passes back the type of
102          * module (i.e., which part of slapd it should be hooked into)
103          * or -1 for error.  If it passes back 0, then you get the 
104          * old behavior (i.e., the library is loaded and not hooked
105          * into anything).
106          *
107          * It might be better if the conf file could specify the type
108          * of module.  That way, a single module could support multiple
109          * type of hooks. This could be done by using something like:
110          *
111          *    moduleload extension /usr/local/openldap/whatever.so
112          *
113          * then we'd search through module_regtable for a matching
114          * module type, and hook in there.
115          */
116         rc = initialize(argc, argv);
117         if (rc == -1) {
118                 Debug(LDAP_DEBUG_CONFIG, "module %s: init_module() failed\n",
119                         file_name, 0, 0);
120                 lt_dlclose(module->lib);
121                 ch_free(module);
122                 return rc;
123         }
124
125         if (rc >= (sizeof(module_regtable) / sizeof(struct module_regtable_t))
126                 || module_regtable[rc].proc == NULL)
127         {
128                 Debug(LDAP_DEBUG_CONFIG, "module %s: unknown registration type (%d)\n",
129                         file_name, rc, 0);
130                 module_unload(module);
131                 return -1;
132         }
133
134         rc = (module_regtable[rc].proc)(module, file_name);
135         if (rc != 0) {
136                 Debug(LDAP_DEBUG_CONFIG, "module %s: %s module could not be registered\n",
137                         file_name, module_regtable[rc].type, 0);
138                 module_unload(module);
139                 return rc;
140         }
141
142         module->next = module_list;
143         module_list = module;
144
145         Debug(LDAP_DEBUG_CONFIG, "module %s: %s module registered\n",
146                 file_name, module_regtable[rc].type, 0);
147         return 0;
148 }
149
150 int module_path(const char *path)
151 {
152         return lt_dlsetsearchpath( path );
153 }
154
155 void *module_resolve (const void *module, const char *name)
156 {
157         if (module == NULL || name == NULL)
158                 return(NULL);
159         return(lt_dlsym(((module_loaded_t *)module)->lib, name));
160 }
161
162 static int module_unload (module_loaded_t *module)
163 {
164         module_loaded_t *mod;
165         MODULE_TERM_FN terminate;
166
167         if (module != NULL) {
168                 /* remove module from tracking list */
169                 if (module_list == module) {
170                         module_list = module->next;
171                 } else {
172                         for (mod = module_list; mod; mod = mod->next) {
173                                 if (mod->next == module) {
174                                         mod->next = module->next;
175                                         break;
176                                 }
177                         }
178                 }
179
180                 /* call module's terminate routine, if present */
181                 if (terminate = lt_dlsym(module->lib, "term_module")) {
182                         terminate();
183                 }
184
185                 /* close the library and free the memory */
186                 lt_dlclose(module->lib);
187                 ch_free(module);
188         }
189         return 0;
190 }
191
192 int load_null_module (const void *module, const char *file_name)
193 {
194         return 0;
195 }
196
197 #ifdef SLAPD_EXTERNAL_EXTENSIONS
198 int
199 load_extop_module (
200         const void *module,
201         const char *file_name
202 )
203 {
204         SLAP_EXTOP_MAIN_FN ext_main;
205         int (*ext_getoid)(int index, char *oid, int blen);
206         char *oid;
207         int rc;
208
209         ext_main = (SLAP_EXTOP_MAIN_FN)module_resolve(module, "ext_main");
210         if (ext_main == NULL) {
211                 return(-1);
212         }
213
214         ext_getoid = module_resolve(module, "ext_getoid");
215         if (ext_getoid == NULL) {
216                 return(-1);
217         }
218
219         oid = ch_malloc(256);
220         rc = (ext_getoid)(0, oid, 256);
221         if (rc != 0) {
222                 ch_free(oid);
223                 return(rc);
224         }
225         if (*oid == 0) {
226                 free(oid);
227                 return(-1);
228         }
229
230         rc = load_extop( oid, ext_main );
231         free(oid);
232         return rc;
233 }
234 #endif /* SLAPD_EXTERNAL_EXTENSIONS */
235 #endif /* SLAPD_MODULES */
236