mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-05-05 01:47:58 +02:00
settings: allow settings service to return partial secrets
This allows the admin to define generic secrets for all users the connection is visible to, but allows user-specific secrets as well.
This commit is contained in:
parent
4f058e2dc4
commit
f7e27ea239
1 changed files with 99 additions and 7 deletions
|
|
@ -351,6 +351,8 @@ struct _Request {
|
||||||
|
|
||||||
guint32 idle_id;
|
guint32 idle_id;
|
||||||
|
|
||||||
|
GHashTable *settings_secrets;
|
||||||
|
|
||||||
NMAgentSecretsResultFunc callback;
|
NMAgentSecretsResultFunc callback;
|
||||||
gpointer callback_data;
|
gpointer callback_data;
|
||||||
gpointer other_data2;
|
gpointer other_data2;
|
||||||
|
|
@ -405,12 +407,60 @@ request_free (Request *req)
|
||||||
g_object_unref (req->connection);
|
g_object_unref (req->connection);
|
||||||
g_free (req->setting_name);
|
g_free (req->setting_name);
|
||||||
g_free (req->hint);
|
g_free (req->hint);
|
||||||
|
if (req->settings_secrets)
|
||||||
|
g_hash_table_unref (req->settings_secrets);
|
||||||
memset (req, 0, sizeof (Request));
|
memset (req, 0, sizeof (Request));
|
||||||
g_free (req);
|
g_free (req);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void request_next (Request *req);
|
static void request_next (Request *req);
|
||||||
|
|
||||||
|
static void
|
||||||
|
destroy_gvalue (gpointer data)
|
||||||
|
{
|
||||||
|
GValue *value = (GValue *) data;
|
||||||
|
|
||||||
|
g_value_unset (value);
|
||||||
|
g_slice_free (GValue, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
merge_secrets (GHashTable *src, GHashTable *dest)
|
||||||
|
{
|
||||||
|
GHashTableIter iter;
|
||||||
|
gpointer key, data;
|
||||||
|
|
||||||
|
g_hash_table_iter_init (&iter, src);
|
||||||
|
while (g_hash_table_iter_next (&iter, &key, &data)) {
|
||||||
|
const char *setting_name = key;
|
||||||
|
GHashTable *dstsetting;
|
||||||
|
GHashTableIter subiter;
|
||||||
|
gpointer subkey, subval;
|
||||||
|
|
||||||
|
/* Find the corresponding setting in the merged secrets hash, or create
|
||||||
|
* it if it doesn't exist.
|
||||||
|
*/
|
||||||
|
dstsetting = g_hash_table_lookup (dest, setting_name);
|
||||||
|
if (!dstsetting) {
|
||||||
|
dstsetting = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) destroy_gvalue);
|
||||||
|
g_hash_table_insert (dest, (gpointer) setting_name, dstsetting);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* And copy in each secret from src */
|
||||||
|
g_hash_table_iter_init (&subiter, (GHashTable *) data);
|
||||||
|
while (g_hash_table_iter_next (&subiter, &subkey, &subval)) {
|
||||||
|
const char *keyname = subkey;
|
||||||
|
GValue *srcval = subval, *dstval;
|
||||||
|
|
||||||
|
dstval = g_slice_new0 (GValue);
|
||||||
|
g_value_init (dstval, G_VALUE_TYPE (srcval));
|
||||||
|
g_value_copy (srcval, dstval);
|
||||||
|
|
||||||
|
g_hash_table_insert (dstsetting, (gpointer) keyname, dstval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
request_secrets_done_cb (DBusGProxy *proxy,
|
request_secrets_done_cb (DBusGProxy *proxy,
|
||||||
DBusGProxyCall *call_id,
|
DBusGProxyCall *call_id,
|
||||||
|
|
@ -459,8 +509,23 @@ request_secrets_done_cb (DBusGProxy *proxy,
|
||||||
nm_secret_agent_get_description (agent),
|
nm_secret_agent_get_description (agent),
|
||||||
req, req->setting_name);
|
req, req->setting_name);
|
||||||
|
|
||||||
/* Success! */
|
/* Success! If we got some secrets from the settings service, merge those
|
||||||
req->complete_callback (req, secrets, NULL, req->complete_callback_data);
|
* with the ones from the secret agent.
|
||||||
|
*/
|
||||||
|
if (req->settings_secrets) {
|
||||||
|
GHashTable *merged;
|
||||||
|
|
||||||
|
merged = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) g_hash_table_unref);
|
||||||
|
|
||||||
|
/* Copy agent secrets first, then overwrite with settings secrets */
|
||||||
|
merge_secrets (secrets, merged);
|
||||||
|
merge_secrets (req->settings_secrets, merged);
|
||||||
|
|
||||||
|
req->complete_callback (req, merged, NULL, req->complete_callback_data);
|
||||||
|
g_hash_table_destroy (merged);
|
||||||
|
} else
|
||||||
|
req->complete_callback (req, secrets, NULL, req->complete_callback_data);
|
||||||
|
|
||||||
g_hash_table_destroy (secrets);
|
g_hash_table_destroy (secrets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -506,7 +571,7 @@ static gboolean
|
||||||
request_start_secrets (gpointer user_data)
|
request_start_secrets (gpointer user_data)
|
||||||
{
|
{
|
||||||
Request *req = user_data;
|
Request *req = user_data;
|
||||||
GHashTable *secrets;
|
GHashTable *secrets, *setting_secrets = NULL;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
req->idle_id = 0;
|
req->idle_id = 0;
|
||||||
|
|
@ -516,9 +581,36 @@ request_start_secrets (gpointer user_data)
|
||||||
req->hint,
|
req->hint,
|
||||||
req->request_new,
|
req->request_new,
|
||||||
&error);
|
&error);
|
||||||
if (secrets && g_hash_table_size (secrets)) {
|
if (secrets)
|
||||||
/* The connection already had secrets, no need to get any */
|
setting_secrets = g_hash_table_lookup (secrets, req->setting_name);
|
||||||
req->complete_callback (req, secrets, NULL, req->complete_callback_data);
|
|
||||||
|
if (setting_secrets && g_hash_table_size (setting_secrets)) {
|
||||||
|
NMConnection *tmp;
|
||||||
|
|
||||||
|
/* The connection already had secrets; check if any more are required.
|
||||||
|
* If no more are required, we're done. If secrets are still needed,
|
||||||
|
* ask a secret agent for more. This allows admins to provide generic
|
||||||
|
* secrets but allow additional user-specific ones as well.
|
||||||
|
*/
|
||||||
|
tmp = nm_connection_duplicate (req->connection);
|
||||||
|
g_assert (tmp);
|
||||||
|
|
||||||
|
if (!nm_connection_update_secrets (tmp, req->setting_name, secrets, &error)) {
|
||||||
|
req->complete_callback (req, NULL, error, req->complete_callback_data);
|
||||||
|
g_clear_error (&error);
|
||||||
|
} else {
|
||||||
|
/* Do we have everything we need? */
|
||||||
|
/* FIXME: handle second check for VPN connections */
|
||||||
|
if (nm_connection_need_secrets (tmp, NULL) == NULL) {
|
||||||
|
/* Got everything, we're done */
|
||||||
|
req->complete_callback (req, secrets, NULL, req->complete_callback_data);
|
||||||
|
} else {
|
||||||
|
/* We don't, so ask some agents for additional secrets */
|
||||||
|
req->settings_secrets = g_hash_table_ref (secrets);
|
||||||
|
request_next (req);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_object_unref (tmp);
|
||||||
} else if (error) {
|
} else if (error) {
|
||||||
/* Errors from the system settings are hard errors; we don't go on
|
/* Errors from the system settings are hard errors; we don't go on
|
||||||
* to ask agents for secrets if the settings service failed.
|
* to ask agents for secrets if the settings service failed.
|
||||||
|
|
@ -534,7 +626,7 @@ request_start_secrets (gpointer user_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (secrets)
|
if (secrets)
|
||||||
g_hash_table_destroy (secrets);
|
g_hash_table_unref (secrets);
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue