X-Git-Url: http://git.samba.org/samba.git/?p=obnox%2Fwireshark%2Fwip.git;a=blobdiff_plain;f=epan%2Fplugins.c;h=2e8e863fa2fab383b755dae0a3311ca162fa3287;hp=6b9b2eb6f97d17a88cc00751725f69c9759b694b;hb=6ed34593966e17116ace8eb57a10c463c6957b95;hpb=13c90cc41fe3a6450e7948aadaf3f761fa0e3e08 diff --git a/epan/plugins.c b/epan/plugins.c index 6b9b2eb6f9..2e8e863fa2 100644 --- a/epan/plugins.c +++ b/epan/plugins.c @@ -3,9 +3,9 @@ * * $Id$ * - * Ethereal - Network traffic analyzer - * By Gerald Combs - * Copyright 1999 Gerald Combs + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -26,11 +26,11 @@ # include "config.h" #endif -#ifdef NEED_SNPRINTF_H -# include "snprintf.h" -#endif - #include "plugins.h" +#include + +/* linked list of Lua plugins */ +wslua_plugin *wslua_plugin_list = NULL; #ifdef HAVE_PLUGINS @@ -44,48 +44,21 @@ #include #endif -#include #include +#include #include -#ifdef HAVE_SYS_STAT_H -#include -#endif - #ifdef HAVE_UNISTD_H #include #endif #include "filesystem.h" - -#ifdef PLUGINS_NEED_ADDRESS_TABLE -#include "conversation.h" -#include "reassemble.h" -#include -#include -#include -#include -#include -#include -#include "asn1.h" -#include -#include -#include -#include -#include -#include +#include +#include #include "report_err.h" -#include "plugins/plugin_table.h" -static plugin_address_table_t patable = { -/* file generated by plugin_gen.py */ -#include "plugins/Xass-list" -}; -#endif /* linked list of all plugins */ -plugin *plugin_list; - -#define PLUGINS_DIR_NAME "plugins" +plugin *plugin_list = NULL; /* * add a new plugin to the list @@ -96,43 +69,55 @@ plugin *plugin_list; */ static int add_plugin(void *handle, gchar *name, gchar *version, - void (*reg_handoff)(void)) + void (*register_protoinfo)(void), + void (*reg_handoff)(void), + void (*register_tap_listener)(void), + void (*register_wtap_module)(void), + void (*register_codec_module)(void)) { plugin *new_plug, *pt_plug; pt_plug = plugin_list; if (!pt_plug) /* the list is empty */ { - new_plug = (plugin *)g_malloc(sizeof(plugin)); - if (new_plug == NULL) return ENOMEM; + new_plug = (plugin *)g_malloc(sizeof(plugin)); + if (new_plug == NULL) + return ENOMEM; plugin_list = new_plug; } else { - while (1) - { - /* check if the same name/version is already registered */ - if (!strcmp(pt_plug->name, name) && - !strcmp(pt_plug->version, version)) - { - return EEXIST; - } - - /* we found the last plugin in the list */ - if (pt_plug->next == NULL) break; - - pt_plug = pt_plug->next; - } - new_plug = (plugin *)g_malloc(sizeof(plugin)); - if (new_plug == NULL) return ENOMEM; - pt_plug->next = new_plug; + while (1) + { + /* check if the same name/version is already registered */ + if (!strcmp(pt_plug->name, name) && + !strcmp(pt_plug->version, version)) + { + return EEXIST; + } + + /* we found the last plugin in the list */ + if (pt_plug->next == NULL) + break; + + pt_plug = pt_plug->next; + } + new_plug = (plugin *)g_malloc(sizeof(plugin)); + if (new_plug == NULL) + return ENOMEM; + pt_plug->next = new_plug; } new_plug->handle = handle; new_plug->name = name; new_plug->version = version; + new_plug->register_protoinfo = register_protoinfo; new_plug->reg_handoff = reg_handoff; + new_plug->register_tap_listener = register_tap_listener; + new_plug->register_wtap_module = register_wtap_module; + new_plug->register_codec_module = register_codec_module; new_plug->next = NULL; + return 0; } @@ -152,273 +137,426 @@ add_plugin(void *handle, gchar *name, gchar *version, static void plugins_scan_dir(const char *dirname) { -#define FILENAME_LEN 1024 -#if GLIB_MAJOR_VERSION < 2 - gchar *hack_path; /* pathname used to construct lt_lib_ext */ - gchar *lt_lib_ext; /* extension for loadable modules */ - DIR *dir; /* scanned directory */ - struct dirent *file; /* current file */ - gchar *name; -#else /* GLIB 2 */ - GDir *dir; /* scanned directory */ - GError **dummy; - const gchar *name; -#endif +#define FILENAME_LEN 1024 + WS_DIR *dir; /* scanned directory */ + WS_DIRENT *file; /* current file */ + const char *name; gchar filename[FILENAME_LEN]; /* current file name */ - GModule *handle; /* handle returned by dlopen */ + GModule *handle; /* handle returned by g_module_open */ gchar *version; gpointer gp; - void (*init)(void *); + void (*register_protoinfo)(void); void (*reg_handoff)(void); + void (*register_tap_listener)(void); + void (*register_wtap_module)(void); + void (*register_codec_module)(void); + gchar *dot; int cr; -#if GLIB_MAJOR_VERSION < 2 - /* - * We find the extension used on this platform for loadable modules - * by the sneaky hack of calling "g_module_build_path" to build - * the pathname for a module with an empty directory name and - * empty module name, and then search for the last "." and use - * everything from the last "." on. - */ - hack_path = g_module_build_path("", ""); - lt_lib_ext = strrchr(hack_path, '.'); - if (lt_lib_ext == NULL) + if ((dir = ws_dir_open(dirname, 0, NULL)) != NULL) { - /* - * Does this mean there *is* no extension? Assume so. - * - * XXX - the code below assumes that all loadable modules have - * an extension.... - */ - lt_lib_ext = ""; + while ((file = ws_dir_read_name(dir)) != NULL) + { + name = ws_dir_get_name(file); + + /* + * GLib 2.x defines G_MODULE_SUFFIX as the extension used on + * this platform for loadable modules. + */ + /* skip anything but files with G_MODULE_SUFFIX */ + dot = strrchr(name, '.'); + if (dot == NULL || strcmp(dot+1, G_MODULE_SUFFIX) != 0) + continue; + + g_snprintf(filename, FILENAME_LEN, "%s" G_DIR_SEPARATOR_S "%s", + dirname, name); + if ((handle = g_module_open(filename, 0)) == NULL) + { + report_failure("Couldn't load module %s: %s", filename, + g_module_error()); + continue; + } + + if (!g_module_symbol(handle, "version", &gp)) + { + report_failure("The plugin %s has no version symbol", name); + g_module_close(handle); + continue; + } + version = gp; + + /* + * Do we have a register routine? + */ + if (g_module_symbol(handle, "plugin_register", &gp)) + { + /* + * Yes - this plugin includes one or more dissectors. + */ + register_protoinfo = gp; + } + else + { + /* + * No - no dissectors. + */ + register_protoinfo = NULL; + } + + /* + * Do we have a reg_handoff routine? + */ + if (g_module_symbol(handle, "plugin_reg_handoff", &gp)) + { + /* + * Yes. + */ + reg_handoff = gp; + } + else + { + /* + * No - that's OK even if we have dissectors, as long + * as the plugin registers by name *and* there's + * a caller looking for that name. + */ + reg_handoff = NULL; + } + + /* + * Do we have a register_tap_listener routine? + */ + if (g_module_symbol(handle, "plugin_register_tap_listener", &gp)) + { + /* + * Yes - this plugin includes one or more taps. + */ + register_tap_listener = gp; + } + else + { + /* + * No - no taps here. + */ + register_tap_listener = NULL; + } + + /* + * Do we have an old-style init routine? + */ + if (g_module_symbol(handle, "plugin_init", &gp)) + { + /* + * Yes - do we also have a register routine or a + * register_tap_listener routine? If so, this is a bogus + * hybrid of an old-style and new-style plugin. + */ + if (register_protoinfo != NULL || register_tap_listener != NULL) + { + report_failure("The plugin '%s' has an old plugin init routine\nand a new register or register_tap_listener routine.", + name); + g_module_close(handle); + continue; + } + + /* + * It's just an unsupported old-style plugin; + */ + report_failure("The plugin '%s' has an old plugin init routine. Support has been dropped.\n Information on how to update your plugin is available at \nhttp://anonsvn.wireshark.org/wireshark/trunk/doc/README.plugins", + name); + g_module_close(handle); + continue; + } + + /* + * Do we have a register_wtap_module routine? + */ + if (g_module_symbol(handle, "register_wtap_module", &gp)) + { + register_wtap_module = gp; + } + else + { + register_wtap_module = NULL; + } + + /* + * Do we have a register_codec_module routine? + */ + if (g_module_symbol(handle, "register_codec_module", &gp)) + { + register_codec_module = gp; + } + else + { + register_codec_module = NULL; + } + + /* + * Does this dissector do anything useful? + */ + if (register_protoinfo == NULL && + register_tap_listener == NULL && + register_wtap_module == NULL && + register_codec_module == NULL ) + { + /* + * No. + */ + report_failure("The plugin '%s' has neither a register routine, " + "a register_tap_listener or a register_wtap_module or a register_codec_module routine", + name); + g_module_close(handle); + continue; + } + + /* + * OK, attempt to add it to the list of plugins. + */ + if ((cr = add_plugin(handle, g_strdup(name), version, + register_protoinfo, reg_handoff, + register_tap_listener,register_wtap_module,register_codec_module))) + { + if (cr == EEXIST) + fprintf(stderr, "The plugin %s, version %s\n" + "was found in multiple directories\n", name, version); + else + fprintf(stderr, "Memory allocation problem\n" + "when processing plugin %s, version %s\n", + name, version); + g_module_close(handle); + continue; + } + + } + ws_dir_close(dir); } +} - if ((dir = opendir(dirname)) != NULL) + +/* + * init plugins + */ +void +init_plugins(void) +{ + const char *plugin_dir; + const char *name; + char *plugin_dir_path; + char *plugins_pers_dir; + WS_DIR *dir; /* scanned directory */ + WS_DIRENT *file; /* current file */ + + if (plugin_list == NULL) /* ensure init_plugins is only run once */ { - while ((file = readdir(dir)) != NULL) - { - /* don't try to open "." and ".." */ - if (!(strcmp(file->d_name, "..") && - strcmp(file->d_name, "."))) continue; - - /* skip anything but files with lt_lib_ext */ - dot = strrchr(file->d_name, '.'); - if (dot == NULL || strcmp(dot, lt_lib_ext) != 0) continue; - - snprintf(filename, FILENAME_LEN, "%s" G_DIR_SEPARATOR_S "%s", - dirname, file->d_name); - name = (gchar *)file->d_name; -#else /* GLIB 2 */ + /* + * Scan the global plugin directory. + * If we're running from a build directory, scan the subdirectories + * of that directory, as the global plugin directory is the + * "plugins" directory of the source tree, and the subdirectories + * are the source directories for the plugins, with the plugins + * built in those subdirectories. + */ + plugin_dir = get_plugin_dir(); + if (running_in_build_directory()) + { + if ((dir = ws_dir_open(plugin_dir, 0, NULL)) != NULL) + { + while ((file = ws_dir_read_name(dir)) != NULL) + { + name = ws_dir_get_name(file); + if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) + continue; /* skip "." and ".." */ + /* + * Get the full path of a ".libs" subdirectory of that + * directory. + */ + plugin_dir_path = g_strdup_printf( + "%s" G_DIR_SEPARATOR_S "%s" G_DIR_SEPARATOR_S ".libs", + plugin_dir, name); + if (test_for_directory(plugin_dir_path) != EISDIR) { + /* + * Either it doesn't refer to a directory or it + * refers to something that doesn't exist. + * + * Assume that means that the plugins are in + * the subdirectory of the plugin directory, not + * a ".libs" subdirectory of that subdirectory. + */ + g_free(plugin_dir_path); + plugin_dir_path = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", + plugin_dir, name); + } + plugins_scan_dir(plugin_dir_path); + g_free(plugin_dir_path); + } + ws_dir_close(dir); + } + } + else + plugins_scan_dir(plugin_dir); + + /* + * If the program wasn't started with special privileges, + * scan the users plugin directory. (Even if we relinquish + * them, plugins aren't safe unless we've *permanently* + * relinquished them, and we can't do that in Wireshark as, + * if we need privileges to start capturing, we'd need to + * reclaim them before each time we start capturing.) + */ + if (!started_with_special_privs()) + { + plugins_pers_dir = get_plugins_pers_dir(); + plugins_scan_dir(plugins_pers_dir); + g_free(plugins_pers_dir); + } + } + + register_all_wiretap_modules(); + register_all_codecs(); +} + +void +register_all_plugin_registrations(void) +{ + plugin *pt_plug; + /* - * GLib 2.x defines G_MODULE_SUFFIX as the extension used on this - * platform for loadable modules. + * For all plugins with register-handoff routines, call the routines. + * This is called from "proto_init()"; it must be called after + * "register_all_protocols()" and "init_plugins()" are called, + * in case one plugin registers itself either with a built-in + * dissector or with another plugin; we must first register all + * dissectors, whether built-in or plugin, so their dissector tables + * are initialized, and only then register all handoffs. */ - dummy = g_malloc(sizeof(GError *)); - *dummy = NULL; - if ((dir = g_dir_open(dirname, 0, dummy)) != NULL) + for (pt_plug = plugin_list; pt_plug != NULL; pt_plug = pt_plug->next) { - while ((name = g_dir_read_name(dir)) != NULL) - { - /* skip anything but files with G_MODULE_SUFFIX */ - dot = strrchr(name, '.'); - if (dot == NULL || strcmp(dot+1, G_MODULE_SUFFIX) != 0) continue; - - snprintf(filename, FILENAME_LEN, "%s" G_DIR_SEPARATOR_S "%s", - dirname, name); -#endif - if ((handle = g_module_open(filename, 0)) == NULL) - { - g_warning("Couldn't load module %s: %s", filename, - g_module_error()); - continue; - } - if (!g_module_symbol(handle, "version", &gp)) - { - g_warning("The plugin %s has no version symbol", name); - g_module_close(handle); - continue; - } - version = gp; - - /* - * Old-style dissectors don't have a "plugin_reg_handoff()" - * routine; we no longer support them. - * - * New-style dissectors have one, because, otherwise, there's - * no way for them to arrange that they ever be called. - */ - if (g_module_symbol(handle, "plugin_reg_handoff", &gp)) - { - reg_handoff = gp; - - /* - * We require it to have a "plugin_init()" routine. - */ - if (!g_module_symbol(handle, "plugin_init", &gp)) - { - g_warning("The plugin %s has a plugin_reg_handoff symbol but no plugin_init routine", - name); - g_module_close(handle); - continue; - } - init = gp; - - /* - * We have a "plugin_reg_handoff()" routine, so we don't - * need the protocol, filter string, or dissector pointer. - */ - if ((cr = add_plugin(handle, g_strdup(name), version, - reg_handoff))) - { - if (cr == EEXIST) - fprintf(stderr, "The plugin %s, version %s\n" - "was found in multiple directories\n", name, version); - else - fprintf(stderr, "Memory allocation problem\n" - "when processing plugin %s, version %s\n", - name, version); - g_module_close(handle); - continue; - } - - /* - * Call its init routine. - */ -#ifdef PLUGINS_NEED_ADDRESS_TABLE - init(&patable); -#else - init(NULL); -#endif - } - else - { - /* - * This is an old-style dissector; warn that it won't - * be used, as those aren't supported. - */ - fprintf(stderr, - "The plugin %s, version %s is an old-style plugin;\n" - "Those are no longer supported.\n", name, version); - } - } -#if GLIB_MAJOR_VERSION < 2 - closedir(dir); + if (pt_plug->register_protoinfo) + (pt_plug->register_protoinfo)(); } - g_free(hack_path); -#else /* GLIB 2 */ - g_dir_close(dir); - } - g_clear_error(dummy); - g_free(dummy); -#endif } - -/* get the global plugin dir */ -/* Return value is malloced so the caller should g_free() it. */ -char *get_plugins_global_dir(const char *plugin_dir) +void +register_all_plugin_handoffs(void) { -#ifdef _WIN32 - char *install_plugin_dir; - - /* - * On Windows, the data file directory is the installation - * directory; the plugins are stored under it. - * - * Assume we're running the installed version of Ethereal; - * on Windows, the data file directory is the directory - * in which the Ethereal binary resides. - */ - install_plugin_dir = g_strdup_printf("%s\\plugins\\%s", get_datafile_dir(), VERSION); - - /* - * Make sure that pathname refers to a directory. - */ - if (test_for_directory(install_plugin_dir) != EISDIR) { - /* - * Either it doesn't refer to a directory or it - * refers to something that doesn't exist. - * - * Assume that means we're running, for example, - * a version of Ethereal we've built in a source - * directory, and fall back on the default - * installation directory, so you can put the plugins - * somewhere so they can be used with this version - * of Ethereal. - * - * XXX - should we, instead, have the Windows build - * procedure create a subdirectory of the "plugins" - * source directory, and copy the plugin DLLs there, - * so that you use the plugins from the build tree? - */ - g_free(install_plugin_dir); - install_plugin_dir = - g_strdup("C:\\Program Files\\Ethereal\\plugins\\" VERSION); - } - - return install_plugin_dir; -#else - /* - * Scan the plugin directory. - */ - return strdup(plugin_dir); -#endif -} + plugin *pt_plug; + /* + * For all plugins with register-handoff routines, call the routines. + * This is called from "proto_init()"; it must be called after + * "register_all_protocols()" and "init_plugins()" are called, + * in case one plugin registers itself either with a built-in + * dissector or with another plugin; we must first register all + * dissectors, whether built-in or plugin, so their dissector tables + * are initialized, and only then register all handoffs. + */ + for (pt_plug = plugin_list; pt_plug != NULL; pt_plug = pt_plug->next) + { + if (pt_plug->reg_handoff) + (pt_plug->reg_handoff)(); + } +} -/* get the personal plugin dir */ -/* Return value is malloced so the caller should g_free() it. */ -char *get_plugins_pers_dir(void) +void +register_all_plugin_tap_listeners(void) { - return get_persconffile_path(PLUGINS_DIR_NAME, FALSE); + plugin *pt_plug; + + /* + * For all plugins with register-tap-listener routines, call the + * routines. + */ + for (pt_plug = plugin_list; pt_plug != NULL; pt_plug = pt_plug->next) + { + if (pt_plug->register_tap_listener) + (pt_plug->register_tap_listener)(); + } } -/* - * init plugins - */ void -init_plugins(const char *plugin_dir) +register_all_wiretap_modules(void) { - char *datafile_dir; + plugin *pt_plug; - if (plugin_list == NULL) /* ensure init_plugins is only run once */ + /* + * For all plugins with register_wtap_module routines, call the + * routines. + */ + for (pt_plug = plugin_list; pt_plug != NULL; pt_plug = pt_plug->next) { - /* - * Scan the global plugin directory. - */ - datafile_dir = get_plugins_global_dir(plugin_dir); - plugins_scan_dir(datafile_dir); - g_free(datafile_dir); - - /* - * Scan the users plugin directory. - */ - datafile_dir = get_plugins_pers_dir(); - plugins_scan_dir(datafile_dir); - g_free(datafile_dir); + if (pt_plug->register_wtap_module) + (pt_plug->register_wtap_module)(); } } void -register_all_plugin_handoffs(void) +register_all_codecs(void) { - plugin *pt_plug; - - /* - * For all new-style plugins, call the register-handoff routine. - * This is called from "proto_init()"; it must be called after - * "register_all_protocols()" and "init_plugins()" are called, - * in case one plugin registers itself either with a built-in - * dissector or with another plugin; we must first register all - * dissectors, whether built-in or plugin, so their dissector tables - * are initialized, and only then register all handoffs. - * - * We treat those protocols as always being enabled; they should - * use the standard mechanism for enabling/disabling protocols, not - * the plugin-specific mechanism. - */ - for (pt_plug = plugin_list; pt_plug != NULL; pt_plug = pt_plug->next) - (pt_plug->reg_handoff)(); + plugin *pt_plug; + + /* + * For all plugins with register_wtap_module routines, call the + * routines. + */ + for (pt_plug = plugin_list; pt_plug != NULL; pt_plug = pt_plug->next) + { + if (pt_plug->register_codec_module) + (pt_plug->register_codec_module)(); + } } + +#endif /* big HAVE_PLUGINS */ + +/* + * Dump plugin info to stdout. Copied from ui/gtk/plugins_dlg.c:plugins_scan. + */ +void +plugins_dump_all(void) +{ +#ifdef HAVE_PLUGINS + plugin *pt_plug; + const char *sep; #endif +#ifdef HAVE_LUA_5_1 + wslua_plugin *lua_plug; +#endif + +#ifdef HAVE_PLUGINS + for (pt_plug = plugin_list; pt_plug != NULL; pt_plug = pt_plug->next) + { + sep = ""; + + printf("%s\t%s\t", pt_plug->name, pt_plug->version); + if (pt_plug->register_protoinfo) + { + printf("dissector"); + sep = ", "; + } + if (pt_plug->register_tap_listener) + { + printf("%stap", sep); + sep = ", "; + } + if (pt_plug->register_wtap_module) + { + printf("%sfile format", sep); + sep = ", "; + } + if (pt_plug->register_codec_module) + { + printf("%scodec", sep); + } + printf("\t%s\n", g_module_name(pt_plug->handle)); + } +#endif + +#ifdef HAVE_LUA_5_1 + for (lua_plug = wslua_plugin_list; lua_plug != NULL; lua_plug = lua_plug->next) + { + printf("%s\t%s\tlua script\t%s\n", lua_plug->name, lua_plug->version, lua_plug->filename); + } +#endif +} +