pyldb: avoid segfault when adding an element with no name
[sfrench/samba-autobuild/.git] / lib / util / modules.c
1 /*
2    Unix SMB/CIFS implementation.
3    Samba utility functions
4    Copyright (C) Jelmer Vernooij 2002-2003,2005-2007
5    Copyright (C) Stefan (metze) Metzmacher 2003
6    Copyright (C) Andrew Bartlett 2011
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "dynconfig/dynconfig.h"
24 #include "lib/util/samba_modules.h"
25 #include "lib/util/util_paths.h"
26 #include "system/filesys.h"
27 #include "system/dir.h"
28
29 /**
30  * Obtain the init function from a shared library file
31  */
32 init_module_fn load_module(const char *path, bool is_probe, void **handle_out)
33 {
34         void *handle;
35         void *init_fn;
36         char *error;
37
38         /* This should be a WAF build, where modules should be built
39          * with no undefined symbols and are already linked against
40          * the libraries that they are loaded by */
41         handle = dlopen(path, RTLD_NOW);
42
43         /* This call should reset any possible non-fatal errors that
44            occurred since last call to dl* functions */
45         error = dlerror();
46
47         if (handle == NULL) {
48                 int level = is_probe ? 5 : 0;
49                 DEBUG(level, ("Error loading module '%s': %s\n", path, error ? error : ""));
50                 return NULL;
51         }
52
53         init_fn = (init_module_fn)dlsym(handle, SAMBA_INIT_MODULE);
54
55         /* we could check dlerror() to determine if it worked, because
56            dlsym() can validly return NULL, but what would we do with
57            a NULL pointer as a module init function? */
58
59         if (init_fn == NULL) {
60                 DEBUG(0, ("Unable to find %s() in %s: %s\n",
61                           SAMBA_INIT_MODULE, path, dlerror()));
62                 DEBUG(1, ("Loading module '%s' failed\n", path));
63                 dlclose(handle);
64                 return NULL;
65         }
66
67         if (handle_out) {
68                 *handle_out = handle;
69         }
70
71         return (init_module_fn)init_fn;
72 }
73
74 /**
75  * Obtain list of init functions from the modules in the specified
76  * directory
77  */
78 static init_module_fn *load_modules(TALLOC_CTX *mem_ctx, const char *path)
79 {
80         DIR *dir;
81         struct dirent *entry;
82         char *filename;
83         int success = 0;
84         init_module_fn *ret = talloc_array(mem_ctx, init_module_fn, 2);
85
86         ret[0] = NULL;
87
88         dir = opendir(path);
89         if (dir == NULL) {
90                 talloc_free(ret);
91                 return NULL;
92         }
93
94         while((entry = readdir(dir))) {
95                 if (ISDOT(entry->d_name) || ISDOTDOT(entry->d_name))
96                         continue;
97
98                 filename = talloc_asprintf(mem_ctx, "%s/%s", path, entry->d_name);
99
100                 ret[success] = load_module(filename, true, NULL);
101                 if (ret[success]) {
102                         ret = talloc_realloc(mem_ctx, ret, init_module_fn, success+2);
103                         success++;
104                         ret[success] = NULL;
105                 }
106
107                 talloc_free(filename);
108         }
109
110         closedir(dir);
111
112         return ret;
113 }
114
115 /**
116  * Run the specified init functions.
117  *
118  * @return true if all functions ran successfully, false otherwise
119  */
120 bool run_init_functions(TALLOC_CTX *ctx, init_module_fn *fns)
121 {
122         int i;
123         bool ret = true;
124
125         if (fns == NULL)
126                 return true;
127
128         for (i = 0; fns[i]; i++) { ret &= (bool)NT_STATUS_IS_OK(fns[i](ctx)); }
129
130         return ret;
131 }
132
133 /**
134  * Load the initialization functions from DSO files for a specific subsystem.
135  *
136  * Will return an array of function pointers to initialization functions
137  */
138
139 init_module_fn *load_samba_modules(TALLOC_CTX *mem_ctx, const char *subsystem)
140 {
141         char *path = modules_path(mem_ctx, subsystem);
142         init_module_fn *ret;
143
144         ret = load_modules(mem_ctx, path);
145
146         talloc_free(path);
147
148         return ret;
149 }
150
151 static NTSTATUS load_module_absolute_path(const char *module_path,
152                                           bool is_probe)
153 {
154         void *handle;
155         init_module_fn init;
156         NTSTATUS status;
157
158         DBG_INFO("%s module '%s'\n",
159                  is_probe ? "Probing" : "Loading",
160                  module_path);
161
162         init = load_module(module_path, is_probe, &handle);
163         if (init == NULL) {
164                 return NT_STATUS_UNSUCCESSFUL;
165         }
166
167         DBG_NOTICE("Module '%s' loaded\n", module_path);
168
169         status = init(NULL);
170         if (!NT_STATUS_IS_OK(status)) {
171                 DBG_ERR("Module '%s' initialization failed: %s\n",
172                         module_path,
173                         get_friendly_nt_error_msg(status));
174                 dlclose(handle);
175                 return status;
176         }
177
178         return NT_STATUS_OK;
179 }
180
181 /* Load all modules in list and return number of
182  * modules that has been successfully loaded */
183 int smb_load_all_modules_absoute_path(const char **modules)
184 {
185         int i;
186         int success = 0;
187
188         for(i = 0; modules[i] != NULL; i++) {
189                 const char *module = modules[i];
190                 NTSTATUS status;
191
192                 if (module[0] != '/') {
193                         continue;
194                 }
195
196                 status = load_module_absolute_path(module, false);
197                 if (NT_STATUS_IS_OK(status)) {
198                         success++;
199                 }
200         }
201
202         DEBUG(2, ("%d modules successfully loaded\n", success));
203
204         return success;
205 }
206
207 /**
208  * @brief Check if a module exist and load it.
209  *
210  * @param[in]  subsystem  The name of the subsystem the module belongs too.
211  *
212  * @param[in]  module     The name of the module
213  *
214  * @return  A NTSTATUS code
215  */
216 NTSTATUS smb_probe_module(const char *subsystem, const char *module)
217 {
218         NTSTATUS status;
219         char *module_path = NULL;
220         TALLOC_CTX *tmp_ctx = talloc_stackframe();
221
222         if (subsystem == NULL) {
223                 status = NT_STATUS_INVALID_PARAMETER;
224                 goto done;
225         }
226         if (module == NULL) {
227                 status = NT_STATUS_INVALID_PARAMETER;
228                 goto done;
229         }
230
231         if (strchr(module, '/')) {
232                 status = NT_STATUS_INVALID_PARAMETER;
233                 goto done;
234         }
235
236         module_path = talloc_asprintf(tmp_ctx,
237                                       "%s/%s.%s",
238                                       modules_path(tmp_ctx, subsystem),
239                                       module,
240                                       shlib_ext());
241         if (module_path == NULL) {
242                 status = NT_STATUS_NO_MEMORY;
243                 goto done;
244         }
245
246         status = load_module_absolute_path(module_path, true);
247
248 done:
249         TALLOC_FREE(tmp_ctx);
250         return status;
251 }
252
253 /**
254  * @brief Check if a module exist and load it.
255  *
256  * Warning: Using this function can have security implecations!
257  *
258  * @param[in]  subsystem  The name of the subsystem the module belongs too.
259  *
260  * @param[in]  module     Load a module using an abolute path.
261  *
262  * @return  A NTSTATUS code
263  */
264 NTSTATUS smb_probe_module_absolute_path(const char *module)
265 {
266         if (module == NULL) {
267                 return NT_STATUS_INVALID_PARAMETER;
268         }
269         if (module[0] != '/') {
270                 return NT_STATUS_INVALID_PARAMETER;
271         }
272
273         return load_module_absolute_path(module, true);
274 }
275
276 /**
277  * @brief Load a module.
278  *
279  * @param[in]  subsystem  The name of the subsystem the module belongs too.
280  *
281  * @param[in]  module     Check if a module exists and load it.
282  *
283  * @return  A NTSTATUS code
284  */
285 NTSTATUS smb_load_module(const char *subsystem, const char *module)
286 {
287         NTSTATUS status;
288         char *module_path = NULL;
289         TALLOC_CTX *tmp_ctx = talloc_stackframe();
290
291         if (subsystem == NULL) {
292                 status = NT_STATUS_INVALID_PARAMETER;
293                 goto done;
294         }
295         if (module == NULL) {
296                 status = NT_STATUS_INVALID_PARAMETER;
297                 goto done;
298         }
299
300         if (strchr(module, '/')) {
301                 status = NT_STATUS_INVALID_PARAMETER;
302                 goto done;
303         }
304
305         module_path = talloc_asprintf(tmp_ctx,
306                                       "%s/%s.%s",
307                                       modules_path(tmp_ctx, subsystem),
308                                       module,
309                                       shlib_ext());
310         if (module_path == NULL) {
311                 status = NT_STATUS_NO_MEMORY;
312                 goto done;
313         }
314
315         status = load_module_absolute_path(module_path, false);
316
317 done:
318         TALLOC_FREE(tmp_ctx);
319         return status;
320 }