summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stef@memberwebs.com>2010-10-18 02:12:30 +0000
committerStef Walter <stef@memberwebs.com>2010-10-18 02:12:30 +0000
commita5fe7f0b52cbce5da67b320c2b62595f59598a19 (patch)
treef212093f22b55496270f310f49819f178993b80b
parent03ba6357792679f96f7d425b2f45f3fbbbad8df1 (diff)
downloadgnome-keyring-a5fe7f0b52cbce5da67b320c2b62595f59598a19.tar.gz
[wrap-layer] Fix login keyring password doesn't match login.
When the user's unix login password doesn't match their login keyring (due to perhaps a change by an administrator) we need to prompt for the password to unlock. Now we keep track of the old one that failed and change their login keyring password to match their unix login.
-rw-r--r--daemon/gkd-main.c2
-rw-r--r--daemon/login/gkd-login.c5
-rw-r--r--pkcs11/wrap-layer/gkm-wrap-layer.h6
-rw-r--r--pkcs11/wrap-layer/gkm-wrap-login.c38
-rw-r--r--pkcs11/wrap-layer/gkm-wrap-login.h2
-rw-r--r--pkcs11/wrap-layer/gkm-wrap-prompt.c89
-rw-r--r--pkcs11/wrap-layer/tests/test-login-hints.c15
7 files changed, 134 insertions, 23 deletions
diff --git a/daemon/gkd-main.c b/daemon/gkd-main.c
index a19ceef7..f78100c8 100644
--- a/daemon/gkd-main.c
+++ b/daemon/gkd-main.c
@@ -684,7 +684,7 @@ gkr_daemon_initialize_steps (const gchar *components)
*/
if (login_password) {
if (!gkd_login_unlock (login_password))
- g_message ("Failed to unlock login on startup");
+ g_message ("failed to unlock login keyring on startup");
egg_secure_strclear (login_password);
}
diff --git a/daemon/login/gkd-login.c b/daemon/login/gkd-login.c
index 408d41ac..abd352a6 100644
--- a/daemon/login/gkd-login.c
+++ b/daemon/login/gkd-login.c
@@ -224,7 +224,7 @@ unlock_or_create_login (GP11Module *module, const gchar *master)
/* Failure, bad password? */
if (cred == NULL) {
if (login && g_error_matches (error, GP11_ERROR, CKR_PIN_INCORRECT))
- gkm_wrap_layer_hint_login_unlock_failure ();
+ gkm_wrap_layer_mark_login_unlock_failure (master);
else
g_warning ("couldn't create login credential: %s", egg_error_message (error));
g_clear_error (&error);
@@ -239,7 +239,7 @@ unlock_or_create_login (GP11Module *module, const gchar *master)
/* The unlock succeeded yay */
} else {
- gkm_wrap_layer_hint_login_unlock_success ();
+ gkm_wrap_layer_mark_login_unlock_success ();
}
if (cred)
@@ -340,7 +340,6 @@ change_or_create_login (GP11Module *module, const gchar *original, const gchar *
g_message ("couldn't change login master password, "
"original password was wrong: %s",
egg_error_message (error));
- gkm_wrap_layer_hint_login_unlock_failure ();
} else {
g_warning ("couldn't create original login credential: %s",
egg_error_message (error));
diff --git a/pkcs11/wrap-layer/gkm-wrap-layer.h b/pkcs11/wrap-layer/gkm-wrap-layer.h
index 531e7b77..df5306ac 100644
--- a/pkcs11/wrap-layer/gkm-wrap-layer.h
+++ b/pkcs11/wrap-layer/gkm-wrap-layer.h
@@ -24,6 +24,8 @@
#include "pkcs11/pkcs11.h"
+#include <glib.h>
+
CK_FUNCTION_LIST_PTR gkm_wrap_layer_get_functions (void);
CK_FUNCTION_LIST_PTR gkm_wrap_layer_get_functions_no_prompts (void);
@@ -32,8 +34,8 @@ void gkm_wrap_layer_reset_modules (void);
void gkm_wrap_layer_add_module (CK_FUNCTION_LIST_PTR funcs);
-void gkm_wrap_layer_hint_login_unlock_success (void);
+void gkm_wrap_layer_mark_login_unlock_success (void);
-void gkm_wrap_layer_hint_login_unlock_failure (void);
+void gkm_wrap_layer_mark_login_unlock_failure (const gchar *failed_password);
#endif /* __GKM_WRAP_LAYER_H__ */
diff --git a/pkcs11/wrap-layer/gkm-wrap-login.c b/pkcs11/wrap-layer/gkm-wrap-login.c
index 7bef4426..d17b7ff2 100644
--- a/pkcs11/wrap-layer/gkm-wrap-login.c
+++ b/pkcs11/wrap-layer/gkm-wrap-login.c
@@ -36,24 +36,50 @@
#include <string.h>
-static gint unlock_failures = 0;
+/* Holds failed unlock password, accessed atomically */
+static gpointer unlock_failure = NULL;
void
-gkm_wrap_layer_hint_login_unlock_success (void)
+gkm_wrap_layer_mark_login_unlock_success (void)
{
- g_atomic_int_set (&unlock_failures, 0);
+ gpointer oldval = g_atomic_pointer_get (&unlock_failure);
+ if (g_atomic_pointer_compare_and_exchange (&unlock_failure, oldval, NULL))
+ egg_secure_strfree (oldval);
}
void
-gkm_wrap_layer_hint_login_unlock_failure (void)
+gkm_wrap_layer_mark_login_unlock_failure (const gchar *failed_password)
{
- g_atomic_int_inc (&unlock_failures);
+ gpointer oldval;
+ gpointer newval;
+
+ g_return_if_fail (failed_password);
+
+ oldval = g_atomic_pointer_get (&unlock_failure);
+ newval = egg_secure_strdup (failed_password);
+
+ if (g_atomic_pointer_compare_and_exchange (&unlock_failure, oldval, newval))
+ egg_secure_strfree (oldval);
+ else
+ egg_secure_strfree (newval);
}
gboolean
gkm_wrap_login_did_unlock_fail (void)
{
- return g_atomic_int_get (&unlock_failures) ? TRUE : FALSE;
+ return g_atomic_pointer_get (&unlock_failure) ? TRUE : FALSE;
+}
+
+gchar*
+gkm_wrap_login_steal_failed_password (void)
+{
+ gpointer oldval;
+
+ oldval = g_atomic_pointer_get (&unlock_failure);
+ if (!g_atomic_pointer_compare_and_exchange (&unlock_failure, oldval, NULL))
+ oldval = NULL;
+
+ return oldval;
}
static gboolean
diff --git a/pkcs11/wrap-layer/gkm-wrap-login.h b/pkcs11/wrap-layer/gkm-wrap-login.h
index 148a1b93..bbdc3a1b 100644
--- a/pkcs11/wrap-layer/gkm-wrap-login.h
+++ b/pkcs11/wrap-layer/gkm-wrap-login.h
@@ -28,6 +28,8 @@ gboolean gkm_wrap_login_is_usable (void);
gboolean gkm_wrap_login_did_unlock_fail (void);
+gchar* gkm_wrap_login_steal_failed_password (void);
+
void gkm_wrap_login_attach_secret (const gchar *label,
const gchar *secret,
const gchar *first,
diff --git a/pkcs11/wrap-layer/gkm-wrap-prompt.c b/pkcs11/wrap-layer/gkm-wrap-prompt.c
index 8c4a1c29..7fcc3ac1 100644
--- a/pkcs11/wrap-layer/gkm-wrap-prompt.c
+++ b/pkcs11/wrap-layer/gkm-wrap-prompt.c
@@ -91,13 +91,21 @@ set_warning_wrong (GkdSecretUnlock *self)
}
#endif
+static gboolean
+is_login_keyring (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
+{
+ gboolean is_login = FALSE;
+ if (!gkm_attributes_find_boolean (attrs, n_attrs, CKA_G_LOGIN_COLLECTION, &is_login))
+ return FALSE;
+ return is_login;
+}
+
static gchar*
auto_unlock_keyring_location (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
{
CK_ATTRIBUTE_PTR attr;
- gboolean is_login = FALSE;
- if (gkm_attributes_find_boolean (attrs, n_attrs, CKA_G_LOGIN_COLLECTION, &is_login) && is_login)
+ if (is_login_keyring (attrs, n_attrs))
return NULL;
attr = gkm_attributes_find (attrs, n_attrs, CKA_ID);
@@ -755,7 +763,6 @@ prepare_unlock_prompt (GkmWrapPrompt *self, CK_ATTRIBUTE_PTR attrs,
GkuPrompt *prompt;
const gchar *label = NULL;
CK_OBJECT_CLASS klass;
- gboolean is_login = FALSE;
g_assert (GKM_WRAP_IS_PROMPT (self));
@@ -782,7 +789,7 @@ prepare_unlock_prompt (GkmWrapPrompt *self, CK_ATTRIBUTE_PTR attrs,
label = _("Unnamed");
if (klass == CKO_G_COLLECTION) {
- if (gkm_attributes_find_boolean (attrs, n_attrs, CKA_G_LOGIN_COLLECTION, &is_login) && is_login)
+ if (is_login_keyring (attrs, n_attrs))
prepare_unlock_keyring_login (self);
else
prepare_unlock_keyring_other (self, label);
@@ -830,6 +837,65 @@ prepare_unlock_token (GkmWrapPrompt *self, CK_TOKEN_INFO_PTR tinfo)
g_free (label);
}
+static void
+fix_login_keyring_if_unlock_failed (GkmWrapPrompt *self, const gchar *password)
+{
+ CK_OBJECT_CLASS klass = CKO_G_CREDENTIAL;
+ CK_OBJECT_HANDLE cred;
+ CK_BBOOL tval = CK_TRUE;
+ CK_ATTRIBUTE attrs[4];
+ gchar *failed;
+ CK_RV rv;
+
+ failed = gkm_wrap_login_steal_failed_password ();
+
+ /* Do we have a failed unlock password? */
+ if (!failed || !failed[0]) {
+ egg_secure_strfree (failed);
+ return;
+ }
+
+ attrs[0].type = CKA_CLASS;
+ attrs[0].pValue = &klass;
+ attrs[0].ulValueLen = sizeof (klass);
+
+ attrs[1].type = CKA_VALUE;
+ attrs[1].pValue = failed;
+ attrs[1].ulValueLen = strlen (failed);
+
+ attrs[2].type = CKA_GNOME_TRANSIENT;
+ attrs[2].pValue = &tval;
+ attrs[2].ulValueLen = sizeof (tval);
+
+ attrs[3].type = CKA_TOKEN;
+ attrs[3].pValue = &tval;
+ attrs[3].ulValueLen = sizeof (tval);
+
+ /* Create a credential object for the failed password */
+ rv = (self->module->C_CreateObject) (self->session, attrs, G_N_ELEMENTS (attrs), &cred);
+ egg_secure_strfree (failed);
+
+ if (rv != CKR_OK) {
+ g_warning ("couldn't create credential to fix login password: %s",
+ gkm_util_rv_to_string (rv));
+ return;
+ }
+
+ attrs[0].type = CKA_G_CREDENTIAL;
+ attrs[0].pValue = &cred;
+ attrs[0].ulValueLen = sizeof (cred);
+
+ /* Set the credential on the object */
+ rv = (self->module->C_SetAttributeValue) (self->session, self->object, attrs, 1);
+ if (rv != CKR_OK) {
+ g_warning ("couldn't change credential to fix login keyring password: %s",
+ gkm_util_rv_to_string (rv));
+ return;
+ }
+
+ g_message ("fixed login keyring password to match login password");
+}
+
/* -----------------------------------------------------------------------------
* OBJECT
*/
@@ -1020,14 +1086,23 @@ gkm_wrap_prompt_done_credential (GkmWrapPrompt *self, CK_RV call_result)
/* Save the options, and possibly auto unlock */
if (call_result == CKR_OK) {
+
+ attrs = get_attributes_from_object (self, &n_attrs);
+
+ /*
+ * For the login keyring, we check for a previous unlock failure,
+ * that would have come from PAM, and try to change the password to
+ * the one that failed earlier.
+ */
+ if (is_login_keyring (attrs, n_attrs))
+ fix_login_keyring_if_unlock_failed (self, data->password);
+
options = get_unlock_options_from_prompt (self, &n_options);
if (options != NULL)
set_unlock_options_on_object (self, options, n_options);
- if (auto_unlock_should_attach (self)) {
- attrs = get_attributes_from_object (self, &n_attrs);
+ if (auto_unlock_should_attach (self))
auto_unlock_attach_object (attrs, n_attrs, data->password);
- }
}
}
diff --git a/pkcs11/wrap-layer/tests/test-login-hints.c b/pkcs11/wrap-layer/tests/test-login-hints.c
index d649c21c..19593523 100644
--- a/pkcs11/wrap-layer/tests/test-login-hints.c
+++ b/pkcs11/wrap-layer/tests/test-login-hints.c
@@ -23,21 +23,28 @@
#include "test-suite.h"
+#include "egg/egg-secure-memory.h"
+
#include "wrap-layer/gkm-wrap-layer.h"
#include "wrap-layer/gkm-wrap-login.h"
DEFINE_TEST (login_did_unlock_fail)
{
+ gchar *password;
gboolean ret;
- gkm_wrap_layer_hint_login_unlock_failure ();
+ gkm_wrap_layer_mark_login_unlock_failure ("failure");
ret = gkm_wrap_login_did_unlock_fail ();
g_assert (ret == TRUE);
- gkm_wrap_layer_hint_login_unlock_failure ();
- gkm_wrap_layer_hint_login_unlock_failure ();
- gkm_wrap_layer_hint_login_unlock_success ();
+ password = gkm_wrap_login_steal_failed_password ();
+ g_assert_cmpstr (password, ==, "failure");
+ egg_secure_strfree (password);
+
+ gkm_wrap_layer_mark_login_unlock_failure ("failed password");
+ gkm_wrap_layer_mark_login_unlock_failure ("failed password");
+ gkm_wrap_layer_mark_login_unlock_success ();
ret = gkm_wrap_login_did_unlock_fail ();
g_assert (ret == FALSE);