Blob Blame History Raw
From 9c45ba07d6ff03ef7a2e67d25c75a4e3fa6179fa Mon Sep 17 00:00:00 2001
From: Stef Walter <stefw@gnome.org>
Date: Fri, 14 Mar 2014 11:08:02 +0100
Subject: [PATCH] pam: Fix issue with changed password not unlocking keyring

This is a backport of fix on master with the same subject. There's
a bit of strange code in the are of this fix, but lets keep it as
minimal as possible.

If a user (needs to) change their password while authenticating (via
GDM for example), and pam_gnome_keyring is configured to start the
daemon from the session PAM stage, then we were failing to pass the
changed password to our session handler.

Fix this issue so that this workflow works.

https://bugzilla.gnome.org/show_bug.cgi?id=726196
---
 pam/gkr-pam-module.c | 40 ++++++++++++++++++++++++++++++----------
 1 file changed, 30 insertions(+), 10 deletions(-)

diff --git a/pam/gkr-pam-module.c b/pam/gkr-pam-module.c
index 8ad814c..52514b8 100644
--- a/pam/gkr-pam-module.c
+++ b/pam/gkr-pam-module.c
@@ -824,6 +824,19 @@ parse_args (pam_handle_t *ph, int argc, const char **argv)
 	return args;
 }
 
+static int
+stash_password_for_session (pam_handle_t *ph,
+                            const char *password)
+{
+	if (pam_set_data (ph, "gkr_system_authtok", strdup (password),
+	                  cleanup_free_password) != PAM_SUCCESS) {
+		syslog (GKR_LOG_ERR, "gkr-pam: error stashing password for session");
+		return PAM_AUTHTOK_RECOVER_ERR;
+	}
+
+	return PAM_SUCCESS;
+}
+
 PAM_EXTERN int
 pam_sm_authenticate (pam_handle_t *ph, int unused, int argc, const char **argv)
 {
@@ -886,11 +899,9 @@ pam_sm_authenticate (pam_handle_t *ph, int unused, int argc, const char **argv)
 		
 	/* Otherwise start later in open session, store password */
 	} else {
-		if (pam_set_data (ph, "gkr_system_authtok", strdup (password),
-		                  cleanup_free_password) != PAM_SUCCESS) {
-			syslog (GKR_LOG_ERR, "gkr-pam: error storing authtok");
+		ret = stash_password_for_session (ph, password);
+		if (ret != PAM_SUCCESS)
 			return PAM_AUTHTOK_RECOVER_ERR;
-		}
  	}
 
 	return PAM_SUCCESS;
@@ -1017,18 +1028,20 @@ pam_chauthtok_update (pam_handle_t *ph, struct passwd *pwd, uint args)
 {
 	const char *password, *original;
 	int ret, started_daemon = 0;
-	
+
+	ret = pam_get_item (ph, PAM_AUTHTOK, (const void**)&password);
+	if (ret != PAM_SUCCESS)
+		password = NULL;
+
 	ret = pam_get_item (ph, PAM_OLDAUTHTOK, (const void**)&original);
 	if (ret != PAM_SUCCESS || original == NULL) {
 		syslog (GKR_LOG_WARN, "gkr-pam: couldn't update the login keyring password: %s",
 		        "no old password was entered");
+		if (password)
+			stash_password_for_session (ph, password);
 		return PAM_IGNORE;
 	}
 		
-	ret = pam_get_item (ph, PAM_AUTHTOK, (const void**)&password);
-	if (ret != PAM_SUCCESS)
-		password = NULL;
-		
 	if (password == NULL) {
 		/* No password was set, and we can't prompt for it */
 		if (args & ARG_USE_AUTHTOK) {
@@ -1064,9 +1077,16 @@ pam_chauthtok_update (pam_handle_t *ph, struct passwd *pwd, uint args)
 
 	/* if not auto_start, kill the daemon if we started it: we don't want
 	 * it to stay */
-	if (started_daemon && !(args & ARG_AUTO_START))
+	if (started_daemon && !(args & ARG_AUTO_START)) {
 		stop_daemon (ph, pwd);
 
+		/*
+		 * Likely the daemon is being started later in the session if we weren't
+		 * allowed to autostart it here. Store the password for our session handler
+		 */
+		stash_password_for_session (ph, password);
+	}
+
 	if (ret != PAM_SUCCESS)
 		return ret;
 		
-- 
1.8.5.3