4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
23 #include <wsutil/filesystem.h>
24 #include <wsutil/privileges.h>
25 #include <wsutil/file_util.h>
26 #include <wsutil/report_message.h>
28 #include <wsutil/plugins.h>
29 #include <wsutil/ws_printf.h> /* ws_debug_printf */
31 typedef struct _plugin {
32 GModule *handle; /* handle returned by g_module_open */
33 gchar *name; /* plugin name */
34 const gchar *version; /* plugin version */
35 const gchar *type_name; /* user-facing name (what it does). Should these be capitalized? */
38 #define TYPE_DIR_EPAN "epan"
39 #define TYPE_DIR_WIRETAP "wiretap"
40 #define TYPE_DIR_CODECS "codecs"
42 #define TYPE_NAME_DISSECTOR "dissector"
43 #define TYPE_NAME_FILE_TYPE "file type"
44 #define TYPE_NAME_CODEC "codec"
47 static GSList *plugins_module_list = NULL;
50 static inline const char *
51 type_to_dir(plugin_type_e type)
56 case WS_PLUGIN_WIRETAP:
57 return TYPE_DIR_WIRETAP;
59 return TYPE_DIR_CODECS;
61 g_error("Unknown plugin type: %u. Aborting.", (unsigned) type);
64 g_assert_not_reached();
67 static inline const char *
68 type_to_name(plugin_type_e type)
72 return TYPE_NAME_DISSECTOR;
73 case WS_PLUGIN_WIRETAP:
74 return TYPE_NAME_FILE_TYPE;
76 return TYPE_NAME_CODEC;
78 g_error("Unknown plugin type: %u. Aborting.", (unsigned) type);
81 g_assert_not_reached();
85 free_plugin(gpointer data)
87 plugin *p = (plugin *)data;
88 g_module_close(p->handle);
94 compare_plugins(gconstpointer a, gconstpointer b)
96 return g_strcmp0((*(plugin *const *)a)->name, (*(plugin *const *)b)->name);
100 pass_plugin_version_compatibility(GModule *handle, const char *name)
105 if(!g_module_symbol(handle, "plugin_want_major", &symb)) {
106 report_failure("The plugin '%s' has no \"plugin_want_major\" symbol", name);
109 major = *(int *)symb;
111 if(!g_module_symbol(handle, "plugin_want_minor", &symb)) {
112 report_failure("The plugin '%s' has no \"plugin_want_minor\" symbol", name);
115 minor = *(int *)symb;
117 if (major != VERSION_MAJOR || minor != VERSION_MINOR) {
118 report_failure("The plugin '%s' was compiled for Wireshark version %d.%d",
127 scan_plugins_dir(GHashTable *plugins_module, const char *dirpath, plugin_type_e type, gboolean append_type)
130 const char *name; /* current file name */
131 gchar *plugin_folder;
132 gchar *plugin_file; /* current file full path */
133 GModule *handle; /* handle returned by g_module_open */
135 const char *plug_version;
139 plugin_folder = g_build_filename(dirpath, type_to_dir(type), (gchar *)NULL);
141 plugin_folder = g_strdup(dirpath);
143 dir = g_dir_open(plugin_folder, 0, NULL);
145 g_free(plugin_folder);
149 while ((name = g_dir_read_name(dir)) != NULL) {
150 /* Skip anything but files with G_MODULE_SUFFIX. */
151 if (!g_str_has_suffix(name, "." G_MODULE_SUFFIX))
155 * Check if the same name is already registered.
157 if (g_hash_table_lookup(plugins_module, name)) {
159 report_warning("The plugin '%s' was found "
160 "in multiple directories", name);
164 plugin_file = g_build_filename(plugin_folder, name, (gchar *)NULL);
165 handle = g_module_open(plugin_file, G_MODULE_BIND_LOCAL);
167 if (handle == NULL) {
168 /* g_module_error() provides file path. */
169 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 (!pass_plugin_version_compatibility(handle, name)) {
183 g_module_close(handle);
187 /* Search for the entry point for the plugin registration function */
188 if (!g_module_symbol(handle, "plugin_register", &symbol)) {
189 report_failure("The plugin '%s' has no \"plugin_register\" symbol", name);
190 g_module_close(handle);
195 /* Found it, call the plugin registration function. */
196 ((plugin_register_func)symbol)();
199 new_plug = (plugin *)g_malloc(sizeof(plugin));
200 new_plug->handle = handle;
201 new_plug->name = g_strdup(name);
202 new_plug->version = plug_version;
203 new_plug->type_name = type_to_name(type);
205 /* Add it to the list of plugins. */
206 g_hash_table_insert(plugins_module, new_plug->name, new_plug);
209 g_free(plugin_folder);
216 plugins_init(plugin_type_e type)
218 if (!g_module_supported())
219 return NULL; /* nothing to do */
221 GHashTable *plugins_module = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, free_plugin);
224 * Scan the global plugin directory.
226 scan_plugins_dir(plugins_module, get_plugins_dir_with_version(), type, TRUE);
229 * If the program wasn't started with special privileges,
230 * scan the users plugin directory. (Even if we relinquish
231 * them, plugins aren't safe unless we've *permanently*
232 * relinquished them, and we can't do that in Wireshark as,
233 * if we need privileges to start capturing, we'd need to
234 * reclaim them before each time we start capturing.)
236 if (!started_with_special_privs()) {
237 scan_plugins_dir(plugins_module, get_plugins_pers_dir_with_version(), type, TRUE);
240 plugins_module_list = g_slist_prepend(plugins_module_list, plugins_module);
242 return plugins_module;
246 plugins_get_descriptions(plugin_description_callback callback, void *callback_data)
248 GPtrArray *plugins_array = g_ptr_array_new();
252 for (GSList *l = plugins_module_list; l != NULL; l = l->next) {
253 g_hash_table_iter_init (&iter, (GHashTable *)l->data);
254 while (g_hash_table_iter_next (&iter, NULL, &value)) {
255 g_ptr_array_add(plugins_array, value);
259 g_ptr_array_sort(plugins_array, compare_plugins);
261 for (guint i = 0; i < plugins_array->len; i++) {
262 plugin *plug = (plugin *)plugins_array->pdata[i];
263 callback(plug->name, plug->version, plug->type_name, g_module_name(plug->handle), callback_data);
266 g_ptr_array_free(plugins_array, TRUE);
270 print_plugin_description(const char *name, const char *version,
271 const char *description, const char *filename,
274 ws_debug_printf("%-16s\t%s\t%s\t%s\n", name, version, description, filename);
278 plugins_dump_all(void)
280 plugins_get_descriptions(print_plugin_description, NULL);
284 plugins_get_count(void)
288 for (GSList *l = plugins_module_list; l != NULL; l = l->next) {
289 count += g_hash_table_size((GHashTable *)l->data);
295 plugins_cleanup(plugins_t *plugins)
300 plugins_module_list = g_slist_remove(plugins_module_list, plugins);
301 g_hash_table_destroy((GHashTable *)plugins);
310 * indent-tabs-mode: nil
313 * ex: set shiftwidth=4 tabstop=8 expandtab:
314 * :indentSize=4:tabSize=8:noTabs=true: