vpn: handle interactive plugin secrets requests

If all agents can handle VPN hints, then we'll try to use
ConnectInteractive() to let the VPN plugin ask for secrets
interactively via the SecretsRequired signal.  These hints
are then passed to agents during the connection process if
the plugin needs more secrets or different secrets, and when
the new secrets are returned, they are passed back to the VPN
plugin.

If at least one agent does not have the VPN hints capability,
we can't use ConnectInteractive(), but fall back to the old
Connect call, because that agent won't be able to send the
hints to the VPN plugin's authentication dialog, and thus
we won't get back the secrets the VPN plugin is looking for.

So, for interactive secrets to work correctly, you need:

1) A VPN plugin updated for interactive secrets requests
2) NM updated for interactive secrets requests
3) all agents to set the VPN_HINTS capability when
    registering with NetworkManager and to pass hints
    along to the VPN authentication dialog
4) a VPN authentication dialog updated to look for hints
    and only return secrets corresponding to the hints
    requested by the plugin
This commit is contained in:
Dan Williams 2013-06-20 23:07:49 -05:00
parent cc924d8bab
commit ab84a86678
4 changed files with 276 additions and 77 deletions

View file

@ -58,7 +58,10 @@
required, so in some cases no hints may be given. The Agent
should return any secrets it has, or that it thinks are
required, regardless of what hints NetworkManager sends
in this request.
in this request. Some hints have special prefixes that
provide information to the agent; for example, VPN requests
may send server-specific messages prefixed with
"x-vpn-message:".
</tp:docstring>
</arg>
<arg name="flags" type="u" direction="in" tp:type="NM_SECRET_AGENT_GET_SECRETS_FLAGS">

View file

