123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425 |
- /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
- /*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program 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
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * Copyright 2013 Red Hat, Inc.
- */
- /**
- * SECTION:vpn-helpers
- * @short_description: VPN-related utilities
- *
- * This is copied directly from libnm-gtk and should probably
- * eventually move into libnm-glib.
- *
- * It is also currently unused in nmtui.
- *
- * FIXME.
- */
- #include <string.h>
- #include <glib.h>
- #include <gmodule.h>
- #include <glib/gi18n.h>
- #include <nm-connection.h>
- #include <nm-setting-connection.h>
- #include <nm-setting-vpn.h>
- #include "vpn-helpers.h"
- #define NM_VPN_API_SUBJECT_TO_CHANGE
- #include "nm-vpn-plugin-ui-interface.h"
- #define VPN_NAME_FILES_DIR SYSCONFDIR"/NetworkManager/VPN"
- static GHashTable *plugins = NULL;
- G_DEFINE_QUARK (NMA_ERROR, nma_error)
- #define NMA_ERROR nma_error_quark ()
- #define NMA_ERROR_GENERIC 0
- NMVpnPluginUiInterface *
- vpn_get_plugin_by_service (const char *service)
- {
- g_return_val_if_fail (service != NULL, NULL);
- return g_hash_table_lookup (plugins, service);
- }
- GHashTable *
- vpn_get_plugins (GError **error)
- {
- GDir *dir;
- const char *f;
- if (error)
- g_return_val_if_fail (*error == NULL, NULL);
- if (plugins)
- return plugins;
- dir = g_dir_open (VPN_NAME_FILES_DIR, 0, NULL);
- if (!dir) {
- g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, "Couldn't read VPN .name files directory " VPN_NAME_FILES_DIR ".");
- return NULL;
- }
- plugins = g_hash_table_new_full (g_str_hash, g_str_equal,
- (GDestroyNotify) g_free, (GDestroyNotify) g_object_unref);
- while ((f = g_dir_read_name (dir))) {
- char *path = NULL, *service = NULL;
- char *so_path = NULL, *so_name = NULL;
- GKeyFile *keyfile = NULL;
- GModule *module;
- NMVpnPluginUiFactory factory = NULL;
- if (!g_str_has_suffix (f, ".name"))
- continue;
- path = g_strdup_printf ("%s/%s", VPN_NAME_FILES_DIR, f);
- keyfile = g_key_file_new ();
- if (!g_key_file_load_from_file (keyfile, path, 0, NULL))
- goto next;
- service = g_key_file_get_string (keyfile, "VPN Connection", "service", NULL);
- if (!service)
- goto next;
- so_path = g_key_file_get_string (keyfile, "GNOME", "properties", NULL);
- if (!so_path)
- goto next;
- /* Remove any path and extension components, then reconstruct path
- * to the SO in LIBDIR
- */
- so_name = g_path_get_basename (so_path);
- g_free (so_path);
- so_path = g_strdup_printf ("%s/NetworkManager/%s", LIBDIR, so_name);
- g_free (so_name);
- module = g_module_open (so_path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
- if (!module) {
- g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, "Cannot load the VPN plugin which provides the "
- "service '%s'.", service);
- goto next;
- }
- if (g_module_symbol (module, "nm_vpn_plugin_ui_factory", (gpointer) &factory)) {
- NMVpnPluginUiInterface *plugin;
- GError *factory_error = NULL;
- gboolean success = FALSE;
- plugin = factory (&factory_error);
- if (plugin) {
- char *plug_name = NULL, *plug_service = NULL;
- /* Validate plugin properties */
- g_object_get (G_OBJECT (plugin),
- NM_VPN_PLUGIN_UI_INTERFACE_NAME, &plug_name,
- NM_VPN_PLUGIN_UI_INTERFACE_SERVICE, &plug_service,
- NULL);
- if (!plug_name || !strlen (plug_name)) {
- g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, "cannot load VPN plugin in '%s': missing plugin name",
- g_module_name (module));
- } else if (!plug_service || strcmp (plug_service, service)) {
- g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, "cannot load VPN plugin in '%s': invalid service name",
- g_module_name (module));
- } else {
- /* Success! */
- g_object_set_data_full (G_OBJECT (plugin), "gmodule", module,
- (GDestroyNotify) g_module_close);
- g_hash_table_insert (plugins, g_strdup (service), plugin);
- success = TRUE;
- }
- g_free (plug_name);
- g_free (plug_service);
- } else {
- g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, "cannot load VPN plugin in '%s': %s",
- g_module_name (module), g_module_error ());
- }
- if (!success)
- g_module_close (module);
- } else {
- g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, "cannot locate nm_vpn_plugin_ui_factory() in '%s': %s",
- g_module_name (module), g_module_error ());
- g_module_close (module);
- }
- next:
- g_free (so_path);
- g_free (service);
- g_key_file_free (keyfile);
- g_free (path);
- }
- g_dir_close (dir);
- return plugins;
- }
- #if 0
- typedef struct {
- VpnImportSuccessCallback callback;
- gpointer user_data;
- } ActionInfo;
- static void
- import_vpn_from_file_cb (GtkWidget *dialog, gint response, gpointer user_data)
- {
- char *filename = NULL;
- ActionInfo *info = (ActionInfo *) user_data;
- GHashTableIter iter;
- gpointer key;
- NMVpnPluginUiInterface *plugin;
- NMConnection *connection = NULL;
- GError *error = NULL;
- if (response != GTK_RESPONSE_ACCEPT)
- goto out;
- filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
- if (!filename) {
- g_warning ("%s: didn't get a filename back from the chooser!", __func__);
- goto out;
- }
- g_hash_table_iter_init (&iter, plugins);
- while (!connection && g_hash_table_iter_next (&iter, &key, (gpointer *)&plugin)) {
- g_clear_error (&error);
- connection = nm_vpn_plugin_ui_interface_import (plugin, filename, &error);
- }
- if (connection)
- info->callback (connection, info->user_data);
- else {
- GtkWidget *err_dialog;
- char *bname = g_path_get_basename (filename);
- err_dialog = gtk_message_dialog_new (NULL,
- GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_ERROR,
- GTK_BUTTONS_OK,
- _("Cannot import VPN connection"));
- gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (err_dialog),
- _("The file '%s' could not be read or does not contain recognized VPN connection information\n\nError: %s."),
- bname, error ? error->message : "unknown error");
- g_free (bname);
- g_signal_connect (err_dialog, "delete-event", G_CALLBACK (gtk_widget_destroy), NULL);
- g_signal_connect (err_dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
- gtk_widget_show_all (err_dialog);
- gtk_window_present (GTK_WINDOW (err_dialog));
- }
- g_clear_error (&error);
- g_free (filename);
- out:
- gtk_widget_hide (dialog);
- gtk_widget_destroy (dialog);
- g_free (info);
- }
- static void
- destroy_import_chooser (GtkWidget *dialog, gpointer user_data)
- {
- g_free (user_data);
- gtk_widget_destroy (dialog);
- }
- void
- vpn_import (VpnImportSuccessCallback callback, gpointer user_data)
- {
- GtkWidget *dialog;
- ActionInfo *info;
- const char *home_folder;
- dialog = gtk_file_chooser_dialog_new (_("Select file to import"),
- NULL,
- GTK_FILE_CHOOSER_ACTION_OPEN,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
- NULL);
- home_folder = g_get_home_dir ();
- gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), home_folder);
- info = g_malloc0 (sizeof (ActionInfo));
- info->callback = callback;
- info->user_data = user_data;
- g_signal_connect (G_OBJECT (dialog), "close", G_CALLBACK (destroy_import_chooser), info);
- g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (import_vpn_from_file_cb), info);
- gtk_widget_show_all (dialog);
- gtk_window_present (GTK_WINDOW (dialog));
- }
- static void
- export_vpn_to_file_cb (GtkWidget *dialog, gint response, gpointer user_data)
- {
- NMConnection *connection = NM_CONNECTION (user_data);
- char *filename = NULL;
- GError *error = NULL;
- NMVpnPluginUiInterface *plugin;
- NMSettingConnection *s_con = NULL;
- NMSettingVPN *s_vpn = NULL;
- const char *service_type;
- const char *id = NULL;
- gboolean success = FALSE;
- if (response != GTK_RESPONSE_ACCEPT)
- goto out;
- filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
- if (!filename) {
- g_set_error (&error, NMA_ERROR, NMA_ERROR_GENERIC, "no filename");
- goto done;
- }
- if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
- int replace_response;
- GtkWidget *replace_dialog;
- char *bname;
- bname = g_path_get_basename (filename);
- replace_dialog = gtk_message_dialog_new (NULL,
- GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_QUESTION,
- GTK_BUTTONS_CANCEL,
- _("A file named \"%s\" already exists."),
- bname);
- gtk_dialog_add_buttons (GTK_DIALOG (replace_dialog), _("_Replace"), GTK_RESPONSE_OK, NULL);
- gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (replace_dialog),
- _("Do you want to replace %s with the VPN connection you are saving?"), bname);
- g_free (bname);
- replace_response = gtk_dialog_run (GTK_DIALOG (replace_dialog));
- gtk_widget_destroy (replace_dialog);
- if (replace_response != GTK_RESPONSE_OK)
- goto out;
- }
- s_con = nm_connection_get_setting_connection (connection);
- id = s_con ? nm_setting_connection_get_id (s_con) : NULL;
- if (!id) {
- g_set_error (&error, NMA_ERROR, NMA_ERROR_GENERIC, "connection setting invalid");
- goto done;
- }
- s_vpn = nm_connection_get_setting_vpn (connection);
- service_type = s_vpn ? nm_setting_vpn_get_service_type (s_vpn) : NULL;
- if (!service_type) {
- g_set_error (&error, NMA_ERROR, NMA_ERROR_GENERIC, "VPN setting invalid");
- goto done;
- }
- plugin = vpn_get_plugin_by_service (service_type);
- if (plugin)
- success = nm_vpn_plugin_ui_interface_export (plugin, filename, connection, &error);
- done:
- if (!success) {
- GtkWidget *err_dialog;
- char *bname = filename ? g_path_get_basename (filename) : g_strdup ("(none)");
- err_dialog = gtk_message_dialog_new (NULL,
- GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_ERROR,
- GTK_BUTTONS_OK,
- _("Cannot export VPN connection"));
- gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (err_dialog),
- _("The VPN connection '%s' could not be exported to %s.\n\nError: %s."),
- id ? id : "(unknown)", bname, error ? error->message : "unknown error");
- g_free (bname);
- g_signal_connect (err_dialog, "delete-event", G_CALLBACK (gtk_widget_destroy), NULL);
- g_signal_connect (err_dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
- gtk_widget_show_all (err_dialog);
- gtk_window_present (GTK_WINDOW (err_dialog));
- }
- out:
- if (error)
- g_error_free (error);
- g_object_unref (connection);
- gtk_widget_hide (dialog);
- gtk_widget_destroy (dialog);
- }
- void
- vpn_export (NMConnection *connection)
- {
- GtkWidget *dialog;
- NMVpnPluginUiInterface *plugin;
- NMSettingVPN *s_vpn = NULL;
- const char *service_type;
- const char *home_folder;
- s_vpn = nm_connection_get_setting_vpn (connection);
- service_type = s_vpn ? nm_setting_vpn_get_service_type (s_vpn) : NULL;
- if (!service_type) {
- g_warning ("%s: invalid VPN connection!", __func__);
- return;
- }
- dialog = gtk_file_chooser_dialog_new (_("Export VPN connection..."),
- NULL,
- GTK_FILE_CHOOSER_ACTION_SAVE,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
- NULL);
- home_folder = g_get_home_dir ();
- gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), home_folder);
- plugin = vpn_get_plugin_by_service (service_type);
- if (plugin) {
- char *suggested = NULL;
- suggested = nm_vpn_plugin_ui_interface_get_suggested_name (plugin, connection);
- if (suggested) {
- gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), suggested);
- g_free (suggested);
- }
- }
- g_signal_connect (G_OBJECT (dialog), "close", G_CALLBACK (gtk_widget_destroy), NULL);
- g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (export_vpn_to_file_cb), g_object_ref (connection));
- gtk_widget_show_all (dialog);
- gtk_window_present (GTK_WINDOW (dialog));
- }
- #endif
- gboolean
- vpn_supports_ipv6 (NMConnection *connection)
- {
- NMSettingVPN *s_vpn;
- const char *service_type;
- NMVpnPluginUiInterface *plugin;
- guint32 capabilities;
- s_vpn = nm_connection_get_setting_vpn (connection);
- g_return_val_if_fail (s_vpn != NULL, FALSE);
- service_type = nm_setting_vpn_get_service_type (s_vpn);
- g_return_val_if_fail (service_type != NULL, FALSE);
- plugin = vpn_get_plugin_by_service (service_type);
- g_return_val_if_fail (plugin != NULL, FALSE);
- capabilities = nm_vpn_plugin_ui_interface_get_capabilities (plugin);
- return (capabilities & NM_VPN_PLUGIN_UI_CAPABILITY_IPV6) != 0;
- }
|