libnm: add nm_vpn_editor_plugin_load_from_file() function
authorThomas Haller <thaller@redhat.com>
Thu, 28 May 2015 20:16:00 +0000 (22:16 +0200)
committerThomas Haller <thaller@redhat.com>
Wed, 29 Jul 2015 20:34:35 +0000 (22:34 +0200)
libnm-core/nm-vpn-editor-plugin.c
libnm-core/nm-vpn-editor-plugin.h
libnm/libnm.ver
po/POTFILES.in

index b36b736..d5fa6d8 100644 (file)
 
 #include "nm-vpn-editor-plugin.h"
 
+#include <gio/gio.h>
+#include <glib/gi18n-lib.h>
+
+#include "nm-macros-internal.h"
+#include "gsystem-local-alloc.h"
+#include "nm-core-internal.h"
+
 static void nm_vpn_editor_plugin_default_init (NMVpnEditorPluginInterface *iface);
 
 G_DEFINE_INTERFACE (NMVpnEditorPlugin, nm_vpn_editor_plugin, G_TYPE_OBJECT)
@@ -67,6 +74,146 @@ nm_vpn_editor_plugin_default_init (NMVpnEditorPluginInterface *iface)
                                      G_PARAM_STATIC_STRINGS));
 }
 
+/*********************************************************************/
+
+/**
+ * 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.
+ * @check_name: if not-null, check that the loaded plugin has
+ *  the given name.
+ * @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: 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_name,
+                                      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;
+
+       g_return_val_if_fail (plugin_filename && *plugin_filename, NULL);
+
+       if (g_path_is_absolute (plugin_filename)) {
+               gs_free char *module_filename = NULL;
+
+               module_filename = _nm_utils_check_module_file (plugin_filename,
+                                                              check_owner,
+                                                              check_file,
+                                                              user_data,
+                                                              &local);
+               if (module_filename)
+                       module = g_module_open (module_filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
+       }
+
+       if (!module) {
+               if (local) {
+                       g_propagate_error (error, local);
+                       local = NULL;
+               } else {
+                       g_set_error (error,
+                                    NM_VPN_PLUGIN_ERROR,
+                                    NM_VPN_PLUGIN_ERROR_FAILED,
+                                    _("cannot load plugin %s"), plugin_filename);
+               }
+               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;
+               gboolean success = FALSE;
+
+               editor_plugin = factory (&factory_error);
+
+               g_assert (!editor_plugin || G_IS_OBJECT (editor_plugin));
+
+               if (editor_plugin) {
+                       gs_free char *plug_name = NULL, *plug_service = NULL;
+
+                       /* Validate plugin properties */
+
+                       g_object_get (G_OBJECT (editor_plugin),
+                                     NM_VPN_EDITOR_PLUGIN_NAME, &plug_name,
+                                     NM_VPN_EDITOR_PLUGIN_SERVICE, &plug_service,
+                                     NULL);
+
+                       if (check_name && g_strcmp0 (plug_name, check_name) != 0) {
+                               g_set_error (error,
+                                            NM_VPN_PLUGIN_ERROR,
+                                            NM_VPN_PLUGIN_ERROR_FAILED,
+                                            _("cannot load VPN plugin in '%s': invalid plugin name"),
+                                            g_module_name (module));
+                       } else if (   check_service
+                                  && g_strcmp0 (plug_service, check_service) != 0) {
+                               g_set_error (error,
+                                            NM_VPN_PLUGIN_ERROR,
+                                            NM_VPN_PLUGIN_ERROR_FAILED,
+                                            _("cannot load VPN plugin in '%s': invalid service name"),
+                                            g_module_name (module));
+                       } else {
+                               /* Success! */
+                               g_object_set_data_full (G_OBJECT (editor_plugin), "gmodule", module,
+                                                       (GDestroyNotify) g_module_close);
+                               success = TRUE;
+                       }
+               } 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 plugin %s"), plugin_filename);
+                       }
+               }
+
+               if (!success) {
+                       g_module_close (module);
+                       editor_plugin = NULL;
+               }
+       } else {
+               g_set_error (error,
+                            NM_VPN_PLUGIN_ERROR,
+                            NM_VPN_PLUGIN_ERROR_FAILED,
+                            _("failed to load nm_vpn_editor_plugin_factory() from %s (%s)"),
+                            g_module_name (module), g_module_error ());
+               g_module_close (module);
+               editor_plugin = NULL;
+       }
+
+       return editor_plugin;
+}
+
+/*********************************************************************/
+
 /**
  * nm_vpn_editor_plugin_get_editor:
  *
index a0b1f7a..83d765d 100644 (file)
@@ -30,6 +30,7 @@
 #include <glib-object.h>
 
 #include "nm-connection.h"
+#include "nm-utils.h"
 
 G_BEGIN_DECLS
 
@@ -138,6 +139,15 @@ gboolean      nm_vpn_editor_plugin_export                 (NMVpnEditorPlugin *pl
 char         *nm_vpn_editor_plugin_get_suggested_filename (NMVpnEditorPlugin *plugin,
                                                            NMConnection *connection);
 
+NM_AVAILABLE_IN_1_2
+NMVpnEditorPlugin *nm_vpn_editor_plugin_load_from_file  (const char *plugin_filename,
+                                                         const char *check_name,
+                                                         const char *check_service,
+                                                         int check_owner,
+                                                         NMUtilsCheckFilePredicate check_file,
+                                                         gpointer user_data,
+                                                         GError **error);
+
 G_END_DECLS
 
 #endif /* __NM_VPN_EDITOR_PLUGIN_H__ */
index 885e063..4368419 100644 (file)
@@ -882,6 +882,7 @@ global:
        nm_utils_bond_mode_string_to_int;
        nm_utils_enum_from_str;
        nm_utils_enum_to_str;
+       nm_vpn_editor_plugin_load_from_file;
        nm_vpn_plugin_info_get_filename;
        nm_vpn_plugin_info_get_name;
        nm_vpn_plugin_info_get_plugin;
index 4b11710..7b2c37a 100644 (file)
@@ -77,6 +77,7 @@ libnm-core/nm-setting-wireless-security.c
 libnm-core/nm-setting-wireless.c
 libnm-core/nm-setting.c
 libnm-core/nm-utils.c
+libnm-core/nm-vpn-editor-plugin.c
 libnm-core/nm-vpn-plugin-info.c
 libnm-glib/nm-device.c
 libnm-glib/nm-remote-connection.c