2013-12-02 16:20:26 -05:00
|
|
|
/* -*- 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/>.
|
|
|
|
|
*
|
2015-11-23 17:47:00 +01:00
|
|
|
* Copyright 2013 - 2015 Red Hat, Inc.
|
2013-12-02 16:20:26 -05:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
2015-11-23 17:47:00 +01:00
|
|
|
* SECTION:nm-vpn-helpers
|
2013-12-02 16:20:26 -05:00
|
|
|
* @short_description: VPN-related utilities
|
|
|
|
|
*
|
2015-11-23 17:47:00 +01:00
|
|
|
* Some functions should probably eventually move into libnm.
|
2013-12-02 16:20:26 -05:00
|
|
|
*/
|
|
|
|
|
|
2016-02-12 14:44:52 +01:00
|
|
|
#include "nm-default.h"
|
2016-02-19 14:57:48 +01:00
|
|
|
|
2016-02-12 14:44:52 +01:00
|
|
|
#include "nm-vpn-helpers.h"
|
|
|
|
|
|
2013-12-02 16:20:26 -05:00
|
|
|
#include <string.h>
|
|
|
|
|
|
2015-12-11 21:47:27 +01:00
|
|
|
#include "nm-utils.h"
|
2013-12-02 16:20:26 -05:00
|
|
|
|
2015-05-26 11:10:12 +02:00
|
|
|
static gboolean plugins_loaded;
|
|
|
|
|
static GSList *plugins = NULL;
|
2013-12-02 16:20:26 -05:00
|
|
|
|
2015-05-26 11:10:12 +02:00
|
|
|
NMVpnEditorPlugin *
|
2016-05-19 10:06:27 +02:00
|
|
|
nm_vpn_lookup_plugin (const char *name, const char *service, GError **error)
|
2013-12-02 16:20:26 -05:00
|
|
|
{
|
2015-05-26 11:10:12 +02:00
|
|
|
NMVpnEditorPlugin *plugin = NULL;
|
|
|
|
|
NMVpnPluginInfo *plugin_info;
|
2016-05-19 11:17:46 +02:00
|
|
|
gs_free_error GError *local = NULL;
|
2015-05-26 11:10:12 +02:00
|
|
|
|
2016-05-19 10:06:27 +02:00
|
|
|
g_return_val_if_fail (!service ^ !name, NULL);
|
2015-11-30 16:20:10 +01:00
|
|
|
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
2013-12-02 16:20:26 -05:00
|
|
|
|
2015-05-26 11:10:12 +02:00
|
|
|
if (G_UNLIKELY (!plugins_loaded))
|
2015-11-23 17:47:00 +01:00
|
|
|
nm_vpn_get_plugins ();
|
2015-05-26 11:10:12 +02:00
|
|
|
|
2016-05-19 10:06:27 +02:00
|
|
|
if (service)
|
|
|
|
|
plugin_info = nm_vpn_plugin_info_list_find_by_service (plugins, service);
|
|
|
|
|
else
|
|
|
|
|
plugin_info = nm_vpn_plugin_info_list_find_by_name (plugins, name);
|
2015-11-30 16:39:55 +01:00
|
|
|
|
2016-05-19 11:17:46 +02:00
|
|
|
if (!plugin_info) {
|
2016-05-19 10:06:27 +02:00
|
|
|
g_set_error (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_FAILED,
|
|
|
|
|
_("unknown VPN plugin \"%s\""), service ?: name);
|
2016-05-19 11:17:46 +02:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
plugin = nm_vpn_plugin_info_get_editor_plugin (plugin_info);
|
|
|
|
|
if (!plugin)
|
|
|
|
|
plugin = nm_vpn_plugin_info_load_editor_plugin (plugin_info, &local);
|
|
|
|
|
|
|
|
|
|
if (!plugin) {
|
|
|
|
|
if ( !nm_vpn_plugin_info_get_plugin (plugin_info)
|
|
|
|
|
&& nm_vpn_plugin_info_lookup_property (plugin_info, NM_VPN_PLUGIN_INFO_KF_GROUP_GNOME, "properties")) {
|
|
|
|
|
g_set_error (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_FAILED,
|
|
|
|
|
_("cannot cannot load legacy-only VPN plugin \"%s\" for \"%s\""),
|
|
|
|
|
nm_vpn_plugin_info_get_name (plugin_info),
|
|
|
|
|
nm_vpn_plugin_info_get_filename (plugin_info));
|
|
|
|
|
} else if (g_error_matches (local, G_FILE_ERROR, G_FILE_ERROR_NOENT)) {
|
|
|
|
|
g_set_error (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_FAILED,
|
|
|
|
|
_("cannot load VPN plugin \"%s\" due to missing \"%s\". Missing client plugin?"),
|
|
|
|
|
nm_vpn_plugin_info_get_name (plugin_info),
|
|
|
|
|
nm_vpn_plugin_info_get_plugin (plugin_info));
|
|
|
|
|
} else {
|
|
|
|
|
g_set_error (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_FAILED,
|
|
|
|
|
_("failed to load VPN plugin \"%s\": %s"),
|
|
|
|
|
nm_vpn_plugin_info_get_name (plugin_info),
|
|
|
|
|
local->message);
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-26 11:10:12 +02:00
|
|
|
return plugin;
|
2013-12-02 16:20:26 -05:00
|
|
|
}
|
|
|
|
|
|
2015-05-26 11:10:12 +02:00
|
|
|
GSList *
|
2015-11-23 17:47:00 +01:00
|
|
|
nm_vpn_get_plugins (void)
|
2013-12-02 16:20:26 -05:00
|
|
|
{
|
2015-05-26 11:10:12 +02:00
|
|
|
if (G_LIKELY (plugins_loaded))
|
2013-12-02 16:20:26 -05:00
|
|
|
return plugins;
|
2015-05-26 11:10:12 +02:00
|
|
|
plugins_loaded = TRUE;
|
|
|
|
|
plugins = nm_vpn_plugin_info_list_load ();
|
2013-12-02 16:20:26 -05:00
|
|
|
return plugins;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-19 10:51:58 +02:00
|
|
|
const char **
|
|
|
|
|
nm_vpn_get_plugin_names (gboolean only_available_plugins)
|
|
|
|
|
{
|
|
|
|
|
GSList *p;
|
|
|
|
|
const char **list;
|
|
|
|
|
const char *known_names[] = {
|
|
|
|
|
"openvpn",
|
|
|
|
|
"vpnc",
|
|
|
|
|
"pptp",
|
|
|
|
|
"openconnect",
|
|
|
|
|
"openswan",
|
|
|
|
|
"libreswan",
|
|
|
|
|
"strongswan",
|
|
|
|
|
"ssh",
|
|
|
|
|
"l2tp",
|
|
|
|
|
"iodine",
|
|
|
|
|
"fortisslvpn",
|
|
|
|
|
};
|
|
|
|
|
guint i, j, k;
|
|
|
|
|
|
|
|
|
|
p = nm_vpn_get_plugins ();
|
|
|
|
|
list = g_new0 (const char *, g_slist_length (p) + G_N_ELEMENTS (known_names) + 1);
|
|
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
for (i = 0; p; p = p->next)
|
|
|
|
|
list[i++] = nm_vpn_plugin_info_get_name (p->data);
|
|
|
|
|
if (!only_available_plugins) {
|
|
|
|
|
for (j = 0; j < G_N_ELEMENTS (known_names); j++)
|
|
|
|
|
list[i++] = known_names[j];
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-07 13:10:38 +02:00
|
|
|
g_qsort_with_data (list, i, sizeof (gpointer), nm_strcmp_p_with_data, NULL);
|
2016-05-19 10:51:58 +02:00
|
|
|
|
|
|
|
|
/* remove duplicates */
|
|
|
|
|
for (k = 0, j = 1; j < i; j++) {
|
|
|
|
|
if (nm_streq (list[k], list[j]))
|
|
|
|
|
continue;
|
|
|
|
|
list[k++] = list[j];
|
|
|
|
|
}
|
|
|
|
|
list[k++] = NULL;
|
|
|
|
|
|
|
|
|
|
return list;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
nm_vpn_get_service_for_name (const char *name)
|
|
|
|
|
{
|
|
|
|
|
NMVpnPluginInfo *plugin_info;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (name, NULL);
|
|
|
|
|
|
|
|
|
|
plugin_info = nm_vpn_plugin_info_list_find_by_name (nm_vpn_get_plugins (), name);
|
|
|
|
|
if (plugin_info) {
|
|
|
|
|
/* this only means we have a .name file (NMVpnPluginInfo). Possibly the
|
|
|
|
|
* NMVpnEditorPlugin is not loadable. */
|
|
|
|
|
return nm_vpn_plugin_info_get_service (plugin_info);
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
nm_vpn_get_service_for_name_default (const char *name)
|
|
|
|
|
{
|
|
|
|
|
return g_strdup_printf ("%s.%s", NM_DBUS_INTERFACE, name);
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-02 16:20:26 -05:00
|
|
|
gboolean
|
2015-11-23 17:47:00 +01:00
|
|
|
nm_vpn_supports_ipv6 (NMConnection *connection)
|
2013-12-02 16:20:26 -05:00
|
|
|
{
|
libnm, core, cli, tui: fix the capitalization of various types
GLib/Gtk have mostly settled on the convention that two-letter
acronyms in type names remain all-caps (eg, "IO"), but longer acronyms
become initial-caps-only (eg, "Tcp").
NM was inconsistent, with most long acronyms using initial caps only
(Adsl, Cdma, Dcb, Gsm, Olpc, Vlan), but others using all caps (DHCP,
PPP, PPPOE, VPN). Fix libnm and src/ to use initial-caps only for all
three-or-more-letter-long acronyms (and update nmcli and nmtui for the
libnm changes).
2014-06-26 13:44:36 -04:00
|
|
|
NMSettingVpn *s_vpn;
|
2013-12-02 16:20:26 -05:00
|
|
|
const char *service_type;
|
2015-05-26 11:10:12 +02:00
|
|
|
NMVpnEditorPlugin *plugin;
|
2013-12-02 16:20:26 -05:00
|
|
|
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);
|
2016-05-19 10:08:47 +02:00
|
|
|
if (!service_type)
|
|
|
|
|
return FALSE;
|
2013-12-02 16:20:26 -05:00
|
|
|
|
2016-05-19 10:06:27 +02:00
|
|
|
plugin = nm_vpn_lookup_plugin (NULL, service_type, NULL);
|
2016-05-19 10:08:47 +02:00
|
|
|
if (!plugin)
|
|
|
|
|
return FALSE;
|
2013-12-02 16:20:26 -05:00
|
|
|
|
2015-05-26 11:10:12 +02:00
|
|
|
capabilities = nm_vpn_editor_plugin_get_capabilities (plugin);
|
|
|
|
|
return NM_FLAGS_HAS (capabilities, NM_VPN_EDITOR_PLUGIN_CAPABILITY_IPV6);
|
2013-12-02 16:20:26 -05:00
|
|
|
}
|
2015-11-27 11:09:20 +01:00
|
|
|
|
|
|
|
|
const VpnPasswordName *
|
|
|
|
|
nm_vpn_get_secret_names (const char *vpn_type)
|
|
|
|
|
{
|
|
|
|
|
const char *type;
|
|
|
|
|
static VpnPasswordName generic_vpn_secrets[] = { {"password", N_("Password")}, {NULL, NULL} };
|
2016-05-03 23:39:40 +02:00
|
|
|
static VpnPasswordName openvpn_secrets[] = { {"password", N_("Password")},
|
|
|
|
|
{"cert-pass", N_("Certificate password")},
|
|
|
|
|
{"http-proxy-password", N_("HTTP proxy password")},
|
|
|
|
|
{NULL, NULL} };
|
2015-11-27 11:09:20 +01:00
|
|
|
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;
|
|
|
|
|
|
2016-05-03 23:39:40 +02:00
|
|
|
if ( !g_strcmp0 (type, "pptp")
|
2015-11-27 11:09:20 +01:00
|
|
|
|| !g_strcmp0 (type, "iodine")
|
|
|
|
|
|| !g_strcmp0 (type, "ssh")
|
|
|
|
|
|| !g_strcmp0 (type, "l2tp")
|
|
|
|
|
|| !g_strcmp0 (type, "fortisslvpn"))
|
|
|
|
|
return generic_vpn_secrets;
|
2016-05-03 23:39:40 +02:00
|
|
|
else if (!g_strcmp0 (type, "openvpn"))
|
|
|
|
|
return openvpn_secrets;
|
2015-11-27 11:09:20 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-11 21:47:27 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|