1 /* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
2 
3 #include "lib.h"
4 #include "array.h"
5 #include "str.h"
6 #include "sort.h"
7 #include "module-dir.h"
8 
9 #ifdef HAVE_MODULES
10 
11 #include <unistd.h>
12 #include <fcntl.h>
13 #include <dirent.h>
14 #include <dlfcn.h>
15 
16 #ifndef RTLD_GLOBAL
17 #  define RTLD_GLOBAL 0
18 #endif
19 
20 #ifndef RTLD_NOW
21 #  define RTLD_NOW 0
22 #endif
23 
24 static const char *module_name_drop_suffix(const char *name);
25 
module_get_symbol_quiet(struct module * module,const char * symbol)26 void *module_get_symbol_quiet(struct module *module, const char *symbol)
27 {
28 	/* clear out old errors */
29 	(void)dlerror();
30 
31 	return dlsym(module->handle, symbol);
32 }
33 
module_get_symbol(struct module * module,const char * symbol)34 void *module_get_symbol(struct module *module, const char *symbol)
35 {
36 	const char *error;
37 	void *ret;
38 
39 	ret = module_get_symbol_quiet(module, symbol);
40 	if (ret == NULL) {
41 		error = dlerror();
42 		if (error != NULL) {
43 			i_error("module %s: dlsym(%s) failed: %s",
44 				module->path, symbol, error);
45 			ret = NULL;
46 		}
47 	}
48 	return ret;
49 }
50 
get_symbol(struct module * module,const char * symbol,bool quiet)51 static void *get_symbol(struct module *module, const char *symbol, bool quiet)
52 {
53 	if (quiet)
54 		return module_get_symbol_quiet(module, symbol);
55 
56 	return module_get_symbol(module, symbol);
57 }
58 
module_free(struct module * module)59 static void module_free(struct module *module)
60 {
61 	if (module->deinit != NULL && module->initialized)
62 		module->deinit();
63 	/* dlclose()ing removes all symbols from valgrind's visibility.
64 	   if GDB environment is set, don't actually unload the module
65 	   (the GDB environment is used elsewhere too) */
66 	if (getenv("GDB") == NULL) {
67 		if (dlclose(module->handle) != 0)
68 			i_error("dlclose(%s) failed: %m", module->path);
69 	}
70 	i_free(module->path);
71 	i_free(module->name);
72 	i_free(module);
73 }
74 
75 static bool
module_check_wrong_binary_dependency(const struct module_dir_load_settings * set,struct module * module,const char ** error_r)76 module_check_wrong_binary_dependency(const struct module_dir_load_settings *set,
77 				     struct module *module, const char **error_r)
78 {
79 	const char *symbol_name, *binary_dep, *const *names;
80 	string_t *errstr;
81 
82 	if (set->binary_name == NULL)
83 		return TRUE;
84 
85 	symbol_name = t_strconcat(module->name, "_binary_dependency", NULL);
86 	binary_dep = dlsym(module->handle, symbol_name);
87 	if (binary_dep == NULL)
88 		return TRUE;
89 
90 	names = t_strsplit(binary_dep, " ");
91 	if (str_array_find(names, set->binary_name))
92 		return TRUE;
93 
94 	errstr = t_str_new(128);
95 	str_printfa(errstr, "Can't load plugin %s: "
96 		    "Plugin is intended to be used only by ", module->name);
97 	if (names[1] == NULL)
98 		str_printfa(errstr, "%s binary", binary_dep);
99 	else
100 		str_printfa(errstr, "binaries: %s", binary_dep);
101 	str_printfa(errstr, " (we're %s)", set->binary_name);
102 	*error_r = str_c(errstr);
103 	return FALSE;
104 }
105 
106 static bool
module_check_missing_plugin_dependencies(const struct module_dir_load_settings * set,struct module * module,struct module * all_modules,const char ** error_r)107 module_check_missing_plugin_dependencies(const struct module_dir_load_settings *set,
108 					 struct module *module,
109 					 struct module *all_modules,
110 					 const char **error_r)
111 {
112 	const char **deps;
113 	struct module *m;
114 	string_t *errmsg;
115 	size_t len;
116 
117 	deps = dlsym(module->handle,
118 		     t_strconcat(module->name, "_dependencies", NULL));
119 	if (deps == NULL)
120 		return TRUE;
121 
122 	for (; *deps != NULL; deps++) {
123 		len = strlen(*deps);
124 		for (m = all_modules; m != NULL; m = m->next) {
125 			if (strncmp(m->name, *deps, len) == 0 &&
126 			    (m->name[len] == '\0' ||
127 			     strcmp(m->name+len, "_plugin") == 0))
128 				break;
129 		}
130 		if (m == NULL) {
131 			errmsg = t_str_new(128);
132 			str_printfa(errmsg, "Plugin %s must be loaded also",
133 				    *deps);
134 			if (set->setting_name != NULL) {
135 				str_printfa(errmsg,
136 					    " (you must set: %s=$%s %s)",
137 					    set->setting_name,
138 					    set->setting_name, *deps);
139 			}
140 			*error_r = str_c(errmsg);
141 			return FALSE;
142 		}
143 	}
144 	return TRUE;
145 }
146 
quiet_dlopen(const char * path,int flags)147 static void *quiet_dlopen(const char *path, int flags)
148 {
149 #ifndef __OpenBSD__
150 	return dlopen(path, flags);
151 #else
152 	void *handle;
153 	int fd;
154 
155 	/* OpenBSD likes to print all "undefined symbol" errors to stderr.
156 	   Hide them by sending them to /dev/null. */
157 	fd = dup(STDERR_FILENO);
158 	if (fd == -1)
159 		i_fatal("dup() failed: %m");
160 	if (dup2(dev_null_fd, STDERR_FILENO) < 0)
161 		i_fatal("dup2() failed: %m");
162 	handle = dlopen(path, flags);
163 	if (dup2(fd, STDERR_FILENO) < 0)
164 		i_fatal("dup2() failed: %m");
165 	if (close(fd) < 0)
166 		i_error("close() failed: %m");
167 	return handle;
168 #endif
169 }
170 
versions_equal(const char * str1,const char * str2)171 static bool versions_equal(const char *str1, const char *str2)
172 {
173 	while (*str1 == *str2) {
174 		if (*str1 == '\0' || *str1 == '(')
175 			return TRUE;
176 		str1++;
177 		str2++;
178 	}
179 	return FALSE;
180 }
181 
182 static int
module_load(const char * path,const char * name,const struct module_dir_load_settings * set,struct module * all_modules,struct module ** module_r,const char ** error_r)183 module_load(const char *path, const char *name,
184 	    const struct module_dir_load_settings *set,
185 	    struct module *all_modules,
186 	    struct module **module_r, const char **error_r)
187 {
188 	void *handle;
189 	struct module *module;
190 	const char *const *module_version;
191 	void (*preinit)(void);
192 
193 	*module_r = NULL;
194 	*error_r = NULL;
195 
196 	if (set->ignore_dlopen_errors) {
197 		handle = quiet_dlopen(path, RTLD_GLOBAL | RTLD_NOW);
198 		if (handle == NULL) {
199 			if (set->debug) {
200 				i_debug("Skipping module %s, "
201 					"because dlopen() failed: %s "
202 					"(this is usually intentional, "
203 					"so just ignore this message)",
204 					name, dlerror());
205 			}
206 			return 0;
207 		}
208 	} else {
209 		handle = dlopen(path, RTLD_GLOBAL | RTLD_NOW);
210 		if (handle == NULL) {
211 			*error_r = t_strdup_printf("dlopen() failed: %s",
212 						   dlerror());
213 #ifdef RTLD_LAZY
214 			/* try to give a better error message by lazily loading
215 			   the plugin and checking its dependencies */
216 			handle = dlopen(path, RTLD_LAZY);
217 			if (handle == NULL)
218 				return -1;
219 #else
220 			return -1;
221 #endif
222 		}
223 	}
224 
225 	module = i_new(struct module, 1);
226 	module->path = i_strdup(path);
227 	module->name = i_strdup(name);
228 	module->handle = handle;
229 
230 	module_version = set->abi_version == NULL ? NULL :
231 		get_symbol(module, t_strconcat(name, "_version", NULL), TRUE);
232 	if (module_version != NULL &&
233 	    !versions_equal(*module_version, set->abi_version)) {
234 		*error_r = t_strdup_printf(
235 			"Module is for different ABI version %s (we have %s)",
236 			*module_version, set->abi_version);
237 		module_free(module);
238 		return -1;
239 	}
240 
241 	/* get our init func */
242 	module->init = (void (*)(struct module *))
243 		get_symbol(module, t_strconcat(name, "_init", NULL),
244 			   !set->require_init_funcs);
245 	module->deinit = (void (*)(void))
246 		get_symbol(module, t_strconcat(name, "_deinit", NULL),
247 			   !set->require_init_funcs);
248 	preinit = (void (*)(void))
249 		get_symbol(module, t_strconcat(name, "_preinit", NULL),
250 			   TRUE);
251 	if (preinit != NULL)
252 		preinit();
253 
254 	if ((module->init == NULL || module->deinit == NULL) &&
255 	    set->require_init_funcs) {
256 		*error_r = t_strdup_printf(
257 			"Module doesn't have %s function",
258 			module->init == NULL ? "init" : "deinit");
259 	} else if (!module_check_wrong_binary_dependency(set, module, error_r)) {
260 		/* failed */
261 	} else if (!module_check_missing_plugin_dependencies(set, module,
262 							     all_modules, error_r)) {
263 		/* failed */
264 	}
265 
266 	if (*error_r != NULL) {
267 		module->deinit = NULL;
268 		module_free(module);
269 		return -1;
270 	}
271 
272 	if (set->debug)
273 		i_debug("Module loaded: %s", path);
274 	*module_r = module;
275 	return 1;
276 }
277 
module_name_cmp(const char * const * n1,const char * const * n2)278 static int module_name_cmp(const char *const *n1, const char *const *n2)
279 {
280 	const char *s1 = *n1, *s2 = *n2;
281 
282 	if (str_begins(s1, "lib"))
283 		s1 += 3;
284 	if (str_begins(s2, "lib"))
285 		s2 += 3;
286 
287 	return strcmp(s1, s2);
288 }
289 
module_want_load(const struct module_dir_load_settings * set,const char ** names,const char * name)290 static bool module_want_load(const struct module_dir_load_settings *set,
291 			     const char **names, const char *name)
292 {
293 	if (set->filter_callback != NULL) {
294 		if (!set->filter_callback(name, set->filter_context))
295 			return FALSE;
296 	}
297 	if (names == NULL)
298 		return TRUE;
299 
300 	for (; *names != NULL; names++) {
301 		if (strcmp(*names, name) == 0) {
302 			*names = "";
303 			return TRUE;
304 		}
305 	}
306 	return FALSE;
307 }
308 
check_duplicates(ARRAY_TYPE (const_string)* names,const char * name,const char * dir)309 static void check_duplicates(ARRAY_TYPE(const_string) *names,
310 			     const char *name, const char *dir)
311 {
312 	const char *const *names_p, *base_name, *tmp;
313 	unsigned int i, count;
314 
315 	base_name = module_file_get_name(name);
316 	names_p = array_get(names, &count);
317 	for (i = 0; i < count; i++) T_BEGIN {
318 		tmp = module_file_get_name(names_p[i]);
319 
320 		if (strcmp(tmp, base_name) == 0)
321 			i_fatal("Multiple files for module %s: %s/%s, %s/%s",
322 				base_name, dir, name, dir, names_p[i]);
323 	} T_END;
324 }
325 
module_dir_find(struct module * modules,const char * name)326 struct module *module_dir_find(struct module *modules, const char *name)
327 {
328 	struct module *module;
329 	size_t len = strlen(name);
330 
331 	for (module = modules; module != NULL; module = module->next) {
332 		if (strncmp(module->name, name, len) == 0) {
333 			if (module->name[len] == '\0' ||
334 			    strcmp(module->name + len, "_plugin") == 0)
335 				return module;
336 		}
337 	}
338 	return NULL;
339 }
340 
module_is_loaded(struct module * modules,const char * name)341 static bool module_is_loaded(struct module *modules, const char *name)
342 {
343 	return module_dir_find(modules, name) != NULL;
344 }
345 
module_names_fix(const char ** module_names)346 static void module_names_fix(const char **module_names)
347 {
348 	unsigned int i, j;
349 
350 	if (module_names[0] == NULL)
351 		return;
352 
353 	/* allow giving the module names also in non-base form.
354 	   convert them in here. */
355 	for (i = 0; module_names[i] != NULL; i++)
356 		module_names[i] = module_file_get_name(module_names[i]);
357 
358 	/* @UNSAFE: drop duplicates */
359 	i_qsort(module_names, i, sizeof(*module_names), i_strcmp_p);
360 	for (i = j = 1; module_names[i] != NULL; i++) {
361 		if (strcmp(module_names[i-1], module_names[i]) != 0)
362 			module_names[j++] = module_names[i];
363 	}
364 	module_names[j] = NULL;
365 }
366 
367 static bool
module_dir_is_all_loaded(struct module * old_modules,const char ** module_names)368 module_dir_is_all_loaded(struct module *old_modules, const char **module_names)
369 {
370 	unsigned int i;
371 
372 	for (i = 0; module_names[i] != NULL; i++) {
373 		if (!module_is_loaded(old_modules, module_names[i]))
374 			return FALSE;
375 	}
376 	return TRUE;
377 }
378 
379 static int
module_dir_load_real(struct module ** _modules,const char * dir,const char ** module_names,const struct module_dir_load_settings * set,char ** error_r)380 module_dir_load_real(struct module **_modules,
381 		     const char *dir, const char **module_names,
382 		     const struct module_dir_load_settings *set,
383 		     char **error_r)
384 {
385 	DIR *dirp;
386 	struct dirent *d;
387 	const char *name, *p, *error, *const *names_p;
388 	struct module *modules, *module, **module_pos, *old_modules = *_modules;
389 	unsigned int i, count;
390 	ARRAY_TYPE(const_string) names;
391 	pool_t pool;
392 	int ret;
393 
394 	*error_r = NULL;
395 
396 	if (module_names != NULL) {
397 		if (module_dir_is_all_loaded(old_modules, module_names))
398 			return 0;
399 	}
400 
401 	if (set->debug)
402 		i_debug("Loading modules from directory: %s", dir);
403 
404 	dirp = opendir(dir);
405 	if (dirp == NULL) {
406 		*error_r = i_strdup_printf("opendir(%s) failed: %m", dir);
407 		if (module_names != NULL) {
408 			/* we were given a list of modules to load.
409 			   we can't fail. */
410 			return -1;
411 		}
412 		return errno == ENOENT ? 0 : -1;
413 	}
414 
415 	pool = pool_alloconly_create("module loader", 4096);
416 	p_array_init(&names, pool, 32);
417 
418 	modules = NULL;
419 	for (errno = 0; (d = readdir(dirp)) != NULL; errno = 0) {
420 		name = d->d_name;
421 
422 		if (name[0] == '.')
423 			continue;
424 
425 		p = strstr(name, MODULE_SUFFIX);
426 		if (p == NULL || strlen(p) != 3)
427 			continue;
428 
429 		T_BEGIN {
430 			check_duplicates(&names, name, dir);
431 		} T_END;
432 
433 		name = p_strdup(pool, d->d_name);
434 		array_push_back(&names, &name);
435 	}
436 	if (errno != 0)
437 		*error_r = i_strdup_printf("readdir(%s) failed: %m", dir);
438 	if (closedir(dirp) < 0 && *error_r == NULL)
439 		*error_r = i_strdup_printf("closedir(%s) failed: %m", dir);
440 	if (*error_r != NULL) {
441 		pool_unref(&pool);
442 		return -1;
443 	}
444 
445 	array_sort(&names, module_name_cmp);
446 	names_p = array_get(&names, &count);
447 
448 	modules = old_modules;
449 	module_pos = &modules;
450 	while (*module_pos != NULL)
451 		module_pos = &(*module_pos)->next;
452 	for (i = 0; i < count; i++) T_BEGIN {
453 		const char *path, *stripped_name, *suffixless_name;
454 
455 		name = names_p[i];
456 		stripped_name = module_file_get_name(name);
457 		suffixless_name = module_name_drop_suffix(stripped_name);
458 		if (!module_want_load(set, module_names, suffixless_name) ||
459 		    module_is_loaded(old_modules, suffixless_name))
460 			module = NULL;
461 		else {
462 			path = t_strconcat(dir, "/", name, NULL);
463 			ret = module_load(path, stripped_name, set, modules, &module, &error);
464 			if (ret >= 0)
465 				;
466 			else if (module_names != NULL) {
467 				*error_r = i_strdup_printf("Couldn't load required plugin %s: %s",
468 							   path, error);
469 				i = count;
470 			} else {
471 				i_error("Couldn't load plugin %s: %s", path, error);
472 			}
473 		}
474 
475 		if (module != NULL) {
476 			*module_pos = module;
477 			module_pos = &module->next;
478 		}
479 	} T_END;
480 	pool_unref(&pool);
481 
482 	if (module_names != NULL && *error_r == NULL && !set->ignore_missing) {
483 		/* make sure all modules were found */
484 		for (; *module_names != NULL; module_names++) {
485 			if (**module_names != '\0') {
486 				*error_r = i_strdup_printf("Plugin '%s' not found from directory %s",
487 					*module_names, dir);
488 				break;
489 			}
490 		}
491 	}
492 	*_modules = modules;
493 	return *error_r != NULL ? -1 : 0;
494 }
495 
module_dir_try_load_missing(struct module ** modules,const char * dir,const char * module_names,const struct module_dir_load_settings * set,const char ** error_r)496 int module_dir_try_load_missing(struct module **modules,
497 				const char *dir, const char *module_names,
498 				const struct module_dir_load_settings *set,
499 				const char **error_r)
500 {
501 	char *error = NULL;
502 	int ret;
503 
504 	T_BEGIN {
505 		const char **arr = NULL;
506 
507 		if (module_names != NULL) {
508 			arr = t_strsplit_spaces(module_names, ", ");
509 			module_names_fix(arr);
510 		}
511 
512 		ret = module_dir_load_real(modules, dir, arr, set, &error);
513 	} T_END;
514 	*error_r = t_strdup(error);
515 	i_free(error);
516 	return ret;
517 }
518 
519 struct module *
module_dir_load_missing(struct module * old_modules,const char * dir,const char * module_names,const struct module_dir_load_settings * set)520 module_dir_load_missing(struct module *old_modules,
521 			const char *dir, const char *module_names,
522 			const struct module_dir_load_settings *set)
523 {
524 	struct module *new_modules = old_modules;
525 	const char *error;
526 
527 	if (module_dir_try_load_missing(&new_modules, dir, module_names,
528 					set, &error) < 0) {
529 		if (module_names != NULL)
530 			i_fatal("%s", error);
531 		else
532 			i_error("%s", error);
533 	}
534 	return new_modules;
535 }
536 
module_dir_init(struct module * modules)537 void module_dir_init(struct module *modules)
538 {
539 	struct module *module;
540 
541 	for (module = modules; module != NULL; module = module->next) {
542 		if (!module->initialized) {
543 			module->initialized = TRUE;
544 			if (module->init != NULL) T_BEGIN {
545 				module->init(module);
546 			} T_END;
547 		}
548 	}
549 }
550 
module_dir_deinit(struct module * modules)551 void module_dir_deinit(struct module *modules)
552 {
553 	struct module *module, **rev;
554 	unsigned int i, count = 0;
555 
556 	for (module = modules; module != NULL; module = module->next) {
557 		if (module->deinit != NULL && module->initialized)
558 			count++;
559 	}
560 
561 	if (count == 0)
562 		return;
563 
564 	/* @UNSAFE: deinitialize in reverse order */
565 	T_BEGIN {
566 		rev = t_new(struct module *, count);
567 		for (i = 0, module = modules; i < count; ) {
568 			if (module->deinit != NULL && module->initialized) {
569 				rev[count-i-1] = module;
570 				i++;
571 			}
572 			module = module->next;
573 		}
574 
575 		for (i = 0; i < count; i++) {
576 			module = rev[i];
577 
578 			T_BEGIN {
579 				module->deinit();
580 			} T_END;
581 			module->initialized = FALSE;
582 		}
583 	} T_END;
584 }
585 
module_dir_unload(struct module ** modules)586 void module_dir_unload(struct module **modules)
587 {
588 	struct module *module, *next;
589 
590 	/* Call all modules' deinit() first, so that they may still call each
591 	   others' functions. */
592 	module_dir_deinit(*modules);
593 
594 	for (module = *modules; module != NULL; module = next) {
595 		next = module->next;
596 		module_free(module);
597 	}
598 
599 	*modules = NULL;
600 }
601 
602 #else
603 
604 #ifndef MODULE_SUFFIX
605 #  define MODULE_SUFFIX ".so" /* just to avoid build failure */
606 #endif
607 
608 struct module *
module_dir_load_missing(struct module * old_modules ATTR_UNUSED,const char * dir ATTR_UNUSED,const char * module_names,const struct module_dir_load_settings * set ATTR_UNUSED)609 module_dir_load_missing(struct module *old_modules ATTR_UNUSED,
610 			const char *dir ATTR_UNUSED,
611 			const char *module_names,
612 			const struct module_dir_load_settings *set ATTR_UNUSED)
613 {
614 #define NO_SUPPORT_ERRSTR "Dynamically loadable module support not built in"
615 	if (module_names == NULL)
616 		i_error(NO_SUPPORT_ERRSTR);
617 	else {
618 		i_fatal(NO_SUPPORT_ERRSTR", can't load plugins: %s",
619 			module_names);
620 	}
621 	return NULL;
622 }
623 
module_dir_init(struct module * modules ATTR_UNUSED)624 void module_dir_init(struct module *modules ATTR_UNUSED)
625 {
626 }
627 
module_dir_deinit(struct module * modules ATTR_UNUSED)628 void module_dir_deinit(struct module *modules ATTR_UNUSED)
629 {
630 }
631 
module_dir_unload(struct module ** modules ATTR_UNUSED)632 void module_dir_unload(struct module **modules ATTR_UNUSED)
633 {
634 }
635 
module_dir_find(struct module * modules ATTR_UNUSED,const char * name ATTR_UNUSED)636 struct module *module_dir_find(struct module *modules ATTR_UNUSED,
637 			       const char *name ATTR_UNUSED)
638 {
639 	return NULL;
640 }
641 
module_get_symbol(struct module * module ATTR_UNUSED,const char * symbol ATTR_UNUSED)642 void *module_get_symbol(struct module *module ATTR_UNUSED,
643 			const char *symbol ATTR_UNUSED)
644 {
645 	return NULL;
646 }
647 
module_get_symbol_quiet(struct module * module ATTR_UNUSED,const char * symbol ATTR_UNUSED)648 void *module_get_symbol_quiet(struct module *module ATTR_UNUSED,
649 			      const char *symbol ATTR_UNUSED)
650 {
651 	return NULL;
652 }
653 
654 #endif
655 
module_dir_load(const char * dir,const char * module_names,const struct module_dir_load_settings * set)656 struct module *module_dir_load(const char *dir, const char *module_names,
657 			       const struct module_dir_load_settings *set)
658 {
659 	return module_dir_load_missing(NULL, dir, module_names, set);
660 }
661 
module_file_get_name(const char * fname)662 const char *module_file_get_name(const char *fname)
663 {
664 	const char *p;
665 
666 	/* [lib][nn_]name(.so) */
667 	if (str_begins(fname, "lib"))
668 		fname += 3;
669 
670 	for (p = fname; *p != '\0'; p++) {
671 		if (*p < '0' || *p > '9')
672 			break;
673 	}
674 	if (*p == '_')
675 		fname = p + 1;
676 
677 	p = strstr(fname, MODULE_SUFFIX);
678 	if (p == NULL)
679 		return fname;
680 
681 	return t_strdup_until(fname, p);
682 }
683 
module_name_drop_suffix(const char * name)684 static const char *module_name_drop_suffix(const char *name)
685 {
686 	size_t len;
687 
688 	len = strlen(name);
689 	if (len > 7 && strcmp(name + len - 7, "_plugin") == 0)
690 		name = t_strndup(name, len - 7);
691 	return name;
692 }
693 
module_get_plugin_name(struct module * module)694 const char *module_get_plugin_name(struct module *module)
695 {
696 	return module_name_drop_suffix(module->name);
697 }
698