diff options
Diffstat (limited to 'clients/common')
| -rw-r--r-- | clients/common/nm-polkit-listener.c | 8 | ||||
| -rw-r--r-- | clients/common/nm-secret-agent-simple.c | 184 | ||||
| -rw-r--r-- | clients/common/nm-secret-agent-simple.h | 4 | ||||
| -rw-r--r-- | clients/common/nm-vpn-helpers.c | 348 | ||||
| -rw-r--r-- | clients/common/nm-vpn-helpers.h | 47 |
5 files changed, 575 insertions, 16 deletions
diff --git a/clients/common/nm-polkit-listener.c b/clients/common/nm-polkit-listener.c index 82df1b2d..c1c7c908 100644 --- a/clients/common/nm-polkit-listener.c +++ b/clients/common/nm-polkit-listener.c @@ -323,9 +323,11 @@ nm_polkit_listener_new (gboolean for_session, GError **error) listener = g_object_new (NM_TYPE_POLKIT_LISTENER, NULL); priv = NM_POLKIT_LISTENER_GET_PRIVATE (listener); - if (for_session) - session = polkit_unix_session_new_for_process_sync (getpid (), NULL, NULL); - else + if (for_session) { + session = polkit_unix_session_new_for_process_sync (getpid (), NULL, error); + if (!session) + return NULL; + } else session = polkit_unix_process_new_for_owner (getpid (), 0, getuid ()); priv->reg_handle = polkit_agent_listener_register (listener, POLKIT_AGENT_REGISTER_FLAGS_NONE, diff --git a/clients/common/nm-secret-agent-simple.c b/clients/common/nm-secret-agent-simple.c index 8eddb440..6cb6c58d 100644 --- a/clients/common/nm-secret-agent-simple.c +++ b/clients/common/nm-secret-agent-simple.c @@ -13,7 +13,7 @@ * 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 2011-2013 Red Hat, Inc. + * Copyright 2011-2015 Red Hat, Inc. * Copyright 2011 Giovanni Campagna <scampa.giovanni@gmail.com> */ @@ -32,8 +32,14 @@ #include "config.h" #include <string.h> +#include <stdlib.h> +#include <errno.h> #include <glib/gi18n-lib.h> +#include <NetworkManager.h> +#include <nm-core-internal.h> + +#include "nm-vpn-helpers.h" #include "nm-secret-agent-simple.h" G_DEFINE_TYPE (NMSecretAgentSimple, nm_secret_agent_simple, NM_TYPE_SECRET_AGENT_OLD) @@ -157,6 +163,8 @@ nm_secret_agent_simple_secret_free (NMSecretAgentSimpleSecret *secret) g_free (secret->name); g_free (secret->prop_name); g_free (secret->value); + g_free (secret->vpn_property); + g_free (secret->vpn_type); g_free (real->property); g_clear_object (&real->setting); @@ -167,20 +175,29 @@ static NMSecretAgentSimpleSecret * nm_secret_agent_simple_secret_new (const char *name, NMSetting *setting, const char *property, + const char *vpn_property, + const char *vpn_type, gboolean password) { NMSecretAgentSimpleSecretReal *real; real = g_slice_new0 (NMSecretAgentSimpleSecretReal); real->base.name = g_strdup (name); - real->base.prop_name = g_strdup_printf ("%s.%s", nm_setting_get_name (setting), property); + real->base.prop_name = vpn_property ? + g_strdup_printf ("%s.%s.%s", nm_setting_get_name (setting), property, vpn_property) : + g_strdup_printf ("%s.%s", nm_setting_get_name (setting), property); + real->base.vpn_property = g_strdup (vpn_property); + real->base.vpn_type = g_strdup (vpn_type); real->base.password = password; if (setting) { real->setting = g_object_ref (setting); real->property = g_strdup (property); - g_object_get (setting, property, &real->base.value, NULL); + if (vpn_property) + real->base.value = g_strdup (nm_setting_vpn_get_secret (NM_SETTING_VPN (setting), vpn_property)); + else + g_object_get (setting, property, &real->base.value, NULL); } return &real->base; @@ -209,11 +226,15 @@ add_8021x_secrets (NMSecretAgentSimpleRequest *request, secret = nm_secret_agent_simple_secret_new (_("Username"), NM_SETTING (s_8021x), NM_SETTING_802_1X_IDENTITY, + NULL, + NULL, FALSE); g_ptr_array_add (secrets, secret); secret = nm_secret_agent_simple_secret_new (_("Password"), NM_SETTING (s_8021x), NM_SETTING_802_1X_PASSWORD, + NULL, + NULL, TRUE); g_ptr_array_add (secrets, secret); return TRUE; @@ -223,11 +244,15 @@ add_8021x_secrets (NMSecretAgentSimpleRequest *request, secret = nm_secret_agent_simple_secret_new (_("Identity"), NM_SETTING (s_8021x), NM_SETTING_802_1X_IDENTITY, + NULL, + NULL, FALSE); g_ptr_array_add (secrets, secret); secret = nm_secret_agent_simple_secret_new (_("Private key password"), NM_SETTING (s_8021x), NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD, + NULL, + NULL, TRUE); g_ptr_array_add (secrets, secret); return TRUE; @@ -251,6 +276,8 @@ add_wireless_secrets (NMSecretAgentSimpleRequest *request, secret = nm_secret_agent_simple_secret_new (_("Password"), NM_SETTING (s_wsec), NM_SETTING_WIRELESS_SECURITY_PSK, + NULL, + NULL, TRUE); g_ptr_array_add (secrets, secret); return TRUE; @@ -265,6 +292,8 @@ add_wireless_secrets (NMSecretAgentSimpleRequest *request, secret = nm_secret_agent_simple_secret_new (_("Key"), NM_SETTING (s_wsec), key, + NULL, + NULL, TRUE); g_free (key); @@ -277,6 +306,8 @@ add_wireless_secrets (NMSecretAgentSimpleRequest *request, secret = nm_secret_agent_simple_secret_new (_("Password"), NM_SETTING (s_wsec), NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD, + NULL, + NULL, TRUE); g_ptr_array_add (secrets, secret); return TRUE; @@ -300,21 +331,116 @@ add_pppoe_secrets (NMSecretAgentSimpleRequest *request, secret = nm_secret_agent_simple_secret_new (_("Username"), NM_SETTING (s_pppoe), NM_SETTING_PPPOE_USERNAME, + NULL, + NULL, FALSE); g_ptr_array_add (secrets, secret); secret = nm_secret_agent_simple_secret_new (_("Service"), NM_SETTING (s_pppoe), NM_SETTING_PPPOE_SERVICE, + NULL, + NULL, FALSE); g_ptr_array_add (secrets, secret); secret = nm_secret_agent_simple_secret_new (_("Password"), NM_SETTING (s_pppoe), NM_SETTING_PPPOE_PASSWORD, + NULL, + NULL, TRUE); g_ptr_array_add (secrets, secret); return TRUE; } +static NMSettingSecretFlags +get_vpn_secret_flags (NMSettingVpn *s_vpn, const char *secret_name) +{ + NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; + GHashTable *vpn_data; + char *flag_name; + const char *val; + unsigned long tmp; + + g_object_get (s_vpn, NM_SETTING_VPN_DATA, &vpn_data, NULL); + + flag_name = g_strdup_printf ("%s-flags", secret_name); + + /* Try new flags value first */ + val = g_hash_table_lookup (vpn_data, flag_name); + if (val) { + errno = 0; + tmp = strtoul (val, NULL, 10); + if (errno == 0 && tmp <= NM_SETTING_SECRET_FLAGS_ALL) + flags = (NMSettingSecretFlags) tmp; + } + g_free (flag_name); + g_hash_table_unref (vpn_data); + + return flags; +} + +static void +add_vpn_secret_helper (GPtrArray *secrets, NMSettingVpn *s_vpn, const char *name, const char *ui_name) +{ + NMSecretAgentSimpleSecret *secret; + NMSettingSecretFlags flags; + int i; + + /* Check for duplicates */ + for (i = 0; i < secrets->len; i++) { + secret = secrets->pdata[i]; + + if (g_strcmp0 (secret->vpn_property, name) == 0) + return; + } + + flags = get_vpn_secret_flags (s_vpn, name); + if ( flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED + || flags & NM_SETTING_SECRET_FLAG_NOT_SAVED) { + secret = nm_secret_agent_simple_secret_new (ui_name, + NM_SETTING (s_vpn), + NM_SETTING_VPN_SECRETS, + name, + nm_setting_vpn_get_service_type (s_vpn), + TRUE); + g_ptr_array_add (secrets, secret); + } +} + +#define VPN_MSG_TAG "x-vpn-message:" + +static gboolean +add_vpn_secrets (NMSecretAgentSimpleRequest *request, + GPtrArray *secrets, + char **msg) +{ + NMSettingVpn *s_vpn = nm_connection_get_setting_vpn (request->connection); + const VpnPasswordName *secret_names, *p; + char *tmp = NULL; + char **iter; + + /* If hints are given, then always ask for what the hints require */ + if (request->hints && g_strv_length (request->hints)) { + for (iter = request->hints; iter && *iter; iter++) { + if (!tmp && g_str_has_prefix (*iter, VPN_MSG_TAG)) + tmp = g_strdup (*iter + strlen (VPN_MSG_TAG)); + else + add_vpn_secret_helper (secrets, s_vpn, *iter, *iter); + } + } + if (msg) + *msg = g_strdup (tmp); + + /* Now add what client thinks might be required, because hints may be empty or incomplete */ + p = secret_names = nm_vpn_get_secret_names (nm_setting_vpn_get_service_type (s_vpn)); + while (p && p->name) { + add_vpn_secret_helper (secrets, s_vpn, p->name, _(p->ui_name)); + p++; + } + + return TRUE; +} + static void request_secrets_from_ui (NMSecretAgentSimpleRequest *request) { @@ -351,6 +477,8 @@ request_secrets_from_ui (NMSecretAgentSimpleRequest *request) secret = nm_secret_agent_simple_secret_new (_("Network name"), NM_SETTING (s_con), NM_SETTING_CONNECTION_ID, + NULL, + NULL, FALSE); g_ptr_array_add (secrets, secret); ok = add_8021x_secrets (request, secrets); @@ -369,6 +497,8 @@ request_secrets_from_ui (NMSecretAgentSimpleRequest *request) secret = nm_secret_agent_simple_secret_new (_("PIN"), NM_SETTING (s_gsm), NM_SETTING_GSM_PIN, + NULL, + NULL, FALSE); g_ptr_array_add (secrets, secret); } else { @@ -379,6 +509,8 @@ request_secrets_from_ui (NMSecretAgentSimpleRequest *request) secret = nm_secret_agent_simple_secret_new (_("Password"), NM_SETTING (s_gsm), NM_SETTING_GSM_PASSWORD, + NULL, + NULL, TRUE); g_ptr_array_add (secrets, secret); } @@ -392,6 +524,8 @@ request_secrets_from_ui (NMSecretAgentSimpleRequest *request) secret = nm_secret_agent_simple_secret_new (_("Password"), NM_SETTING (s_cdma), NM_SETTING_CDMA_PASSWORD, + NULL, + NULL, TRUE); g_ptr_array_add (secrets, secret); } else if (nm_connection_is_type (request->connection, NM_SETTING_BLUETOOTH_SETTING_NAME)) { @@ -408,8 +542,22 @@ request_secrets_from_ui (NMSecretAgentSimpleRequest *request) secret = nm_secret_agent_simple_secret_new (_("Password"), setting, "password", + NULL, + NULL, TRUE); g_ptr_array_add (secrets, secret); + } else if (nm_connection_is_type (request->connection, NM_SETTING_VPN_SETTING_NAME)) { + NMSettingConnection *s_con; + + s_con = nm_connection_get_setting_connection (request->connection); + + title = _("VPN password required"); + msg = NULL; + + ok = add_vpn_secrets (request, secrets, &msg); + if (!msg) + msg = g_strdup_printf (_("A password is required to connect to '%s'."), + nm_connection_get_id (request->connection)); } else ok = FALSE; @@ -455,13 +603,6 @@ nm_secret_agent_simple_get_secrets (NMSecretAgentOld *agent, s_con = nm_connection_get_setting_connection (connection); connection_type = nm_setting_connection_get_connection_type (s_con); - if (!strcmp (connection_type, NM_SETTING_VPN_SETTING_NAME)) { - /* We don't support VPN secrets yet */ - error = g_error_new (NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_NO_SECRETS, - "VPN secrets not supported"); - goto nope; - } - if (!(flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION)) { /* We don't do stored passwords */ error = g_error_new (NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_NO_SECRETS, @@ -515,9 +656,13 @@ nm_secret_agent_simple_response (NMSecretAgentSimple *self, if (secrets) { GVariantBuilder conn_builder, *setting_builder; + GVariantBuilder vpn_secrets_builder; GHashTable *settings; GHashTableIter iter; const char *name; + const char *vpn_secrets_base_name = NULL; + + g_variant_builder_init (&vpn_secrets_builder, G_VARIANT_TYPE ("a{ss}")); settings = g_hash_table_new (g_str_hash, g_str_equal); for (i = 0; i < secrets->len; i++) { @@ -530,9 +675,23 @@ nm_secret_agent_simple_response (NMSecretAgentSimple *self, setting_builder); } + if (secret->base.vpn_property) { + /* VPN secrets need slightly different treatment. + * "secrets" property is actually a hash table of secrets. */ + vpn_secrets_base_name = secret->property; + g_variant_builder_add (&vpn_secrets_builder, "{ss}", + secret->base.vpn_property, secret->base.value); + } else { + g_variant_builder_add (setting_builder, "{sv}", + secret->property, + g_variant_new_string (secret->base.value)); + } + } + + if (vpn_secrets_base_name) { g_variant_builder_add (setting_builder, "{sv}", - secret->property, - g_variant_new_string (secret->base.value)); + vpn_secrets_base_name, + g_variant_builder_end (&vpn_secrets_builder)); } g_variant_builder_init (&conn_builder, NM_VARIANT_TYPE_CONNECTION); @@ -691,5 +850,6 @@ nm_secret_agent_simple_new (const char *name) { return g_initable_new (NM_TYPE_SECRET_AGENT_SIMPLE, NULL, NULL, NM_SECRET_AGENT_OLD_IDENTIFIER, name, + NM_SECRET_AGENT_OLD_CAPABILITIES, NM_SECRET_AGENT_CAPABILITY_VPN_HINTS, NULL); } diff --git a/clients/common/nm-secret-agent-simple.h b/clients/common/nm-secret-agent-simple.h index 81fec651..d2c58822 100644 --- a/clients/common/nm-secret-agent-simple.h +++ b/clients/common/nm-secret-agent-simple.h @@ -13,7 +13,7 @@ * 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 - 2014 Red Hat, Inc. + * Copyright 2013 - 2015 Red Hat, Inc. */ #ifndef __NM_SECRET_AGENT_SIMPLE_H__ @@ -43,6 +43,8 @@ typedef struct { typedef struct { char *name, *prop_name, *value; + char *vpn_property; + char *vpn_type; gboolean password; } NMSecretAgentSimpleSecret; diff --git a/clients/common/nm-vpn-helpers.c b/clients/common/nm-vpn-helpers.c new file mode 100644 index 00000000..370e128c --- /dev/null +++ b/clients/common/nm-vpn-helpers.c @@ -0,0 +1,348 @@ +/* -*- 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 - 2015 Red Hat, Inc. + */ + +/** + * SECTION:nm-vpn-helpers + * @short_description: VPN-related utilities + * + * Some functions should probably eventually move into libnm. + */ + +#include "config.h" + +#include <string.h> +#include <glib.h> +#include <gmodule.h> +#include <glib/gi18n-lib.h> + +#include <NetworkManager.h> + +#include "nm-utils.h" +#include "nm-vpn-helpers.h" +#include "nm-glib-compat.h" + +#define VPN_NAME_FILES_DIR NMCONFDIR "/VPN" +#define DEFAULT_DIR_LIB NMLIBDIR"/VPN" + +static gboolean plugins_loaded = FALSE; +static GHashTable *plugins_hash = NULL; +static GSList *plugins_list = NULL; + + +GQuark nm_vpn_error_quark (void); +G_DEFINE_QUARK (NM_VPN_ERROR, nm_vpn_error) +#define NM_VPN_ERROR nm_vpn_error_quark () +#define NM_VPN_ERROR_GENERIC 0 + +NMVpnEditorPlugin * +nm_vpn_get_plugin_by_service (const char *service) +{ + NMVpnEditorPlugin *plugin; + const char *str; + char *tmp = NULL; + + g_return_val_if_fail (service != NULL, NULL); + + if (G_UNLIKELY (!plugins_loaded)) + nm_vpn_get_plugins (NULL); + + if (!plugins_hash) + return NULL; + + if (g_str_has_prefix (service, NM_DBUS_SERVICE)) + str = service; + else + str = tmp = g_strdup_printf ("%s.%s", NM_DBUS_SERVICE, service); + + plugin = g_hash_table_lookup (plugins_hash, str); + g_free (tmp); + + return plugin; +} + +GSList * +nm_vpn_get_plugins (GError **error) +{ + GDir *dir; + const char *f; + GHashTableIter iter; + NMVpnEditorPlugin *plugin; + + if (error) + g_return_val_if_fail (*error == NULL, NULL); + + if (G_LIKELY (plugins_loaded)) + return plugins_list; + + plugins_loaded = TRUE; + + dir = g_dir_open (VPN_NAME_FILES_DIR, 0, NULL); + if (!dir) { + g_set_error (error, NM_VPN_ERROR, NM_VPN_ERROR_GENERIC, "Couldn't read VPN .name files directory " VPN_NAME_FILES_DIR "."); + return NULL; + } + + plugins_hash = 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 = NULL; + NMVpnEditorPluginFactory 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, "libnm", "plugin", NULL); + if (!so_path) + goto next; + + if (g_path_is_absolute (so_path)) + module = g_module_open (so_path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); + + if (!module) { + /* 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", NMLIBDIR, so_name); + g_free (so_name); + + module = g_module_open (so_path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); + if (!module) { + g_clear_error (error); + g_set_error (error, NM_VPN_ERROR, NM_VPN_ERROR_GENERIC, "Cannot load the VPN plugin which provides the " + "service '%s'.", service); + goto next; + } + } + + if (g_module_symbol (module, "nm_vpn_editor_plugin_factory", (gpointer) &factory)) { + 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_EDITOR_PLUGIN_NAME, &plug_name, + NM_VPN_EDITOR_PLUGIN_SERVICE, &plug_service, + NULL); + if (!plug_name || !strlen (plug_name)) { + g_clear_error (error); + g_set_error (error, NM_VPN_ERROR, NM_VPN_ERROR_GENERIC, "cannot load VPN plugin in '%s': missing plugin name", + g_module_name (module)); + } else if (!plug_service || strcmp (plug_service, service)) { + g_clear_error (error); + g_set_error (error, NM_VPN_ERROR, NM_VPN_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_hash, g_strdup (service), plugin); + success = TRUE; + } + g_free (plug_name); + g_free (plug_service); + } else { + g_clear_error (error); + g_set_error (error, NM_VPN_ERROR, NM_VPN_ERROR_GENERIC, "cannot load VPN plugin in '%s': %s", + g_module_name (module), g_module_error ()); + } + + if (!success) + g_module_close (module); + } else { + g_clear_error (error); + g_set_error (error, NM_VPN_ERROR, NM_VPN_ERROR_GENERIC, "cannot locate nm_vpn_editor_plugin_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); + + /* Copy hash to list */ + g_hash_table_iter_init (&iter, plugins_hash); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &plugin)) + plugins_list = g_slist_prepend (plugins_list, plugin); + + return plugins_list; +} + +gboolean +nm_vpn_supports_ipv6 (NMConnection *connection) +{ + NMSettingVpn *s_vpn; + const char *service_type; + NMVpnEditorPlugin *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 = nm_vpn_get_plugin_by_service (service_type); + g_return_val_if_fail (plugin != NULL, FALSE); + + capabilities = nm_vpn_editor_plugin_get_capabilities (plugin); + return (capabilities & NM_VPN_EDITOR_PLUGIN_CAPABILITY_IPV6) != 0; +} + +const VpnPasswordName * +nm_vpn_get_secret_names (const char *vpn_type) +{ + const char *type; + static VpnPasswordName generic_vpn_secrets[] = { {"password", N_("Password")}, {NULL, NULL} }; + static VpnPasswordName vpnc_secrets[] = { {"Xauth password", N_("Password")}, + {"IPSec secret", N_("Group password")}, + {NULL, NULL} }; + static VpnPasswordName swan_secrets[] = { {"xauthpassword", N_("Password")}, + {"pskvalue", N_("Group password")}, + {NULL, NULL} }; + static VpnPasswordName openconnect_secrets[] = { {"gateway", N_("Gateway")}, + {"cookie", N_("Cookie")}, + {"gwcert", N_("Gateway certificate hash")}, + {NULL, NULL} }; + + if (!vpn_type) + return NULL; + + if (g_str_has_prefix (vpn_type, NM_DBUS_INTERFACE)) + type = vpn_type + strlen (NM_DBUS_INTERFACE) + 1; + else + type = vpn_type; + + if ( !g_strcmp0 (type, "openvpn") + || !g_strcmp0 (type, "pptp") + || !g_strcmp0 (type, "iodine") + || !g_strcmp0 (type, "ssh") + || !g_strcmp0 (type, "l2tp") + || !g_strcmp0 (type, "fortisslvpn")) + return generic_vpn_secrets; + else if (!g_strcmp0 (type, "vpnc")) + return vpnc_secrets; + else if ( !g_strcmp0 (type, "openswan") + || !g_strcmp0 (type, "libreswan") + || !g_strcmp0 (type, "strongswan")) + return swan_secrets; + else if (!g_strcmp0 (type, "openconnect")) + return openconnect_secrets; + return NULL; +} + +static gboolean +_extract_variable_value (char *line, const char *tag, char **value) +{ + char *p1, *p2; + + if (g_str_has_prefix (line, tag)) { + p1 = line + strlen (tag); + p2 = line + strlen (line) - 1; + if ((*p1 == '\'' || *p1 == '"') && (*p1 == *p2)) { + p1++; + *p2 = '\0'; + } + if (value) + *value = g_strdup (p1); + return TRUE; + } + return FALSE; +} + +gboolean +nm_vpn_openconnect_authenticate_helper (const char *host, + char **cookie, + char **gateway, + char **gwcert, + int *status, + GError **error) +{ + char *output = NULL; + gboolean ret; + char **strv = NULL, **iter; + char *argv[4]; + const char *path; + const char *const DEFAULT_PATHS[] = { + "/sbin/", + "/usr/sbin/", + "/usr/local/sbin/", + "/bin/", + "/usr/bin/", + "/usr/local/bin/", + NULL, + }; + + path = nm_utils_file_search_in_paths ("openconnect", "/usr/sbin/openconnect", DEFAULT_PATHS, + G_FILE_TEST_IS_EXECUTABLE, NULL, NULL, error); + if (!path) + return FALSE; + + argv[0] = (char *) path; + argv[1] = "--authenticate"; + argv[2] = (char *) host; + argv[3] = NULL; + + ret = g_spawn_sync (NULL, argv, NULL, + G_SPAWN_SEARCH_PATH | G_SPAWN_CHILD_INHERITS_STDIN, + NULL, NULL, &output, NULL, + status, error); + + if (!ret) + return FALSE; + + /* Parse output and set cookie, gateway and gwcert + * output example: + * COOKIE='loremipsum' + * HOST='1.2.3.4' + * FINGERPRINT='sha1:32bac90cf09a722e10ecc1942c67fe2ac8c21e2e' + */ + strv = g_strsplit_set (output ? output : "", "\r\n", 0); + for (iter = strv; iter && *iter; iter++) { + _extract_variable_value (*iter, "COOKIE=", cookie); + _extract_variable_value (*iter, "HOST=", gateway); + _extract_variable_value (*iter, "FINGERPRINT=", gwcert); + } + g_strfreev (strv); + + return TRUE; +} + diff --git a/clients/common/nm-vpn-helpers.h b/clients/common/nm-vpn-helpers.h new file mode 100644 index 00000000..6b3396ef --- /dev/null +++ b/clients/common/nm-vpn-helpers.h @@ -0,0 +1,47 @@ +/* -*- 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 - 2015 Red Hat, Inc. + */ + +#ifndef __NM_VPN_HELPERS_H__ +#define __NM_VPN_HELPERS_H__ + +#include <glib.h> +#include <NetworkManager.h> + +#include <nm-vpn-editor-plugin.h> + +struct { + const char *name; + const char *ui_name; +} typedef VpnPasswordName; + +GSList *nm_vpn_get_plugins (GError **error); + +NMVpnEditorPlugin *nm_vpn_get_plugin_by_service (const char *service); + +gboolean nm_vpn_supports_ipv6 (NMConnection *connection); + +const VpnPasswordName * nm_vpn_get_secret_names (const char *vpn_type); + +gboolean nm_vpn_openconnect_authenticate_helper (const char *host, + char **cookie, + char **gateway, + char **gwcert, + int *status, + GError **error); + +#endif /* __NM_VPN_HELPERS_H__ */ |