summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog22
-rw-r--r--daemon/gnome-keyring-daemon-ops.c210
-rw-r--r--daemon/gnome-keyring-daemon.c4
-rw-r--r--keyrings/gkr-keyring-item.c66
-rw-r--r--keyrings/gkr-keyring-item.h5
-rw-r--r--keyrings/gkr-keyring.c22
-rw-r--r--keyrings/gkr-keyring.h5
-rw-r--r--keyrings/gkr-keyrings.c22
-rw-r--r--keyrings/gkr-keyrings.h2
-rw-r--r--library/gnome-keyring-utils.c41
-rw-r--r--library/gnome-keyring.c41
-rw-r--r--library/gnome-keyring.h1
-rw-r--r--reference/tmpl/gnome-keyring-item-info.sgml1
-rw-r--r--tests/Makefile.am1
-rw-r--r--tests/unit-test-keyrings.c25
-rw-r--r--tests/unit-test-login-prompt.c116
-rw-r--r--ui/gkr-ask-request.c26
-rw-r--r--ui/gkr-ask-request.h4
-rw-r--r--ui/gkr-ask-tool.c67
19 files changed, 512 insertions, 169 deletions
diff --git a/ChangeLog b/ChangeLog
index cd0f9adc..31bf5840 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2007-07-23 Stef Walter <stef@memberwebs.com>
+
+ * daemon/gnome-keyring-daemon.c:
+ * daemon/gnome-keyring-daemon-ops.c:
+ * keyrings/gkr-keyring.c:
+ * keyrings/gkr-keyring.h:
+ * keyrings/gkr-keyring-item.c:
+ * keyrings/gkr-keyring-item.h:
+ * keyrings/gkr-keyrings.c:
+ * keyrings/gkr-keyrings.h:
+ * library/gnome-keyring.c:
+ * library/gnome-keyring.h:
+ * library/gnome-keyring-utils.c:
+ * tests/Makefile.am:
+ * tests/unit-test-keyrings.c:
+ * tests/unit-test-login-prompt.c:
+ * ui/gkr-ask-request.c:
+ * ui/gkr-ask-requset.h:
+ * ui/gkr-ask-tool.c: Add support for automatically unlocking other
+ keyrings when their password is entered into the 'login' keyring.
+ Fixes bug #459069
+
2007-07-22 Stef Walter <stef@memberwebs.com>
* keyrings/gkr-keyrings.c: The first keyring automatically becomes
diff --git a/daemon/gnome-keyring-daemon-ops.c b/daemon/gnome-keyring-daemon-ops.c
index 70f5eb01..0ec8d866 100644
--- a/daemon/gnome-keyring-daemon-ops.c
+++ b/daemon/gnome-keyring-daemon-ops.c
@@ -157,6 +157,86 @@ gnome_keyring_application_ref_new_from_pid (pid_t pid)
return app_ref;
}
+static void
+save_keyring_password_in_login (GkrKeyring *keyring, const gchar *password)
+{
+ GkrKeyring *login;
+ GnomeKeyringAttributeList *attrs;
+ GkrKeyringItem *item;
+
+ login = gkr_keyrings_get_login ();
+ if (!login || login->locked)
+ return;
+
+ attrs = gnome_keyring_attribute_list_new ();
+ gnome_keyring_attribute_list_append_string (attrs, "keyring", keyring->keyring_name);
+
+ item = gkr_keyring_find_item (login, GNOME_KEYRING_ITEM_AUTO_UNLOCK_KEYRING, attrs);
+
+ if (!item) {
+ item = gkr_keyring_item_create (login, GNOME_KEYRING_ITEM_AUTO_UNLOCK_KEYRING);
+ gkr_keyring_add_item (login, item);
+ }
+
+ g_free (item->display_name);
+ /* TRANSLATORS: this is the title for an item */
+ item->display_name = g_strdup_printf (_("Unlock password for %s keyring"),
+ keyring->keyring_name);
+ gnome_keyring_free_password (item->secret);
+ item->secret = gnome_keyring_memory_strdup (password);
+
+ gnome_keyring_attribute_list_free (item->attributes);
+ item->attributes = attrs;
+
+ gkr_keyring_save_to_disk (login);
+}
+
+static const gchar*
+lookup_keyring_password_in_login (GkrKeyring *keyring)
+{
+ GkrKeyring *login;
+ GkrKeyringItem *item;
+ GnomeKeyringAttributeList *attrs;
+
+ login = gkr_keyrings_get_login ();
+ if (!login || login->locked)
+ return NULL;
+
+ attrs = gnome_keyring_attribute_list_new ();
+ gnome_keyring_attribute_list_append_string (attrs, "keyring", keyring->keyring_name);
+
+ item = gkr_keyring_find_item (login, GNOME_KEYRING_ITEM_AUTO_UNLOCK_KEYRING, attrs);
+ gnome_keyring_attribute_list_free (attrs);
+
+ if (item)
+ return item->secret;
+
+ return NULL;
+}
+
+static void
+remove_keyring_password_from_login (GkrKeyring *keyring)
+{
+ GkrKeyring *login;
+ GkrKeyringItem *item;
+ GnomeKeyringAttributeList *attrs;
+
+ login = gkr_keyrings_get_login ();
+ if (!login || login->locked)
+ return;
+
+ attrs = gnome_keyring_attribute_list_new ();
+ gnome_keyring_attribute_list_append_string (attrs, "keyring", keyring->keyring_name);
+
+ item = gkr_keyring_find_item (login, GNOME_KEYRING_ITEM_AUTO_UNLOCK_KEYRING, attrs);
+ gnome_keyring_attribute_list_free (attrs);
+
+ if (item) {
+ gkr_keyring_remove_item (login, item);
+ gkr_keyring_save_to_disk (login);
+ }
+}
+
static gboolean
app_ref_match (GnomeKeyringApplicationRef *app1,
GnomeKeyringApplicationRef *app2)
@@ -245,63 +325,6 @@ add_item_acl (GkrKeyringItem *item,
}
}
-static gboolean
-match_attributes (GkrKeyringItem *item,
- GnomeKeyringAttributeList *attributes,
- gboolean match_all)
-{
- int i, j;
- GnomeKeyringAttribute *item_attribute;
- GnomeKeyringAttribute *attribute;
- gboolean found;
- int attributes_matching;
-
- attributes_matching = 0;
- for (i = 0; i < attributes->len; i++) {
- found = FALSE;
- attribute = &g_array_index (attributes,
- GnomeKeyringAttribute,
- i);
- for (j = 0; j < item->attributes->len; j++) {
- item_attribute = &g_array_index (item->attributes,
- GnomeKeyringAttribute,
- j);
- if (strcmp (attribute->name, item_attribute->name) == 0) {
- found = TRUE;
- attributes_matching++;
- if (attribute->type != item_attribute->type) {
- return FALSE;
- }
- switch (attribute->type) {
- case GNOME_KEYRING_ATTRIBUTE_TYPE_STRING:
- if ((attribute->value.string == NULL || item_attribute->value.string == NULL) &&
- attribute->value.string != item_attribute->value.string) {
- return FALSE;
- }
- if (strcmp (attribute->value.string, item_attribute->value.string) != 0) {
- return FALSE;
- }
- break;
- case GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32:
- if (attribute->value.integer != item_attribute->value.integer) {
- return FALSE;
- }
- break;
- default:
- g_assert_not_reached ();
- }
- }
- }
- if (!found) {
- return FALSE;
- }
- }
- if (match_all) {
- return attributes_matching == attributes->len;
- }
- return TRUE;
-}
-
static guint
check_acl_ask_request (GkrAskRequest* ask, GnomeKeyringApplicationRef *app)
{
@@ -434,11 +457,11 @@ static gboolean
check_keyring_ask_request (GkrAskRequest* ask)
{
GkrKeyring *keyring;
+ const gchar *password;
keyring = GKR_KEYRING (gkr_ask_request_get_object (ask));
g_assert (GKR_IS_KEYRING (keyring));
-
- /* If the keyring is unlocked then no need to continue */
+
if (!keyring->locked) {
ask->response = GKR_ASK_RESPONSE_ALLOW;
return GKR_ASK_STOP_REQUEST;
@@ -448,12 +471,40 @@ check_keyring_ask_request (GkrAskRequest* ask)
if (ask->response >= GKR_ASK_RESPONSE_ALLOW) {
g_assert (ask->typed_password);
- gkr_keyring_unlock (keyring, ask->typed_password);
- if (keyring->locked) {
- /* Not happy, try again */
+ if (!gkr_keyring_unlock (keyring, ask->typed_password)) {
+ /* Bad password, try again */
ask->response = GKR_ASK_RESPONSE_NONE;
return GKR_ASK_CONTINUE_REQUEST;
}
+
+ /* Did they ask us to remember the password? */
+ if (ask->checked)
+ save_keyring_password_in_login (keyring, ask->typed_password);
+ }
+
+ /*
+ * We can automatically unlock keyrings that have their password
+ * stored in the 'login' keyring.
+ */
+ password = lookup_keyring_password_in_login (keyring);
+ if (password) {
+ if (gkr_keyring_unlock (keyring, password)) {
+
+ /* A good password, unlocked, all done */
+ ask->response = GKR_ASK_RESPONSE_ALLOW;
+ return GKR_ASK_STOP_REQUEST;
+
+ } else {
+
+ /* A bad internal password */
+ remove_keyring_password_from_login (keyring);
+ }
+ }
+
+ /* If the keyring is unlocked then no need to continue */
+ if (!keyring->locked) {
+ ask->response = GKR_ASK_RESPONSE_ALLOW;
+ return GKR_ASK_STOP_REQUEST;
}
return GKR_ASK_DONT_CARE;
@@ -467,6 +518,7 @@ request_keyring_access (GkrKeyringRequest *req, GkrKeyring *keyring)
const gchar *keyring_name;
gboolean is_default, ret;
gchar *message, *primary;
+ GkrKeyring *login;
keyring_name = keyring->keyring_name;
g_assert (keyring_name);
@@ -530,6 +582,14 @@ request_keyring_access (GkrKeyringRequest *req, GkrKeyring *keyring)
gkr_ask_request_set_secondary (ask, message);
gkr_ask_request_set_object (ask, G_OBJECT (keyring));
+ /*
+ * If it's not the login keyring, and we have a login keyring, we can offer
+ * to unlock automatically next time.
+ */
+ login = gkr_keyrings_get_login ();
+ if (login && login != keyring)
+ gkr_ask_request_set_check_option (ask, _("Automatically unlock this kerying when I log in."));
+
/* Intercept item access requests to see if we still need to prompt */
g_signal_connect (ask, "check-request", G_CALLBACK (check_keyring_ask_request), NULL);
@@ -818,7 +878,7 @@ lookup_and_request_item_access (GkrKeyringRequest *req, gchar *keyring_name,
g_object_ref (keyring);
- item = gkr_keyring_find_item (keyring, item_id);
+ item = gkr_keyring_get_item (keyring, item_id);
if (item != NULL) {
g_object_ref (item);
@@ -1281,7 +1341,6 @@ op_create_item (GkrBuffer *packet, GkrBuffer *result,
GnomeKeyringResult res;
guint32 id;
gboolean update_if_exists;
- GList *l;
keyring_name = display_name = secret = NULL;
item = NULL;
@@ -1331,19 +1390,12 @@ op_create_item (GkrBuffer *packet, GkrBuffer *result,
}
if (update_if_exists) {
- for (l = keyring->items; l; l = g_list_next (l)) {
- item = GKR_KEYRING_ITEM (l->data);
- if ((item->type & GNOME_KEYRING_ITEM_TYPE_MASK) == (type & GNOME_KEYRING_ITEM_TYPE_MASK) &&
- match_attributes (item, keyring->locked ? hashed : attributes, TRUE)) {
-
- /* Make sure we have access to the previous item */
- if (!request_item_access (req, item, GNOME_KEYRING_ACCESS_WRITE, TRUE))
- item = NULL;
-
- break;
- }
+ item = gkr_keyring_find_item (keyring, type, keyring->locked ? hashed : attributes);
+ if (item) {
+ /* Make sure we have access to the previous item */
+ if (!request_item_access (req, item, GNOME_KEYRING_ACCESS_WRITE, TRUE))
+ item = NULL;
}
-
}
if (!item) {
@@ -1770,8 +1822,7 @@ find_in_each_keyring (GkrKeyring* keyring, gpointer data)
for (ilist = keyring->items; ilist != NULL; ilist = ilist->next) {
item = ilist->data;
- if ((item->type & GNOME_KEYRING_ITEM_TYPE_MASK) != (ctx->type & GNOME_KEYRING_ITEM_TYPE_MASK) ||
- !match_attributes (item, keyring->locked ? ctx->hashed : ctx->attributes, FALSE))
+ if (!gkr_keyring_item_match (item, ctx->type, keyring->locked ? ctx->hashed : ctx->attributes, FALSE))
continue;
++ctx->nfound;
@@ -1835,8 +1886,7 @@ op_find (GkrBuffer *packet, GkrBuffer *result, GkrKeyringRequest *req)
for (l = ctx.items; l; l = g_list_next (l)) {
GkrKeyringItem *item = GKR_KEYRING_ITEM (l->data);
- if ((item->type & GNOME_KEYRING_ITEM_TYPE_MASK) == (ctx.type & GNOME_KEYRING_ITEM_TYPE_MASK) &&
- !item->locked && match_attributes (item, ctx.attributes, FALSE)) {
+ if (!item->locked && gkr_keyring_item_match (item, ctx.type, ctx.attributes, FALSE)) {
/* Add it to the output */
if (!gnome_keyring_proto_add_utf8_string (result, item->keyring->keyring_name)) {
diff --git a/daemon/gnome-keyring-daemon.c b/daemon/gnome-keyring-daemon.c
index 5d7bf768..11cc15ae 100644
--- a/daemon/gnome-keyring-daemon.c
+++ b/daemon/gnome-keyring-daemon.c
@@ -247,6 +247,8 @@ main (int argc, char *argv[])
exit (0);
}
}
+
+ close_stdinout ();
}
/* final child continues here */
@@ -269,8 +271,6 @@ main (int argc, char *argv[])
exit (0);
}
- close_stdinout ();
-
} else {
g_print ("GNOME_KEYRING_SOCKET=%s\n", path);
g_print ("GNOME_KEYRING_PID=%d\n", (gint)getpid ());
diff --git a/keyrings/gkr-keyring-item.c b/keyrings/gkr-keyring-item.c
index 00dfbf3b..8b6a8c7b 100644
--- a/keyrings/gkr-keyring-item.c
+++ b/keyrings/gkr-keyring-item.c
@@ -23,13 +23,15 @@
#include "config.h"
-#include <glib.h>
-
#include "gkr-keyring-item.h"
#include "gkr-keyring.h"
#include "library/gnome-keyring-memory.h"
+#include <glib.h>
+
+#include <string.h>
+
enum {
PROP_0,
PROP_NAME
@@ -146,3 +148,63 @@ gkr_keyring_item_create (GkrKeyring* keyring, GnomeKeyringItemType type)
return item;
}
+
+gboolean
+gkr_keyring_item_match (GkrKeyringItem *item, GnomeKeyringItemType type,
+ GnomeKeyringAttributeList *attributes, gboolean match_all)
+{
+ int i, j;
+ GnomeKeyringAttribute *item_attribute;
+ GnomeKeyringAttribute *attribute;
+ gboolean found;
+ int attributes_matching;
+
+ if ((item->type & GNOME_KEYRING_ITEM_TYPE_MASK) != (type & GNOME_KEYRING_ITEM_TYPE_MASK))
+ return FALSE;
+
+ attributes_matching = 0;
+ for (i = 0; i < attributes->len; i++) {
+ found = FALSE;
+ attribute = &g_array_index (attributes,
+ GnomeKeyringAttribute,
+ i);
+ for (j = 0; j < item->attributes->len; j++) {
+ item_attribute = &g_array_index (item->attributes,
+ GnomeKeyringAttribute,
+ j);
+ if (strcmp (attribute->name, item_attribute->name) == 0) {
+ found = TRUE;
+ attributes_matching++;
+ if (attribute->type != item_attribute->type) {
+ return FALSE;
+ }
+ switch (attribute->type) {
+ case GNOME_KEYRING_ATTRIBUTE_TYPE_STRING:
+ if ((attribute->value.string == NULL || item_attribute->value.string == NULL) &&
+ attribute->value.string != item_attribute->value.string) {
+ return FALSE;
+ }
+ if (strcmp (attribute->value.string, item_attribute->value.string) != 0) {
+ return FALSE;
+ }
+ break;
+ case GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32:
+ if (attribute->value.integer != item_attribute->value.integer) {
+ return FALSE;
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+ }
+ if (!found) {
+ return FALSE;
+ }
+ }
+ if (match_all) {
+ return attributes_matching == attributes->len;
+ }
+
+ return TRUE;
+}
diff --git a/keyrings/gkr-keyring-item.h b/keyrings/gkr-keyring-item.h
index b6871441..876982f0 100644
--- a/keyrings/gkr-keyring-item.h
+++ b/keyrings/gkr-keyring-item.h
@@ -83,6 +83,11 @@ GkrKeyringItem* gkr_keyring_item_new (GkrKeyring* keyring, guint id,
GkrKeyringItem* gkr_keyring_item_create (GkrKeyring* keyring,
GnomeKeyringItemType type);
+gboolean gkr_keyring_item_match (GkrKeyringItem *item,
+ GnomeKeyringItemType type,
+ GnomeKeyringAttributeList *attributes,
+ gboolean match_all);
+
G_END_DECLS
#endif /* __GKR_KEYRING_ITEM_H__ */
diff --git a/keyrings/gkr-keyring.c b/keyrings/gkr-keyring.c
index 6f25c718..9c89f0a9 100644
--- a/keyrings/gkr-keyring.c
+++ b/keyrings/gkr-keyring.c
@@ -515,7 +515,7 @@ remove_unavailable_item (gpointer key, gpointer dummy, GkrKeyring *keyring)
g_assert (GKR_IS_KEYRING (keyring));
- item = gkr_keyring_find_item (keyring, id);
+ item = gkr_keyring_get_item (keyring, id);
if (item)
gkr_keyring_remove_item (keyring, item);
}
@@ -717,7 +717,7 @@ update_keyring_from_data (GkrKeyring *keyring, GkrBuffer *buffer)
/* We've seen this id */
g_hash_table_remove (checks, GUINT_TO_POINTER (items[i].id));
- item = gkr_keyring_find_item (keyring, items[i].id);
+ item = gkr_keyring_get_item (keyring, items[i].id);
if (item == NULL) {
item = gkr_keyring_item_new (keyring, items[i].id, items[i].type);
gkr_keyring_add_item (keyring, item);
@@ -982,7 +982,7 @@ gkr_keyring_get_new_id (GkrKeyring *keyring)
}
GkrKeyringItem*
-gkr_keyring_find_item (GkrKeyring *keyring, guint id)
+gkr_keyring_get_item (GkrKeyring *keyring, guint id)
{
GkrKeyringItem *item;
GList *l;
@@ -996,6 +996,22 @@ gkr_keyring_find_item (GkrKeyring *keyring, guint id)
return NULL;
}
+GkrKeyringItem*
+gkr_keyring_find_item (GkrKeyring *keyring, GnomeKeyringItemType type,
+ GnomeKeyringAttributeList *attrs)
+{
+ GkrKeyringItem *item;
+ GList *l;
+
+ for (l = keyring->items; l; l = g_list_next (l)) {
+ item = GKR_KEYRING_ITEM (l->data);
+ if (gkr_keyring_item_match (item, type, attrs, TRUE))
+ return item;
+ }
+
+ return NULL;
+}
+
void
gkr_keyring_add_item (GkrKeyring* keyring, GkrKeyringItem* item)
{
diff --git a/keyrings/gkr-keyring.h b/keyrings/gkr-keyring.h
index afcd4be3..2aefcda2 100644
--- a/keyrings/gkr-keyring.h
+++ b/keyrings/gkr-keyring.h
@@ -88,7 +88,10 @@ GkrKeyring* gkr_keyring_create (const gchar* name, const gchar*
guint gkr_keyring_get_new_id (GkrKeyring *keyring);
-GkrKeyringItem* gkr_keyring_find_item (GkrKeyring *keyring, guint id);
+GkrKeyringItem* gkr_keyring_get_item (GkrKeyring *keyring, guint id);
+
+GkrKeyringItem* gkr_keyring_find_item (GkrKeyring *keyring, GnomeKeyringItemType type,
+ GnomeKeyringAttributeList *attrs);
void gkr_keyring_add_item (GkrKeyring* keyring, GkrKeyringItem* item);
diff --git a/keyrings/gkr-keyrings.c b/keyrings/gkr-keyrings.c
index f649ec59..baa461e9 100644
--- a/keyrings/gkr-keyrings.c
+++ b/keyrings/gkr-keyrings.c
@@ -105,6 +105,18 @@ update_default (void)
g_free (path);
g_free (dirname);
+ /*
+ * We prefer to make the 'login' keyring the default
+ * keyring when nothing else is setup.
+ */
+ if (keyring == NULL)
+ keyring = gkr_keyrings_get_login ();
+
+ /*
+ * Otherwise fall back to the 'default' keyring setup
+ * if PAM integration is borked, and the user had to
+ * create a new keyring.
+ */
if (keyring == NULL)
keyring = gkr_keyrings_find ("default");
@@ -213,6 +225,12 @@ gkr_keyrings_set_default (GkrKeyring *keyring)
default_keyring = keyring;
}
+GkrKeyring*
+gkr_keyrings_get_login (void)
+{
+ return gkr_keyrings_find ("login");
+}
+
void
gkr_keyrings_update (void)
{
@@ -273,7 +291,7 @@ gkr_keyrings_update (void)
keyring = g_hash_table_lookup (checks, path);
if (keyring == NULL) {
/* Make a new blank keyring and add it */
- keyring = gkr_keyring_new (NULL, path);
+ keyring = gkr_keyring_new ("", path);
gkr_keyrings_add (keyring);
g_object_unref (keyring);
} else {
@@ -283,7 +301,7 @@ gkr_keyrings_update (void)
/* Try and update/load it */
if (!gkr_keyring_update_from_disk (keyring, FALSE) ||
- keyring->keyring_name == NULL) {
+ !keyring->keyring_name || !keyring->keyring_name[0]) {
gkr_keyrings_remove (keyring);
}
diff --git a/keyrings/gkr-keyrings.h b/keyrings/gkr-keyrings.h
index 1f4bd487..685147c7 100644
--- a/keyrings/gkr-keyrings.h
+++ b/keyrings/gkr-keyrings.h
@@ -34,6 +34,8 @@ GkrKeyring* gkr_keyrings_get_default (void);
void gkr_keyrings_set_default (GkrKeyring *keyring);
+GkrKeyring* gkr_keyrings_get_login (void);
+
void gkr_keyrings_add (GkrKeyring *keyring);
void gkr_keyrings_remove (GkrKeyring *keyring);
diff --git a/library/gnome-keyring-utils.c b/library/gnome-keyring-utils.c
index fd124d95..c6990731 100644
--- a/library/gnome-keyring-utils.c
+++ b/library/gnome-keyring-utils.c
@@ -163,6 +163,47 @@ gnome_keyring_found_list_free (GList *found_list)
}
/**
+ * gnome_keyring_attribute_list_append_string:
+ * @attributes: A #GnomeKeyringAttributeList
+ * @name: The name of the new attribute
+ * @value: The value to store in @attributes
+ *
+ * Store a key-value-pair with a string value in @attributes.
+ */
+void
+gnome_keyring_attribute_list_append_string (GnomeKeyringAttributeList *attributes,
+ const char *name, const char *value)
+{
+ GnomeKeyringAttribute attribute;
+
+ attribute.name = g_strdup (name);
+ attribute.type = GNOME_KEYRING_ATTRIBUTE_TYPE_STRING;
+ attribute.value.string = g_strdup (value);
+
+ g_array_append_val (attributes, attribute);
+}
+
+/**
+ * gnome_keyring_attribute_list_append_uint32:
+ * @attributes: A #GnomeKeyringAttributeList
+ * @name: The name of the new attribute
+ * @value: The value to store in @attributes
+ *
+ * Store a key-value-pair with an unsigned 32bit number value in @attributes.
+ */
+void
+gnome_keyring_attribute_list_append_uint32 (GnomeKeyringAttributeList *attributes,
+ const char *name, guint32 value)
+{
+ GnomeKeyringAttribute attribute;
+
+ attribute.name = g_strdup (name);
+ attribute.type = GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32;
+ attribute.value.integer = value;
+ g_array_append_val (attributes, attribute);
+}
+
+/**
* gnome_keyring_attribute_list_free:
* @attributes: A #GnomeKeyringAttributeList
*
diff --git a/library/gnome-keyring.c b/library/gnome-keyring.c
index 916d211d..eca1cb90 100644
--- a/library/gnome-keyring.c
+++ b/library/gnome-keyring.c
@@ -3711,47 +3711,6 @@ find_network_password_callback (GnomeKeyringResult result,
return;
}
-/**
- * gnome_keyring_attribute_list_append_string:
- * @attributes: A #GnomeKeyringAttributeList
- * @name: The name of the new attribute
- * @value: The value to store in @attributes
- *
- * Store a key-value-pair with a string value in @attributes.
- */
-void
-gnome_keyring_attribute_list_append_string (GnomeKeyringAttributeList *attributes,
- const char *name, const char *value)
-{
- GnomeKeyringAttribute attribute;
-
- attribute.name = g_strdup (name);
- attribute.type = GNOME_KEYRING_ATTRIBUTE_TYPE_STRING;
- attribute.value.string = g_strdup (value);
-
- g_array_append_val (attributes, attribute);
-}
-
-/**
- * gnome_keyring_attribute_list_append_uint32:
- * @attributes: A #GnomeKeyringAttributeList
- * @name: The name of the new attribute
- * @value: The value to store in @attributes
- *
- * Store a key-value-pair with an unsigned 32bit number value in @attributes.
- */
-void
-gnome_keyring_attribute_list_append_uint32 (GnomeKeyringAttributeList *attributes,
- const char *name, guint32 value)
-{
- GnomeKeyringAttribute attribute;
-
- attribute.name = g_strdup (name);
- attribute.type = GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32;
- attribute.value.integer = value;
- g_array_append_val (attributes, attribute);
-}
-
static GnomeKeyringAttributeList *
make_attribute_list_for_network_password (const char *user,
const char *domain,
diff --git a/library/gnome-keyring.h b/library/gnome-keyring.h
index 75359949..a2d95c26 100644
--- a/library/gnome-keyring.h
+++ b/library/gnome-keyring.h
@@ -40,6 +40,7 @@ typedef enum {
GNOME_KEYRING_ITEM_GENERIC_SECRET = 0,
GNOME_KEYRING_ITEM_NETWORK_PASSWORD,
GNOME_KEYRING_ITEM_NOTE,
+ GNOME_KEYRING_ITEM_AUTO_UNLOCK_KEYRING,
/*< private >*/
GNOME_KEYRING_ITEM_LAST_TYPE,
diff --git a/reference/tmpl/gnome-keyring-item-info.sgml b/reference/tmpl/gnome-keyring-item-info.sgml
index f309481a..be474da0 100644
--- a/reference/tmpl/gnome-keyring-item-info.sgml
+++ b/reference/tmpl/gnome-keyring-item-info.sgml
@@ -26,6 +26,7 @@ Use gnome_keyring_item_get_info() or gnome_keyring_item_set_info().</para>
@GNOME_KEYRING_ITEM_GENERIC_SECRET:
@GNOME_KEYRING_ITEM_NETWORK_PASSWORD:
@GNOME_KEYRING_ITEM_NOTE:
+@GNOME_KEYRING_ITEM_AUTO_UNLOCK_KEYRING:
@GNOME_KEYRING_ITEM_LAST_TYPE:
@GNOME_KEYRING_ITEM_APPLICATION_SECRET:
diff --git a/tests/Makefile.am b/tests/Makefile.am
index df447c6c..87c7df88 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -102,6 +102,7 @@ run_library_test_LDADD = \
# Propmting tests
UNIT_TESTS_PROMPT = \
+ unit-test-login-prompt.c \
unit-test-keyrings-prompt.c \
unit-test-daemon-setup.c
diff --git a/tests/unit-test-keyrings.c b/tests/unit-test-keyrings.c
index 71573d0b..1dc45d00 100644
--- a/tests/unit-test-keyrings.c
+++ b/tests/unit-test-keyrings.c
@@ -43,7 +43,6 @@
*/
static GList* keyrings = NULL;
-gchar* default_keyring = NULL;
#define PASSWORD "my-keyring-password"
#define KEYRING_NAME "unit-test-keyring"
@@ -51,19 +50,32 @@ gchar* default_keyring = NULL;
#define DISPLAY_NAME "Item Display Name"
#define SECRET "item-secret"
-void unit_test_stash_default (CuTest* cu)
+void unit_test_remove_incomplete (CuTest* cu)
{
GnomeKeyringResult res;
- res = gnome_keyring_get_default_keyring_sync (&default_keyring);
- CuAssertIntEquals(cu, GNOME_KEYRING_RESULT_OK, res);
+
+ res = gnome_keyring_delete_sync (KEYRING_NAME);
+ if (res != GNOME_KEYRING_RESULT_NO_SUCH_KEYRING)
+ CuAssertIntEquals(cu, GNOME_KEYRING_RESULT_OK, res);
}
void unit_test_create_keyring (CuTest* cu)
{
GnomeKeyringResult res;
+ char *default_keyring;
+
+ /* No default keyring */
+ res = gnome_keyring_set_default_keyring_sync (NULL);
+ CuAssertIntEquals(cu, GNOME_KEYRING_RESULT_OK, res);
res = gnome_keyring_create_sync (KEYRING_NAME, PASSWORD);
CuAssertIntEquals(cu, GNOME_KEYRING_RESULT_OK, res);
+
+ /* It should become the default keyring */
+ res = gnome_keyring_get_default_keyring_sync (&default_keyring);
+ CuAssertIntEquals(cu, GNOME_KEYRING_RESULT_OK, res);
+ CuAssert (cu, "No default keyring set when creating keyring", default_keyring != NULL);
+ CuAssert (cu, "Wrong keyring is the default", strcmp (default_keyring, KEYRING_NAME) == 0);
res = gnome_keyring_create_sync (KEYRING_NAME, PASSWORD);
CuAssertIntEquals(cu, GNOME_KEYRING_RESULT_ALREADY_EXISTS, res);
@@ -374,9 +386,4 @@ void unit_test_cleaup (CuTest* cu)
res = gnome_keyring_delete_sync (KEYRING_NAME);
CuAssertIntEquals(cu, GNOME_KEYRING_RESULT_OK, res);
-
- if (default_keyring) {
- res = gnome_keyring_set_default_keyring_sync (default_keyring);
- CuAssertIntEquals(cu, GNOME_KEYRING_RESULT_OK, res);
- }
}
diff --git a/tests/unit-test-login-prompt.c b/tests/unit-test-login-prompt.c
new file mode 100644
index 00000000..2a2ed63e
--- /dev/null
+++ b/tests/unit-test-login-prompt.c
@@ -0,0 +1,116 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-keyrings-prompt.c: Test basic prompt functionality
+
+ Copyright (C) 2007 Stefan Walter
+
+ The Gnome Keyring Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Keyring Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Stef Walter <stef@memberwebs.com>
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "run-prompt-test.h"
+#include "library/gnome-keyring.h"
+
+/*
+ * Each test looks like (on one line):
+ * void unit_test_xxxxx (CuTest* cu)
+ *
+ * Each setup looks like (on one line):
+ * void unit_setup_xxxxx (void);
+ *
+ * Each teardown looks like (on one line):
+ * void unit_teardown_xxxxx (void);
+ *
+ * Tests be run in the order specified here.
+ */
+
+static void
+TELL(const char* what)
+{
+ printf("INTERACTION: %s\n", what);
+}
+
+
+#define THE_PASSWORD "test"
+#define OTHER_PASSWORD "other"
+#define KEYRING_LOGIN "login"
+#define KEYRING_NAME "auto-unlock-keyring"
+#define DISPLAY_NAME "Item Display Name"
+#define SECRET "item-secret"
+
+void unit_test_create_unlock_login (CuTest* cu)
+{
+ GnomeKeyringResult res;
+
+ /* Remove the login keyring */
+ res = gnome_keyring_delete_sync (KEYRING_LOGIN);
+ if (res != GNOME_KEYRING_RESULT_NO_SUCH_KEYRING)
+ CuAssertIntEquals(cu, GNOME_KEYRING_RESULT_OK, res);
+
+ /* Now create it with our password */
+ res = gnome_keyring_create_sync (KEYRING_LOGIN, THE_PASSWORD);
+ CuAssertIntEquals(cu, GNOME_KEYRING_RESULT_OK, res);
+}
+
+void unit_test_auto_keyring (CuTest* cu)
+{
+ GnomeKeyringResult res;
+
+ /* Remove the auto unlock keyring */
+ res = gnome_keyring_delete_sync (KEYRING_NAME);
+ if (res != GNOME_KEYRING_RESULT_NO_SUCH_KEYRING)
+ CuAssertIntEquals(cu, GNOME_KEYRING_RESULT_OK, res);
+
+ res = gnome_keyring_create_sync (KEYRING_NAME, THE_PASSWORD);
+ CuAssertIntEquals(cu, GNOME_KEYRING_RESULT_OK, res);
+
+ res = gnome_keyring_lock_sync (KEYRING_NAME);
+ CuAssertIntEquals(cu, GNOME_KEYRING_RESULT_OK, res);
+
+ /* Prompt the user to unlock, and check the option */
+ TELL("type 'test' as the password and check the 'Automatically unlock' option");
+ res = gnome_keyring_unlock_sync (KEYRING_NAME, NULL);
+ CuAssertIntEquals(cu, GNOME_KEYRING_RESULT_OK, res);
+
+ res = gnome_keyring_lock_sync (KEYRING_NAME);
+ CuAssertIntEquals(cu, GNOME_KEYRING_RESULT_OK, res);
+
+ TELL("No prompt should show up at this point");
+ res = gnome_keyring_unlock_sync (KEYRING_NAME, NULL);
+ CuAssertIntEquals(cu, GNOME_KEYRING_RESULT_OK, res);
+ sleep(2);
+}
+
+void unit_test_auto_keyring_stale (CuTest* cu)
+{
+ GnomeKeyringResult res;
+
+ /* Remove the auto unlock keyring */
+ res = gnome_keyring_change_password_sync (KEYRING_NAME, THE_PASSWORD, OTHER_PASSWORD);
+ CuAssertIntEquals(cu, GNOME_KEYRING_RESULT_OK, res);
+
+ res = gnome_keyring_lock_sync (KEYRING_NAME);
+ CuAssertIntEquals(cu, GNOME_KEYRING_RESULT_OK, res);
+
+ TELL("Press 'deny' here");
+ res = gnome_keyring_unlock_sync (KEYRING_NAME, NULL);
+ CuAssertIntEquals(cu, GNOME_KEYRING_RESULT_DENIED, res);
+}
diff --git a/ui/gkr-ask-request.c b/ui/gkr-ask-request.c
index b6ebb97a..6218f9eb 100644
--- a/ui/gkr-ask-request.c
+++ b/ui/gkr-ask-request.c
@@ -69,9 +69,10 @@ typedef struct _GkrAskRequestPrivate GkrAskRequestPrivate;
struct _GkrAskRequestPrivate {
GObject* object;
- gchar* title;
- gchar* primary;
- gchar* secondary;
+ gchar *title;
+ gchar *primary;
+ gchar *secondary;
+ gchar *checktext;
gboolean completed;
guint flags;
@@ -301,6 +302,8 @@ finish_ask_io (GkrAskRequest *ask, gboolean success)
/* First line is the response */
if (i == 0) {
+ if (pv->checktext)
+ ask->checked = g_strrstr (line, "checked") ? TRUE : FALSE;
ask->response = atol (line);
if (ask->response < GKR_ASK_RESPONSE_ALLOW)
break;
@@ -427,6 +430,8 @@ launch_ask_helper (GkrAskRequest *ask)
envp[i++] = format_object_markup (pv->object, "ASK_TITLE=", pv->title);
envp[i++] = format_object_markup (pv->object, "ASK_PRIMARY=", pv->primary);
envp[i++] = format_object_markup (pv->object, "ASK_SECONDARY=", pv->secondary);
+ if (pv->checktext)
+ envp[i++] = g_strdup_printf ("ASK_CHECK=%s", pv->checktext);
envp[i++] = g_strdup_printf ("ASK_FLAGS=%d", pv->flags);
envp[i++] = NULL;
@@ -488,6 +493,7 @@ gkr_ask_request_init (GkrAskRequest *ask)
pv->title = g_strdup ("");
pv->primary = g_strdup ("");
pv->secondary = g_strdup ("");
+ pv->checktext = NULL;
/* Use a secure memory buffer */
gkr_buffer_init_full (&pv->buffer, 128, gnome_keyring_memory_realloc);
@@ -529,7 +535,8 @@ gkr_ask_request_finalize (GObject *obj)
g_free (pv->title);
g_free (pv->primary);
g_free (pv->secondary);
- pv->title = pv->primary = pv->secondary = NULL;
+ g_free (pv->checktext);
+ pv->title = pv->primary = pv->secondary = pv->checktext = NULL;
g_assert (pv->ask_pid == 0);
@@ -594,6 +601,17 @@ gkr_ask_request_set_secondary (GkrAskRequest *ask, const gchar *secondary)
pv->secondary = g_strdup (secondary);
}
+void
+gkr_ask_request_set_check_option (GkrAskRequest *ask, const gchar *check_text)
+{
+ GkrAskRequestPrivate *pv = GKR_ASK_REQUEST_GET_PRIVATE (ask);
+
+ g_assert (GKR_IS_ASK_REQUEST (ask));
+
+ g_free (pv->checktext);
+ pv->checktext = g_strdup (check_text);
+}
+
GObject*
gkr_ask_request_get_object (GkrAskRequest *ask)
{
diff --git a/ui/gkr-ask-request.h b/ui/gkr-ask-request.h
index 3d41213c..739a58f0 100644
--- a/ui/gkr-ask-request.h
+++ b/ui/gkr-ask-request.h
@@ -81,6 +81,7 @@ struct _GkrAskRequest {
/* Results */
GkrAskResponse response;
+ gboolean checked;
gchar* original_password;
gchar* typed_password;
};
@@ -100,6 +101,9 @@ GkrAskRequest* gkr_ask_request_new (const gchar *title,
void gkr_ask_request_set_secondary (GkrAskRequest *ask,
const gchar *secondary);
+
+void gkr_ask_request_set_check_option (GkrAskRequest *ask,
+ const gchar *check_text);
GObject* gkr_ask_request_get_object (GkrAskRequest *ask);
diff --git a/ui/gkr-ask-tool.c b/ui/gkr-ask-tool.c
index a11dcfc8..3cf59c04 100644
--- a/ui/gkr-ask-tool.c
+++ b/ui/gkr-ask-tool.c
@@ -37,6 +37,7 @@
static const gchar *env_title = NULL;
static const gchar *env_primary = NULL;
static const gchar *env_secondary = NULL;
+static const gchar *env_checktext = NULL;
static guint env_flags = 0;
static gchar*
@@ -150,14 +151,12 @@ lock_memory (void)
}
static gint
-run_dialog (const char *title,
- const char *primary,
- const char *secondary,
- gboolean include_password,
+run_dialog (gboolean include_password,
gboolean include_confirm,
gboolean include_original,
char **password_out,
char **original_out,
+ gboolean *check_out,
guint default_response,
const gchar *first_button_text,
...)
@@ -174,13 +173,13 @@ run_dialog (const char *title,
const char *text;
gint response_id;
GtkWidget *table, *ptable;
- GtkWidget *image;
+ GtkWidget *image, *check;
const char *password;
const char *confirmation;
const char *original;
int row;
- dialog = gtk_dialog_new_with_buttons (title , NULL, 0, NULL, NULL);
+ dialog = gtk_dialog_new_with_buttons (env_title , NULL, 0, NULL, NULL);
gtk_window_set_icon_name(GTK_WINDOW(dialog), "stock_lock");
gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
gtk_container_set_border_width (GTK_CONTAINER (dialog), 6);
@@ -223,7 +222,7 @@ run_dialog (const char *title,
gtk_table_attach (GTK_TABLE (table), image,
0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
- message = create_markup (primary, secondary);
+ message = create_markup (env_primary, env_secondary);
message_widget = GTK_LABEL (gtk_label_new (message));
g_free (message);
gtk_label_set_use_markup (message_widget, TRUE);
@@ -253,7 +252,8 @@ run_dialog (const char *title,
old = NULL;
if (include_original) {
GtkWidget *label_old;
-
+
+ gtk_table_resize (GTK_TABLE (ptable), ++row, 2);
label_old = gtk_label_new_with_mnemonic (_("_Old password:"));
old = gtk_entry_new ();
gtk_entry_set_visibility (GTK_ENTRY (old), FALSE);
@@ -264,19 +264,19 @@ run_dialog (const char *title,
G_CALLBACK (gtk_window_activate_default),
dialog);
gtk_table_attach (GTK_TABLE (ptable), label_old,
- 0, 1, row, row+1,
+ 0, 1, row - 1, row,
GTK_FILL, GTK_SHRINK, 0, 6);
gtk_misc_set_alignment (GTK_MISC (label_old), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (ptable), old,
- 1, 2, row, row+1,
+ 1, 2, row - 1, row,
GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 6);
- row++;
}
entry = NULL;
if (include_password) {
GtkWidget *label_entry;
+ gtk_table_resize (GTK_TABLE (ptable), ++row, 2);
label_entry = gtk_label_new_with_mnemonic (_("_Password:"));
entry = gtk_entry_new ();
gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE);
@@ -287,13 +287,12 @@ run_dialog (const char *title,
G_CALLBACK (gtk_window_activate_default),
dialog);
gtk_table_attach (GTK_TABLE (ptable), label_entry,
- 0, 1, row, row+1,
+ 0, 1, row - 1, row,
GTK_FILL, GTK_SHRINK, 0, 0);
gtk_misc_set_alignment (GTK_MISC (label_entry), 0.0, 0.5);
gtk_table_attach_defaults (GTK_TABLE (ptable),
entry,
- 1, 2, row, row+1);
- row++;
+ 1, 2, row - 1, row);
}
confirm = NULL;
@@ -301,7 +300,7 @@ run_dialog (const char *title,
GtkWidget *label_confirm;
GtkWidget *strength_bar;
- gtk_table_resize (GTK_TABLE (ptable),4,2);
+ gtk_table_resize (GTK_TABLE (ptable), ++row, 2);
label_confirm = gtk_label_new_with_mnemonic (_("_Confirm password:"));
confirm = gtk_entry_new ();
gtk_entry_set_visibility (GTK_ENTRY (confirm), FALSE);
@@ -311,15 +310,15 @@ run_dialog (const char *title,
G_CALLBACK (gtk_window_activate_default),
dialog);
gtk_table_attach (GTK_TABLE (ptable), label_confirm,
- 0, 1, row, row+1,
+ 0, 1, row - 1, row,
GTK_FILL, GTK_SHRINK, 0, 0);
gtk_misc_set_alignment (GTK_MISC (label_confirm), 0.0, 0.5);
gtk_table_attach_defaults (GTK_TABLE (ptable),
confirm,
- 1, 2, row, row+1);
- row++;
+ 1, 2, row - 1, row);
/* Strength bar: */
+ gtk_table_resize (GTK_TABLE (ptable), ++row, 2);
strength_bar = gtk_progress_bar_new ();
gtk_progress_bar_set_text (GTK_PROGRESS_BAR (strength_bar), _("New password strength"));
g_signal_connect ((gpointer) entry, "changed",
@@ -327,8 +326,15 @@ run_dialog (const char *title,
strength_bar);
gtk_table_attach_defaults (GTK_TABLE (ptable),
strength_bar,
- 1, 2, row, row+1);
- row++;
+ 1, 2, row - 1, row);
+ }
+
+ check = NULL;
+ if (env_checktext) {
+ gtk_table_resize (GTK_TABLE (ptable), ++row, 2);
+ check = gtk_check_button_new_with_mnemonic (env_checktext);
+ gtk_table_attach_defaults (GTK_TABLE (ptable), check,
+ 1, 2, row - 1, row);
}
if (row > 0)
@@ -377,6 +383,13 @@ run_dialog (const char *title,
}
*password_out = g_strdup (password);
}
+
+ if (check_out) {
+ if (check != NULL && response >= GKR_ASK_RESPONSE_ALLOW)
+ *check_out = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check));
+ else
+ *check_out = FALSE;
+ }
gtk_widget_destroy (dialog);
@@ -391,6 +404,7 @@ prepare_dialog (void)
guint resps[6];
int i = 0;
guint response;
+ gboolean checked;
g_assert (env_title);
g_assert (env_primary);
@@ -428,11 +442,10 @@ prepare_dialog (void)
g_assert (i > 0);
password = NULL;
- response = run_dialog (env_title, env_primary, env_secondary,
- env_flags & GKR_ASK_REQUEST_PASSWORD,
+ response = run_dialog (env_flags & GKR_ASK_REQUEST_PASSWORD,
env_flags & GKR_ASK_REQUEST_CONFIRM_PASSWORD,
env_flags & GKR_ASK_REQUEST_ORIGINAL_PASSWORD,
- &password, &original,
+ &password, &original, &checked,
resps[i - 1], /* default response, last one added */
buttons[0], resps[0],
buttons[1], resps[1],
@@ -450,8 +463,8 @@ prepare_dialog (void)
}
/* Send back the response */
- printf ("%d\n", response);
-
+ printf ("%d %s\n", response, checked ? "checked" : "");
+
if (response >= GKR_ASK_RESPONSE_ALLOW) {
/* Send back the password */
@@ -472,6 +485,7 @@ main (int argc, char *argv[])
env_title = g_getenv ("ASK_TITLE");
env_primary = g_getenv ("ASK_PRIMARY");
env_secondary = g_getenv ("ASK_SECONDARY");
+ env_checktext = g_getenv ("ASK_CHECK");
flags = g_getenv ("ASK_FLAGS");
if (!env_title || !env_primary || !env_secondary || !flags) {
@@ -480,6 +494,9 @@ main (int argc, char *argv[])
}
env_flags = atoi (flags);
+
+ if (env_checktext && !env_checktext[0])
+ env_checktext = NULL;
gtk_init (&argc, &argv);