4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0+
25 #include <wsutil/filesystem.h>
26 #include <wsutil/privileges.h>
27 #include <wsutil/file_util.h>
28 #include <wsutil/report_message.h>
30 #include <wsutil/plugins.h>
31 #include <wsutil/ws_printf.h> /* ws_debug_printf */
33 typedef struct _plugin {
34 GModule *handle; /* handle returned by g_module_open */
35 gchar *name; /* plugin name */
36 const gchar *version; /* plugin version */
37 GString *types; /* description with types this plugin supports */
40 static GHashTable *plugins_table = NULL;
43 free_plugin(gpointer _p)
45 plugin *p = (plugin *)_p;
46 g_module_close(p->handle);
48 g_string_free(p->types, TRUE);
53 * Add a new plugin type.
54 * Takes a callback routine as an argument; it is called for each plugin
55 * we find, and handed a handle for the plugin, the name of the plugin,
56 * and the version string for the plugin. The plugin returns TRUE if
57 * it's a plugin for that type and FALSE if not.
61 plugin_check_type_callback check_type;
64 static GSList *plugin_types = NULL;
67 free_plugin_type(gpointer p, gpointer user_data _U_)
73 add_plugin_type(const char *name, plugin_check_type_callback check_type)
75 plugin_type *new_type;
77 new_type = (plugin_type *)g_malloc(sizeof (plugin_type));
78 new_type->name = name;
79 new_type->check_type = check_type;
80 plugin_types = g_slist_prepend(plugin_types, new_type);
84 call_plugin_callback(gpointer data, gpointer user_data)
86 plugin_type *type = (plugin_type *)data;
87 plugin *new_plug = (plugin *)user_data;
89 if (type->check_type(new_plug->handle)) {
90 /* The plugin supports this type */
91 if (new_plug->types->len > 0)
92 g_string_append(new_plug->types, ", ");
93 g_string_append(new_plug->types, type->name);
98 plugins_scan_dir(const char *dirname, plugin_load_failure_mode mode)
100 WS_DIR *dir; /* scanned directory */
101 WS_DIRENT *file; /* current file */
103 gchar *filename; /* current file name */
104 GModule *handle; /* handle returned by g_module_open */
106 const char *plug_version, *plug_release;
110 if (!g_file_test(dirname, G_FILE_TEST_EXISTS) || !g_file_test(dirname, G_FILE_TEST_IS_DIR)) {
114 if ((dir = ws_dir_open(dirname, 0, NULL)) != NULL)
116 while ((file = ws_dir_read_name(dir)) != NULL)
118 name = ws_dir_get_name(file);
121 * GLib 2.x defines G_MODULE_SUFFIX as the extension used on
122 * this platform for loadable modules.
124 /* skip anything but files with G_MODULE_SUFFIX */
125 dot = strrchr(name, '.');
126 if (dot == NULL || strcmp(dot+1, G_MODULE_SUFFIX) != 0)
130 if (strncmp(name, "nordic_ble.dll", 14) == 0)
132 * Skip the Nordic BLE Sniffer dll on WIN32 because
133 * the dissector has been added as internal.
139 * Check if the same name is already registered.
141 if (g_hash_table_lookup(plugins_table, name)) {
143 if (mode == REPORT_LOAD_FAILURE) {
144 report_warning("The plugin '%s' was found "
145 "in multiple directories", name);
150 filename = g_build_filename(dirname, name, (gchar *)NULL);
151 handle = g_module_open(filename, G_MODULE_BIND_LOCAL);
156 * Only report load failures if we were asked to.
158 * XXX - we really should put different types of plugins
159 * (libwiretap, libwireshark) in different subdirectories,
160 * give libwiretap and libwireshark init routines that
161 * load the plugins, and have them scan the appropriate
162 * subdirectories so tha we don't even *try* to, for
163 * example, load libwireshark plugins in programs that
164 * only use libwiretap.
166 if (mode == REPORT_LOAD_FAILURE) {
167 /* g_module_error() provides filename. */
168 report_failure("Couldn't load plugin '%s': %s", name,
174 if (!g_module_symbol(handle, "plugin_version", &symbol))
176 report_failure("The plugin '%s' has no \"plugin_version\" symbol", name);
177 g_module_close(handle);
180 plug_version = (const char *)symbol;
182 if (!g_module_symbol(handle, "plugin_release", &symbol))
184 report_failure("The plugin '%s' has no \"plugin_release\" symbol", name);
185 g_module_close(handle);
188 plug_release = (const char *)symbol;
189 if (strcmp(plug_release, VERSION_RELEASE) != 0) {
190 report_failure("The plugin '%s' was compiled for Wireshark version %s", name, plug_release);
191 g_module_close(handle);
195 new_plug = (plugin *)g_malloc(sizeof(plugin));
196 new_plug->handle = handle;
197 new_plug->name = g_strdup(name);
198 new_plug->version = plug_version;
199 new_plug->types = g_string_new(NULL);
202 * Hand the plugin to each of the plugin type callbacks.
204 g_slist_foreach(plugin_types, call_plugin_callback, new_plug);
207 * Does this dissector do anything useful?
209 if (new_plug->types->len == 0)
214 * Only report this failure if we were asked to; it might
215 * just mean that it's a plugin type that this program
216 * doesn't support, such as a libwireshark plugin in
217 * a program that doesn't use libwireshark.
219 * XXX - we really should put different types of plugins
220 * (libwiretap, libwireshark) in different subdirectories,
221 * give libwiretap and libwireshark init routines that
222 * load the plugins, and have them scan the appropriate
223 * subdirectories so tha we don't even *try* to, for
224 * example, load libwireshark plugins in programs that
225 * only use libwiretap.
227 if (mode == REPORT_LOAD_FAILURE) {
228 report_failure("The plugin '%s' has no registration routines",
231 free_plugin(new_plug);
236 * OK, add it to the list of plugins.
238 g_hash_table_insert(plugins_table, new_plug->name, new_plug);
245 * Scan the buildir for plugins.
248 scan_plugins_build_dir(plugin_load_failure_mode mode)
250 const char *plugin_dir;
252 char *plugin_dir_path;
253 WS_DIR *dir; /* scanned directory */
254 WS_DIRENT *file; /* current file */
256 plugin_dir = get_plugins_dir();
257 if ((dir = ws_dir_open(plugin_dir, 0, NULL)) == NULL)
260 plugins_scan_dir(plugin_dir, mode);
261 while ((file = ws_dir_read_name(dir)) != NULL)
263 name = ws_dir_get_name(file);
264 if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
265 continue; /* skip "." and ".." */
267 * Get the full path of a ".libs" subdirectory of that
270 plugin_dir_path = g_build_filename(plugin_dir, name, ".libs", (gchar *)NULL);
271 if (test_for_directory(plugin_dir_path) != EISDIR) {
273 * Either it doesn't refer to a directory or it
274 * refers to something that doesn't exist.
276 * Assume that means that the plugins are in
277 * the subdirectory of the plugin directory, not
278 * a ".libs" subdirectory of that subdirectory.
280 g_free(plugin_dir_path);
281 plugin_dir_path = g_build_filename(plugin_dir, name, (gchar *)NULL);
283 plugins_scan_dir(plugin_dir_path, mode);
284 g_free(plugin_dir_path);
293 scan_plugins(plugin_load_failure_mode mode)
295 if (!g_module_supported())
296 return; /* nothing to do */
298 if (plugins_table != NULL)
299 return; /* only scan for plugins once */
301 plugins_table = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, free_plugin);
303 * Scan the global plugin directory.
304 * If we're running from a build directory, scan the "plugins"
305 * subdirectory, as that's where plugins are located in an
306 * out-of-tree build. If we find subdirectories scan those since
307 * they will contain plugins in the case of an in-tree build.
309 if (running_in_build_directory())
311 scan_plugins_build_dir(mode);
315 plugins_scan_dir(get_plugins_dir_with_version(), mode);
319 * If the program wasn't started with special privileges,
320 * scan the users plugin directory. (Even if we relinquish
321 * them, plugins aren't safe unless we've *permanently*
322 * relinquished them, and we can't do that in Wireshark as,
323 * if we need privileges to start capturing, we'd need to
324 * reclaim them before each time we start capturing.)
326 if (!started_with_special_privs())
328 plugins_scan_dir(get_plugins_pers_dir_with_version(), mode);
333 add_plugin_to_descriptions(gpointer key _U_, gpointer value, gpointer user_data)
335 g_ptr_array_add((GPtrArray *)user_data, value);
339 compare_plugins(gconstpointer _a, gconstpointer _b)
341 const plugin *a = *(const plugin **)_a;
342 const plugin *b = *(const plugin **)_b;
344 return strcmp(a->name, b->name);
347 struct description_callback {
348 plugin_description_callback callback;
349 gpointer callback_data;
353 call_description_callback(gpointer data, gpointer user_data)
355 plugin *plug = (plugin *)data;
356 struct description_callback *desc = (struct description_callback *)user_data;
358 desc->callback(plug->name, plug->version, plug->types->str, g_module_name(plug->handle), desc->callback_data);
362 plugins_get_descriptions(plugin_description_callback callback, void *user_data)
364 GPtrArray *descriptions;
365 struct description_callback cb;
370 descriptions = g_ptr_array_sized_new(g_hash_table_size(plugins_table));
371 g_hash_table_foreach(plugins_table, add_plugin_to_descriptions, descriptions);
372 g_ptr_array_sort(descriptions, compare_plugins);
373 cb.callback = callback;
374 cb.callback_data = user_data;
375 g_ptr_array_foreach(descriptions, call_description_callback, &cb);
376 g_ptr_array_free(descriptions, FALSE);
380 print_plugin_description(const char *name, const char *version,
381 const char *description, const char *filename,
384 ws_debug_printf("%s\t%s\t%s\t%s\n", name, version, description, filename);
388 plugins_dump_all(void)
390 plugins_get_descriptions(print_plugin_description, NULL);
394 plugins_get_count(void)
397 return g_hash_table_size(plugins_table);
402 plugins_cleanup(void)
405 g_hash_table_destroy(plugins_table);
406 g_slist_foreach(plugin_types, free_plugin_type, NULL);
407 g_slist_free(plugin_types);
410 #endif /* HAVE_PLUGINS */
418 * indent-tabs-mode: nil
421 * ex: set shiftwidth=4 tabstop=8 expandtab:
422 * :indentSize=4:tabSize=8:noTabs=true: