Commit 28a04fcb54 for strongswan.org

commit 28a04fcb54ea2ebc13cac77517aa7bddf72d29a8
Author: Jarno Mäkelä <jarno.makela@iki.fi>
Date:   Mon Oct 12 14:50:29 2026 +0300

    nm: Add private key password field to editor and auth dialog

    The editor now has a dedicated row for the private key passphrase,
    saved as the "userkey-password" secret.  An empty private key password
    defaults to "not required" so that unencrypted keys do not prompt for
    a passphrase.  The password row no longer serves the key for certificate
    methods with a key file; it remains the EAP and PSK password.  A
    smartcard PIN is stored as "pin" and is never saved in the connection,
    only supplied by the auth dialog.  A key passphrase that was saved as
    "password" before this change is carried over to "userkey-password" when
    the connection is edited and ignored for the password field.

    For new connections, the auth dialog returns the secret whose name
    depends on the method:  "password" for eap and psk, "pin" for a smartcard
    certificate source, and "userkey-password" otherwise.  For legacy
    connections it defaults to "password" based on the flags.  The dialog
    now also reads the password flags from the correct hash table.

    Signed-off-by: Jarno Mäkelä <jarno.makela@iki.fi>

diff --git a/src/frontends/gnome/auth-dialog/main.c b/src/frontends/gnome/auth-dialog/main.c
index fe42875c15..39e0e1e3a0 100644
--- a/src/frontends/gnome/auth-dialog/main.c
+++ b/src/frontends/gnome/auth-dialog/main.c
@@ -106,6 +106,7 @@ static void keyfile_print_stdout (GKeyFile *keyfile)
 }

 static gboolean get_secrets(const char *type, const char *cert_source, const char *uuid, const char *name,
+							const char *secret_name,
 							gboolean retry, gboolean allow_interaction, gboolean external_ui_mode,
 							const char *in_pw, char **out_pw, NMSettingSecretFlags flags)
 {
@@ -123,7 +124,7 @@ static gboolean get_secrets(const char *type, const char *cert_source, const cha
 		}
 		else
 		{
-			pw = keyring_lookup_secret (uuid, "password");
+			pw = keyring_lookup_secret (uuid, secret_name);
 		}
 	}
 	if (flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED)
@@ -165,7 +166,7 @@ static gboolean get_secrets(const char *type, const char *cert_source, const cha
 		g_key_file_set_string (keyfile, UI_KEYFILE_GROUP, "Description", prompt);
 		g_key_file_set_string (keyfile, UI_KEYFILE_GROUP, "Title", _("Authenticate VPN"));

-		keyfile_add_entry_info (keyfile, "password", pw ?: "", _("Password:"), TRUE, allow_interaction);
+		keyfile_add_entry_info (keyfile, secret_name, pw ?: "", _("Password:"), TRUE, allow_interaction);

 		keyfile_print_stdout (keyfile);
 		g_key_file_unref (keyfile);
@@ -254,6 +255,7 @@ int main (int argc, char *argv[])
 	NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
 	GOptionContext *context;
 	char *agent, *type, *cert_source;
+	const char *secret_name = "password";
 	int status = 0;
 	GOptionEntry entries[] = {
 		{ "reprompt", 'r', 0, G_OPTION_ARG_NONE, &retry, "Reprompt for passwords", NULL},
@@ -350,7 +352,17 @@ int main (int argc, char *argv[])
 		}
 		else
 		{
+			NMSettingSecretFlags new_flags = NM_SETTING_SECRET_FLAG_NONE;
+
 			need_secret = TRUE;
+			secret_name = !strcmp(cert_source, "smartcard") ? "pin" : "userkey-password";
+			/* fallback to the legacy field for connections that were saved
+			 * before the rename, otherwise stored passwords/flags won't be used
+			 * and the returned flagless password is stored in the connection */
+			if (!nm_vpn_service_plugin_get_secret_flags (data, secret_name, &new_flags))
+			{
+				secret_name = "password";
+			}
 		}
 	}

@@ -358,15 +370,15 @@ int main (int argc, char *argv[])
 		!strcmp(type, "eap") ||
 		!strcmp(type, "psk"))
 	{
-		nm_vpn_service_plugin_get_secret_flags (secrets, "password", &flags);
-		if (!get_secrets(type, cert_source, uuid, name, retry, allow_interaction,
-						 external_ui_mode, g_hash_table_lookup (secrets, "password"), &pass, flags))
+		nm_vpn_service_plugin_get_secret_flags (data, secret_name, &flags);
+		if (!get_secrets(type, cert_source, uuid, name, secret_name, retry, allow_interaction,
+						 external_ui_mode, g_hash_table_lookup (secrets, secret_name), &pass, flags))
 		{
 			status = 1;
 		}
 		else if (!external_ui_mode)
 		{
-			print_secret("password", pass);
+			print_secret(secret_name, pass);
 			wait_for_quit ();
 		}
 	}
diff --git a/src/frontends/gnome/properties/nm-strongswan-dialog.ui b/src/frontends/gnome/properties/nm-strongswan-dialog.ui
index f90c2c7262..a0aaeb979c 100644
--- a/src/frontends/gnome/properties/nm-strongswan-dialog.ui
+++ b/src/frontends/gnome/properties/nm-strongswan-dialog.ui
@@ -397,6 +397,33 @@
                 <property name="top-attach">3</property>
               </packing>
             </child>
+            <child>
+              <object class="GtkLabel" id="userkey-password-label">
+                <property name="visible">True</property>
+                <property name="can-focus">False</property>
+                <property name="label" translatable="yes">Private key pass_word:</property>
+                <property name="use-underline">True</property>
+                <property name="xalign">0</property>
+              </object>
+              <packing>
+                <property name="left-attach">0</property>
+                <property name="top-attach">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkEntry" id="userkey-password-entry">
+                <property name="visible">True</property>
+                <property name="can-focus">True</property>
+                <property name="tooltip-text" translatable="yes">The password to decrypt the private key, if it is encrypted.</property>
+                <property name="hexpand">True</property>
+                <property name="visibility">False</property>
+                <property name="placeholder-text" translatable="yes">(Use icon to change password storage policy)</property>
+              </object>
+              <packing>
+                <property name="left-attach">1</property>
+                <property name="top-attach">4</property>
+              </packing>
+            </child>
             <child>
               <object class="GtkLabel" id="user-label">
                 <property name="visible">True</property>
@@ -407,7 +434,7 @@
               </object>
               <packing>
                 <property name="left-attach">0</property>
-                <property name="top-attach">5</property>
+                <property name="top-attach">6</property>
               </packing>
             </child>
             <child>
@@ -419,7 +446,7 @@
               </object>
               <packing>
                 <property name="left-attach">1</property>
-                <property name="top-attach">5</property>
+                <property name="top-attach">6</property>
               </packing>
             </child>
             <child>
@@ -432,7 +459,7 @@
               </object>
               <packing>
                 <property name="left-attach">0</property>
-                <property name="top-attach">6</property>
+                <property name="top-attach">7</property>
               </packing>
             </child>
             <child>
@@ -446,7 +473,7 @@
               </object>
               <packing>
                 <property name="left-attach">1</property>
-                <property name="top-attach">6</property>
+                <property name="top-attach">7</property>
               </packing>
             </child>
             <child>
@@ -461,7 +488,7 @@
               </object>
               <packing>
                 <property name="left-attach">1</property>
-                <property name="top-attach">7</property>
+                <property name="top-attach">8</property>
               </packing>
             </child>
             <child>
@@ -474,7 +501,7 @@
               </object>
               <packing>
                 <property name="left-attach">0</property>
-                <property name="top-attach">4</property>
+                <property name="top-attach">5</property>
               </packing>
             </child>
             <child>
@@ -487,7 +514,7 @@
               </object>
               <packing>
                 <property name="left-attach">1</property>
-                <property name="top-attach">4</property>
+                <property name="top-attach">5</property>
               </packing>
             </child>
             <child>
diff --git a/src/frontends/gnome/properties/nm-strongswan.c b/src/frontends/gnome/properties/nm-strongswan.c
index 4b518c79c8..f74eb9be96 100644
--- a/src/frontends/gnome/properties/nm-strongswan.c
+++ b/src/frontends/gnome/properties/nm-strongswan.c
@@ -168,7 +168,6 @@ static void update_cert_fields (StrongswanPluginUiWidgetPrivate *priv, gboolean
 			gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
 			/* FALL */
 		case 0:
-			update_pass_field (priv, TRUE);
 			cert = key = TRUE;
 			break;
 		case 1:
@@ -184,6 +183,8 @@ static void update_cert_fields (StrongswanPluginUiWidgetPrivate *priv, gboolean
 	gtk_widget_set_sensitive (GTK_WIDGET (gtk_builder_get_object (priv->builder, "usercert-button")), enabled && cert);
 	gtk_widget_set_sensitive (GTK_WIDGET (gtk_builder_get_object (priv->builder, "userkey-label")), enabled && key);
 	gtk_widget_set_sensitive (GTK_WIDGET (gtk_builder_get_object (priv->builder, "userkey-button")), enabled && key);
+	gtk_widget_set_sensitive (GTK_WIDGET (gtk_builder_get_object (priv->builder, "userkey-password-label")), enabled && key);
+	gtk_widget_set_sensitive (GTK_WIDGET (gtk_builder_get_object (priv->builder, "userkey-password-entry")), enabled && key);
 }

 static void update_sensitive (StrongswanPluginUiWidgetPrivate *priv)
@@ -316,7 +317,8 @@ password_storage_changed_cb (GObject *entry, GParamSpec *pspec, gpointer user_da

 static void
 init_password_icon (StrongswanPluginUiWidget *self, NMSettingVpn *settings,
-					const char *secret_key, const char *entry_name)
+					const char *secret_key, const char *entry_name,
+					NMSettingSecretFlags empty_flags)
 {
 	StrongswanPluginUiWidgetPrivate *priv = STRONGSWAN_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
 	GtkWidget *entry;
@@ -331,7 +333,7 @@ init_password_icon (StrongswanPluginUiWidget *self, NMSettingVpn *settings,
 	nma_utils_setup_password_storage (entry, 0, NM_SETTING (settings), secret_key, TRUE, FALSE);

 	/* If there's no password and no flags in the setting,
-	 * initialize flags as "always-ask".
+	 * initialize flags as given by the caller.
 	 */
 	if (settings)
 	{
@@ -341,7 +343,7 @@ init_password_icon (StrongswanPluginUiWidget *self, NMSettingVpn *settings,
 	value = gtk_editable_get_text (GTK_EDITABLE (entry));
 	if ((!value || !*value) && (pw_flags == NM_SETTING_SECRET_FLAG_NONE))
 	{
-		nma_utils_update_password_storage (entry, NM_SETTING_SECRET_FLAG_NOT_SAVED,
+		nma_utils_update_password_storage (entry, empty_flags,
 										   NM_SETTING (settings), secret_key);
 	}

@@ -382,8 +384,9 @@ init_plugin_ui (StrongswanPluginUiWidget *self, NMConnection *connection, GError
 {
 	StrongswanPluginUiWidgetPrivate *priv = STRONGSWAN_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
 	NMSettingVpn *settings;
+	NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
 	GtkWidget *widget;
-	const char *value, *method;
+	const char *value, *method, *secret;

 	settings = NM_SETTING_VPN(nm_connection_get_setting(connection, NM_TYPE_SETTING_VPN));

@@ -426,14 +429,37 @@ init_plugin_ui (StrongswanPluginUiWidget *self, NMConnection *connection, GError
 		gtk_editable_set_text (GTK_EDITABLE (widget), value);
 	g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (settings_changed_cb), self);

+	/* fallback to the password for old certificate configs, before the password
+	 * field below stores default flags for it */
+	secret = "userkey-password";
+	if (!nm_setting_vpn_get_secret (settings, "userkey-password") &&
+		!(nm_setting_get_secret_flags (NM_SETTING (settings), "userkey-password",
+									   &flags, NULL) && flags) &&
+		(nm_setting_vpn_get_secret (settings, "password") ||
+		 (nm_setting_get_secret_flags (NM_SETTING (settings), "password",
+									   &flags, NULL) && flags)) &&
+		method && g_strcmp0 (method, "eap") != 0 && g_strcmp0 (method, "psk") != 0)
+	{
+		secret = "password";
+	}
+	widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "userkey-password-entry"));
+	value = nm_setting_vpn_get_secret (settings, secret);
+	if (value)
+		gtk_editable_set_text (GTK_EDITABLE (widget), value);
+	g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (settings_changed_cb), self);
+	init_password_icon (self, settings, secret, "userkey-password-entry",
+						NM_SETTING_SECRET_FLAG_NOT_REQUIRED);
+
 	widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "passwd-show"));
 	g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (show_toggled_cb), self);
 	widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "passwd-entry"));
 	value = nm_setting_vpn_get_secret (settings, "password");
-	if (value)
+	/* ignore legacy password for certificate configs */
+	if (value && method && (g_strcmp0 (method, "eap") == 0 || g_strcmp0 (method, "psk") == 0))
 		gtk_editable_set_text (GTK_EDITABLE (widget), value);
 	g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (settings_changed_cb), self);
-	init_password_icon (self, settings, "password", "passwd-entry");
+	init_password_icon (self, settings, "password", "passwd-entry",
+						NM_SETTING_SECRET_FLAG_NOT_SAVED);

 	widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "method-combo"));
 	gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), _("EAP (Username/Password)"));
@@ -646,8 +672,8 @@ save_cert (NMSettingVpn *settings, GtkBuilder *builder)
 	{
 		default:
 		case 0:
-			save_password_and_flags (settings, builder, "passwd-entry",
-									 "password");
+			save_password_and_flags (settings, builder, "userkey-password-entry",
+									 "userkey-password");
 			cert = key = TRUE;
 			str = "file";
 			break;
@@ -656,7 +682,7 @@ save_cert (NMSettingVpn *settings, GtkBuilder *builder)
 			str = "agent";
 			break;
 		case 2:
-			nm_setting_set_secret_flags (NM_SETTING (settings), "password",
+			nm_setting_set_secret_flags (NM_SETTING (settings), "pin",
 										 NM_SETTING_SECRET_FLAG_NOT_SAVED, NULL);
 			str = "smartcard";
 			break;
@@ -769,6 +795,8 @@ dispose (GObject *object)

 	widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "passwd-entry"));
 	g_signal_handlers_disconnect_by_func (G_OBJECT (widget), G_CALLBACK (password_storage_changed_cb), plugin);
+	widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "userkey-password-entry"));
+	g_signal_handlers_disconnect_by_func (G_OBJECT (widget), G_CALLBACK (password_storage_changed_cb), plugin);

 	if (priv->widget)
 		g_object_unref (priv->widget);