From 1c2d783932e4645a60b6fe9f15f6fc85b7cc71bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Bene=C5=A1?= Date: Mon, 30 Mar 2026 11:27:41 +0200 Subject: [PATCH] policy: delete never-connected profiles that fail with no-secrets When a connection profile fails with no-secrets and has never been successfully activated (timestamp is 0 or unset), delete it instead of just blocking autoconnect. This prevents a race where a secret agent (e.g. nmtui) unregisters and re-registers, causing reset_autoconnect_all() to clear the no-secrets block and triggering autoconnect on a profile that has no stored secrets. Profiles with always-ask secrets (NM_SETTING_SECRET_FLAG_NOT_SAVED) are preserved as they intentionally have no stored secrets. --- src/core/nm-policy.c | 59 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/core/nm-policy.c b/src/core/nm-policy.c index f7be1a9f87..aaf526d45d 100644 --- a/src/core/nm-policy.c +++ b/src/core/nm-policy.c @@ -2267,6 +2267,64 @@ device_state_changed(NMDevice *device, switch (nm_device_state_reason_check(reason)) { case NM_DEVICE_STATE_REASON_NO_SECRETS: + { + guint64 ts = 0; + NMConnection *conn; + gs_unref_ptrarray GPtrArray *hints = NULL; + const char *need_setting; + gboolean is_always_ask = FALSE; + + conn = nm_settings_connection_get_connection(sett_conn); + + /* Check if missing secrets have the always-ask (NOT_SAVED) flag. + * Such profiles are intentionally created without stored secrets + * and should not be deleted. */ + need_setting = nm_connection_need_secrets(conn, &hints); + if (need_setting && hints) { + NMSetting *s = nm_connection_get_setting_by_name(conn, need_setting); + + if (s) { + for (guint i = 0; i < hints->len; i++) { + NMSettingSecretFlags f = NM_SETTING_SECRET_FLAG_NONE; + + nm_setting_get_secret_flags(s, hints->pdata[i], &f, NULL); + if (NM_FLAGS_HAS(f, NM_SETTING_SECRET_FLAG_NOT_SAVED)) { + is_always_ask = TRUE; + break; + } + } + } + } + + /* Mark as volatile profiles that need secrets but those were never + * provided and the profile never connected successfully. These are + * profiles created by accident or for networks where the user does + * not have the credentials. There is no point in keeping them around + * as they have no secrets and cannot connect without user intervention. + * The volatile flag causes them to be deleted once they fully + * disconnect. + * + * Preserve profiles with always-ask secrets (NOT_SAVED flag) as + * those are intentionally created without stored secrets. + * + * Note: nm_device_state_changed() in nm-device.c calls + * nm_settings_connection_update_timestamp(sett_conn, 0) before we get + * here, so nm_settings_connection_get_timestamp() returns TRUE even for + * never-connected profiles. We must also check that the timestamp + * value itself is zero. */ + if (!is_always_ask + && (!nm_settings_connection_get_timestamp(sett_conn, &ts) || ts == 0)) { + _LOGD(LOGD_DEVICE, + "policy: connection[" NM_HASH_OBFUSCATE_PTR_FMT + "] (%s) never connected and has no secrets, marking volatile", + NM_HASH_OBFUSCATE_PTR(sett_conn), + nm_settings_connection_get_id(sett_conn)); + nm_settings_connection_set_flags(sett_conn, + NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE, + TRUE); + break; + } + /* we want to block the connection from auto-connect if it failed due to no-secrets. * However, if a secret-agent registered, since the connection made the last * secret-request, we do not block it. The new secret-agent might not yet @@ -2295,6 +2353,7 @@ device_state_changed(NMDevice *device, blocked = TRUE; } break; + } case NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED: /* A connection that fails due to dependency-failed is not able to * reconnect until the connection it depends on activates again;