summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2016-04-28 15:43:58 +0200
committerThomas Haller <thaller@redhat.com>2016-04-28 22:42:27 +0200
commitd70533498b15a73e65064564ececd2ae1dfeef40 (patch)
tree71181020e8c87d6bd295cd27284f61b29e838405
parent46c4b94a00bed5d1d74541708b8f08978e09b248 (diff)
downloadNetworkManager-th/vpn-editor-split-bgo765732.tar.gz
libnm/vpn: add nm_vpn_editor_plugin_get_editor_load() to load the editor pluginth/vpn-editor-split-bgo765732
Currently, libnm-core allows to load the NMVpnEditorPlugin interface by loading the shared library from the libnm.plugin setting. NMVpnEditorPlugin has a method nm_vpn_editor_plugin_get_editor(), which returns a NMVpnEditor interface, which in turn can return a GtkWidged via nm_vpn_editor_get_widget(). So, although NMVpnEditor itself has no direct GTK dependency, it is strongly related to the GUI and GTK. On the other hand, NMVpnEditorPlugin interface is more generic and lives in libnm-core. It can and should contain only parts that are independent from the GUI and not drag in the entire GTK dependency. Extend nm_vpn_editor_plugin_get_editor() to allow for a new generation of plugins that split their implementation of NMVpnEditorPlugin and NMVpnEditor in two different libraries. Only the latter has a dependency on GTK. New plugins no longer overwrite NMVpnEditorPluginInterface::get_editor. Instead, their .name file specifies a library path in GNOME.editor-plugin. This path is passed ot NMVpnEditorPlugin, and used to create to load the editor-plugin. Also expose a low-level function nm_vpn_editor_plugin_get_editor_load() which allows for more control when loading the library.
-rw-r--r--libnm-core/nm-vpn-editor-plugin.c139
-rw-r--r--libnm-core/nm-vpn-editor-plugin.h34
-rw-r--r--libnm/libnm.ver1
3 files changed, 170 insertions, 4 deletions
diff --git a/libnm-core/nm-vpn-editor-plugin.c b/libnm-core/nm-vpn-editor-plugin.c
index 5bf72b0cdd..5a2bfa49a0 100644
--- a/libnm-core/nm-vpn-editor-plugin.c
+++ b/libnm-core/nm-vpn-editor-plugin.c
@@ -403,21 +403,152 @@ nm_vpn_editor_plugin_set_editor_library_path (NMVpnEditorPlugin *self,
}
/**
+ * nm_vpn_editor_plugin_get_editor_load:
+ * @self: the #NMVpnEditorPlugin instance
+ * @editor_library_path: (allow-none): the library path to load. If %NULL,
+ * fallback to nm_vpn_editor_plugin_get_editor_library_path().
+ * @connection: the #NMConnection instance passed to the factory method.
+ * @do_file_checks: if %TRUE, check that the file is valid and has proper
+ * permissions before loading the library. Otherwise, the path is passed
+ * directly to dlopen.
+ * @check_owner: if positive, only allow plugins owned by this owner.
+ * This argument is ignored if @do_file_checks is %FALSE.
+ * @check_file: (allow-none): a predicate to test whether the file is valid
+ * before loading the shared library. This argument is ignored if @do_file_checks
+ * is %FALSE.
+ * @user_data: the user-data for @check_file callback.
+ * @load_data: the data passed to the factory method. Currently %NMVpnEditorLoadData
+ * is an opaque type that contains no fields. In the future we might extend this
+ * structure to pass additional arguments to the factory method.
+ * @error: %GError with the error reason
+ *
+ * This loads the shared library from @editor_library_path, optionally performs some checks
+ * on the file before dlopen(), looks up the factory method "nm_vpn_editor_factory"
+ * and calls it to create an NMVpnEditor instance.
+ *
+ * Returns: (transfer-full): a #NMVpnEditor instance of %NULL in case of error.
+ *
+ * Since: 1.4
+ **/
+NMVpnEditor *
+nm_vpn_editor_plugin_get_editor_load (NMVpnEditorPlugin *self,
+ const char *editor_library_path,
+ NMConnection *connection,
+ gboolean do_file_checks,
+ int check_owner,
+ NMUtilsCheckFilePredicate check_file,
+ gpointer user_data,
+ NMVpnEditorLoadData *load_data,
+ GError **error)
+{
+ GModule *module = NULL;
+ NMVpnEditorFactory factory = NULL;
+ NMVpnEditor *editor = NULL;
+ gs_free char *editor_library_path_free = NULL;
+
+ g_return_val_if_fail (NM_IS_VPN_EDITOR_PLUGIN (self), NULL);
+
+ if (!editor_library_path) {
+ editor_library_path_free = nm_vpn_editor_plugin_get_editor_library_path (self, TRUE);
+ editor_library_path = editor_library_path_free;
+ } else if (do_file_checks) {
+ editor_library_path_free = _get_editor_library_path_validate_and_absolute (editor_library_path);
+ editor_library_path = editor_library_path_free;
+ }
+
+ if (!editor_library_path) {
+ g_set_error_literal (error,
+ NM_VPN_PLUGIN_ERROR,
+ NM_VPN_PLUGIN_ERROR_FAILED,
+ _("Cannot create VPN editor due to missing editor-library-path"));
+ return NULL;
+ }
+
+ if (do_file_checks) {
+ if (!_nm_utils_check_module_file (editor_library_path,
+ check_owner,
+ check_file,
+ user_data,
+ error))
+ return NULL;
+ }
+
+ module = g_module_open (editor_library_path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
+ if (!module) {
+ g_set_error (error,
+ NM_VPN_PLUGIN_ERROR,
+ NM_VPN_PLUGIN_ERROR_FAILED,
+ _("cannot load plugin %s"), editor_library_path);
+ return NULL;
+ }
+
+ if (g_module_symbol (module, "nm_vpn_editor_factory", (gpointer) &factory)) {
+ gs_free_error GError *factory_error = NULL;
+
+ editor = factory (self,
+ connection,
+ load_data,
+ &factory_error);
+
+ g_assert (!editor || G_IS_OBJECT (editor));
+
+ if (editor) {
+ g_object_set_data_full (G_OBJECT (editor), "gmodule", module,
+ (GDestroyNotify) g_module_close);
+ } else {
+ if (factory_error) {
+ g_propagate_error (error, factory_error);
+ factory_error = NULL;
+ } else {
+ g_set_error (error,
+ NM_VPN_PLUGIN_ERROR,
+ NM_VPN_PLUGIN_ERROR_FAILED,
+ _("unknown error initializing editor plugin %s"), editor_library_path);
+ }
+ g_module_close (module);
+ }
+ } else {
+ g_set_error (error,
+ NM_VPN_PLUGIN_ERROR,
+ NM_VPN_PLUGIN_ERROR_FAILED,
+ _("failed to load nm_vpn_editor_factory() from %s (%s)"),
+ g_module_name (module), g_module_error ());
+ g_module_close (module);
+ }
+
+ return editor;
+}
+
+/**
* nm_vpn_editor_plugin_get_editor:
- * @plugin: the #NMVpnEditorPlugin
+ * @self: the #NMVpnEditorPlugin
* @connection: the #NMConnection to be edited
* @error: on return, an error or %NULL
*
* Returns: (transfer full): a new #NMVpnEditor or %NULL on error
*/
NMVpnEditor *
-nm_vpn_editor_plugin_get_editor (NMVpnEditorPlugin *plugin,
+nm_vpn_editor_plugin_get_editor (NMVpnEditorPlugin *self,
NMConnection *connection,
GError **error)
{
- g_return_val_if_fail (NM_IS_VPN_EDITOR_PLUGIN (plugin), NULL);
+ NMVpnEditorPluginInterface *interface;
+
+ g_return_val_if_fail (NM_IS_VPN_EDITOR_PLUGIN (self), NULL);
- return NM_VPN_EDITOR_PLUGIN_GET_INTERFACE (plugin)->get_editor (plugin, connection, error);
+ interface = NM_VPN_EDITOR_PLUGIN_GET_INTERFACE (self);
+ if (interface->get_editor)
+ return interface->get_editor (self, connection, error);
+
+ return nm_vpn_editor_plugin_get_editor_load (self,
+ NULL,
+ connection,
+ TRUE,
+ getuid (),
+ NULL,
+ NULL,
+ NULL,
+ error);
}
NMVpnEditorPluginCapability
diff --git a/libnm-core/nm-vpn-editor-plugin.h b/libnm-core/nm-vpn-editor-plugin.h
index ffddf72f34..51e43473a0 100644
--- a/libnm-core/nm-vpn-editor-plugin.h
+++ b/libnm-core/nm-vpn-editor-plugin.h
@@ -37,12 +37,32 @@ G_BEGIN_DECLS
typedef struct _NMVpnEditorPlugin NMVpnEditorPlugin;
typedef struct _NMVpnEditor NMVpnEditor;
+/**
+ * NMVpnEditorLoadData:
+ *
+ * Used to pass addtional arguments to the nm_vpn_editor_factory method
+ * of the library and nm_vpn_editor_plugin_get_editor_load(). Currently
+ * no values are defined. This structure is used for future extensions.
+ *
+ * Since: 1.4
+ **/
+typedef struct _NMVpnEditorLoadData NMVpnEditorLoadData;
+
/* Plugin's factory function that returns a GObject that implements
* NMVpnEditorPlugin.
*/
#ifndef __GI_SCANNER__
typedef NMVpnEditorPlugin * (*NMVpnEditorPluginFactory) (GError **error);
NMVpnEditorPlugin *nm_vpn_editor_plugin_factory (GError **error);
+
+typedef NMVpnEditor *(*NMVpnEditorFactory) (NMVpnEditorPlugin *editor_plugin,
+ NMConnection *connection,
+ NMVpnEditorLoadData *load_data,
+ GError **error);
+NMVpnEditor *nm_vpn_editor_factory (NMVpnEditorPlugin *editor_plugin,
+ NMConnection *connection,
+ NMVpnEditorLoadData *load_data,
+ GError **error);
#endif
@@ -85,6 +105,11 @@ typedef enum /*< flags >*/ {
* @g_iface: the parent interface
* @get_editor: returns an #NMVpnEditor, pre-filled with values from @connection
* if non-%NULL.
+ * This #NMVpnEditor is a GUI class and usually includes gtk dependencies. Newer
+ * VPN plugins allow to split the base VPN plugin from the GUI dependency. In this
+ * case they leave get_editor plugin unset and specify GNOME.editor-plugin path
+ * in the name file. In that case, nm_vpn_editor_plugin_get_editor() will load
+ * the module and return the editor plugin from there.
* @get_capabilities: returns a bitmask of capabilities.
* @import_from_file: Try to import a connection from the specified path. On
* success, return a partial #NMConnection object. On error, return %NULL and
@@ -131,6 +156,15 @@ void nm_vpn_editor_plugin_set_editor_library_path (NMVpnEditorPlugin *self,
NMVpnEditor *nm_vpn_editor_plugin_get_editor (NMVpnEditorPlugin *plugin,
NMConnection *connection,
GError **error);
+NMVpnEditor *nm_vpn_editor_plugin_get_editor_load (NMVpnEditorPlugin *self,
+ const char *editor_library_path,
+ NMConnection *connection,
+ gboolean do_file_checks,
+ int check_owner,
+ NMUtilsCheckFilePredicate check_file,
+ gpointer user_data,
+ NMVpnEditorLoadData *load_data,
+ GError **error);
NMVpnEditorPluginCapability nm_vpn_editor_plugin_get_capabilities (NMVpnEditorPlugin *plugin);
diff --git a/libnm/libnm.ver b/libnm/libnm.ver
index 1d5c125f6c..1f89a53b6b 100644
--- a/libnm/libnm.ver
+++ b/libnm/libnm.ver
@@ -1062,6 +1062,7 @@ global:
libnm_1_4_0 {
global:
nm_vpn_editor_plugin_get_editor_library_path;
+ nm_vpn_editor_plugin_get_editor_load;
nm_vpn_editor_plugin_load;
nm_vpn_editor_plugin_set_editor_library_path;
nm_vpn_plugin_info_get_auth_dialog;