mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-02-05 12:20:36 +01:00
settings: request secrets from agents when clients call GetSecrets
A client calling GetSecrets on the connection should also request secrets from agents in that client's session. ie, a connection editor should be able to call GetSecrets, and get the secrets stored by the agent in that session (the applet).
This commit is contained in:
parent
75af6105b7
commit
68812f61d9
4 changed files with 191 additions and 109 deletions
|
|
@ -26,4 +26,5 @@ BOOLEAN:VOID
|
|||
VOID:STRING,BOOLEAN
|
||||
VOID:STRING,OBJECT,POINTER
|
||||
VOID:BOOLEAN,UINT
|
||||
UINT:STRING,POINTER,POINTER
|
||||
|
||||
|
|
|
|||
|
|
@ -924,6 +924,71 @@ connections_changed (NMSettings *settings,
|
|||
bluez_manager_resync_devices (manager);
|
||||
}
|
||||
|
||||
static void
|
||||
secrets_result_cb (NMAgentManager *manager,
|
||||
guint32 call_id,
|
||||
NMConnection *connection,
|
||||
const char *setting_name,
|
||||
GError *error,
|
||||
gpointer user_data,
|
||||
gpointer user_data2,
|
||||
gpointer user_data3)
|
||||
{
|
||||
NMSettingsConnectionSecretsUpdatedFunc callback = user_data2;
|
||||
gpointer callback_data = user_data3;
|
||||
|
||||
callback (NM_SETTINGS_CONNECTION (connection), setting_name, call_id, error, callback_data);
|
||||
}
|
||||
|
||||
static guint32
|
||||
system_connection_get_secrets_cb (NMSettingsConnection *connection,
|
||||
const char *setting_name,
|
||||
NMSettingsConnectionSecretsUpdatedFunc callback,
|
||||
gpointer callback_data,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMManager *self = NM_MANAGER (user_data);
|
||||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
||||
gboolean call_id;
|
||||
|
||||
call_id = nm_agent_manager_get_secrets (priv->agent_mgr,
|
||||
NM_CONNECTION (connection),
|
||||
setting_name,
|
||||
NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE,
|
||||
NULL,
|
||||
secrets_result_cb,
|
||||
self,
|
||||
callback,
|
||||
callback_data);
|
||||
return call_id;
|
||||
}
|
||||
|
||||
static void
|
||||
system_connection_cancel_secrets_cb (NMSettingsConnection *connection,
|
||||
guint32 call_id,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMManager *self = NM_MANAGER (user_data);
|
||||
|
||||
nm_agent_manager_cancel_secrets (NM_MANAGER_GET_PRIVATE (self)->agent_mgr, call_id);
|
||||
}
|
||||
|
||||
static void
|
||||
connection_added (NMSettings *settings,
|
||||
NMSettingsConnection *connection,
|
||||
NMManager *manager)
|
||||
{
|
||||
/* Hook up secrets request listeners */
|
||||
g_signal_connect (connection, NM_SETTINGS_CONNECTION_GET_SECRETS,
|
||||
G_CALLBACK (system_connection_get_secrets_cb),
|
||||
manager);
|
||||
g_signal_connect (connection, NM_SETTINGS_CONNECTION_CANCEL_SECRETS,
|
||||
G_CALLBACK (system_connection_cancel_secrets_cb),
|
||||
manager);
|
||||
|
||||
connections_changed (settings, connection, manager);
|
||||
}
|
||||
|
||||
static void
|
||||
system_unmanaged_devices_changed_cb (NMSettings *settings,
|
||||
GParamSpec *pspec,
|
||||
|
|
@ -3098,7 +3163,7 @@ nm_manager_get (NMSettings *settings,
|
|||
g_signal_connect (priv->settings, "notify::" NM_SETTINGS_HOSTNAME,
|
||||
G_CALLBACK (system_hostname_changed_cb), singleton);
|
||||
g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_ADDED,
|
||||
G_CALLBACK (connections_changed), singleton);
|
||||
G_CALLBACK (connection_added), singleton);
|
||||
g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED,
|
||||
G_CALLBACK (connections_changed), singleton);
|
||||
g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED,
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "nm-polkit-helpers.h"
|
||||
#include "nm-logging.h"
|
||||
#include "nm-manager-auth.h"
|
||||
#include "nm-marshal.h"
|
||||
|
||||
static void impl_settings_connection_get_settings (NMSettingsConnection *connection,
|
||||
DBusGMethodInvocation *context);
|
||||
|
|
@ -65,16 +66,22 @@ enum {
|
|||
enum {
|
||||
UPDATED,
|
||||
REMOVED,
|
||||
GET_SECRETS,
|
||||
CANCEL_SECRETS,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
typedef struct {
|
||||
gboolean disposed;
|
||||
|
||||
PolkitAuthority *authority;
|
||||
GSList *pending_auths; /* List of pending authentication requests */
|
||||
NMConnection *secrets;
|
||||
gboolean visible; /* Is this connection is visible by some session? */
|
||||
|
||||
GSList *reqs; /* in-progress secrets requests */
|
||||
|
||||
NMSessionMonitor *session_monitor;
|
||||
guint session_changed_id;
|
||||
} NMSettingsConnectionPrivate;
|
||||
|
|
@ -333,80 +340,6 @@ supports_secrets (NMSettingsConnection *connection, const char *setting_name)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static GValue *
|
||||
string_to_gvalue (const char *str)
|
||||
{
|
||||
GValue *val = g_slice_new0 (GValue);
|
||||
|
||||
g_value_init (val, G_TYPE_STRING);
|
||||
g_value_set_string (val, str);
|
||||
return val;
|
||||
}
|
||||
|
||||
static GValue *
|
||||
byte_array_to_gvalue (const GByteArray *array)
|
||||
{
|
||||
GValue *val;
|
||||
|
||||
val = g_slice_new0 (GValue);
|
||||
g_value_init (val, DBUS_TYPE_G_UCHAR_ARRAY);
|
||||
g_value_set_boxed (val, array);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void
|
||||
copy_one_secret (gpointer key, gpointer value, gpointer user_data)
|
||||
{
|
||||
const char *value_str = (const char *) value;
|
||||
|
||||
if (value_str) {
|
||||
g_hash_table_insert ((GHashTable *) user_data,
|
||||
g_strdup ((char *) key),
|
||||
string_to_gvalue (value_str));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_secrets (NMSetting *setting,
|
||||
const char *key,
|
||||
const GValue *value,
|
||||
GParamFlags flags,
|
||||
gpointer user_data)
|
||||
{
|
||||
GHashTable *secrets = user_data;
|
||||
|
||||
if (!(flags & NM_SETTING_PARAM_SECRET))
|
||||
return;
|
||||
|
||||
/* Copy secrets into the returned hash table */
|
||||
if (G_VALUE_HOLDS_STRING (value)) {
|
||||
const char *tmp;
|
||||
|
||||
tmp = g_value_get_string (value);
|
||||
if (tmp)
|
||||
g_hash_table_insert (secrets, g_strdup (key), string_to_gvalue (tmp));
|
||||
} else if (G_VALUE_HOLDS (value, DBUS_TYPE_G_MAP_OF_STRING)) {
|
||||
/* Flatten the string hash by pulling its keys/values out; for VPN secrets */
|
||||
g_hash_table_foreach (g_value_get_boxed (value), copy_one_secret, secrets);
|
||||
} else if (G_VALUE_TYPE (value) == DBUS_TYPE_G_UCHAR_ARRAY) {
|
||||
GByteArray *array;
|
||||
|
||||
array = g_value_get_boxed (value);
|
||||
if (array)
|
||||
g_hash_table_insert (secrets, g_strdup (key), byte_array_to_gvalue (array));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_gvalue (gpointer data)
|
||||
{
|
||||
GValue *value = (GValue *) data;
|
||||
|
||||
g_value_unset (value);
|
||||
g_slice_free (GValue, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_settings_connection_get_secrets:
|
||||
* @connection: the #NMSettingsConnection
|
||||
|
|
@ -415,6 +348,9 @@ destroy_gvalue (gpointer data)
|
|||
*
|
||||
* Return secrets in persistent storage, if any. Does not query any Secret
|
||||
* Agents for secrets.
|
||||
*
|
||||
* Returns: a hash mapping setting names to hash tables, each inner hash
|
||||
* containing string:value mappings of secrets
|
||||
**/
|
||||
GHashTable *
|
||||
nm_settings_connection_get_secrets (NMSettingsConnection *connection,
|
||||
|
|
@ -422,8 +358,6 @@ nm_settings_connection_get_secrets (NMSettingsConnection *connection,
|
|||
GError **error)
|
||||
{
|
||||
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (connection);
|
||||
GHashTable *settings = NULL;
|
||||
GHashTable *secrets = NULL;
|
||||
NMSetting *setting;
|
||||
|
||||
/* Use priv->secrets to work around the fact that nm_connection_clear_secrets()
|
||||
|
|
@ -448,19 +382,7 @@ nm_settings_connection_get_secrets (NMSettingsConnection *connection,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Returned secrets are a{sa{sv}}; this is the outer a{s...} hash that
|
||||
* will contain all the individual settings hashes.
|
||||
*/
|
||||
settings = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
g_free, (GDestroyNotify) g_hash_table_destroy);
|
||||
|
||||
/* Add the secrets from this setting to the inner secrets hash for this setting */
|
||||
secrets = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, destroy_gvalue);
|
||||
nm_setting_enumerate_values (setting, add_secrets, secrets);
|
||||
|
||||
g_hash_table_insert (settings, g_strdup (setting_name), secrets);
|
||||
|
||||
return secrets;
|
||||
return nm_connection_to_hash (priv->secrets, NM_SETTING_HASH_FLAG_ONLY_SECRETS);
|
||||
}
|
||||
|
||||
/**** User authorization **************************************/
|
||||
|
|
@ -736,31 +658,79 @@ impl_settings_connection_delete (NMSettingsConnection *self,
|
|||
auth_start (self, context, TRUE, delete_auth_cb, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
secrets_auth_cb (NMSettingsConnection *self,
|
||||
DBusGMethodInvocation *context,
|
||||
GError *error,
|
||||
gpointer user_data)
|
||||
/**************************************************************/
|
||||
|
||||
static gboolean
|
||||
get_secrets_accumulator (GSignalInvocationHint *ihint,
|
||||
GValue *return_accu,
|
||||
const GValue *handler_return,
|
||||
gpointer data)
|
||||
{
|
||||
guint handler_call_id = g_value_get_uint (handler_return);
|
||||
|
||||
if (handler_call_id > 0)
|
||||
g_value_set_uint (return_accu, handler_call_id);
|
||||
|
||||
/* Abort signal emission if a valid call ID got returned */
|
||||
return handler_call_id ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_get_agent_secrets_cb (NMSettingsConnection *self,
|
||||
const char *setting_name,
|
||||
guint32 call_id,
|
||||
GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
|
||||
DBusGMethodInvocation *context = user_data;
|
||||
GHashTable *hash;
|
||||
|
||||
priv->reqs = g_slist_remove (priv->reqs, GUINT_TO_POINTER (call_id));
|
||||
|
||||
/* The connection's secrets will have been updated by the agent manager,
|
||||
* so we want to refresh the secrets cache.
|
||||
*/
|
||||
if (priv->secrets)
|
||||
g_object_unref (priv->secrets);
|
||||
priv->secrets = nm_connection_duplicate (NM_CONNECTION (self));
|
||||
|
||||
if (error)
|
||||
dbus_g_method_return_error (context, error);
|
||||
else {
|
||||
hash = nm_connection_to_hash (NM_CONNECTION (self), NM_SETTING_HASH_FLAG_ONLY_SECRETS);
|
||||
dbus_g_method_return (context, hash);
|
||||
g_hash_table_destroy (hash);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_secrets_auth_cb (NMSettingsConnection *self,
|
||||
DBusGMethodInvocation *context,
|
||||
GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
|
||||
char *setting_name = user_data;
|
||||
GHashTable *secrets;
|
||||
guint32 call_id = 0;
|
||||
GError *local = NULL;
|
||||
|
||||
if (error) {
|
||||
if (error)
|
||||
dbus_g_method_return_error (context, error);
|
||||
goto out;
|
||||
else {
|
||||
g_signal_emit (self, signals[GET_SECRETS], 0, setting_name, dbus_get_agent_secrets_cb, context, &call_id);
|
||||
if (call_id > 0) {
|
||||
/* track the request and wait for the callback */
|
||||
priv->reqs = g_slist_append (priv->reqs, GUINT_TO_POINTER (call_id));
|
||||
} else {
|
||||
local = g_error_new_literal (NM_SETTINGS_ERROR,
|
||||
NM_SETTINGS_ERROR_SECRETS_UNAVAILABLE,
|
||||
"No secrets were available");
|
||||
dbus_g_method_return_error (context, local);
|
||||
g_error_free (local);
|
||||
}
|
||||
}
|
||||
|
||||
secrets = nm_settings_connection_get_secrets (self, setting_name, &error);
|
||||
if (secrets) {
|
||||
dbus_g_method_return (context, secrets);
|
||||
g_hash_table_destroy (secrets);
|
||||
} else {
|
||||
dbus_g_method_return_error (context, local);
|
||||
g_clear_error (&local);
|
||||
}
|
||||
|
||||
out:
|
||||
g_free (setting_name);
|
||||
}
|
||||
|
||||
|
|
@ -769,7 +739,7 @@ impl_settings_connection_get_secrets (NMSettingsConnection *self,
|
|||
const gchar *setting_name,
|
||||
DBusGMethodInvocation *context)
|
||||
{
|
||||
auth_start (self, context, TRUE, secrets_auth_cb, g_strdup (setting_name));
|
||||
auth_start (self, context, TRUE, dbus_secrets_auth_cb, g_strdup (setting_name));
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
|
|
@ -809,6 +779,10 @@ dispose (GObject *object)
|
|||
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
|
||||
GSList *iter;
|
||||
|
||||
if (priv->disposed)
|
||||
goto out;
|
||||
priv->disposed = TRUE;
|
||||
|
||||
if (priv->secrets)
|
||||
g_object_unref (priv->secrets);
|
||||
|
||||
|
|
@ -818,10 +792,16 @@ dispose (GObject *object)
|
|||
g_slist_free (priv->pending_auths);
|
||||
priv->pending_auths = NULL;
|
||||
|
||||
/* Cancel in-progress secrets requests */
|
||||
for (iter = priv->reqs; iter; iter = g_slist_next (iter))
|
||||
g_signal_emit (self, signals[CANCEL_SECRETS], 0, GPOINTER_TO_UINT (iter->data));
|
||||
g_slist_free (priv->reqs);
|
||||
|
||||
set_visible (self, FALSE);
|
||||
|
||||
g_object_unref (priv->session_monitor);
|
||||
|
||||
out:
|
||||
G_OBJECT_CLASS (nm_settings_connection_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
|
|
@ -890,6 +870,24 @@ nm_settings_connection_class_init (NMSettingsConnectionClass *class)
|
|||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
/* not exported over D-Bus */
|
||||
signals[GET_SECRETS] =
|
||||
g_signal_new (NM_SETTINGS_CONNECTION_GET_SECRETS,
|
||||
G_TYPE_FROM_CLASS (class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (NMSettingsConnectionClass, get_secrets),
|
||||
get_secrets_accumulator, NULL,
|
||||
_nm_marshal_UINT__STRING_POINTER_POINTER,
|
||||
G_TYPE_UINT, 3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER);
|
||||
|
||||
signals[CANCEL_SECRETS] =
|
||||
g_signal_new (NM_SETTINGS_CONNECTION_CANCEL_SECRETS,
|
||||
G_TYPE_FROM_CLASS (class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL,
|
||||
g_cclosure_marshal_VOID__UINT,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (class),
|
||||
&dbus_glib_nm_settings_connection_object_info);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,9 @@ G_BEGIN_DECLS
|
|||
|
||||
#define NM_SETTINGS_CONNECTION_UPDATED "updated"
|
||||
#define NM_SETTINGS_CONNECTION_REMOVED "removed"
|
||||
#define NM_SETTINGS_CONNECTION_GET_SECRETS "get-secrets"
|
||||
#define NM_SETTINGS_CONNECTION_CANCEL_SECRETS "cancel-secrets"
|
||||
|
||||
#define NM_SETTINGS_CONNECTION_VISIBLE "visible"
|
||||
|
||||
typedef struct _NMSettingsConnection NMSettingsConnection;
|
||||
|
|
@ -50,6 +53,12 @@ typedef void (*NMSettingsConnectionDeleteFunc) (NMSettingsConnection *connection
|
|||
GError *error,
|
||||
gpointer user_data);
|
||||
|
||||
typedef void (*NMSettingsConnectionSecretsUpdatedFunc) (NMSettingsConnection *connection,
|
||||
const char *setting_name,
|
||||
guint32 call_id,
|
||||
GError *error,
|
||||
gpointer user_data);
|
||||
|
||||
struct _NMSettingsConnection {
|
||||
NMConnection parent;
|
||||
};
|
||||
|
|
@ -57,6 +66,7 @@ struct _NMSettingsConnection {
|
|||
struct _NMSettingsConnectionClass {
|
||||
NMConnectionClass parent;
|
||||
|
||||
/* virtual methods */
|
||||
void (*commit_changes) (NMSettingsConnection *connection,
|
||||
NMSettingsConnectionCommitFunc callback,
|
||||
gpointer user_data);
|
||||
|
|
@ -67,6 +77,14 @@ struct _NMSettingsConnectionClass {
|
|||
|
||||
gboolean (*supports_secrets) (NMSettingsConnection *connection,
|
||||
const char *setting_name);
|
||||
|
||||
/* signals */
|
||||
guint32 (*get_secrets) (NMSettingsConnection *connection,
|
||||
const char *setting_name,
|
||||
NMSettingsConnectionSecretsUpdatedFunc callback,
|
||||
gpointer callback_data);
|
||||
|
||||
void (*cancel_secrets) (NMSettingsConnection *connection, guint32 call_id);
|
||||
};
|
||||
|
||||
GType nm_settings_connection_get_type (void);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue