mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-28 16:50:16 +01:00
merge: enable VPN secrets for nmtui/nmcli secret agent (rh #975185)
It allows nmcli and nmtui to ask for VPN passwords and thus successfully activate VPN connections. There is a special handling for OpenConnect, because the user does not know the secrets. They have to be obtained by authenticating to OpenConnect server. https://bugzilla.redhat.com/show_bug.cgi?id=975185
This commit is contained in:
commit
5745e954a1
10 changed files with 520 additions and 22 deletions
|
|
@ -14,7 +14,9 @@ AM_CPPFLAGS = \
|
|||
$(GLIB_CFLAGS) \
|
||||
-DG_LOG_DOMAIN=\""nmcli"\" \
|
||||
-DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
|
||||
-DNMCLI_LOCALEDIR=\"$(datadir)/locale\"
|
||||
-DNMCLI_LOCALEDIR=\"$(datadir)/locale\" \
|
||||
-DNMCONFDIR=\"$(nmconfdir)\" \
|
||||
-DNMLIBDIR=\"$(libdir)\"
|
||||
|
||||
nmcli_SOURCES = \
|
||||
agent.c \
|
||||
|
|
@ -38,6 +40,8 @@ nmcli_SOURCES = \
|
|||
\
|
||||
$(srcdir)/../common/nm-secret-agent-simple.c \
|
||||
$(srcdir)/../common/nm-secret-agent-simple.h \
|
||||
$(srcdir)/../common/nm-vpn-helpers.c \
|
||||
$(srcdir)/../common/nm-vpn-helpers.h \
|
||||
$(NULL)
|
||||
|
||||
nmcli_LDADD = \
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "nm-glib-compat.h"
|
||||
|
||||
#include "nm-vpn-helpers.h"
|
||||
#include "common.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
|
@ -926,16 +927,97 @@ nmc_find_connection (const GPtrArray *connections,
|
|||
return found;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
vpn_openconnect_get_secrets (NMConnection *connection, GPtrArray *secrets)
|
||||
{
|
||||
GError *error = NULL;
|
||||
NMSettingVpn *s_vpn;
|
||||
const char *vpn_type, *gw, *port;
|
||||
char *cookie = NULL;
|
||||
char *gateway = NULL;
|
||||
char *gwcert = NULL;
|
||||
int status = 0;
|
||||
int i;
|
||||
gboolean ret;
|
||||
|
||||
if (!connection)
|
||||
return FALSE;
|
||||
|
||||
if (!nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME))
|
||||
return FALSE;
|
||||
|
||||
s_vpn = nm_connection_get_setting_vpn (connection);
|
||||
vpn_type = nm_setting_vpn_get_service_type (s_vpn);
|
||||
if (g_strcmp0 (vpn_type, NM_DBUS_INTERFACE ".openconnect"))
|
||||
return FALSE;
|
||||
|
||||
/* Get gateway and port */
|
||||
gw = nm_setting_vpn_get_data_item (s_vpn, "gateway");
|
||||
port = gw ? strrchr (gw, ':') : NULL;
|
||||
|
||||
/* Interactively authenticate to OpenConnect server and get secrets */
|
||||
ret = nm_vpn_openconnect_authenticate_helper (gw, &cookie, &gateway, &gwcert, &status, &error);
|
||||
if (!ret) {
|
||||
g_printerr (_("Error: openconnect failed: %s\n"), error->message);
|
||||
g_clear_error (&error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (WIFEXITED (status)) {
|
||||
if (WEXITSTATUS (status) != 0)
|
||||
g_printerr (_("Error: openconnect failed with status %d\n"), WEXITSTATUS (status));
|
||||
} else if (WIFSIGNALED (status))
|
||||
g_printerr (_("Error: openconnect failed with signal %d\n"), WTERMSIG (status));
|
||||
|
||||
/* Append port to the host value */
|
||||
if (gateway && port) {
|
||||
char *tmp = gateway;
|
||||
gateway = g_strdup_printf ("%s%s", gateway, port);
|
||||
g_free (tmp);
|
||||
}
|
||||
|
||||
/* Fill secrets to the array */
|
||||
for (i = 0; i < secrets->len; i++) {
|
||||
NMSecretAgentSimpleSecret *secret = secrets->pdata[i];
|
||||
|
||||
if (!g_strcmp0 (secret->vpn_type, vpn_type)) {
|
||||
if (!g_strcmp0 (secret->vpn_property, "cookie")) {
|
||||
g_free (secret->value);
|
||||
secret->value = cookie;
|
||||
cookie = NULL;
|
||||
} else if (!g_strcmp0 (secret->vpn_property, "gateway")) {
|
||||
g_free (secret->value);
|
||||
secret->value = gateway;
|
||||
gateway = NULL;
|
||||
} else if (!g_strcmp0 (secret->vpn_property, "gwcert")) {
|
||||
g_free (secret->value);
|
||||
secret->value = gwcert;
|
||||
gwcert = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
g_free (cookie);
|
||||
g_free (gateway);
|
||||
g_free (gwcert);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_secrets_from_user (const char *request_id,
|
||||
const char *title,
|
||||
const char *msg,
|
||||
NMConnection *connection,
|
||||
gboolean ask,
|
||||
GHashTable *pwds_hash,
|
||||
GPtrArray *secrets)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Check if there is a VPN OpenConnect secret to ask for */
|
||||
if (ask)
|
||||
vpn_openconnect_get_secrets (connection, secrets);
|
||||
|
||||
for (i = 0; i < secrets->len; i++) {
|
||||
NMSecretAgentSimpleSecret *secret = secrets->pdata[i];
|
||||
char *pwd = NULL;
|
||||
|
|
@ -945,17 +1027,23 @@ get_secrets_from_user (const char *request_id,
|
|||
if (pwds_hash && (pwd = g_hash_table_lookup (pwds_hash, secret->prop_name))) {
|
||||
pwd = g_strdup (pwd);
|
||||
} else {
|
||||
g_print ("%s\n", msg);
|
||||
if (ask) {
|
||||
if (secret->value) {
|
||||
/* Prefill the password if we have it. */
|
||||
rl_startup_hook = nmc_rl_set_deftext;
|
||||
nmc_rl_pre_input_deftext = g_strdup (secret->value);
|
||||
if (!g_strcmp0 (secret->vpn_type, NM_DBUS_INTERFACE ".openconnect")) {
|
||||
/* Do not present and ask user for openconnect secrets, we already have them */
|
||||
continue;
|
||||
} else {
|
||||
/* Prefill the password if we have it. */
|
||||
rl_startup_hook = nmc_rl_set_deftext;
|
||||
nmc_rl_pre_input_deftext = g_strdup (secret->value);
|
||||
}
|
||||
}
|
||||
g_print ("%s\n", msg);
|
||||
pwd = nmc_readline ("%s (%s): ", secret->name, secret->prop_name);
|
||||
if (!pwd)
|
||||
pwd = g_strdup ("");
|
||||
} else {
|
||||
g_print ("%s\n", msg);
|
||||
g_printerr (_("Warning: password for '%s' not given in 'passwd-file' "
|
||||
"and nmcli cannot ask without '--ask' option.\n"),
|
||||
secret->prop_name);
|
||||
|
|
@ -993,12 +1081,24 @@ nmc_secrets_requested (NMSecretAgentSimple *agent,
|
|||
gpointer user_data)
|
||||
{
|
||||
NmCli *nmc = (NmCli *) user_data;
|
||||
NMConnection *connection = NULL;
|
||||
char *path, *p;
|
||||
gboolean success = FALSE;
|
||||
|
||||
if (nmc->print_output == NMC_PRINT_PRETTY)
|
||||
nmc_terminal_erase_line ();
|
||||
|
||||
success = get_secrets_from_user (request_id, title, msg, nmc->in_editor || nmc->ask,
|
||||
/* Find the connection for the request */
|
||||
path = g_strdup (request_id);
|
||||
if (path) {
|
||||
p = strrchr (path, '/');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
connection = nmc_find_connection (nmc->connections, "path", path, NULL);
|
||||
g_free (path);
|
||||
}
|
||||
|
||||
success = get_secrets_from_user (request_id, title, msg, connection, nmc->in_editor || nmc->ask,
|
||||
nmc->pwds_hash, secrets);
|
||||
if (success)
|
||||
nm_secret_agent_simple_response (agent, request_id, secrets);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -28,10 +28,11 @@
|
|||
#include <string.h>
|
||||
#include <glib.h>
|
||||
#include <gmodule.h>
|
||||
#include <glib/gi18n-lib.h>
|
||||
|
||||
#include <NetworkManager.h>
|
||||
#include "nm-vpn-editor-plugin.h"
|
||||
|
||||
#include "nm-utils.h"
|
||||
#include "nm-vpn-helpers.h"
|
||||
|
||||
|
||||
|
|
@ -225,3 +226,123 @@ nm_vpn_supports_ipv6 (NMConnection *connection)
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,14 +20,28 @@
|
|||
#define __NM_VPN_HELPERS_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include <nm-connection.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__ */
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ AM_CPPFLAGS= \
|
|||
-DG_LOG_DOMAIN=\""nmtui"\" \
|
||||
-DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
|
||||
-DLOCALEDIR=\""$(localedir)"\" \
|
||||
-DNMCONFDIR=\"$(nmconfdir)\" \
|
||||
-DNMLIBDIR=\"$(libdir)\" \
|
||||
$(NULL)
|
||||
|
||||
bin_PROGRAMS = nmtui
|
||||
|
|
@ -116,6 +118,8 @@ nmtui_SOURCES = \
|
|||
nmt-widget-list.h \
|
||||
$(srcdir)/../common/nm-secret-agent-simple.c \
|
||||
$(srcdir)/../common/nm-secret-agent-simple.h \
|
||||
$(srcdir)/../common/nm-vpn-helpers.c \
|
||||
$(srcdir)/../common/nm-vpn-helpers.h \
|
||||
$(NULL)
|
||||
|
||||
nmtui_LDADD = \
|
||||
|
|
|
|||
|
|
@ -154,6 +154,8 @@ nmt_password_dialog_constructed (GObject *object)
|
|||
if (secret->password)
|
||||
flags |= NMT_NEWT_ENTRY_PASSWORD;
|
||||
widget = nmt_newt_entry_new (30, flags);
|
||||
if (secret->value)
|
||||
nmt_newt_entry_set_text (NMT_NEWT_ENTRY (widget), secret->value);
|
||||
nmt_newt_grid_add (secret_grid, widget, 1, i);
|
||||
g_ptr_array_add (priv->entries, widget);
|
||||
|
||||
|
|
|
|||
|
|
@ -39,8 +39,60 @@
|
|||
#include "nmt-connect-connection-list.h"
|
||||
#include "nmt-password-dialog.h"
|
||||
#include "nm-secret-agent-simple.h"
|
||||
#include "nm-vpn-helpers.h"
|
||||
#include "nmt-utils.h"
|
||||
|
||||
/**
|
||||
* Runs openconnect to authenticate. The current screen state is saved
|
||||
* before starting the command and restored after it returns.
|
||||
*/
|
||||
static gboolean
|
||||
openconnect_authenticate (NMConnection *connection, char **cookie, char **gateway, char **gwcert)
|
||||
{
|
||||
GError *error = NULL;
|
||||
NMSettingVpn *s_vpn;
|
||||
gboolean ret;
|
||||
int status = 0;
|
||||
const char *gw, *port;
|
||||
|
||||
nmt_newt_message_dialog (_("openconnect will be run to authenticate.\nIt will return to nmtui when completed."));
|
||||
|
||||
/* Get port */
|
||||
s_vpn = nm_connection_get_setting_vpn (connection);
|
||||
gw = nm_setting_vpn_get_data_item (s_vpn, "gateway");
|
||||
port = gw ? strrchr (gw, ':') : NULL;
|
||||
|
||||
newtSuspend ();
|
||||
|
||||
ret = nm_vpn_openconnect_authenticate_helper (gw, cookie, gateway, gwcert, &status, &error);
|
||||
|
||||
newtResume ();
|
||||
|
||||
if (!ret) {
|
||||
nmt_newt_message_dialog (_("Error: openconnect failed: %s"), error->message);
|
||||
g_clear_error (&error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (WIFEXITED (status)) {
|
||||
if (WEXITSTATUS (status) != 0) {
|
||||
nmt_newt_message_dialog (_("openconnect failed with status %d"), WEXITSTATUS (status));
|
||||
return FALSE;
|
||||
}
|
||||
} else if (WIFSIGNALED (status)) {
|
||||
nmt_newt_message_dialog (_("openconnect failed with signal %d"), WTERMSIG (status));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (gateway && *gateway && port) {
|
||||
char *tmp = *gateway;
|
||||
*gateway = g_strdup_printf ("%s%s", *gateway, port);
|
||||
g_free (tmp);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
secrets_requested (NMSecretAgentSimple *agent,
|
||||
const char *request_id,
|
||||
|
|
@ -50,6 +102,44 @@ secrets_requested (NMSecretAgentSimple *agent,
|
|||
gpointer user_data)
|
||||
{
|
||||
NmtNewtForm *form;
|
||||
NMConnection *connection = NM_CONNECTION (user_data);
|
||||
char *cookie = NULL;
|
||||
char *gateway = NULL;
|
||||
char *gwcert = NULL;
|
||||
int i;
|
||||
|
||||
/* Get secrets for OpenConnect VPN */
|
||||
if (connection && nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME)) {
|
||||
NMSettingVpn *s_vpn = nm_connection_get_setting_vpn (connection);
|
||||
const char *vpn_type = nm_setting_vpn_get_service_type (s_vpn);
|
||||
|
||||
if (!g_strcmp0 (vpn_type, NM_DBUS_INTERFACE ".openconnect")) {
|
||||
openconnect_authenticate (connection, &cookie, &gateway, &gwcert);
|
||||
|
||||
for (i = 0; i < secrets->len; i++) {
|
||||
NMSecretAgentSimpleSecret *secret = secrets->pdata[i];
|
||||
|
||||
if (!g_strcmp0 (secret->vpn_type, NM_DBUS_INTERFACE ".openconnect")) {
|
||||
if (!g_strcmp0 (secret->vpn_property, "cookie")) {
|
||||
g_free (secret->value);
|
||||
secret->value = cookie;
|
||||
cookie = NULL;
|
||||
} else if (!g_strcmp0 (secret->vpn_property, "gateway")) {
|
||||
g_free (secret->value);
|
||||
secret->value = gateway;
|
||||
gateway = NULL;
|
||||
} else if (!g_strcmp0 (secret->vpn_property, "gwcert")) {
|
||||
g_free (secret->value);
|
||||
secret->value = gwcert;
|
||||
gwcert = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
g_free (cookie);
|
||||
g_free (gateway);
|
||||
g_free (gwcert);
|
||||
}
|
||||
}
|
||||
|
||||
form = nmt_password_dialog_new (request_id, title, msg, secrets);
|
||||
nmt_newt_form_run_sync (form);
|
||||
|
|
@ -153,7 +243,7 @@ activate_connection (NMConnection *connection,
|
|||
nm_secret_agent_simple_enable (NM_SECRET_AGENT_SIMPLE (agent),
|
||||
nm_object_get_path (NM_OBJECT (connection)));
|
||||
}
|
||||
g_signal_connect (agent, "request-secrets", G_CALLBACK (secrets_requested), NULL);
|
||||
g_signal_connect (agent, "request-secrets", G_CALLBACK (secrets_requested), connection);
|
||||
}
|
||||
|
||||
specific_object_path = specific_object ? nm_object_get_path (specific_object) : NULL;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ clients/cli/settings.c
|
|||
clients/cli/utils.c
|
||||
clients/common/nm-polkit-listener.c
|
||||
clients/common/nm-secret-agent-simple.c
|
||||
clients/common/nm-vpn-helpers.c
|
||||
clients/nm-online.c
|
||||
clients/tui/newt/nmt-newt-utils.c
|
||||
clients/tui/nm-editor-utils.c
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue