diff --git a/po/POTFILES.skip b/po/POTFILES.skip index 7bf60bea5..1d7880e80 100644 --- a/po/POTFILES.skip +++ b/po/POTFILES.skip @@ -7,5 +7,6 @@ vpn-daemons/pptp vpn-daemons/vpnc contrib/fedora/rpm/ shared/nm-utils/nm-vpn-editor-plugin-call.h +shared/nm-utils/nm-vpn-plugin-utils.c # https://bugs.launchpad.net/intltool/+bug/1117944 sub/policy/org.freedesktop.NetworkManager.policy.in diff --git a/shared/Makefile.am b/shared/Makefile.am index 41df29a32..be2f777ee 100644 --- a/shared/Makefile.am +++ b/shared/Makefile.am @@ -6,6 +6,8 @@ EXTRA_DIST = \ nm-utils/nm-shared-utils.h \ nm-utils/nm-test-utils.h \ nm-utils/nm-vpn-editor-plugin-call.h \ + nm-utils/nm-vpn-plugin-utils.c \ + nm-utils/nm-vpn-plugin-utils.h \ nm-common-macros.h \ nm-dbus-compat.h \ nm-default.h \ diff --git a/shared/nm-utils/nm-vpn-plugin-utils.c b/shared/nm-utils/nm-vpn-plugin-utils.c new file mode 100644 index 000000000..772aa39ae --- /dev/null +++ b/shared/nm-utils/nm-vpn-plugin-utils.c @@ -0,0 +1,130 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2016 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-vpn-plugin-utils.h" + +#include + +/*****************************************************************************/ + +NMVpnEditor * +nm_vpn_plugin_utils_load_editor (const char *module_name, + const char *factory_name, + NMVpnPluginUtilsEditorFactory editor_factory, + NMVpnEditorPlugin *editor_plugin, + NMConnection *connection, + gpointer user_data, + GError **error) + +{ + static struct { + gpointer factory; + void *dl_module; + char *module_name; + char *factory_name; + } cached = { 0 }; + NMVpnEditor *editor; + + g_return_val_if_fail (module_name && g_path_is_absolute (module_name), NULL); + g_return_val_if_fail (factory_name && factory_name[0], NULL); + g_return_val_if_fail (editor_factory, NULL); + g_return_val_if_fail (NM_IS_VPN_EDITOR_PLUGIN (editor_plugin), NULL); + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + g_return_val_if_fail (!error || !*error, NULL); + + /* we really expect this function to be called with unchanging @module_name + * and @factory_name. And we only want to load the module once, hence it would + * be more complicated to accept changing @module_name/@factory_name arguments. + * + * The reason for only loading once is that due to glib types, we cannot create a + * certain type-name more then once, so loading the same module or another version + * of the same module will fail horribly as both try to create a GType with the same + * name. + * + * Only support loading once, any future calls will reuse the handle. To simplify + * that, we enforce that the @factory_name and @module_name is the same. */ + if (cached.factory) { + g_return_val_if_fail (cached.dl_module, NULL); + g_return_val_if_fail (cached.factory_name && nm_streq0 (cached.factory_name, factory_name), NULL); + g_return_val_if_fail (cached.module_name && nm_streq0 (cached.module_name, module_name), NULL); + } else { + gpointer factory; + void *dl_module; + + dl_module = dlopen (module_name, RTLD_LAZY | RTLD_LOCAL); + if (!dl_module) { + if (!g_file_test (module_name, G_FILE_TEST_EXISTS)) { + g_set_error (error, + G_FILE_ERROR, + G_FILE_ERROR_NOENT, + _("missing plugin file \"%s\""), module_name); + return NULL; + } + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + _("cannot load editor plugin: %s"), dlerror ()); + return NULL; + } + + factory = dlsym (dl_module, factory_name); + if (!factory) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + _("cannot load factory %s from plugin: %s"), + factory_name, dlerror ()); + dlclose (dl_module); + return NULL; + } + + /* we cannot ever unload the module because it creates glib types, which + * cannot be unregistered. + * + * Thus we just leak the dl_module handle indefinitely. */ + cached.factory = factory; + cached.dl_module = dl_module; + cached.module_name = g_strdup (module_name); + cached.factory_name = g_strdup (factory_name); + } + + editor = editor_factory (cached.factory, + editor_plugin, + connection, + user_data, + error); + if (!editor) { + if (error && !*error ) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + _("unknown error creating editor instance")); + g_return_val_if_reached (NULL); + } + return NULL; + } + + g_return_val_if_fail (NM_IS_VPN_EDITOR (editor), NULL); + return editor; +} + diff --git a/shared/nm-utils/nm-vpn-plugin-utils.h b/shared/nm-utils/nm-vpn-plugin-utils.h new file mode 100644 index 000000000..f3928d1eb --- /dev/null +++ b/shared/nm-utils/nm-vpn-plugin-utils.h @@ -0,0 +1,42 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2016 Red Hat, Inc. + */ + +#ifndef __NM_VPN_PLUGIN_UTILS_H__ +#define __NM_VPN_PLUGIN_UTILS_H__ + +#include + +typedef NMVpnEditor *(NMVpnPluginUtilsEditorFactory) (gpointer factory, + NMVpnEditorPlugin *editor_plugin, + NMConnection *connection, + gpointer user_data, + GError **error); + +NMVpnEditor *nm_vpn_plugin_utils_load_editor (const char *module_name, + const char *factory_name, + NMVpnPluginUtilsEditorFactory editor_factory, + NMVpnEditorPlugin *editor_plugin, + NMConnection *connection, + gpointer user_data, + GError **error); + +#endif /* __NM_VPN_PLUGIN_UTILS_H__ */ +