From 375be1c1b0eb852bbfb897f813f64d86b4211963 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 23 Feb 2026 17:23:23 +0100 Subject: [PATCH] settings: fix check on existing system secrets The previous check was based only on the presence of a non-NULL "existing_secrets" GVariant. That GVariant is created via: nm_connection_to_dbus(nm_settings_connection_get_connection(self), NM_CONNECTION_SERIALIZE_WITH_SECRETS_SYSTEM_OWNED) The function returns a GVariant containing a first-level dictionary for each setting, even for those that doesn't contain any secrets. As a result, the check was requiring the system.modify permission even if there weren't any cached secrets to send to the agent. Fix the check to actually check for the presence of any secrets in the cached dictionary. Some connection types have a third-level dictionary that can be empty, for example VPNs have vpn.secrets. (cherry picked from commit 024360bffa1d0848f2acb0d4eabefedf1b5f8787) --- src/core/settings/nm-agent-manager.c | 35 +++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/core/settings/nm-agent-manager.c b/src/core/settings/nm-agent-manager.c index 19b3cfcbaf..ce7dbab2f0 100644 --- a/src/core/settings/nm-agent-manager.c +++ b/src/core/settings/nm-agent-manager.c @@ -1083,6 +1083,39 @@ _con_get_request_start_validated(NMAuthChain *chain, _con_get_request_start_proceed(req, req->con.current_has_modify); } +static gboolean +_req_has_existing_secrets(Request *req) +{ + GVariantIter iter; + const char *setting_name; + GVariant *setting_dict; + gboolean has; + + if (!req->con.get.existing_secrets) + return FALSE; + + nm_assert(g_variant_is_of_type(req->con.get.existing_secrets, NM_VARIANT_TYPE_CONNECTION)); + + g_variant_iter_init(&iter, req->con.get.existing_secrets); + while (g_variant_iter_next(&iter, "{&s@a{sv}}", &setting_name, &setting_dict)) { + GVariantIter setting_iter; + GVariant *val; + + g_variant_iter_init(&setting_iter, setting_dict); + while (g_variant_iter_next(&setting_iter, "{&sv}", NULL, &val)) { + has = !g_variant_is_container(val) || g_variant_n_children(val) > 0; + g_variant_unref(val); + if (has) { + g_variant_unref(setting_dict); + return TRUE; + } + } + g_variant_unref(setting_dict); + } + + return FALSE; +} + static void _con_get_request_start(Request *req) { @@ -1103,7 +1136,7 @@ _con_get_request_start(Request *req) * unprivileged users. */ if ((req->con.get.flags != NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE) - && (req->con.get.existing_secrets + && (_req_has_existing_secrets(req) || _nm_connection_aggregate(req->con.connection, NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS, NULL))) {