Qt: Add Install Plugin to Tools menu
Add an option to the tools menu to copy a binary plugin file (a .dll or .so) to the personal plugin folder. This avoids the user having to create the paths manually and knowning a lot of relatively unimportant details about where and how Wireshark loads binary plugins. It will also try to validate the plugin and do some sanity checks to ensure the ABI is compatible.
This commit is contained in:
parent
158e104569
commit
c76a28fca4
@ -105,6 +105,9 @@ The following features are new (or have been significantly updated) since versio
|
||||
selected rows or the entire table can be saved or copied to the clipboard
|
||||
in several formats.
|
||||
|
||||
* New menu:Tools[Install Plugin] option provides a convenient method to install
|
||||
a binary plugin to the personal folder.
|
||||
|
||||
//=== Removed Features and Support
|
||||
|
||||
// === Removed Dissectors
|
||||
|
@ -25,6 +25,9 @@ DIAG_ON(frame-larger-than=)
|
||||
#include <wsutil/wslog.h>
|
||||
#include <wsutil/ws_assert.h>
|
||||
#include <wsutil/version_info.h>
|
||||
#ifdef HAVE_PLUGINS
|
||||
#include <wsutil/plugins.h>
|
||||
#endif
|
||||
#include <epan/prefs.h>
|
||||
#include <epan/stats_tree_priv.h>
|
||||
#include <epan/plugin_if.h>
|
||||
@ -3292,3 +3295,89 @@ void WiresharkMainWindow::openTLSKeylogDialog()
|
||||
tlskeylog_dialog_->raise();
|
||||
tlskeylog_dialog_->activateWindow();
|
||||
}
|
||||
|
||||
#ifdef HAVE_PLUGINS
|
||||
void WiresharkMainWindow::installPersonalBinaryPlugin()
|
||||
{
|
||||
QMessageBox::StandardButton reply;
|
||||
|
||||
QString caption = mainApp->windowTitleString(tr("Install plugin"));
|
||||
|
||||
// Get the plugin file path to install
|
||||
QString plugin_filter = tr("Binary plugin (*%1)").arg(WS_PLUGIN_MODULE_SUFFIX);
|
||||
QString src_path = WiresharkFileDialog::getOpenFileName(this, caption, "", plugin_filter);
|
||||
if (src_path.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Plugins from untrusted sources can be dangerous.
|
||||
// Inform the user and ask for confirmation.
|
||||
// We need to do this before checking the plugin compatibility.
|
||||
reply = QMessageBox::question(this, caption,
|
||||
tr("Plugins can execute arbitrary code as the current user. "
|
||||
"Make sure you trust it before installing.\n\n"
|
||||
"Continue installing the file \"%1\" to the personal plugin folder?")
|
||||
.arg(src_path));
|
||||
if (reply != QMessageBox::Yes) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if this is a valid plugin file and get the plugin binary type.
|
||||
// The function will report any errors.
|
||||
plugin_type_e have_type = plugins_check_file(qUtf8Printable(src_path));
|
||||
if (have_type == WS_PLUGIN_NONE)
|
||||
return;
|
||||
|
||||
// Create the destination folder if necessary
|
||||
QString type_path = gchar_free_to_qstring(plugins_pers_type_folder(have_type));
|
||||
QDir type_dir(type_path);
|
||||
if (!type_dir.exists(type_path)) {
|
||||
if (!type_dir.mkpath(type_path)) {
|
||||
QMessageBox::warning(this, caption,
|
||||
tr("Failed to create the directory: %1").arg(type_path));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the file exists in the destination folder, in case we need to overwrite it
|
||||
// XXX Overwriting will probably fail on Windows because the plugin is loaded. We need
|
||||
// a way to load and unload plugins without having to restart the program.
|
||||
QFileInfo file_info(src_path);
|
||||
QString file_name = file_info.fileName();
|
||||
if (type_dir.exists(file_name)) {
|
||||
#ifdef Q_OS_WIN
|
||||
QMessageBox::warning(this, tr("Install Plugin"),
|
||||
tr("The plugin already exists in the personal plugin folder."));
|
||||
return;
|
||||
#else
|
||||
reply = QMessageBox::question(this, caption,
|
||||
tr("The file already exists. Do you want to overwrite it?"));
|
||||
if (reply == QMessageBox::Yes) {
|
||||
if (!type_dir.remove(file_name)) {
|
||||
QMessageBox::warning(this, caption,
|
||||
tr("Error removing the old plugin file from the personal plugin folder."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Overwrite refused, we are done
|
||||
return;
|
||||
}
|
||||
#endif // Q_OS_WIN
|
||||
}
|
||||
|
||||
// File does not exist in the destination or the user chose to overwrite it
|
||||
// Do the copy to install it.
|
||||
QString dst_path = type_dir.filePath(file_name);
|
||||
if (!QFile::copy(src_path, dst_path)) {
|
||||
QMessageBox::warning(this, caption,
|
||||
tr("Failed to copy the file to the destination: %1").arg(dst_path));
|
||||
return;
|
||||
}
|
||||
|
||||
// Success
|
||||
QMessageBox::information(this, caption,
|
||||
tr("Plugin '%1' installed successfully. "
|
||||
"You must restart the program to be able to use it.").arg(file_name));
|
||||
}
|
||||
#endif
|
||||
|
@ -524,6 +524,9 @@ private slots:
|
||||
QString findRtpStreams(QVector<rtpstream_id_t *> *stream_ids, bool reverse);
|
||||
|
||||
void openTLSKeylogDialog();
|
||||
#ifdef HAVE_PLUGINS
|
||||
void installPersonalBinaryPlugin();
|
||||
#endif
|
||||
|
||||
friend class MainApplication;
|
||||
};
|
||||
|
@ -3798,6 +3798,12 @@ void WiresharkMainWindow::connectToolsMenuActions()
|
||||
});
|
||||
|
||||
connect(main_ui_->actionToolsTLSKeylog, &QAction::triggered, this, &WiresharkMainWindow::openTLSKeylogDialog);
|
||||
|
||||
#ifdef HAVE_PLUGINS
|
||||
QAction *actionToolsInstallPlugin = new QAction(tr("Install Plugin"), this);
|
||||
connect(actionToolsInstallPlugin, &QAction::triggered, this, &WiresharkMainWindow::installPersonalBinaryPlugin);
|
||||
main_ui_->menuTools->addAction(actionToolsInstallPlugin);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Help Menu
|
||||
|
@ -122,13 +122,6 @@ pass_plugin_compatibility(const char *name, plugin_type_e type,
|
||||
return true;
|
||||
}
|
||||
|
||||
// GLib and Qt allow ".dylib" and ".so" on macOS. Should we do the same?
|
||||
#ifdef _WIN32
|
||||
#define MODULE_SUFFIX ".dll"
|
||||
#else
|
||||
#define MODULE_SUFFIX ".so"
|
||||
#endif
|
||||
|
||||
static void
|
||||
scan_plugins_dir(GHashTable *plugins_module, const char *dirpath,
|
||||
plugin_type_e type, plugin_scope_e scope)
|
||||
@ -156,7 +149,7 @@ scan_plugins_dir(GHashTable *plugins_module, const char *dirpath,
|
||||
|
||||
while ((name = g_dir_read_name(dir)) != NULL) {
|
||||
/* Skip anything but files with .dll or .so. */
|
||||
if (!g_str_has_suffix(name, MODULE_SUFFIX))
|
||||
if (!g_str_has_suffix(name, WS_PLUGIN_MODULE_SUFFIX))
|
||||
continue;
|
||||
|
||||
/*
|
||||
@ -330,6 +323,54 @@ plugins_supported(void)
|
||||
return g_module_supported();
|
||||
}
|
||||
|
||||
plugin_type_e
|
||||
plugins_check_file(const char *from_filename)
|
||||
{
|
||||
char *name;
|
||||
GModule *handle;
|
||||
void *symbol;
|
||||
plugin_type_e have_type;
|
||||
int abi_version;
|
||||
struct ws_module *module;
|
||||
|
||||
handle = g_module_open(from_filename, G_MODULE_BIND_LAZY);
|
||||
if (handle == NULL) {
|
||||
/* g_module_error() provides file path. */
|
||||
report_failure("Couldn't load file: %s", g_module_error());
|
||||
return WS_PLUGIN_NONE;
|
||||
}
|
||||
|
||||
/* Search for the entry point for the plugin registration function */
|
||||
if (!g_module_symbol(handle, "wireshark_load_module", &symbol)) {
|
||||
report_failure("The file '%s' has no \"wireshark_load_module\" symbol", from_filename);
|
||||
return WS_PLUGIN_NONE;
|
||||
}
|
||||
|
||||
DIAG_OFF_PEDANTIC
|
||||
/* Load module. */
|
||||
have_type = ((ws_load_module_func)symbol)(&abi_version, NULL, &module);
|
||||
DIAG_ON_PEDANTIC
|
||||
|
||||
name = g_path_get_basename(from_filename);
|
||||
|
||||
if (!pass_plugin_compatibility(name, have_type, abi_version)) {
|
||||
g_module_close(handle);
|
||||
g_free(name);
|
||||
return WS_PLUGIN_NONE;
|
||||
}
|
||||
|
||||
g_module_close(handle);
|
||||
g_free(name);
|
||||
return have_type;
|
||||
}
|
||||
|
||||
char *
|
||||
plugins_pers_type_folder(plugin_type_e type)
|
||||
{
|
||||
return g_build_filename(get_plugins_pers_dir_with_version(),
|
||||
type_to_dir(type), (const char *)NULL);
|
||||
}
|
||||
|
||||
int
|
||||
plugins_abi_version(plugin_type_e type)
|
||||
{
|
||||
|
@ -18,6 +18,7 @@ extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef enum {
|
||||
WS_PLUGIN_NONE,
|
||||
WS_PLUGIN_EPAN,
|
||||
WS_PLUGIN_WIRETAP,
|
||||
WS_PLUGIN_CODEC
|
||||
@ -39,6 +40,13 @@ typedef enum {
|
||||
#define WS_PLUGIN_DESC_TAP_LISTENER (1UL << 4)
|
||||
#define WS_PLUGIN_DESC_DFILTER (1UL << 5)
|
||||
|
||||
// GLib and Qt allow ".dylib" and ".so" on macOS. Should we do the same?
|
||||
#ifdef _WIN32
|
||||
#define WS_PLUGIN_MODULE_SUFFIX ".dll"
|
||||
#else
|
||||
#define WS_PLUGIN_MODULE_SUFFIX ".so"
|
||||
#endif
|
||||
|
||||
typedef void plugins_t;
|
||||
|
||||
typedef void (*module_register_func)(void);
|
||||
@ -72,6 +80,10 @@ WS_DLL_PUBLIC void plugins_cleanup(plugins_t *plugins);
|
||||
|
||||
WS_DLL_PUBLIC bool plugins_supported(void);
|
||||
|
||||
WS_DLL_PUBLIC plugin_type_e plugins_check_file(const char *path);
|
||||
|
||||
WS_DLL_PUBLIC char *plugins_pers_type_folder(plugin_type_e type);
|
||||
|
||||
WS_DLL_PUBLIC
|
||||
int plugins_abi_version(plugin_type_e type);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user