diff options
author | Thomas Haller <thaller@redhat.com> | 2016-04-28 15:43:58 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2016-04-28 22:42:27 +0200 |
commit | d70533498b15a73e65064564ececd2ae1dfeef40 (patch) | |
tree | 71181020e8c87d6bd295cd27284f61b29e838405 | |
parent | 46c4b94a00bed5d1d74541708b8f08978e09b248 (diff) | |
download | NetworkManager-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.c | 139 | ||||
-rw-r--r-- | libnm-core/nm-vpn-editor-plugin.h | 34 | ||||
-rw-r--r-- | libnm/libnm.ver | 1 |
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; |