@ -1422,6 +1422,30 @@ nm_agent_manager_get_agent_by_user (NMAgentManager *self, const char *username)
/*************************************************************/
gboolean
nm_agent_manager_all_agents_have_capability (NMAgentManager *manager,
gboolean filter_by_uid,
gulong owner_uid,
NMSecretAgentCapabilities capability)
{
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (manager);
GHashTableIter iter;
NMSecretAgent *agent;
g_hash_table_iter_init (&iter, priv->agents);
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &agent)) {
if (filter_by_uid && nm_secret_agent_get_owner_uid (agent) != owner_uid)
continue;
if (!(nm_secret_agent_get_capabilities (agent) & capability))
return FALSE;
}
return TRUE;
}
/*************************************************************/
static void
name_owner_changed_cb (NMDBusManager *dbus_mgr,
const char *name,

View file

@ -102,4 +102,9 @@ guint32 nm_agent_manager_delete_secrets (NMAgentManager *manager,
NMSecretAgent *nm_agent_manager_get_agent_by_user (NMAgentManager *manager,
const char *username);
gboolean nm_agent_manager_all_agents_have_capability (NMAgentManager *manager,
gboolean filter_by_uid,
gulong owner_uid,
NMSecretAgentCapabilities capability);
#endif /* NM_AGENT_MANAGER_H */

View file

@ -43,6 +43,7 @@
#include "nm-glib-compat.h"
#include "settings/nm-settings-connection.h"
#include "nm-dispatcher.h"
#include "nm-agent-manager.h"
#include "nm-vpn-connection-glue.h"
@ -55,6 +56,8 @@ typedef enum {
SECRETS_REQ_EXISTING = 1,
/* New secrets required; ask an agent */
SECRETS_REQ_NEW = 2,
/* Plugin requests secrets interactively */
SECRETS_REQ_INTERACTIVE = 3,
/* Placeholder for bounds checking */
SECRETS_REQ_LAST
} SecretsReq;
@ -76,7 +79,8 @@ typedef struct {
NMVPNConnectionState vpn_state;
NMVPNConnectionStateReason failure_reason;
DBusGProxy *proxy;
guint ipconfig_timeout;
GHashTable *connect_hash;
guint connect_timeout;
gboolean has_ip4;
NMIP4Config *ip4_config;
guint32 ip4_internal_gw;
@ -114,7 +118,14 @@ enum {
LAST_PROP
};
static void get_secrets (NMVPNConnection *self, SecretsReq secrets_idx);
static void get_secrets (NMVPNConnection *self,
SecretsReq secrets_idx,
const char **hints);
static void plugin_interactive_secrets_required (DBusGProxy *proxy,
const char *message,
const char **secrets,
gpointer user_data);
static NMActiveConnectionState
ac_state_from_vpn_state (NMVPNConnectionState vpn_state)
@ -226,7 +237,6 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection,
nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (priv->connection), priv->secrets_id);
priv->secrets_id = 0;
}
priv->secrets_idx = SECRETS_REQ_SYSTEM;
/* The connection gets destroyed by the VPN manager when it enters the
* disconnected/failed state, but we need to keep it around for a bit
@ -240,12 +250,10 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection,
switch (vpn_state) {
case NM_VPN_CONNECTION_STATE_NEED_AUTH:
/* Kick off the secrets requests; first we get existing system secrets
* and ask the plugin if these are sufficient, next we get all existing
* secrets from system and from user agents and ask the plugin again,
* and last we ask the user for new secrets if required.
/* Do nothing; not part of 'default' because we don't want to touch
* priv->secrets_req as NEED_AUTH is re-entered during interactive
* secrets.
*/
get_secrets (connection, SECRETS_REQ_SYSTEM);
break;
case NM_VPN_CONNECTION_STATE_ACTIVATED:
/* Secrets no longer needed now that we're connected */
@ -278,8 +286,9 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection,
/* Tear down and clean up the connection */
call_plugin_disconnect (connection);
vpn_cleanup (connection);
break;
/* Fall through */
default:
priv->secrets_idx = SECRETS_REQ_SYSTEM;
break;
}
@ -748,7 +757,7 @@ nm_vpn_connection_config_maybe_complete (NMVPNConnection *connection,
{
NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
if (priv->ipconfig_timeout == 0) {
if (priv->connect_timeout == 0) {
/* config_complete() was already called with an error;
* ignore further calls.
*/
@ -763,8 +772,8 @@ nm_vpn_connection_config_maybe_complete (NMVPNConnection *connection,
}
}
g_source_remove (priv->ipconfig_timeout);
priv->ipconfig_timeout = 0;
g_source_remove (priv->connect_timeout);
priv->connect_timeout = 0;
if (success) {
print_vpn_config (connection);
@ -857,6 +866,12 @@ nm_vpn_connection_config_get (DBusGProxy *proxy,
nm_log_info (LOGD_VPN, "VPN connection '%s' (IP Config Get) reply received.",
nm_connection_get_id (priv->connection));
if (nm_vpn_connection_get_vpn_state (connection) == NM_VPN_CONNECTION_STATE_CONNECT) {
nm_vpn_connection_set_vpn_state (connection,
NM_VPN_CONNECTION_STATE_IP_CONFIG_GET,
NM_VPN_CONNECTION_STATE_REASON_NONE);
}
if (!process_generic_config (connection, config_hash))
return;
@ -882,6 +897,12 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
GValue *val;
int i;
if (nm_vpn_connection_get_vpn_state (connection) == NM_VPN_CONNECTION_STATE_CONNECT) {
nm_vpn_connection_set_vpn_state (connection,
NM_VPN_CONNECTION_STATE_IP_CONFIG_GET,
NM_VPN_CONNECTION_STATE_REASON_NONE);
}
if (priv->has_ip4) {
nm_log_info (LOGD_VPN, "VPN connection '%s' (IP4 Config Get) reply received.",
nm_connection_get_id (priv->connection));
@ -1028,6 +1049,12 @@ nm_vpn_connection_ip6_config_get (DBusGProxy *proxy,
nm_log_info (LOGD_VPN, "VPN connection '%s' (IP6 Config Get) reply received.",
nm_connection_get_id (priv->connection));
if (nm_vpn_connection_get_vpn_state (connection) == NM_VPN_CONNECTION_STATE_CONNECT) {
nm_vpn_connection_set_vpn_state (connection,
NM_VPN_CONNECTION_STATE_IP_CONFIG_GET,
NM_VPN_CONNECTION_STATE_REASON_NONE);
}
if (g_hash_table_size (config_hash) == 0) {
priv->has_ip6 = FALSE;
nm_vpn_connection_config_maybe_complete (connection, TRUE);
@ -1148,18 +1175,19 @@ nm_vpn_connection_ip6_config_get (DBusGProxy *proxy,
}
static gboolean
nm_vpn_connection_ip_config_timeout (gpointer user_data)
connect_timeout_cb (gpointer user_data)
{
NMVPNConnection *connection = NM_VPN_CONNECTION (user_data);
NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
NMVPNConnectionState state;
priv->ipconfig_timeout = 0;
priv->connect_timeout = 0;
/* If the activation request's state is still IP_CONFIG_GET and we're
* in this timeout, cancel activation because it's taken too long.
*/
if (nm_vpn_connection_get_vpn_state (connection) == NM_VPN_CONNECTION_STATE_IP_CONFIG_GET) {
nm_log_warn (LOGD_VPN, "VPN connection '%s' (IP Config Get) timeout exceeded.",
/* Cancel activation if it's taken too long */
state = nm_vpn_connection_get_vpn_state (connection);
if (state == NM_VPN_CONNECTION_STATE_CONNECT ||
state == NM_VPN_CONNECTION_STATE_IP_CONFIG_GET) {
nm_log_warn (LOGD_VPN, "VPN connection '%s' connect timeout exceeded.",
nm_connection_get_id (priv->connection));
nm_vpn_connection_set_vpn_state (connection,
NM_VPN_CONNECTION_STATE_FAILED,
@ -1170,31 +1198,62 @@ nm_vpn_connection_ip_config_timeout (gpointer user_data)
}
static void
nm_vpn_connection_connect_cb (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
connect_success (NMVPNConnection *connection)
{
NMVPNConnection *connection = NM_VPN_CONNECTION (user_data);
NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
/* 40 second timeout waiting for IP config signal from VPN service */
priv->connect_timeout = g_timeout_add_seconds (40, connect_timeout_cb, connection);
g_hash_table_destroy (priv->connect_hash);
priv->connect_hash = NULL;
}
static void
connect_cb (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
{
NMVPNConnection *self = NM_VPN_CONNECTION (user_data);
NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
GError *err = NULL;
nm_log_info (LOGD_VPN, "VPN connection '%s' (Connect) reply received.",
nm_connection_get_id (priv->connection));
dbus_g_proxy_end_call (proxy, call, &err, G_TYPE_INVALID);
if (err) {
nm_log_warn (LOGD_VPN, "VPN connection '%s' failed to connect: '%s'.",
nm_connection_get_id (priv->connection), err->message);
g_error_free (err);
nm_vpn_connection_set_vpn_state (connection,
NM_VPN_CONNECTION_STATE_FAILED,
NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED);
} else {
nm_vpn_connection_set_vpn_state (connection,
NM_VPN_CONNECTION_STATE_IP_CONFIG_GET,
NM_VPN_CONNECTION_STATE_REASON_NONE);
/* 40 second timeout waiting for IP config signal from VPN service */
priv->ipconfig_timeout = g_timeout_add_seconds (40, nm_vpn_connection_ip_config_timeout, connection);
if (!err) {
connect_success (self);
return;
}
nm_log_warn (LOGD_VPN, "VPN connection '%s' failed to connect: '%s'.",
nm_connection_get_id (priv->connection), err->message);
g_error_free (err);
nm_vpn_connection_set_vpn_state (self,
NM_VPN_CONNECTION_STATE_FAILED,
NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED);
}
static void
connect_interactive_cb (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
{
NMVPNConnection *self = NM_VPN_CONNECTION (user_data);
NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
GError *err = NULL;
nm_log_info (LOGD_VPN, "VPN connection '%s' (ConnectInteractive) reply received.",
nm_connection_get_id (priv->connection));
dbus_g_proxy_end_call (proxy, call, &err, G_TYPE_INVALID);
if (!err) {
connect_success (self);
return;
}
/* Fall back to Connect() */
dbus_g_proxy_begin_call (priv->proxy, "Connect",
connect_cb, self, NULL,
DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, priv->connect_hash,
G_TYPE_INVALID);
}
/* Add a username to a hashed connection */
@ -1229,7 +1288,8 @@ static void
really_activate (NMVPNConnection *connection, const char *username)
{
NMVPNConnectionPrivate *priv;
GHashTable *hash;
NMAgentManager *agent_mgr;
GHashTable *details;
g_return_if_fail (NM_IS_VPN_CONNECTION (connection));
g_return_if_fail (nm_vpn_connection_get_vpn_state (connection) == NM_VPN_CONNECTION_STATE_NEED_AUTH);
@ -1237,38 +1297,56 @@ really_activate (NMVPNConnection *connection, const char *username)
priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
dbus_g_object_register_marshaller (g_cclosure_marshal_VOID__BOXED,
G_TYPE_NONE, G_TYPE_VALUE, G_TYPE_INVALID);
G_TYPE_NONE, G_TYPE_VALUE, G_TYPE_INVALID);
/* Config signal */
dbus_g_proxy_add_signal (priv->proxy, "Config",
DBUS_TYPE_G_MAP_OF_VARIANT,
G_TYPE_INVALID);
dbus_g_proxy_add_signal (priv->proxy, "Config", DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_INVALID);
dbus_g_proxy_connect_signal (priv->proxy, "Config",
G_CALLBACK (nm_vpn_connection_config_get),
connection, NULL);
G_CALLBACK (nm_vpn_connection_config_get),
connection, NULL);
/* Ip4Config signal */
dbus_g_proxy_add_signal (priv->proxy, "Ip4Config",
DBUS_TYPE_G_MAP_OF_VARIANT,
G_TYPE_INVALID);
dbus_g_proxy_add_signal (priv->proxy, "Ip4Config", DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_INVALID);
dbus_g_proxy_connect_signal (priv->proxy, "Ip4Config",
G_CALLBACK (nm_vpn_connection_ip4_config_get),
connection, NULL);
G_CALLBACK (nm_vpn_connection_ip4_config_get),
connection, NULL);
/* Ip6Config signal */
dbus_g_proxy_add_signal (priv->proxy, "Ip6Config",
DBUS_TYPE_G_MAP_OF_VARIANT,
G_TYPE_INVALID);
dbus_g_proxy_add_signal (priv->proxy, "Ip6Config", DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_INVALID);
dbus_g_proxy_connect_signal (priv->proxy, "Ip6Config",
G_CALLBACK (nm_vpn_connection_ip6_config_get),
connection, NULL);
G_CALLBACK (nm_vpn_connection_ip6_config_get),
connection, NULL);
hash = _hash_with_username (priv->connection, username);
dbus_g_proxy_begin_call (priv->proxy, "Connect",
nm_vpn_connection_connect_cb, connection, NULL,
DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, hash,
G_TYPE_INVALID);
g_hash_table_destroy (hash);
if (priv->connect_hash)
g_hash_table_destroy (priv->connect_hash);
priv->connect_hash = _hash_with_username (priv->connection, username);
details = g_hash_table_new (g_str_hash, g_str_equal);
/* If at least one agent doesn't support VPN hints, then we can't use
* ConnectInteractive(), because that agent won't be able to pass hints
* from the VPN plugin's interactive secrets requests to the VPN authentication
* dialog and we won't get the secrets we need. In this case fall back to
* the old Connect() call.
*/
agent_mgr = nm_agent_manager_get ();
if (nm_agent_manager_all_agents_have_capability (agent_mgr,
nm_active_connection_get_user_requested (NM_ACTIVE_CONNECTION (connection)),
nm_active_connection_get_user_uid (NM_ACTIVE_CONNECTION (connection)),
NM_SECRET_AGENT_CAPABILITY_VPN_HINTS)) {
nm_log_dbg (LOGD_VPN, "Allowing interactive secrets as all agents have that capability");
dbus_g_proxy_begin_call (priv->proxy, "ConnectInteractive",
connect_interactive_cb, connection, NULL,
DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, priv->connect_hash,
DBUS_TYPE_G_MAP_OF_VARIANT, details,
G_TYPE_INVALID);
} else {
nm_log_dbg (LOGD_VPN, "Calling old Connect function as not all agents support interactive secrets");
dbus_g_proxy_begin_call (priv->proxy, "Connect",
connect_cb, connection, NULL,
DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, priv->connect_hash,
G_TYPE_INVALID);
}
g_object_unref (agent_mgr);
g_hash_table_destroy (details);
nm_vpn_connection_set_vpn_state (connection,
NM_VPN_CONNECTION_STATE_CONNECT,
@ -1294,8 +1372,8 @@ nm_vpn_connection_activate (NMVPNConnection *connection)
dbus_g_proxy_add_signal (priv->proxy, "Failure", G_TYPE_UINT, G_TYPE_INVALID);
dbus_g_proxy_connect_signal (priv->proxy, "Failure",
G_CALLBACK (plugin_failed),
connection, NULL);
G_CALLBACK (plugin_failed),
connection, NULL);
/* StateChanged signal */
dbus_g_proxy_add_signal (priv->proxy, "StateChanged", G_TYPE_UINT, G_TYPE_INVALID);
@ -1303,9 +1381,23 @@ nm_vpn_connection_activate (NMVPNConnection *connection)
G_CALLBACK (plugin_state_changed),
connection, NULL);
dbus_g_object_register_marshaller (g_cclosure_marshal_generic,
G_TYPE_NONE, G_TYPE_STRING, G_TYPE_STRV, G_TYPE_INVALID);
dbus_g_proxy_add_signal (priv->proxy, "SecretsRequired", G_TYPE_STRING, G_TYPE_STRV, G_TYPE_INVALID);
dbus_g_proxy_connect_signal (priv->proxy, "SecretsRequired",
G_CALLBACK (plugin_interactive_secrets_required),
connection, NULL);
nm_vpn_connection_set_vpn_state (connection,
NM_VPN_CONNECTION_STATE_NEED_AUTH,
NM_VPN_CONNECTION_STATE_REASON_NONE);
/* Kick off the secrets requests; first we get existing system secrets
* and ask the plugin if these are sufficient, next we get all existing
* secrets from system and from user agents and ask the plugin again,
* and last we ask the user for new secrets if required.
*/
get_secrets (connection, SECRETS_REQ_SYSTEM, NULL);
}
NMConnection *
@ -1448,7 +1540,7 @@ plugin_need_secrets_cb (DBusGProxy *proxy, DBusGProxyCall *call, void *user_dat
nm_connection_get_uuid (priv->connection),
nm_connection_get_id (priv->connection));
get_secrets (self, priv->secrets_idx + 1);
get_secrets (self, priv->secrets_idx + 1, NULL);
}
return;
}
@ -1461,6 +1553,24 @@ plugin_need_secrets_cb (DBusGProxy *proxy, DBusGProxyCall *call, void *user_dat
really_activate (self, priv->username);
}
static void
plugin_new_secrets_cb (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
{
NMVPNConnection *self = NM_VPN_CONNECTION (user_data);
NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
GError *error = NULL;
if (!dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID)) {
nm_log_err (LOGD_VPN, "(%s/%s) sending new secrets to the plugin failed: %s %s",
nm_connection_get_uuid (priv->connection),
nm_connection_get_id (priv->connection),
g_quark_to_string (error->domain),
error->message);
nm_vpn_connection_fail (self, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS);
g_error_free (error);
}
}
static void
get_secrets_cb (NMSettingsConnection *connection,
guint32 call_id,
@ -1483,28 +1593,44 @@ get_secrets_cb (NMSettingsConnection *connection,
priv->secrets_idx + 1, error->code, error->message);
nm_vpn_connection_fail (self, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS);
} else {
nm_log_dbg (LOGD_VPN, "(%s/%s) asking service if additional secrets are required",
nm_connection_get_uuid (priv->connection),
nm_connection_get_id (priv->connection));
/* Cache the username for later */
if (agent_username) {
g_free (priv->username);
priv->username = g_strdup (agent_username);
}
/* Ask the VPN service if more secrets are required */
hash = _hash_with_username (priv->connection, priv->username);
dbus_g_proxy_begin_call (priv->proxy, "NeedSecrets",
plugin_need_secrets_cb, self, NULL,
DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, hash,
G_TYPE_INVALID);
if (priv->secrets_idx == SECRETS_REQ_INTERACTIVE) {
nm_log_dbg (LOGD_VPN, "(%s/%s) sending secrets to the plugin",
nm_connection_get_uuid (priv->connection),
nm_connection_get_id (priv->connection));
/* Send the secrets back to the plugin */
dbus_g_proxy_begin_call (priv->proxy, "NewSecrets",
plugin_new_secrets_cb, self, NULL,
DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, hash,
G_TYPE_INVALID);
} else {
nm_log_dbg (LOGD_VPN, "(%s/%s) asking service if additional secrets are required",
nm_connection_get_uuid (priv->connection),
nm_connection_get_id (priv->connection));
/* Ask the VPN service if more secrets are required */
dbus_g_proxy_begin_call (priv->proxy, "NeedSecrets",
plugin_need_secrets_cb, self, NULL,
DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, hash,
G_TYPE_INVALID);
}
g_hash_table_destroy (hash);
}
}
static void
get_secrets (NMVPNConnection *self, SecretsReq secrets_idx)
get_secrets (NMVPNConnection *self,
SecretsReq secrets_idx,
const char **hints)
{
NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
NMSettingsGetSecretsFlags flags = NM_SETTINGS_GET_SECRETS_FLAG_NONE;
@ -1530,6 +1656,7 @@ get_secrets (NMVPNConnection *self, SecretsReq secrets_idx)
flags = NM_SETTINGS_GET_SECRETS_FLAG_NONE;
break;
case SECRETS_REQ_NEW:
case SECRETS_REQ_INTERACTIVE:
flags = NM_SETTINGS_GET_SECRETS_FLAG_ALLOW_INTERACTION;
break;
default:
@ -1544,7 +1671,7 @@ get_secrets (NMVPNConnection *self, SecretsReq secrets_idx)
nm_active_connection_get_user_uid (NM_ACTIVE_CONNECTION (self)),
NM_SETTING_VPN_SETTING_NAME,
flags,
NULL,
hints,
get_secrets_cb,
self,
&error);
@ -1558,12 +1685,49 @@ get_secrets (NMVPNConnection *self, SecretsReq secrets_idx)
}
}
static void
plugin_interactive_secrets_required (DBusGProxy *proxy,
const char *message,
const char **secrets,
gpointer user_data)
{
NMVPNConnection *connection = NM_VPN_CONNECTION (user_data);
NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
guint32 secrets_len = secrets ? g_strv_length ((char **) secrets) : 0;
char **hints;
guint32 i;
nm_log_info (LOGD_VPN, "VPN plugin requested secrets; state %s (%d)",
vpn_state_to_string (priv->vpn_state), priv->vpn_state);
g_return_if_fail (priv->vpn_state == NM_VPN_CONNECTION_STATE_CONNECT ||
priv->vpn_state == NM_VPN_CONNECTION_STATE_NEED_AUTH);
priv->secrets_idx = SECRETS_REQ_INTERACTIVE;
nm_vpn_connection_set_vpn_state (connection,
NM_VPN_CONNECTION_STATE_NEED_AUTH,
NM_VPN_CONNECTION_STATE_REASON_NONE);
/* Copy hints and add message to the end */
hints = g_malloc0 (sizeof (char *) * (secrets_len + 2));
for (i = 0; i < secrets_len; i++)
hints[i] = g_strdup (secrets[i]);
if (message)
hints[i] = g_strdup_printf ("x-vpn-message:%s", message);
get_secrets (connection, SECRETS_REQ_INTERACTIVE, (const char **) hints);
g_strfreev (hints);
}
/******************************************************************************/
static void
nm_vpn_connection_init (NMVPNConnection *self)
{
NM_VPN_CONNECTION_GET_PRIVATE (self)->vpn_state = NM_VPN_CONNECTION_STATE_PREPARE;
NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
priv->vpn_state = NM_VPN_CONNECTION_STATE_PREPARE;
priv->secrets_idx = SECRETS_REQ_SYSTEM;
}
static void
@ -1609,6 +1773,9 @@ dispose (GObject *object)
g_clear_pointer (&priv->ip4_gw_route, g_free);
g_clear_pointer (&priv->ip6_gw_route, g_free);
if (priv->connect_hash)
g_hash_table_destroy (priv->connect_hash);
if (priv->ip6_internal_gw)
g_free (priv->ip6_internal_gw);
if (priv->ip6_external_gw)
@ -1629,8 +1796,8 @@ dispose (GObject *object)
if (priv->ip6_config)
g_object_unref (priv->ip6_config);
if (priv->ipconfig_timeout)
g_source_remove (priv->ipconfig_timeout);
if (priv->connect_timeout)
g_source_remove (priv->connect_timeout);
if (priv->proxy)
g_object_unref (priv->proxy);