From 7e41c15ace01e7bf940c8d355b8cb67fee223d3d Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 18 Apr 2016 17:11:49 +0200 Subject: [PATCH 1/6] shared: move nm_utils_ascii_str_to_bool() to shared/nm-shared-utils.h (cherry picked from commit 186787744c5678f60c054b1223a44e7890901f11) --- shared/nm-shared-utils.c | 34 ++++++++++++++++++++++++++++++++++ shared/nm-shared-utils.h | 3 +++ src/nm-config.c | 2 +- src/nm-core-utils.c | 34 ---------------------------------- src/nm-core-utils.h | 5 ----- 5 files changed, 38 insertions(+), 40 deletions(-) diff --git a/shared/nm-shared-utils.c b/shared/nm-shared-utils.c index 0ae54bdcf0..932b7432c3 100644 --- a/shared/nm-shared-utils.c +++ b/shared/nm-shared-utils.c @@ -102,6 +102,40 @@ _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 ma /*****************************************************************************/ +gint +_nm_utils_ascii_str_to_bool (const char *str, + gint default_value) +{ + gsize len; + char *s = NULL; + + if (!str) + return default_value; + + while (str[0] && g_ascii_isspace (str[0])) + str++; + + if (!str[0]) + return default_value; + + len = strlen (str); + if (g_ascii_isspace (str[len - 1])) { + s = g_strdup (str); + g_strchomp (s); + str = s; + } + + if (!g_ascii_strcasecmp (str, "true") || !g_ascii_strcasecmp (str, "yes") || !g_ascii_strcasecmp (str, "on") || !g_ascii_strcasecmp (str, "1")) + default_value = TRUE; + else if (!g_ascii_strcasecmp (str, "false") || !g_ascii_strcasecmp (str, "no") || !g_ascii_strcasecmp (str, "off") || !g_ascii_strcasecmp (str, "0")) + default_value = FALSE; + if (s) + g_free (s); + return default_value; +} + +/*****************************************************************************/ + G_DEFINE_QUARK (nm-utils-error-quark, nm_utils_error) void diff --git a/shared/nm-shared-utils.h b/shared/nm-shared-utils.h index f80c850c69..cfa8f994f7 100644 --- a/shared/nm-shared-utils.h +++ b/shared/nm-shared-utils.h @@ -26,6 +26,9 @@ gint64 _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback); +gint _nm_utils_ascii_str_to_bool (const char *str, + gint default_value); + /******************************************************************************/ /** diff --git a/src/nm-config.c b/src/nm-config.c index 58fd96cbf4..8bca6870e1 100644 --- a/src/nm-config.c +++ b/src/nm-config.c @@ -125,7 +125,7 @@ gint nm_config_parse_boolean (const char *str, gint default_value) { - return nm_utils_ascii_str_to_bool (str, default_value); + return _nm_utils_ascii_str_to_bool (str, default_value); } gint diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index 714aaa9279..bbe466545d 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -154,40 +154,6 @@ _nm_singleton_instance_register_destruction (GObject *instance) /*****************************************************************************/ -gint -nm_utils_ascii_str_to_bool (const char *str, - gint default_value) -{ - gsize len; - char *s = NULL; - - if (!str) - return default_value; - - while (str[0] && g_ascii_isspace (str[0])) - str++; - - if (!str[0]) - return default_value; - - len = strlen (str); - if (g_ascii_isspace (str[len - 1])) { - s = g_strdup (str); - g_strchomp (s); - str = s; - } - - if (!g_ascii_strcasecmp (str, "true") || !g_ascii_strcasecmp (str, "yes") || !g_ascii_strcasecmp (str, "on") || !g_ascii_strcasecmp (str, "1")) - default_value = TRUE; - else if (!g_ascii_strcasecmp (str, "false") || !g_ascii_strcasecmp (str, "no") || !g_ascii_strcasecmp (str, "off") || !g_ascii_strcasecmp (str, "0")) - default_value = FALSE; - if (s) - g_free (s); - return default_value; -} - -/*****************************************************************************/ - /* * nm_ethernet_address_is_valid: * @addr: pointer to a binary or ASCII Ethernet address diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index 280be04736..528288c34c 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -91,11 +91,6 @@ GETTER (void) \ /*****************************************************************************/ -gint nm_utils_ascii_str_to_bool (const char *str, - gint default_value); - -/*****************************************************************************/ - gboolean nm_ethernet_address_is_valid (gconstpointer addr, gssize len); in_addr_t nm_utils_ip4_address_clear_host_address (in_addr_t addr, guint8 plen); From f25a8fee7eebddddcbd439e981d1d6894484720f Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 18 Apr 2016 17:14:00 +0200 Subject: [PATCH 2/6] libnm/vpn: lookup nm_vpn_plugin_info_supports_multiple() from cached values Instead of looking into the keyfile, lookup the "supports-multiple-connections" setting in the "keys" hash. This has some behavioral difference: - g_key_file_get_boolean() first does g_key_file_get_value(), and then converts the string using the private g_key_file_parse_value_as_boolean() function -- which is case-sensitive, accepts "true|false|0|1" and considers only the text until the first whitespace. - now, we put g_key_file_get_string() into the cache "keys" and parse it with _nm_utils_ascii_str_to_bool(). The latter is case insensitive, allows also "yes|no|on|off", strips whitespaces. However, the difference is subtle and shouldn't matter. The point of this change is to free "keyfile" after construction. (cherry picked from commit 6878999ca388bc747e1a9546837f82929cb7575c) --- libnm-core/nm-vpn-plugin-info.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libnm-core/nm-vpn-plugin-info.c b/libnm-core/nm-vpn-plugin-info.c index 53278fcac8..430f9125ed 100644 --- a/libnm-core/nm-vpn-plugin-info.c +++ b/libnm-core/nm-vpn-plugin-info.c @@ -620,12 +620,12 @@ nm_vpn_plugin_info_get_program (NMVpnPluginInfo *self) gboolean nm_vpn_plugin_info_supports_multiple (NMVpnPluginInfo *self) { + const char *s; + g_return_val_if_fail (NM_IS_VPN_PLUGIN_INFO (self), FALSE); - return g_key_file_get_boolean (NM_VPN_PLUGIN_INFO_GET_PRIVATE (self)->keyfile, - NM_VPN_PLUGIN_INFO_KF_GROUP_CONNECTION, - "supports-multiple-connections", - NULL); + s = nm_vpn_plugin_info_lookup_property (self, NM_VPN_PLUGIN_INFO_KF_GROUP_CONNECTION, "supports-multiple-connections"); + return _nm_utils_ascii_str_to_bool (s, FALSE); } From dd28e792ee95dd428901ad98a02c210db23697a0 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 18 Apr 2016 17:19:02 +0200 Subject: [PATCH 3/6] libnm/vpn: clear internal "keyfile" from NMVpnPluginInfo The GKeyFile is no longer needed after constuction. All strings are copied over to the "keys" hash. (cherry picked from commit 4003edbbf91910d9da55e68381d5eb164ca9669c) --- libnm-core/nm-vpn-plugin-info.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libnm-core/nm-vpn-plugin-info.c b/libnm-core/nm-vpn-plugin-info.c index 430f9125ed..2e6275e341 100644 --- a/libnm-core/nm-vpn-plugin-info.c +++ b/libnm-core/nm-vpn-plugin-info.c @@ -877,15 +877,16 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error) for (j = 0; keys && keys[j]; j++) { char *s; - /* Lookup the value via get_string(). We want that behavior. - * You could still lookup the original values via g_key_file_get_value() - * based on priv->keyfile. */ + /* Lookup the value via get_string(). We want that behavior for all our + * values. */ s = g_key_file_get_string (priv->keyfile, groups[i], keys[j], NULL); if (s) g_hash_table_insert (priv->keys, _nm_utils_strstrdictkey_create (groups[i], keys[j]), s); } } + g_clear_pointer (&priv->keyfile, g_key_file_unref); + return TRUE; } @@ -948,9 +949,10 @@ finalize (GObject *object) g_free (priv->service); g_strfreev (priv->aliases); g_free (priv->filename); - g_key_file_unref (priv->keyfile); g_hash_table_unref (priv->keys); + g_clear_pointer (&priv->keyfile, g_key_file_unref); + G_OBJECT_CLASS (nm_vpn_plugin_info_parent_class)->finalize (object); } From e10f50400fbd8f6bb38a604e6ef704161778879e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 18 Apr 2016 17:59:56 +0200 Subject: [PATCH 4/6] libnm/vpn: fix code comment for nm_vpn_editor_plugin_load_from_file() The @plugin_filename argument must be an absolute path. That was changed later, but forgot to update the comment. Fixes: 3dfbbb227e82b47973f612b6b031d8d591727436 (cherry picked from commit cb22f025886ffdeca7dec3615e0e5cbb0fe2470b) --- libnm-core/nm-vpn-editor-plugin.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/libnm-core/nm-vpn-editor-plugin.c b/libnm-core/nm-vpn-editor-plugin.c index 5a1eed88dd..e1c2f450ef 100644 --- a/libnm-core/nm-vpn-editor-plugin.c +++ b/libnm-core/nm-vpn-editor-plugin.c @@ -74,11 +74,7 @@ nm_vpn_editor_plugin_default_init (NMVpnEditorPluginInterface *iface) /** * nm_vpn_editor_plugin_load_from_file: * @plugin_filename: The path to the share library to load. - * Apply some common heuristics to find the library, such as - * appending "so" file ending. - * If the path is not an absolute path or no matching module - * can be found, lookup inside a directory defined at compile time. - * Due to this, @check_file might be called for two different paths. + * The path must be an absolute filename to an existing file. * @check_service: if not-null, check that the loaded plugin advertises * the given service. * @check_owner: if non-negative, check whether the file is owned From 5bc6e22528c02ed68250c3c68ac87fd9df359f60 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 18 Apr 2016 18:19:04 +0200 Subject: [PATCH 5/6] libnm/vpn: allow specifying non-absolute plugin name in VPN .name file Since commit 3dfbbb227e82b47973f612b6b031d8d591727436, we enforce that the plugin path in the .name file is absolute and we perform several checks on the file before loading it (ownership, etc). Relax that, to also allow libray names without path component. In that case, g_module_open()/dlopen() will search for a library in various search paths. This allows, to omit absolute paths in the .name file. The latter is problematic, because by default we install the .name file in the architecture independent location /usr/lib/NetworkManager. As such, it should not contain paths to architecture dependent libraries. With this change, a .name file can contain only the library name and it will be loaded using the usual mechanism. However, specifying absolute paths is still possible and works same as before, including checking file permissions. As such, distributions probably should package the VPN plugins to have no path in the .name file. On the other hand, a user compiling from source probably wants to specify an absolute path. The reason is, that the user probably doesn't build the plugin for multiple achitectures and that way, he can install the plugin in a separate (private) prefix. (cherry picked from commit ca000cffbb9ef20c6dd965283df3f1babf0a7745) --- libnm-core/nm-core-internal.h | 9 +++ libnm-core/nm-vpn-editor-plugin.c | 104 ++++++++++++++++++++---------- libnm-core/nm-vpn-plugin-info.c | 13 ++-- 3 files changed, 87 insertions(+), 39 deletions(-) diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index 082ebc9e28..8d97b066ee 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -72,6 +72,7 @@ #include "nm-utils.h" #include "nm-vpn-dbus-interface.h" #include "nm-core-types-internal.h" +#include "nm-vpn-editor-plugin.h" /* NM_SETTING_COMPARE_FLAG_INFERRABLE: check whether a device-generated * connection can be replaced by a already-defined connection. This flag only @@ -245,6 +246,14 @@ GSList *_nm_vpn_plugin_info_list_load_dir (const char *dirname, NMUtilsCheckFilePredicate check_file, gpointer user_data); +NMVpnEditorPlugin * _nm_vpn_editor_plugin_load (const char *plugin_filename, + gboolean force_absolute_path, + const char *check_service, + int check_owner, + NMUtilsCheckFilePredicate check_file, + gpointer user_data, + GError **error); + /***********************************************************/ typedef struct { diff --git a/libnm-core/nm-vpn-editor-plugin.c b/libnm-core/nm-vpn-editor-plugin.c index e1c2f450ef..3257acc0c0 100644 --- a/libnm-core/nm-vpn-editor-plugin.c +++ b/libnm-core/nm-vpn-editor-plugin.c @@ -71,56 +71,55 @@ nm_vpn_editor_plugin_default_init (NMVpnEditorPluginInterface *iface) /*********************************************************************/ -/** - * nm_vpn_editor_plugin_load_from_file: - * @plugin_filename: The path to the share library to load. - * The path must be an absolute filename to an existing file. - * @check_service: if not-null, check that the loaded plugin advertises - * the given service. - * @check_owner: if non-negative, check whether the file is owned - * by UID @check_owner or by root. In this case also check that - * the file is not writable by anybody else. - * @check_file: (scope call): optional callback to validate the file prior to - * loading the shared library. - * @user_data: user data for @check_file - * @error: on failure the error reason. - * - * Load the shared libary @plugin_filename and create a new - * #NMVpnEditorPlugin instace via the #NMVpnEditorPluginFactory - * function. - * - * Returns: (transfer full): a new plugin instance or %NULL on error. - * - * Since: 1.2 - */ NMVpnEditorPlugin * -nm_vpn_editor_plugin_load_from_file (const char *plugin_filename, - const char *check_service, - int check_owner, - NMUtilsCheckFilePredicate check_file, - gpointer user_data, - GError **error) +_nm_vpn_editor_plugin_load (const char *plugin_filename, + gboolean force_absolute_filename, + const char *check_service, + int check_owner, + NMUtilsCheckFilePredicate check_file, + gpointer user_data, + GError **error) { GModule *module = NULL; gs_free_error GError *local = NULL; NMVpnEditorPluginFactory factory = NULL; NMVpnEditorPlugin *editor_plugin = NULL; + gboolean search_lib = FALSE; g_return_val_if_fail (plugin_filename && *plugin_filename, NULL); + if ( !force_absolute_filename + && !strchr (plugin_filename, '/') + && !g_str_has_suffix (plugin_filename, ".la")) { + /* we allow omitting the (absolute) path. + * + * If the @plugin_filename contains no '/', we skip any checks + * for the file and pass it directly to g_module_open()/dlopen(). + * One exception is that we don't allow for the "la" suffix. The + * reason is that g_module_open() interprets files with this extension + * special and we don't want that. */ + search_lib = TRUE; + } + /* _nm_utils_check_module_file() fails with ENOENT if the plugin file * does not exist. That is relevant, because nm-applet checks for that. */ - if (_nm_utils_check_module_file (plugin_filename, - check_owner, - check_file, - user_data, - &local)) + if ( search_lib + || _nm_utils_check_module_file (plugin_filename, + check_owner, + check_file, + user_data, + &local)) module = g_module_open (plugin_filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); if (!module) { if (local) { g_propagate_error (error, local); local = NULL; + } else if (search_lib) { + g_set_error (error, + G_FILE_ERROR, + G_FILE_ERROR_NOENT, + _("Plugin does not exist (%s)"), plugin_filename); } else { g_set_error (error, NM_VPN_PLUGIN_ERROR, @@ -197,6 +196,45 @@ nm_vpn_editor_plugin_load_from_file (const char *plugin_filename, return editor_plugin; } +/** + * nm_vpn_editor_plugin_load_from_file: + * @plugin_filename: The path to the shared library to load. + * The path must be an absolute filename to an existing file. + * @check_service: if not-null, check that the loaded plugin advertises + * the given service. + * @check_owner: if non-negative, check whether the file is owned + * by UID @check_owner or by root. In this case also check that + * the file is not writable by anybody else. + * @check_file: (scope call): optional callback to validate the file prior to + * loading the shared library. + * @user_data: user data for @check_file + * @error: on failure the error reason. + * + * Load the shared libary @plugin_filename and create a new + * #NMVpnEditorPlugin instace via the #NMVpnEditorPluginFactory + * function. + * + * Returns: (transfer full): a new plugin instance or %NULL on error. + * + * Since: 1.2 + */ +NMVpnEditorPlugin * +nm_vpn_editor_plugin_load_from_file (const char *plugin_filename, + const char *check_service, + int check_owner, + NMUtilsCheckFilePredicate check_file, + gpointer user_data, + GError **error) +{ + return _nm_vpn_editor_plugin_load (plugin_filename, + TRUE, + check_service, + check_owner, + check_file, + user_data, + error); +} + /*********************************************************************/ /** diff --git a/libnm-core/nm-vpn-plugin-info.c b/libnm-core/nm-vpn-plugin-info.c index 2e6275e341..6c77f3c142 100644 --- a/libnm-core/nm-vpn-plugin-info.c +++ b/libnm-core/nm-vpn-plugin-info.c @@ -752,12 +752,13 @@ nm_vpn_plugin_info_load_editor_plugin (NMVpnPluginInfo *self, GError **error) } priv->editor_plugin_loaded = TRUE; - priv->editor_plugin = nm_vpn_editor_plugin_load_from_file (plugin_filename, - priv->service, - getuid (), - NULL, - NULL, - error); + priv->editor_plugin = _nm_vpn_editor_plugin_load (plugin_filename, + FALSE, + priv->service, + getuid (), + NULL, + NULL, + error); return priv->editor_plugin; } From 2fb5aaecef56df2ccd8c0daee34222e4d8966f9b Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 19 Apr 2016 14:39:33 +0200 Subject: [PATCH 6/6] libnm/vpn: search VPN plugin in NMPLUGINDIR In commit ca000cffbb9ef20c6dd965283df3f1babf0a7745, we changed to accept a plugin library name without path. One reason for that is to keep architecture dependent parts out of the .name file and possibly support multilib. However, the shared libraries of VPN plugins are not installed in a global library search path, but for example into "/usr/lib64/NetworkManager/libnm-vpn-plugin-openvpn.so". In that case, specifying "plugin=libnm-vpn-plugin-openvpn.so" would not be enough to find plugin. Instead, when configuring a plugin name without path, assume it is in NMPLUGINDIR directory. Modify nm_vpn_editor_plugin_load_from_file() to allow path-less plugin-names. Previously such names would be rejected as not being absolute. This API allows to do file verification before loading the plugin, but it now supports prepending NMPLUGINDIR to the plugin name. Basically, this function mangles the plugin_name argument and checks that such a file exists. The recently added nm_vpn_editor_plugin_load() continues to behave as before: it does no checks whatsoever and passes the name directly to dlopen(). That way, it uses system search paths like LD_LIBRARY_PATH and performs no checks on the file. Fixes: ca000cffbb9ef20c6dd965283df3f1babf0a7745 (cherry picked from commit 0b128aeced540d98dd4fdea2598dbf1a6c47c6ad) --- libnm-core/Makefile.am | 1 + libnm-core/nm-core-internal.h | 8 --- libnm-core/nm-vpn-editor-plugin.c | 98 ++++++++++++++++--------------- libnm-core/nm-vpn-editor-plugin.h | 2 +- libnm-core/nm-vpn-plugin-info.c | 13 ++-- 5 files changed, 58 insertions(+), 64 deletions(-) diff --git a/libnm-core/Makefile.am b/libnm-core/Makefile.am index 23aa042d44..58dc204b76 100644 --- a/libnm-core/Makefile.am +++ b/libnm-core/Makefile.am @@ -11,6 +11,7 @@ AM_CPPFLAGS = \ -DLOCALEDIR=\"$(datadir)/locale\" \ -DNMCONFDIR=\"$(nmconfdir)\" \ -DNMLIBDIR=\"$(nmlibdir)\" \ + -DNMPLUGINDIR=\"$(pkglibdir)\" \ -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_LIB \ $(GLIB_CFLAGS) \ $(CODE_COVERAGE_CFLAGS) diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index 8d97b066ee..2041a1d3a1 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -246,14 +246,6 @@ GSList *_nm_vpn_plugin_info_list_load_dir (const char *dirname, NMUtilsCheckFilePredicate check_file, gpointer user_data); -NMVpnEditorPlugin * _nm_vpn_editor_plugin_load (const char *plugin_filename, - gboolean force_absolute_path, - const char *check_service, - int check_owner, - NMUtilsCheckFilePredicate check_file, - gpointer user_data, - GError **error); - /***********************************************************/ typedef struct { diff --git a/libnm-core/nm-vpn-editor-plugin.c b/libnm-core/nm-vpn-editor-plugin.c index 3257acc0c0..a49c3957eb 100644 --- a/libnm-core/nm-vpn-editor-plugin.c +++ b/libnm-core/nm-vpn-editor-plugin.c @@ -71,9 +71,9 @@ nm_vpn_editor_plugin_default_init (NMVpnEditorPluginInterface *iface) /*********************************************************************/ -NMVpnEditorPlugin * -_nm_vpn_editor_plugin_load (const char *plugin_filename, - gboolean force_absolute_filename, +static NMVpnEditorPlugin * +_nm_vpn_editor_plugin_load (const char *plugin_name, + gboolean do_file_checks, const char *check_service, int check_owner, NMUtilsCheckFilePredicate check_file, @@ -81,54 +81,49 @@ _nm_vpn_editor_plugin_load (const char *plugin_filename, GError **error) { GModule *module = NULL; - gs_free_error GError *local = NULL; NMVpnEditorPluginFactory factory = NULL; NMVpnEditorPlugin *editor_plugin = NULL; - gboolean search_lib = FALSE; + gs_free char *plugin_filename_free = NULL; + const char *plugin_filename; - g_return_val_if_fail (plugin_filename && *plugin_filename, NULL); + g_return_val_if_fail (plugin_name && *plugin_name, NULL); - if ( !force_absolute_filename - && !strchr (plugin_filename, '/') - && !g_str_has_suffix (plugin_filename, ".la")) { - /* we allow omitting the (absolute) path. - * - * If the @plugin_filename contains no '/', we skip any checks - * for the file and pass it directly to g_module_open()/dlopen(). - * One exception is that we don't allow for the "la" suffix. The - * reason is that g_module_open() interprets files with this extension - * special and we don't want that. */ - search_lib = TRUE; + /* if @do_file_checks is FALSE, we pass plugin_name directly to + * g_module_open(). + * + * Otherwise, we allow for library names without path component. + * In which case, we prepend the plugin directory and form an + * absolute path. In that case, we perform checks on the file. + * + * One exception is that we don't allow for the "la" suffix. The + * reason is that g_module_open() interprets files with this extension + * special and we don't want that. */ + plugin_filename = plugin_name; + if (do_file_checks) { + if ( !strchr (plugin_name, '/') + && !g_str_has_suffix (plugin_name, ".la")) { + plugin_filename_free = g_module_build_path (NMPLUGINDIR, plugin_name); + plugin_filename = plugin_filename_free; + } + + /* _nm_utils_check_module_file() fails with ENOENT if the plugin file + * does not exist. That is relevant, because nm-applet checks for that. */ + if (!_nm_utils_check_module_file (plugin_filename, + check_owner, + check_file, + user_data, + error)) + return NULL; } - /* _nm_utils_check_module_file() fails with ENOENT if the plugin file - * does not exist. That is relevant, because nm-applet checks for that. */ - if ( search_lib - || _nm_utils_check_module_file (plugin_filename, - check_owner, - check_file, - user_data, - &local)) - module = g_module_open (plugin_filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); - + module = g_module_open (plugin_filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); if (!module) { - if (local) { - g_propagate_error (error, local); - local = NULL; - } else if (search_lib) { - g_set_error (error, - G_FILE_ERROR, - G_FILE_ERROR_NOENT, - _("Plugin does not exist (%s)"), plugin_filename); - } else { - g_set_error (error, - NM_VPN_PLUGIN_ERROR, - NM_VPN_PLUGIN_ERROR_FAILED, - _("cannot load plugin %s"), plugin_filename); - } + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("cannot load plugin %s"), plugin_name); return NULL; } - g_clear_error (&local); if (g_module_symbol (module, "nm_vpn_editor_plugin_factory", (gpointer) &factory)) { gs_free_error GError *factory_error = NULL; @@ -175,7 +170,7 @@ _nm_vpn_editor_plugin_load (const char *plugin_filename, g_set_error (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_FAILED, - _("unknown error initializing plugin %s"), plugin_filename); + _("unknown error initializing plugin %s"), plugin_name); } } @@ -198,8 +193,10 @@ _nm_vpn_editor_plugin_load (const char *plugin_filename, /** * nm_vpn_editor_plugin_load_from_file: - * @plugin_filename: The path to the shared library to load. - * The path must be an absolute filename to an existing file. + * @plugin_name: The path or name of the shared library to load. + * The path must either be an absolute filename to an existing file. + * Alternatively, it can be the name (without path) of a library in the + * plugin directory of NetworkManager. * @check_service: if not-null, check that the loaded plugin advertises * the given service. * @check_owner: if non-negative, check whether the file is owned @@ -210,23 +207,28 @@ _nm_vpn_editor_plugin_load (const char *plugin_filename, * @user_data: user data for @check_file * @error: on failure the error reason. * - * Load the shared libary @plugin_filename and create a new + * Load the shared libary @plugin_name and create a new * #NMVpnEditorPlugin instace via the #NMVpnEditorPluginFactory * function. * + * If @plugin_name is not an absolute path name, it assumes the file + * is in the plugin directory of NetworkManager. In any case, the call + * will do certain checks on the file before passing it to dlopen. + * A consequence for that is, that you cannot omit the ".so" suffix. + * * Returns: (transfer full): a new plugin instance or %NULL on error. * * Since: 1.2 */ NMVpnEditorPlugin * -nm_vpn_editor_plugin_load_from_file (const char *plugin_filename, +nm_vpn_editor_plugin_load_from_file (const char *plugin_name, const char *check_service, int check_owner, NMUtilsCheckFilePredicate check_file, gpointer user_data, GError **error) { - return _nm_vpn_editor_plugin_load (plugin_filename, + return _nm_vpn_editor_plugin_load (plugin_name, TRUE, check_service, check_owner, diff --git a/libnm-core/nm-vpn-editor-plugin.h b/libnm-core/nm-vpn-editor-plugin.h index 16e9533d23..9ff23a8134 100644 --- a/libnm-core/nm-vpn-editor-plugin.h +++ b/libnm-core/nm-vpn-editor-plugin.h @@ -140,7 +140,7 @@ char *nm_vpn_editor_plugin_get_suggested_filename (NMVpnEditorPlugin *pl NMConnection *connection); NM_AVAILABLE_IN_1_2 -NMVpnEditorPlugin *nm_vpn_editor_plugin_load_from_file (const char *plugin_filename, +NMVpnEditorPlugin *nm_vpn_editor_plugin_load_from_file (const char *plugin_name, const char *check_service, int check_owner, NMUtilsCheckFilePredicate check_file, diff --git a/libnm-core/nm-vpn-plugin-info.c b/libnm-core/nm-vpn-plugin-info.c index 6c77f3c142..2e6275e341 100644 --- a/libnm-core/nm-vpn-plugin-info.c +++ b/libnm-core/nm-vpn-plugin-info.c @@ -752,13 +752,12 @@ nm_vpn_plugin_info_load_editor_plugin (NMVpnPluginInfo *self, GError **error) } priv->editor_plugin_loaded = TRUE; - priv->editor_plugin = _nm_vpn_editor_plugin_load (plugin_filename, - FALSE, - priv->service, - getuid (), - NULL, - NULL, - error); + priv->editor_plugin = nm_vpn_editor_plugin_load_from_file (plugin_filename, + priv->service, + getuid (), + NULL, + NULL, + error); return priv->editor_plugin; }