diff options
-rw-r--r-- | ChangeLog | 22 | ||||
-rw-r--r-- | daemon/gnome-keyring-daemon-ops.c | 210 | ||||
-rw-r--r-- | daemon/gnome-keyring-daemon.c | 4 | ||||
-rw-r--r-- | keyrings/gkr-keyring-item.c | 66 | ||||
-rw-r--r-- | keyrings/gkr-keyring-item.h | 5 | ||||
-rw-r--r-- | keyrings/gkr-keyring.c | 22 | ||||
-rw-r--r-- | keyrings/gkr-keyring.h | 5 | ||||
-rw-r--r-- | keyrings/gkr-keyrings.c | 22 | ||||
-rw-r--r-- | keyrings/gkr-keyrings.h | 2 | ||||
-rw-r--r-- | library/gnome-keyring-utils.c | 41 | ||||
-rw-r--r-- | library/gnome-keyring.c | 41 | ||||
-rw-r--r-- | library/gnome-keyring.h | 1 | ||||
-rw-r--r-- | reference/tmpl/gnome-keyring-item-info.sgml | 1 | ||||
-rw-r--r-- | tests/Makefile.am | 1 | ||||
-rw-r--r-- | tests/unit-test-keyrings.c | 25 | ||||
-rw-r--r-- | tests/unit-test-login-prompt.c | 116 | ||||
-rw-r--r-- | ui/gkr-ask-request.c | 26 | ||||
-rw-r--r-- | ui/gkr-ask-request.h | 4 | ||||
-rw-r--r-- | ui/gkr-ask-tool.c | 67 |
19 files changed, 512 insertions, 169 deletions
@@ -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); |