gnome-keyring r1169 - in trunk: . common common/tests daemon keyrings keyrings/tests library pk pk/tests pkcs11 pkix pkix/tests po reference/tmpl ssh ssh/tests
- From: nnielsen svn gnome org
- To: svn-commits-list gnome org
- Subject: gnome-keyring r1169 - in trunk: . common common/tests daemon keyrings keyrings/tests library pk pk/tests pkcs11 pkix pkix/tests po reference/tmpl ssh ssh/tests
- Date: Mon, 7 Jul 2008 21:17:26 +0000 (UTC)
Author: nnielsen
Date: Mon Jul 7 21:17:26 2008
New Revision: 1169
URL: http://svn.gnome.org/viewvc/gnome-keyring?rev=1169&view=rev
Log:
* common/gkr-crypto.c: Null terminate hex encodings properly
* common/gkr-location.c:
* common/gkr-location.h:
* common/tests/unit-test-location.c: Add function to delete
files, and
check if a location is a volume.
* daemon/gkr-daemon-ops.c: Allow arbitrary item types.
* keyrings/gkr-keyring.c:
* keyrings/gkr-keyrings.c:
* keyrings/gkr-keyrings.h: Can create keyrings in arbitrary
locations.
* daemon/gkr-daemon-ops.c:
* keyrings/gkr-keyring.c: Consolidate the keyring unlocking
logic.
* keyrings/gkr-keyring-binary.c:
* keyrings/gkr-keyring-item.c:
* keyrings/gkr-keyring-item.h: Functions to manage item
attribute lists.
* keyrings/gkr-keyring-item.c:
* keyrings/gkr-keyring-login.c:
* keyrings/tests/unit-test-keyring-file.c:
* library/gnome-keyring.h:
* pk/gkr-pk-cert.c:
* pk/gkr-pk-index.c:
* pk/gkr-pk-index.h:
* pk/gkr-pk-object.c:
* pk/gkr-pk-object.h:
* pk/gkr-pk-object-manager.c:
* pk/gkr-pk-privkey.c:
* pk/gkr-pk-pubkey.c:
* pk/gkr-pk-root-storage.c: (added)
* pk/gkr-pk-root-storage.h: (added)
* pk/gkr-pk-session-storage.c: (added)
* pk/gkr-pk-session-storage.h: (added)
* pk/gkr-pk-storage.c: (added)
* pk/gkr-pk-storage.h: (added)
* pk/Makefile.am:
* pk/tests/unit-test-pk-cert.c:
* pk/tests/unit-test-pk-index.c:
* pk/tests/unit-test-pk-netscape-trust.c:
* pkcs11/gkr-pkcs11-daemon-session.c:
* pkix/gkr-pkix-marshal.list
* pkix/gkr-pkix-parser.c:
* pkix/gkr-pkix-parser.h:
* pkix/tests/unit-test-pkix-parser.c:
* pkix/tests/unit-test-pkix-serialize.c:
* configure.in: Put indexes into keyrings, and rework how
storage
of PK objects is thought out.
* daemon/gkr-daemon.c:
* pkix/gkr-pkix-openssl.c:
* pkix/gkr-pkix-openssl.h:
* pkix/gkr-pkix-pem.c:
* pkix/gkr-pkix-pem.h:
* pkix/tests/unit-test-pkix-openssl.c: (added)
* ssh/gkr-ssh-daemon-io.c:
* ssh/gkr-ssh-daemon-ops.c:
* ssh/gkr-ssh-proto.c:
* ssh/gkr-ssh-storage.c: (added)
* ssh/gkr-ssh-storage.h: (added)
* ssh/Makefile.am:
* ssh/tests/Makefile.am: (added)
* ssh/tests/unit-test-ssh-storage.c: (added)
Add an SSH key store which loads ~/.ssh
Added:
trunk/pk/gkr-pk-root-storage.c
trunk/pk/gkr-pk-root-storage.h
trunk/pk/gkr-pk-session-storage.c
trunk/pk/gkr-pk-session-storage.h
trunk/pk/gkr-pk-storage.c
trunk/pk/gkr-pk-storage.h
trunk/pkix/tests/unit-test-pkix-openssl.c
trunk/ssh/gkr-ssh-storage.c
trunk/ssh/gkr-ssh-storage.h
trunk/ssh/tests/ (props changed)
trunk/ssh/tests/Makefile.am
trunk/ssh/tests/unit-test-ssh-storage.c
Modified:
trunk/ChangeLog
trunk/common/gkr-crypto.c
trunk/common/gkr-location.c
trunk/common/gkr-location.h
trunk/common/tests/unit-test-location.c
trunk/configure.in
trunk/daemon/gkr-daemon-ops.c
trunk/daemon/gkr-daemon.c
trunk/keyrings/gkr-keyring-binary.c
trunk/keyrings/gkr-keyring-item.c
trunk/keyrings/gkr-keyring-item.h
trunk/keyrings/gkr-keyring-login.c
trunk/keyrings/gkr-keyring.c
trunk/keyrings/gkr-keyring.h
trunk/keyrings/gkr-keyrings.c
trunk/keyrings/gkr-keyrings.h
trunk/keyrings/tests/unit-test-keyring-file.c
trunk/library/gnome-keyring.h
trunk/pk/Makefile.am
trunk/pk/gkr-pk-cert.c
trunk/pk/gkr-pk-index.c
trunk/pk/gkr-pk-index.h
trunk/pk/gkr-pk-object-manager.c
trunk/pk/gkr-pk-object-storage.c
trunk/pk/gkr-pk-object-storage.h
trunk/pk/gkr-pk-object.c
trunk/pk/gkr-pk-object.h
trunk/pk/gkr-pk-privkey.c
trunk/pk/gkr-pk-pubkey.c
trunk/pk/tests/unit-test-pk-cert.c
trunk/pk/tests/unit-test-pk-index.c
trunk/pk/tests/unit-test-pk-netscape-trust.c
trunk/pkcs11/gkr-pkcs11-daemon-session.c
trunk/pkix/gkr-pkix-marshal.list
trunk/pkix/gkr-pkix-openssl.c
trunk/pkix/gkr-pkix-openssl.h
trunk/pkix/gkr-pkix-parser.c
trunk/pkix/gkr-pkix-parser.h
trunk/pkix/gkr-pkix-pem.c
trunk/pkix/gkr-pkix-pem.h
trunk/pkix/tests/Makefile.am
trunk/pkix/tests/unit-test-pkix-parser.c
trunk/pkix/tests/unit-test-pkix-serialize.c
trunk/po/ChangeLog
trunk/po/POTFILES.in
trunk/reference/tmpl/gnome-keyring-item-info.sgml
trunk/ssh/Makefile.am
trunk/ssh/gkr-ssh-daemon-io.c
trunk/ssh/gkr-ssh-daemon-ops.c
trunk/ssh/gkr-ssh-proto.c
Modified: trunk/common/gkr-crypto.c
==============================================================================
--- trunk/common/gkr-crypto.c (original)
+++ trunk/common/gkr-crypto.c Mon Jul 7 21:17:26 2008
@@ -82,7 +82,7 @@
gcrypt_initialized = TRUE;
}
-static const char HEXC[] = "0123456789abcdef";
+static const char HEXC[] = "0123456789ABCDEF";
gboolean
gkr_crypto_hex_encode (const guchar *data, gsize n_data,
@@ -101,7 +101,9 @@
n_data--;
}
-
+
+ /* Null terminate */
+ *encoded = 0;
return TRUE;
}
@@ -125,7 +127,7 @@
if (!isspace (*data)) {
/* Find the position */
- pos = strchr (HEXC, tolower (*data));
+ pos = strchr (HEXC, toupper (*data));
if (pos == 0)
break;
Modified: trunk/common/gkr-location.c
==============================================================================
--- trunk/common/gkr-location.c (original)
+++ trunk/common/gkr-location.c Mon Jul 7 21:17:26 2008
@@ -35,7 +35,9 @@
#include <glib.h>
#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <errno.h>
#include <string.h>
#define LOC_DELIMITER ":"
@@ -1017,6 +1019,27 @@
}
gboolean
+gkr_location_is_volume (GQuark loc)
+{
+ const gchar *sloc;
+ const gchar *delim;
+
+ if (!loc)
+ return FALSE;
+
+ sloc = g_quark_to_string (loc);
+ g_return_val_if_fail (sloc, FALSE);
+
+ delim = strchr (sloc, LOC_DELIMITER_C);
+ if (!delim) {
+ g_warning ("The '%s' location is invalid", sloc);
+ return FALSE;
+ }
+
+ return (delim[1] == 0);
+}
+
+gboolean
gkr_location_is_descendant (GQuark parent, GQuark descendant)
{
const gchar *sparent = g_quark_to_string (parent);
@@ -1103,3 +1126,32 @@
return ret;
}
+
+gboolean
+gkr_location_delete_file (GQuark loc, GError **err)
+{
+ gchar *path;
+ int eno;
+
+ g_return_val_if_fail (loc != 0, FALSE);
+ g_return_val_if_fail (!err || !*err, FALSE);
+
+ /* Should be successful when file doesn't exist */
+ path = gkr_location_to_path (loc);
+ if (!path)
+ return TRUE;
+
+ if (g_unlink (path) < 0) {
+ eno = errno;
+
+ /* Should be successful when file doesn't exist */
+ if (eno != ENOENT) {
+ g_set_error (err, G_FILE_ERROR, g_file_error_from_errno (eno),
+ _("Couldn't delete the file: %s"), g_strerror (eno));
+ return FALSE;
+ }
+ }
+
+ g_free (path);
+ return TRUE;
+}
Modified: trunk/common/gkr-location.h
==============================================================================
--- trunk/common/gkr-location.h (original)
+++ trunk/common/gkr-location.h Mon Jul 7 21:17:26 2008
@@ -57,6 +57,8 @@
gchar* gkr_location_to_path (GQuark loc);
+gboolean gkr_location_is_volume (GQuark loc);
+
gboolean gkr_location_is_descendant (GQuark parent, GQuark descendant);
GQuark gkr_location_get_volume (GQuark loc);
@@ -73,6 +75,8 @@
gboolean gkr_location_write_file (GQuark loc, const guchar *data, gssize len, GError **err);
+gboolean gkr_location_delete_file (GQuark loc, GError **err);
+
/* -------------------------------------------------------------------------- */
#define GKR_TYPE_LOCATION_MANAGER (gkr_location_manager_get_type ())
Modified: trunk/common/tests/unit-test-location.c
==============================================================================
--- trunk/common/tests/unit-test-location.c (original)
+++ trunk/common/tests/unit-test-location.c Mon Jul 7 21:17:26 2008
@@ -72,6 +72,10 @@
path2 = gkr_location_to_path (child);
CuAssert (cu, "should return non-null path", path2 != NULL);
+
+ CuAssert (cu, "should be volume", gkr_location_is_volume (GKR_LOCATION_VOLUME_HOME));
+ CuAssert (cu, "should not be volume", !gkr_location_is_volume (loc));
+ CuAssert (cu, "should not be volume", !gkr_location_is_volume (child));
}
void unit_test_location_trailing (CuTest* cu)
@@ -142,3 +146,32 @@
}
+void unit_test_location_fileops (CuTest* cu)
+{
+ const guchar *data = (guchar*)"TEST DATA FOR FILE";
+ guchar *result;
+ gsize n_result, len;
+ gboolean ret;
+ GQuark loc;
+
+ loc = gkr_location_from_child (GKR_LOCATION_VOLUME_FILE, "/tmp/gkr-test-location-fileops");
+ CuAssert (cu, "should return a non-zero quark", loc != 0);
+
+ len = strlen ((gchar*)data);
+ ret = gkr_location_write_file (loc, data, len, NULL);
+ CuAssert (cu, "should be successful writing to temp file", ret == TRUE);
+
+ ret = gkr_location_read_file (loc, &result, &n_result, NULL);
+ CuAssert (cu, "should be successful reading from temp file", ret == TRUE);
+ CuAssert (cu, "should have read same length as written", n_result == len);
+ CuAssert (cu, "should have read same data as written", memcmp (data, result, len) == 0);
+
+ ret = gkr_location_delete_file (loc, NULL);
+ CuAssert (cu, "should have successfully deleted file", ret == TRUE);
+
+ ret = gkr_location_read_file (loc, &result, &n_result, NULL);
+ CuAssert (cu, "shouldn't be able to read from deleted file", ret == FALSE);
+
+ ret = gkr_location_delete_file (loc, NULL);
+ CuAssert (cu, "should be able to successfully delete non-existant file", ret == TRUE);
+}
Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in (original)
+++ trunk/configure.in Mon Jul 7 21:17:26 2008
@@ -362,6 +362,8 @@
root_status="$with_root_certs"
fi
+AM_CONDITIONAL(WITH_ROOT_CERTS, test -n "$with_root_certs")
+
# --------------------------------------------------------------------
# Check for /dev/random
@@ -477,6 +479,7 @@
po/Makefile.in
reference/Makefile
ssh/Makefile
+ssh/tests/Makefile
tests/Makefile
ui/Makefile
library/gnome-keyring-1.pc
Modified: trunk/daemon/gkr-daemon-ops.c
==============================================================================
--- trunk/daemon/gkr-daemon-ops.c (original)
+++ trunk/daemon/gkr-daemon-ops.c Mon Jul 7 21:17:26 2008
@@ -286,72 +286,6 @@
return ret;
}
-static gboolean
-check_keyring_ask_request (GkrAskRequest* ask)
-{
- GkrKeyring *keyring;
- const gchar *password;
- gchar *display;
-
- keyring = GKR_KEYRING (gkr_ask_request_get_object (ask));
- g_assert (GKR_IS_KEYRING (keyring));
-
- if (!keyring->locked) {
- ask->response = GKR_ASK_RESPONSE_ALLOW;
- return GKR_ASK_STOP_REQUEST;
- }
-
- /* If they typed a password, try it out */
- if (ask->response >= GKR_ASK_RESPONSE_ALLOW) {
-
- g_assert (ask->typed_password);
- 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) {
- display = g_strdup_printf (_("Unlock password for %s keyring"),
- keyring->keyring_name);
- gkr_keyring_login_attach_secret (GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD,
- display, ask->typed_password,
- "keyring", gkr_location_to_string (keyring->location), NULL);
- g_free (display);
- }
- }
-
- /*
- * We can automatically unlock keyrings that have their password
- * stored in the 'login' keyring.
- */
- password = gkr_keyring_login_lookup_secret (GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD,
- "keyring", gkr_location_to_string (keyring->location), NULL);
- 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 */
- gkr_keyring_login_remove_secret (GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD,
- "keyring", gkr_location_to_string (keyring->location), NULL);
- }
- }
-
- /* 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;
-}
-
static gboolean
request_keyring_access (GkrKeyringRequest *req, GkrKeyring *keyring)
{
@@ -433,7 +367,7 @@
gkr_ask_request_set_check_option (ask, _("Automatically unlock this keyring 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);
+ g_signal_connect (ask, "check-request", G_CALLBACK (gkr_keyring_ask_check_unlock), NULL);
g_free (primary);
g_free (message);
@@ -1196,8 +1130,7 @@
return FALSE;
}
- if ((type & GNOME_KEYRING_ITEM_TYPE_MASK) >= GNOME_KEYRING_ITEM_LAST_TYPE ||
- display_name == NULL || secret == NULL) {
+ if (display_name == NULL || secret == NULL) {
res = GNOME_KEYRING_RESULT_BAD_ARGUMENTS;
goto out;
}
@@ -1227,7 +1160,7 @@
}
if (update_if_exists) {
- item = gkr_keyring_find_item (keyring, type, keyring->locked ? hashed : attributes);
+ item = gkr_keyring_find_item (keyring, type, keyring->locked ? hashed : attributes, TRUE);
if (item) {
/* Make sure we have access to the previous item */
if (!request_item_access (req, item, GNOME_KEYRING_ACCESS_WRITE, TRUE))
@@ -1691,7 +1624,7 @@
/* Need at least one attribute to match on */
if (ctx.attributes->len > 0) {
- ctx.hashed = gkr_keyring_item_attributes_hash (ctx.attributes);
+ ctx.hashed = gkr_attribute_list_hash (ctx.attributes);
ctx.nfound = 0;
ctx.req = req;
ctx.items = NULL;
Modified: trunk/daemon/gkr-daemon.c
==============================================================================
--- trunk/daemon/gkr-daemon.c (original)
+++ trunk/daemon/gkr-daemon.c Mon Jul 7 21:17:26 2008
@@ -39,6 +39,7 @@
#ifdef WITH_SSH
#include "ssh/gkr-ssh-daemon.h"
+#include "ssh/gkr-ssh-storage.h"
#endif
#include "ui/gkr-ask-daemon.h"
@@ -460,7 +461,8 @@
#ifdef WITH_SSH
if (check_run_component ("ssh")) {
- if (!gkr_daemon_ssh_io_initialize ())
+ if (!gkr_daemon_ssh_io_initialize () ||
+ !gkr_ssh_storage_initialize ())
cleanup_and_exit (1);
}
#endif
Modified: trunk/keyrings/gkr-keyring-binary.c
==============================================================================
--- trunk/keyrings/gkr-keyring-binary.c (original)
+++ trunk/keyrings/gkr-keyring-binary.c Mon Jul 7 21:17:26 2008
@@ -341,7 +341,7 @@
gkr_buffer_add_uint32 (buffer, item->id);
gkr_buffer_add_uint32 (buffer, item->type);
- hashed = gkr_keyring_item_attributes_hash (item->attributes);
+ hashed = gkr_attribute_list_hash (item->attributes);
if (!gkr_proto_add_attribute_list (buffer, hashed)) {
gnome_keyring_attribute_list_free (hashed);
Modified: trunk/keyrings/gkr-keyring-item.c
==============================================================================
--- trunk/keyrings/gkr-keyring-item.c (original)
+++ trunk/keyrings/gkr-keyring-item.c Mon Jul 7 21:17:26 2008
@@ -169,6 +169,7 @@
item->keyring = keyring;
item->id = id;
item->type = type;
+ item->attributes = gnome_keyring_attribute_list_new ();
/* Make sure we get disconnected when keyring goes away */
g_object_add_weak_pointer (G_OBJECT (item->keyring), (gpointer*)&(item->keyring));
@@ -195,6 +196,34 @@
return item;
}
+GkrKeyringItem*
+gkr_keyring_item_clone (GkrKeyring* new_keyring, GkrKeyringItem *item)
+{
+ GkrKeyringItem *nitem = g_object_new (GKR_TYPE_KEYRING_ITEM, NULL);
+
+ g_return_val_if_fail (GKR_IS_KEYRING (new_keyring), NULL);
+ g_return_val_if_fail (GKR_IS_KEYRING_ITEM (item), NULL);
+
+ nitem->keyring = new_keyring;
+ nitem->id = item->id;
+ nitem->locked = item->locked;
+
+ nitem->type = item->type;
+ nitem->secret = gkr_secure_strdup (item->secret);
+ nitem->display_name = g_strdup (item->display_name);
+
+ nitem->attributes = gnome_keyring_attribute_list_copy (item->attributes);
+ nitem->acl = gnome_keyring_acl_copy (item->acl);
+
+ nitem->ctime = item->ctime;
+ nitem->mtime = item->mtime;
+
+ /* Make sure we get disconnected when keyring goes away */
+ g_object_add_weak_pointer (G_OBJECT (item->keyring), (gpointer*)&(item->keyring));
+
+ return item;
+}
+
gboolean
gkr_keyring_item_match (GkrKeyringItem *item, GnomeKeyringItemType type,
GnomeKeyringAttributeList *attributes, gboolean match_all)
@@ -254,8 +283,94 @@
return TRUE;
}
+/* -----------------------------------------------------------------------------
+ * ATTRIBUTE LIST FUNCTIONS
+ */
+
+void
+gkr_attribute_list_set (GnomeKeyringAttributeList *attrs, GnomeKeyringAttribute *attr)
+{
+ GnomeKeyringAttribute *set;
+ GnomeKeyringAttribute last;
+ gchar *tofree = NULL;
+
+ g_return_if_fail (attrs);
+ g_return_if_fail (attr);
+ g_return_if_fail (attr->name);
+
+ set = gkr_attribute_list_find (attrs, attr->name);
+
+ /* Found, appropriate for our own uses */
+ if (set) {
+ if (set->type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING) {
+ tofree = set->value.string;
+ set->value.string = NULL;
+ }
+
+ /* Not found, add a new one to the end */
+ } else {
+ memset (&last, 0, sizeof (last));
+ g_array_append_val (attrs, last);
+ set = &g_array_index (attrs, GnomeKeyringAttribute, attrs->len - 1);
+ set->name = g_strdup (attr->name);
+ }
+
+ /* Set the actual value */
+ set->type = attr->type;
+ switch (attr->type) {
+ case GNOME_KEYRING_ATTRIBUTE_TYPE_STRING:
+ set->value.string = g_strdup (attr->value.string);
+ break;
+ case GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32:
+ set->value.integer = attr->value.integer;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ g_free (tofree);
+}
+
+GnomeKeyringAttribute*
+gkr_attribute_list_find (GnomeKeyringAttributeList *attrs, const gchar *name)
+{
+ GnomeKeyringAttribute *attr;
+ int i;
+
+ g_return_val_if_fail (attrs, NULL);
+ g_return_val_if_fail (name, NULL);
+
+ for (i = 0; i < attrs->len; i++) {
+ attr = &gnome_keyring_attribute_list_index (attrs, i);
+ g_return_val_if_fail (attr->name, NULL);
+ if (strcmp (attr->name, name) == 0)
+ return attr;
+ }
+
+ return NULL;
+}
+
+void
+gkr_attribute_list_delete (GnomeKeyringAttributeList *attrs, const gchar *name)
+{
+ GnomeKeyringAttribute *attr;
+ int i;
+
+ g_return_if_fail (attrs);
+ g_return_if_fail (name);
+
+ for (i = 0; i < attrs->len; i++) {
+ attr = &gnome_keyring_attribute_list_index (attrs, i);
+ g_return_if_fail (attr->name);
+ if (strcmp (attr->name, name) == 0) {
+ g_array_remove_index_fast (attrs, i);
+ return;
+ }
+ }
+}
+
GnomeKeyringAttributeList *
-gkr_keyring_item_attributes_hash (GnomeKeyringAttributeList *attributes)
+gkr_attribute_list_hash (GnomeKeyringAttributeList *attributes)
{
GnomeKeyringAttributeList *hashed;
GnomeKeyringAttribute *orig_attribute;
Modified: trunk/keyrings/gkr-keyring-item.h
==============================================================================
--- trunk/keyrings/gkr-keyring-item.h (original)
+++ trunk/keyrings/gkr-keyring-item.h Mon Jul 7 21:17:26 2008
@@ -83,13 +83,24 @@
GkrKeyringItem* gkr_keyring_item_create (GkrKeyring* keyring,
GnomeKeyringItemType type);
+GkrKeyringItem* gkr_keyring_item_clone (GkrKeyring* new_keyring,
+ GkrKeyringItem *item);
+
gboolean gkr_keyring_item_match (GkrKeyringItem *item,
GnomeKeyringItemType type,
GnomeKeyringAttributeList *attributes,
gboolean match_all);
+void gkr_attribute_list_set (GnomeKeyringAttributeList *attrs,
+ GnomeKeyringAttribute *attr);
+
+GnomeKeyringAttribute* gkr_attribute_list_find (GnomeKeyringAttributeList *attrs,
+ const gchar *name);
+
+void gkr_attribute_list_delete (GnomeKeyringAttributeList *attrs,
+ const gchar *name);
-GnomeKeyringAttributeList* gkr_keyring_item_attributes_hash (GnomeKeyringAttributeList *attributes);
+GnomeKeyringAttributeList* gkr_attribute_list_hash (GnomeKeyringAttributeList *attrs);
G_END_DECLS
Modified: trunk/keyrings/gkr-keyring-login.c
==============================================================================
--- trunk/keyrings/gkr-keyring-login.c (original)
+++ trunk/keyrings/gkr-keyring-login.c Mon Jul 7 21:17:26 2008
@@ -232,7 +232,7 @@
attrs = string_attribute_list_va (args);
va_end (args);
- item = gkr_keyring_find_item (login, type, attrs);
+ item = gkr_keyring_find_item (login, type, attrs, TRUE);
if (!item) {
item = gkr_keyring_item_create (login, type);
@@ -270,7 +270,7 @@
attrs = string_attribute_list_va (args);
va_end (args);
- item = gkr_keyring_find_item (login, type, attrs);
+ item = gkr_keyring_find_item (login, type, attrs, TRUE);
gnome_keyring_attribute_list_free (attrs);
if (item)
@@ -298,7 +298,7 @@
attrs = string_attribute_list_va (args);
va_end (args);
- item = gkr_keyring_find_item (login, type, attrs);
+ item = gkr_keyring_find_item (login, type, attrs, TRUE);
gnome_keyring_attribute_list_free (attrs);
if (item) {
Modified: trunk/keyrings/gkr-keyring.c
==============================================================================
--- trunk/keyrings/gkr-keyring.c (original)
+++ trunk/keyrings/gkr-keyring.c Mon Jul 7 21:17:26 2008
@@ -25,8 +25,9 @@
#include "config.h"
#include "gkr-keyring.h"
-#include "gkr-keyrings.h"
#include "gkr-keyring-item.h"
+#include "gkr-keyring-login.h"
+#include "gkr-keyrings.h"
#include "common/gkr-buffer.h"
#include "common/gkr-location.h"
@@ -36,6 +37,7 @@
#include "library/gnome-keyring-proto.h"
#include <glib.h>
+#include <glib/gi18n.h>
#include <gcrypt.h>
@@ -248,16 +250,18 @@
}
GkrKeyring*
-gkr_keyring_create (GQuark volume, const gchar *keyring_name, const gchar *password)
+gkr_keyring_create (GQuark location, const gchar *keyring_name, const gchar *password)
{
GkrKeyring *keyring;
- if (!volume)
- volume = GKR_LOCATION_VOLUME_LOCAL;
+ if (!location)
+ location = GKR_LOCATION_VOLUME_LOCAL;
+ if (gkr_location_is_volume (location))
+ location = get_default_location_for_name (location, keyring_name);
keyring = gkr_keyring_new (keyring_name, 0);
if (keyring != NULL) {
- keyring->location = get_default_location_for_name (volume, keyring_name);
+ keyring->location = location;
keyring->locked = FALSE;
keyring->password = gkr_secure_strdup (password);
keyring->salt_valid = FALSE;
@@ -306,14 +310,14 @@
GkrKeyringItem*
gkr_keyring_find_item (GkrKeyring *keyring, GnomeKeyringItemType type,
- GnomeKeyringAttributeList *attrs)
+ GnomeKeyringAttributeList *attrs, gboolean match_all)
{
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))
+ if (gkr_keyring_item_match (item, type, attrs, match_all))
return item;
}
@@ -549,3 +553,69 @@
return FALSE;
}
+
+gboolean
+gkr_keyring_ask_check_unlock (GkrAskRequest* ask)
+{
+ GkrKeyring *keyring;
+ const gchar *password;
+ gchar *display;
+
+ keyring = GKR_KEYRING (gkr_ask_request_get_object (ask));
+ g_assert (GKR_IS_KEYRING (keyring));
+
+ if (!keyring->locked) {
+ ask->response = GKR_ASK_RESPONSE_ALLOW;
+ return GKR_ASK_STOP_REQUEST;
+ }
+
+ /* If they typed a password, try it out */
+ if (ask->response >= GKR_ASK_RESPONSE_ALLOW) {
+
+ g_assert (ask->typed_password);
+ 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) {
+ display = g_strdup_printf (_("Unlock password for %s keyring"),
+ keyring->keyring_name);
+ gkr_keyring_login_attach_secret (GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD,
+ display, ask->typed_password,
+ "keyring", gkr_location_to_string (keyring->location), NULL);
+ g_free (display);
+ }
+ }
+
+ /*
+ * We can automatically unlock keyrings that have their password
+ * stored in the 'login' keyring.
+ */
+ password = gkr_keyring_login_lookup_secret (GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD,
+ "keyring", gkr_location_to_string (keyring->location), NULL);
+ 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 */
+ gkr_keyring_login_remove_secret (GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD,
+ "keyring", gkr_location_to_string (keyring->location), NULL);
+ }
+ }
+
+ /* 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;
+}
Modified: trunk/keyrings/gkr-keyring.h
==============================================================================
--- trunk/keyrings/gkr-keyring.h (original)
+++ trunk/keyrings/gkr-keyring.h Mon Jul 7 21:17:26 2008
@@ -37,6 +37,8 @@
#include "library/gnome-keyring.h"
+#include "ui/gkr-ask-request.h"
+
G_BEGIN_DECLS
#define GKR_TYPE_KEYRING (gkr_keyring_get_type())
@@ -95,7 +97,7 @@
GkrKeyringItem* gkr_keyring_get_item (GkrKeyring *keyring, guint id);
GkrKeyringItem* gkr_keyring_find_item (GkrKeyring *keyring, GnomeKeyringItemType type,
- GnomeKeyringAttributeList *attrs);
+ GnomeKeyringAttributeList *attrs, gboolean match_all);
void gkr_keyring_add_item (GkrKeyring* keyring, GkrKeyringItem* item);
@@ -117,6 +119,9 @@
gboolean gkr_keyring_is_insecure (GkrKeyring *keyring);
+/* Used with the check-request signal on GkrAskRequest to unlock a keyring */
+gboolean gkr_keyring_ask_check_unlock (GkrAskRequest* ask);
+
/* -----------------------------------------------------------------------------
* FILE FORMATS
*
Modified: trunk/keyrings/gkr-keyrings.c
==============================================================================
--- trunk/keyrings/gkr-keyrings.c (original)
+++ trunk/keyrings/gkr-keyrings.c Mon Jul 7 21:17:26 2008
@@ -338,6 +338,34 @@
return NULL;
}
+GkrKeyring*
+gkr_keyrings_for_location (GQuark location)
+{
+ GkrKeyring *keyring;
+ GList *l;
+
+ keyrings_init ();
+
+ for (l = keyrings; l != NULL; l = l->next) {
+ keyring = GKR_KEYRING (l->data);
+ if (keyring->location == location)
+ return keyring;
+ }
+
+ /* Try and load the keyring */
+ if (gkr_location_test_file (location, G_FILE_TEST_IS_REGULAR)) {
+ keyring = gkr_keyring_new ("", location);
+ if (gkr_keyring_update_from_disk (keyring))
+ gkr_keyrings_add (keyring);
+ else
+ keyring = NULL;
+ g_object_unref (keyring);
+ return keyring;
+ }
+
+ return NULL;
+}
+
gboolean
gkr_keyrings_foreach (GkrKeyringEnumFunc func, gpointer data)
{
Modified: trunk/keyrings/gkr-keyrings.h
==============================================================================
--- trunk/keyrings/gkr-keyrings.h (original)
+++ trunk/keyrings/gkr-keyrings.h Mon Jul 7 21:17:26 2008
@@ -40,6 +40,8 @@
GkrKeyring* gkr_keyrings_find (const gchar *name);
+GkrKeyring* gkr_keyrings_for_location (GQuark location);
+
GkrKeyring* gkr_keyrings_get_session (void);
guint gkr_keyrings_get_count (void);
Modified: trunk/keyrings/tests/unit-test-keyring-file.c
==============================================================================
--- trunk/keyrings/tests/unit-test-keyring-file.c (original)
+++ trunk/keyrings/tests/unit-test-keyring-file.c Mon Jul 7 21:17:26 2008
@@ -87,7 +87,7 @@
gnome_keyring_attribute_list_append_string (attrs, "bird", "cheep");
gnome_keyring_attribute_list_append_string (attrs, "iguana", "");
gnome_keyring_attribute_list_append_uint32 (attrs, "num", 3);
- item = gkr_keyring_find_item (keyring, GNOME_KEYRING_ITEM_GENERIC_SECRET, attrs);
+ item = gkr_keyring_find_item (keyring, GNOME_KEYRING_ITEM_GENERIC_SECRET, attrs, TRUE);
gnome_keyring_attribute_list_free (attrs);
CuAssert (cu, "Couldn't find item #3", item != NULL);
CuAssert (cu, "Invalid item found", item->id == 3);
Modified: trunk/library/gnome-keyring.h
==============================================================================
--- trunk/library/gnome-keyring.h (original)
+++ trunk/library/gnome-keyring.h Mon Jul 7 21:17:26 2008
@@ -41,7 +41,9 @@
GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD,
GNOME_KEYRING_ITEM_ENCRYPTION_KEY_PASSWORD,
- /*< private >*/
+ GNOME_KEYRING_ITEM_PK_STORAGE = 0x100,
+
+ /* Not used, remains here only for compatibility */
GNOME_KEYRING_ITEM_LAST_TYPE,
} GnomeKeyringItemType;
Modified: trunk/pk/Makefile.am
==============================================================================
--- trunk/pk/Makefile.am (original)
+++ trunk/pk/Makefile.am Mon Jul 7 21:17:26 2008
@@ -1,3 +1,10 @@
+
+if WITH_ROOT_CERTS
+ROOT_SRCS = gkr-pk-root-storage.c gkr-pk-root-storage.h
+else
+ROOT_SRCS =
+endif
+
noinst_LTLIBRARIES=libgkr-pk.la
INCLUDES= \
@@ -17,11 +24,13 @@
gkr-pk-netscape-trust.c gkr-pk-netscape-trust.h \
gkr-pk-object.c gkr-pk-object.h \
gkr-pk-object-manager.c gkr-pk-object-manager.h \
- gkr-pk-object-storage.c gkr-pk-object-storage.h \
gkr-pk-places.h \
gkr-pk-privkey.c gkr-pk-privkey.h \
gkr-pk-pubkey.c gkr-pk-pubkey.h \
- gkr-pk-util.c gkr-pk-util.h
+ gkr-pk-session-storage.c gkr-pk-session-storage.h \
+ gkr-pk-storage.c gkr-pk-storage.h \
+ gkr-pk-util.c gkr-pk-util.h \
+ $(ROOT_SRCS)
libgkr_pk_la_LIBADD = \
$(top_builddir)/ui/libgkr-ui.la \
Modified: trunk/pk/gkr-pk-cert.c
==============================================================================
--- trunk/pk/gkr-pk-cert.c (original)
+++ trunk/pk/gkr-pk-cert.c Mon Jul 7 21:17:26 2008
@@ -28,9 +28,9 @@
#include "gkr-pk-netscape-trust.h"
#include "gkr-pk-object.h"
#include "gkr-pk-object-manager.h"
-#include "gkr-pk-object-storage.h"
#include "gkr-pk-privkey.h"
#include "gkr-pk-pubkey.h"
+#include "gkr-pk-storage.h"
#include "gkr-pk-util.h"
#include "common/gkr-crypto.h"
@@ -125,7 +125,7 @@
obj = GKR_PK_OBJECT (cert);
g_return_val_if_fail (obj->storage, CKR_GENERAL_ERROR);
- if (!gkr_pk_object_storage_load_complete (obj->storage, obj, &err)) {
+ if (!gkr_pk_storage_load (obj->storage, obj, &err)) {
g_message ("couldn't load certificate at: %s: %s",
g_quark_to_string (obj->location),
err && err->message ? err->message : "");
@@ -227,7 +227,7 @@
GkrPkObject *obj = GKR_PK_OBJECT (cert);
/* Check if the index has such a value */
- if (gkr_pk_index_has_value (obj, "purposes"))
+ if (gkr_pk_object_index_has_value (obj, "purposes"))
return TRUE;
if (gkr_pk_cert_has_extension (cert, OID_ENHANCED_USAGE, NULL))
@@ -249,10 +249,10 @@
return ret;
*oids = NULL;
-
+
/* Look in the index if the purposes have been overridden there */
- if (gkr_pk_index_has_value (obj, "purposes")) {
- *oids = gkr_pk_index_get_quarks (obj, "purposes");
+ if (gkr_pk_object_index_has_value (obj, "purposes")) {
+ *oids = gkr_pk_object_index_get_quarks (obj, "purposes");
/* Otherwise look in the certificate */
} else {
@@ -485,7 +485,7 @@
value = CKT_GNOME_UNKNOWN;
/* Explicity set? */
- index = gkr_pk_index_get_string (obj, "user-trust");
+ index = gkr_pk_object_index_get_string (obj, "user-trust");
if (index) {
if (g_str_equal (index, "trusted"))
value = CKT_GNOME_TRUSTED;
Modified: trunk/pk/gkr-pk-index.c
==============================================================================
--- trunk/pk/gkr-pk-index.c (original)
+++ trunk/pk/gkr-pk-index.c Mon Jul 7 21:17:26 2008
@@ -30,203 +30,36 @@
#include "common/gkr-cleanup.h"
#include "common/gkr-crypto.h"
#include "common/gkr-location.h"
+#include "common/gkr-secure-memory.h"
-#include <sys/file.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#define MAX_LOCK_TRIES 16
-
-#define GKR_TYPE_PK_INDEX (gkr_pk_index_get_type())
-#define GKR_PK_INDEX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GKR_TYPE_PK_INDEX, GkrPkIndex))
-#define GKR_IS_PK_INDEX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GKR_TYPE_PK_INDEX))
-
-typedef struct _GkrPkIndex GkrPkIndex;
-typedef struct _GkrPkIndexClass GkrPkIndexClass;
-
-struct _GkrPkIndex {
- GObject parent;
- GHashTable *path_by_location;
- GHashTable *mtime_by_location;
- GHashTable *file_by_location;
- GHashTable *defaults_by_parent;
-};
+#include "keyrings/gkr-keyring-login.h"
+#include "keyrings/gkr-keyrings.h"
+
+#include "ui/gkr-ask-daemon.h"
+#include "ui/gkr-ask-request.h"
-struct _GkrPkIndexClass {
- GObjectClass parent_class;
+#include <glib/gi18n.h>
+
+enum {
+ PROP_0,
+ PROP_KEYRING,
+ PROP_DEFAULTS
};
-static GType gkr_pk_index_get_type (void);
G_DEFINE_TYPE (GkrPkIndex, gkr_pk_index, G_TYPE_OBJECT);
-static GkrPkIndex *index_singleton = NULL;
-static GQuark no_location = 0;
-
-typedef gboolean (*ReadValueFunc) (GKeyFile *file, const gchar *group, const gchar *field,
- GError **err, gpointer user_data);
-
-typedef gboolean (*WriteValueFunc) (GKeyFile *file, const gchar *group, const gchar *field,
- GError **err, gpointer user_data);
+static GkrPkIndex *index_default = NULL;
/* -----------------------------------------------------------------------------
* HELPERS
*/
-
-#ifndef HAVE_FLOCK
-#define LOCK_SH 1
-#define LOCK_EX 2
-#define LOCK_NB 4
-#define LOCK_UN 8
-
-static int flock(int fd, int operation)
-{
- struct flock flock;
-
- switch (operation & ~LOCK_NB) {
- case LOCK_SH:
- flock.l_type = F_RDLCK;
- break;
- case LOCK_EX:
- flock.l_type = F_WRLCK;
- break;
- case LOCK_UN:
- flock.l_type = F_UNLCK;
- break;
- default:
- errno = EINVAL;
- return -1;
- }
-
- flock.l_whence = 0;
- flock.l_start = 0;
- flock.l_len = 0;
-
- return fcntl(fd, (operation & LOCK_NB) ? F_SETLK : F_SETLKW, &flock);
-}
-#endif //NOT_HAVE_FLOCK
static void
-free_mtime (gpointer v)
-{
- g_slice_free (time_t, v);
-}
-
-static GQuark*
-quarks_from_strings (const gchar **strv, gsize *n_quarks)
+cleanup_default_index (void *unused)
{
- GArray *arr;
- GQuark quark;
-
- arr = g_array_new (TRUE, TRUE, sizeof (GQuark));
- while (*strv) {
- quark = g_quark_from_string (*strv);
- g_array_append_val (arr, quark);
- ++strv;
- }
-
- if (n_quarks)
- *n_quarks = arr->len;
-
- return (GQuark*)g_array_free (arr, FALSE);
-}
-
-static gchar**
-quarks_to_strings (const GQuark* quarks, gsize *n_strings)
-{
- const gchar *value;
- GArray *arr;
-
- arr = g_array_new (TRUE, TRUE, sizeof (const gchar*));
- while (*quarks) {
- value = g_quark_to_string (*quarks);
- g_array_append_val (arr, value);
- ++quarks;
- }
-
- if (n_strings)
- *n_strings = arr->len;
- return (gchar**)g_array_free (arr, FALSE);
-}
-
-static gboolean
-strings_are_equal (const gchar **one, const gchar **two)
-{
- while (*one && *two) {
- if (!g_str_equal (*one, *two))
- return FALSE;
- ++one;
- ++two;
- }
-
- return *one == *two;
-}
-
-static gpointer
-location_to_key (GQuark loc)
-{
- return GUINT_TO_POINTER (loc ? loc : no_location);
-}
-
-static GQuark
-location_from_key (gpointer key)
-{
- GQuark ret = GPOINTER_TO_UINT (key);
- return ret == no_location ? 0 : ret;
-}
-
-static const gchar*
-index_path_for_location (GkrPkIndex *index, GQuark loc)
-{
- gchar *locpath;
- gchar *path;
-
- if (!loc)
- return NULL;
-
- path = g_hash_table_lookup (index->path_by_location, location_to_key (loc));
- if (!path) {
- locpath = gkr_location_to_path (loc);
- if (!locpath) {
- g_message ("The disk or drive this file is located on is not present: %s",
- g_quark_to_string (loc));
- return NULL;
- }
-
- /* Our index files have a .keystore extension */
- path = g_strconcat (locpath, ".keystore", NULL);
- g_free (locpath);
-
- g_hash_table_replace (index->path_by_location, location_to_key (loc), path);
- }
-
- return path;
-}
-
-static gboolean
-check_index_mtime (GkrPkIndex *index, GQuark loc, time_t mtime)
-{
- gpointer k;
- gboolean ret = FALSE;
- time_t *last;
-
- k = location_to_key (loc);
-
- /* Check on last mtime */
- last = (time_t*)g_hash_table_lookup (index->mtime_by_location, k);
- ret = !last || (*last != mtime);
-
- /* Setup new mtime */
- if (ret) {
- last = g_slice_new (time_t);
- *last = mtime;
- g_hash_table_replace (index->mtime_by_location, k, last);
- }
-
- return ret;
+ g_assert (index_default);
+ g_object_unref (index_default);
+ index_default = NULL;
}
static gchar*
@@ -234,635 +67,218 @@
{
const guchar *digdata;
gsize n_group, n_digdata;
- gboolean r;
gchar *group;
+ gboolean r;
- g_return_val_if_fail (digest, NULL);
-
+ /* Encode the digest */
digdata = gkr_id_get_raw (digest, &n_digdata);
g_assert (digdata);
n_group = (n_digdata * 2) + 1;
group = g_malloc0 (n_group);
-
r = gkr_crypto_hex_encode (digdata, n_digdata, group, &n_group);
g_assert (r == TRUE);
-
- return group;
-}
-
-static gboolean
-read_exists_any_value (GKeyFile *file, const gchar *group, const gchar *field,
- GError **err, gboolean *value)
-{
- g_assert (value);
- *value = g_key_file_has_group (file, group);
- return TRUE;
-}
-
-static gboolean
-read_exists_value (GKeyFile *file, const gchar *group, const gchar *field,
- GError **err, gboolean *value)
-{
- g_assert (value);
- g_assert (field);
- *value = g_key_file_has_key (file, group, field, err);
- return *err == NULL;
-}
-static gboolean
-read_boolean_value (GKeyFile *file, const gchar *group, const gchar *field,
- GError **err, gboolean *value)
-{
- g_assert (value);
- g_assert (field);
- *value = g_key_file_get_boolean (file, group, field, err);
- return *err == NULL;
-}
-
-static gboolean
-read_int_value (GKeyFile *file, const gchar *group, const gchar *field,
- GError **err, gint *value)
-{
- g_assert (value);
- g_assert (field);
- *value = g_key_file_get_integer (file, group, field, err);
- return *err == NULL;
-}
-
-static gboolean
-read_string_value (GKeyFile *file, const gchar *group, const gchar *field,
- GError **err, gchar **value)
-{
- g_assert (value);
- g_assert (field);
- *value = g_key_file_get_string (file, group, field, err);
- return *value != NULL;
+ return group;
}
-
+
static gboolean
-read_quarks_value (GKeyFile *file, const gchar *group, const gchar *field,
- GError **err, GQuark **value)
+request_keyring_new (GQuark location, gchar **password)
{
- gchar **vals;
+ GkrAskRequest* ask;
+ gboolean ret;
- g_assert (value);
- g_assert (field);
+ g_assert (password);
+ g_assert (!*password);
+
+ /* And put together the ask request */
+ ask = gkr_ask_request_new (_("Create Storage for Key Information"),
+ _("Choose password to protect storage"),
+ GKR_ASK_REQUEST_NEW_PASSWORD);
- vals = g_key_file_get_string_list (file, group, field, NULL, err);
- if (vals != NULL) {
- g_assert (*err == NULL);
- *value = quarks_from_strings ((const gchar**)vals, NULL);
- g_strfreev (vals);
- return TRUE;
- }
+ gkr_ask_request_set_secondary (ask, _("The system wants to store information about your keys and certificates. "
+ "In order to protect this information, choose a password with which it will be locked."));
- return FALSE;
-}
+ gkr_ask_request_set_location (ask, location);
-static gint
-get_keyfile_value (GKeyFile *key_file, const gchar *group,
- const gchar *field, ReadValueFunc func, gpointer data)
-{
- GError *err = NULL;
-
- g_assert (key_file);
- g_assert (group);
- g_assert (func);
-
- if ((func) (key_file, group, field, &err, data))
- return 1;
-
- if (err != NULL) {
- if (err->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND &&
- err->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
- g_warning ("couldn't read field '%s' from index: %s",
- field, err->message ? err->message : "");
- g_error_free (err);
- return -1;
- }
-
- g_error_free (err);
- }
-
- return 0;
+ /* And do the prompt */
+ gkr_ask_daemon_process (ask);
+ ret = ask->response >= GKR_ASK_RESPONSE_ALLOW;
+ if (ret)
+ *password = gkr_secure_strdup (ask->typed_password);
+ g_object_unref (ask);
+ return ret;
}
static gboolean
-write_clear (GKeyFile *file, const gchar *group, const gchar *field,
- GError **err, gpointer user_data)
-{
- if (!g_key_file_has_group (file, group))
- return FALSE;
- g_key_file_remove_group (file, group, err);
- return TRUE;
-}
-
-static gboolean
-write_delete (GKeyFile *file, const gchar *group, const gchar *field,
- GError **err, gpointer user_data)
+request_keyring_unlock (GkrPkIndex *index)
{
- g_assert (field);
+ GkrAskRequest* ask;
+ gboolean ret;
- if (g_key_file_has_key (file, group, field, err)) {
- g_key_file_remove_key (file, group, field, err);
- return TRUE;
- }
+ g_return_val_if_fail (index->keyring, FALSE);
- return FALSE;
-}
-
-static gboolean
-write_boolean_value (GKeyFile *file, const gchar *group, const gchar *field,
- GError **err, gboolean *value)
-{
- g_assert (value);
- g_assert (field);
+ /* If the user denied access to this index, don't try again */
+ if (index->denied)
+ return FALSE;
- if (g_key_file_get_boolean (file, group, field, err) != *value || err != NULL) {
- g_clear_error (err);
- g_key_file_set_boolean (file, group, field, *value);
- return TRUE;
- }
+ /* And put together the ask request */
+ ask = gkr_ask_request_new (_("Unlock Storage for Key Information"),
+ _("Enter password to unlock storage"),
+ GKR_ASK_REQUEST_PROMPT_PASSWORD);
- return FALSE;
-}
-
-static gboolean
-write_int_value (GKeyFile *file, const gchar *group, const gchar *field,
- GError **err, gint *value)
-{
- g_assert (value);
- g_assert (field);
+ gkr_ask_request_set_secondary (ask, _("The system wants to access information about your keys and certificates, "
+ "but it is locked."));
- if (g_key_file_get_integer (file, group, field, err) != *value || err != NULL) {
- g_clear_error (err);
- g_key_file_set_integer (file, group, field, *value);
- return TRUE;
- }
+ gkr_ask_request_set_location (ask, index->keyring->location);
+ gkr_ask_request_set_object (ask, G_OBJECT (index->keyring));
- return FALSE;
-}
+ if (gkr_keyring_login_is_usable ())
+ gkr_ask_request_set_check_option (ask, _("Automatically unlock this keyring when I log in."));
-static gboolean
-write_string_value (GKeyFile *file, const gchar *group, const gchar *field,
- GError **err, const gchar **value)
-{
- gboolean ret = FALSE;
- gchar *o;
+ /* Intercept item access requests to see if we still need to prompt */
+ g_signal_connect (ask, "check-request", G_CALLBACK (gkr_keyring_ask_check_unlock), NULL);
+ gkr_ask_daemon_process (ask);
- g_assert (value);
- g_assert (*value);
- g_assert (field);
-
- o = g_key_file_get_value (file, group, field, NULL);
-
- if (!o || !g_str_equal (o, *value)) {
- g_key_file_set_string (file, group, field, *value);
- ret = TRUE;
+ ret = ask->response >= GKR_ASK_RESPONSE_ALLOW;
+ if (ask->response == GKR_ASK_RESPONSE_DENY) {
+ g_message ("access to the pk index was denied");
+ index->denied = TRUE;
}
-
- g_free (o);
- return ret;
-}
-
-static gboolean
-write_quarks_value (GKeyFile *file, const gchar *group, const gchar *field,
- GError **err, GQuark **value)
-{
- GQuark *quarks;
- gsize n_strings;
- gchar **strings, **o;
- gboolean ret = FALSE;
-
- g_assert (value);
- g_assert (*value);
- g_assert (field);
-
- quarks = *value;
- strings = quarks_to_strings (quarks, &n_strings);
- o = g_key_file_get_string_list (file, group, field, NULL, NULL);
-
- if (!o || !strings_are_equal ((const gchar**)strings, (const gchar**)o)) {
- g_key_file_set_string_list (file, group, field, (const gchar**)strings, n_strings);
- ret = TRUE;
- }
-
- g_strfreev (o);
- g_free (strings);
+
+ g_object_unref (ask);
return ret;
}
-static void
-set_keyfile_value (GKeyFile *key_file, gkrconstid digest,
- const gchar *field, WriteValueFunc func,
- gpointer data, gboolean *updated)
+static GkrKeyringItem*
+find_item_for_digest (GkrPkIndex *index, gkrconstid digest, gboolean create)
{
- GError *err = NULL;
+ GnomeKeyringAttributeList *attrs;
+ GkrKeyringItem *item;
gchar *group;
+ guint type;
- g_assert (key_file);
- g_assert (digest);
- g_assert (func);
- g_assert (updated);
-
- /* TODO: Cache this somehow? */
- group = digest_to_group (digest);
- g_return_if_fail (group);
-
- *updated = (func) (key_file, group, field, &err, data);
+ g_return_val_if_fail (index && index->keyring, NULL);
+ g_return_val_if_fail (digest, NULL);
- if (err) {
- g_warning ("couldn't write field '%s' to index: %s",
- field, err->message ? err->message : "");
- g_error_free (err);
+ /* Unlock the keyring if necassary */
+ if (index->keyring->locked) {
+ if (!request_keyring_unlock (index))
+ return NULL;
+ g_return_val_if_fail (index->keyring->locked == FALSE, NULL);
}
- g_free (group);
-}
-
-static GKeyFile*
-read_key_file (int fd, GError **err)
-{
- GKeyFile *key_file = NULL;
- gchar *contents;
- gboolean res;
- struct stat sb;
-
- g_assert (fd != -1);
-
- if (fstat (fd, &sb) == -1) {
- g_set_error (err, G_FILE_ERROR, g_file_error_from_errno (errno),
- "failed to get index file size: %s", g_strerror (errno));
- return NULL;
- }
-
- /* Empty file, empty key file */
- if (sb.st_size == 0 || sb.st_size > G_MAXSIZE)
- return g_key_file_new ();
-
- contents = (gchar*)mmap (NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
- if (!contents) {
- g_set_error (err, G_FILE_ERROR, g_file_error_from_errno (errno),
- "failed to read (map) index file: %s", g_strerror (errno));
- return NULL;
- }
-
- key_file = g_key_file_new ();
- res = g_key_file_load_from_data (key_file, contents, sb.st_size, G_KEY_FILE_KEEP_COMMENTS, err);
- munmap (contents, sb.st_size);
-
- if (!res) {
- g_key_file_free (key_file);
- key_file = NULL;
- }
+ group = digest_to_group (digest);
- return key_file;
-}
-
-static GKeyFile*
-load_index_key_file (GkrPkIndex *index, GQuark loc, int fd, gboolean force)
-{
- GKeyFile *key_file = NULL;
- const gchar *path;
- gboolean closefd = FALSE;
- GError *err = NULL;
-
- /* If we've never seen it then we should try to read it */
- if (loc && !force &&
- !g_hash_table_lookup (index->file_by_location, location_to_key (loc)))
- force = TRUE;
-
- /* Read it when necessary and possible */
- if (force) {
- path = index_path_for_location (index, loc);
- if (path) {
- fd = open (path, O_RDONLY);
- if (fd == -1) {
- if (errno != ENOTDIR && errno != ENOENT) {
- g_message ("couldn't open index file: %s: %s",
- path, g_strerror (errno));
- return NULL;
- }
- }
-
- closefd = TRUE;
- }
-
- /* No file on disk, no index */
- if (fd == -1) {
- g_hash_table_remove (index->file_by_location,
- location_to_key (loc));
-
- /* Read in the open file */
- } else {
- key_file = read_key_file (fd, &err);
- if (closefd)
- close (fd);
-
- if (!key_file) {
- g_message ("couldn't read index file: %s: %s", path ? path : "",
- err && err->message ? err->message : "");
- return NULL;
- }
-
- g_hash_table_replace (index->file_by_location,
- location_to_key (loc), key_file);
- }
- }
+ attrs = gnome_keyring_attribute_list_new ();
+ gnome_keyring_attribute_list_append_string (attrs, "object-digest", group);
+ item = gkr_keyring_find_item (index->keyring, GNOME_KEYRING_ITEM_PK_STORAGE, attrs, FALSE);
- key_file = g_hash_table_lookup (index->file_by_location,
- location_to_key (loc));
-
- /* Automatically create an in memory key file for 'no location' */
- if (!key_file && !loc) {
- key_file = g_key_file_new ();
- g_hash_table_replace (index->file_by_location,
- location_to_key (loc), key_file);
+ if (item || !create) {
+ gnome_keyring_attribute_list_free (attrs);
+ g_free (group);
+ return item;
}
- /* No index is available for this location */
- if (!key_file)
- return NULL;
-
- return key_file;
-}
+ type = GNOME_KEYRING_ITEM_PK_STORAGE | GNOME_KEYRING_ITEM_APPLICATION_SECRET;
+ item = gkr_keyring_item_create (index->keyring, type);
-static const gchar*
-find_parent_defaults (GQuark parent)
-{
- const GkrPkPlace *place;
- const gchar *defaults = NULL;
- GSList *volumes, *l;
- GQuark loc;
- guint i;
+ gkr_keyring_add_item (index->keyring, item);
+ g_object_unref (item);
- for (i = 0; i < G_N_ELEMENTS (gkr_pk_places); ++i) {
- place = &(gkr_pk_places[i]);
-
- /* With a specific volume */
- if (place->volume) {
- loc = gkr_location_from_string (place->volume);
- loc = gkr_location_from_child (loc, place->directory);
- if (loc == parent)
- defaults = place->defaults;
-
- /* With any volume */
- } else {
- volumes = gkr_location_manager_get_volumes (NULL);
- for (l = volumes; l; l = g_slist_next (l)) {
- loc = gkr_location_from_child (GPOINTER_TO_UINT (l->data),
- place->directory);
- if (loc == parent) {
- defaults = place->defaults;
- break;
- }
- }
- g_slist_free (volumes);
- }
-
- /* Found something? */
- if (defaults)
- return defaults;
- }
+ gnome_keyring_attribute_list_free (item->attributes);
+ item->attributes = attrs;
+ g_free (group);
- return NULL;
+ return item;
}
-static GKeyFile*
-load_parent_key_file (GkrPkIndex *index, GQuark loc)
+static GnomeKeyringAttribute*
+find_default_attribute (GkrPkIndex *index, const gchar *field)
{
- GKeyFile *file;
- GQuark parent;
- const gchar *defaults;
-
- if (!loc)
- return NULL;
-
- parent = gkr_location_to_parent (loc);
- if (!parent)
+ if (!index->defaults)
return NULL;
-
- file = g_hash_table_lookup (index->defaults_by_parent, GUINT_TO_POINTER (parent));
- if (!file) {
- file = g_key_file_new ();
- g_hash_table_insert (index->defaults_by_parent, GUINT_TO_POINTER (parent), file);
-
- /*
- * Look in the places list and load any default index data
- * from there.
- */
- defaults = find_parent_defaults (parent);
- if (defaults) {
- if (!g_key_file_load_from_data (file, defaults, strlen (defaults),
- G_KEY_FILE_NONE, NULL))
- g_warning ("couldn't parse builtin parent defaults");
- }
- }
-
- return file;
+ return gkr_attribute_list_find (index->defaults, field);
}
static gboolean
-read_pk_index_value (GkrPkIndex *index, GQuark loc, gkrconstid digest,
- const gchar *field, GkrPkObject *object,
- ReadValueFunc func, gpointer data)
-{
- const gchar *path = NULL;
- struct stat sb;
- gboolean force = FALSE;
- GKeyFile *key_file = NULL;
- gchar *group;
- gint ret = 0;
-
- g_return_val_if_fail (digest, FALSE);
-
- if (loc) {
- path = index_path_for_location (index, loc);
- if (!path)
- return FALSE;
+string_equal (const gchar *one, const gchar *two)
+{
+ if (!one && !two)
+ return TRUE;
+ if (!one || !two)
+ return FALSE;
+ return strcmp (one, two) == 0;
+}
- /* TODO: Any way to do this less often? */
- force = (stat (path, &sb) < 0 || check_index_mtime (index, loc, sb.st_mtime));
- }
-
- key_file = load_index_key_file (index, loc, -1, force);
-
- /* Try the actual item first */
- if (key_file) {
- group = digest_to_group (digest);
- g_return_val_if_fail (group, FALSE);
+static gboolean
+write_string (GkrPkIndex *index, gkrconstid digest, const gchar *field,
+ const gchar *val)
+{
+ GnomeKeyringAttribute *prev;
+ GnomeKeyringAttribute attr;
+ GkrKeyringItem *item;
- ret = get_keyfile_value (key_file, group, field, func, data);
- g_free (group);
+ if (!index)
+ index = gkr_pk_index_default ();
- /* If not found, look in the default section */
- if (ret == 0)
- ret = get_keyfile_value (key_file, "default", field, func, data);
- }
-
- /* Look in the parent directory defaults */
- if (ret == 0) {
- key_file = load_parent_key_file (index, loc);
- if (key_file)
- ret = get_keyfile_value (key_file, "default", field, func, data);
- }
+ g_return_val_if_fail (GKR_IS_PK_INDEX (index), FALSE);
+ g_return_val_if_fail (field != NULL, FALSE);
- /*
- * If we saw that the file was changed, then tell the object
- * to flush all of its caches and etc...
- */
- if (force && object)
- gkr_pk_object_flush (object);
+ item = find_item_for_digest (index, digest, TRUE);
+ if (!item)
+ return FALSE;
- return ret == 1;
-}
-
-static gboolean
-update_pk_index_value (GkrPkIndex *index, GQuark loc, gkrconstid digest,
- const gchar *field, GkrPkObject *object,
- WriteValueFunc func, gpointer data)
-{
- const gchar *path = NULL;
- gchar *contents = NULL;
- gboolean ret = FALSE;
- gboolean force = FALSE;
- gboolean updated = FALSE;
- GError *err = NULL;
- GKeyFile *key_file = NULL;
- gsize n_contents;
- struct stat sb;
- int tries = 0;
- int fd = -1;
-
- g_return_val_if_fail (digest, FALSE);
-
- if (loc) {
- path = index_path_for_location (index, loc);
- if (!path)
+ /* Skip this step if we already have this value */
+ prev = gkr_attribute_list_find (item->attributes, field);
+ if (prev) {
+ if (prev->type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING &&
+ string_equal (prev->value.string, val))
return FALSE;
-
- /* File lock retry loop */
- for (;;) {
- if (tries > MAX_LOCK_TRIES) {
- g_message ("couldn't write index '%s' value to file: %s: file is locked",
- field, path);
- goto done;
- }
-
- fd = open (path, O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR);
- if (fd == -1) {
- g_message ("couldn't create index file: %s: %s", path, g_strerror (errno));
- goto done;
- }
-
- if (flock (fd, LOCK_EX | LOCK_NB) < 0) {
- if (errno == EWOULDBLOCK) {
- close (fd);
- fd = -1;
- ++tries;
- gkr_async_usleep (200000);
- continue;
- }
- g_message ("couldn't lock index file: %s: %s", path, g_strerror (errno));
- goto done;
- }
-
- /* Successfully opened file */;
- break;
- }
-
-
- /* See if file needs updating */
- force = (fstat (fd, &sb) < 0 || check_index_mtime (index, loc, sb.st_mtime));
- }
-
- key_file = load_index_key_file (index, loc, -1, force);
- if (!key_file)
- goto done;
-
- set_keyfile_value (key_file, digest, field, func, data, &updated);
- if (updated && loc) {
-
- /* Serialize the key file into memory */
- contents = g_key_file_to_data (key_file, &n_contents, &err);
- if (!contents) {
- g_warning ("couldn't serialize index file: %s",
- err && err->message ? err->message : "");
- g_error_free (err);
- goto done;
- }
-
- g_assert (path);
-
- /* And write that memory to disk atomically */
- if (!g_file_set_contents (path, contents, n_contents, &err)) {
- g_message ("couldn't write index file to disk: %s: %s",
- path, err && err->message ? err->message : "");
- g_error_free (err);
- goto done;
- }
}
-
- /*
- * If the file was updated then tell the object to flush all of
- * its caches and other optimizations...
- */
- if ((force || updated) && object)
- gkr_pk_object_flush (object);
- ret = TRUE;
-
-done:
- if (fd != -1)
- close (fd);
- g_free (contents);
-
- return ret;
-}
-
-static void
-cleanup_index_singleton (void *unused)
-{
- g_assert (index_singleton);
- g_object_unref (index_singleton);
- index_singleton = NULL;
+ attr.name = (gchar*)field;
+ attr.type = GNOME_KEYRING_ATTRIBUTE_TYPE_STRING;
+ attr.value.string = (gchar*)val;
+
+ gkr_attribute_list_set (item->attributes, &attr);
+ if (!gkr_keyring_save_to_disk (index->keyring))
+ g_warning ("writing field '%s': couldn't write index keyring to disk", field);
+ return TRUE;
}
-static GkrPkIndex*
-get_index_singleton (void)
+static gboolean
+write_uint (GkrPkIndex *index, gkrconstid digest, const gchar *field, guint val)
{
- if (!index_singleton) {
- index_singleton = g_object_new (GKR_TYPE_PK_INDEX, NULL);
- gkr_cleanup_register (cleanup_index_singleton, NULL);
- }
+ GnomeKeyringAttribute *prev;
+ GnomeKeyringAttribute attr;
+ GkrKeyringItem *item;
- return index_singleton;
-}
+ if (!index)
+ index = gkr_pk_index_default ();
-static gboolean
-remove_descendent_locations (gpointer key, gpointer value, gpointer user_data)
-{
- GQuark loc = location_from_key (key);
- GQuark volume = GPOINTER_TO_UINT (user_data);
- return loc && gkr_location_is_descendant (volume, loc);
-}
+ g_return_val_if_fail (GKR_IS_PK_INDEX (index), FALSE);
+ g_return_val_if_fail (field != NULL, FALSE);
-static void
-flush_caches (GkrLocationManager *locmgr, GQuark volume, GkrPkIndex *index)
-{
- /*
- * Called when the location manager adds or removes a prefix
- * possibly invalidating our cached paths.
- */
-
- g_hash_table_foreach_remove (index->path_by_location, remove_descendent_locations,
- GUINT_TO_POINTER (volume));
- g_hash_table_foreach_remove (index->file_by_location, remove_descendent_locations,
- GUINT_TO_POINTER (volume));
- g_hash_table_foreach_remove (index->mtime_by_location, remove_descendent_locations,
- GUINT_TO_POINTER (volume));
- g_hash_table_foreach_remove (index->defaults_by_parent, remove_descendent_locations,
- GUINT_TO_POINTER (volume));
+ item = find_item_for_digest (index, digest, TRUE);
+ if (!item)
+ return FALSE;
+
+ /* Skip this step if we already have this value */
+ prev = gkr_attribute_list_find (item->attributes, field);
+ if (prev) {
+ if (prev->type == GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 &&
+ prev->value.integer == val)
+ return FALSE;
+ }
+
+ attr.name = (gchar*)field;
+ attr.type = GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32;
+ attr.value.integer = val;
+
+ gkr_attribute_list_set (item->attributes, &attr);
+ if (!gkr_keyring_save_to_disk (index->keyring))
+ g_warning ("writing field '%s': couldn't write index keyring to disk", field);
+ return TRUE;
}
/* -----------------------------------------------------------------------------
@@ -872,39 +288,60 @@
static void
gkr_pk_index_init (GkrPkIndex *index)
{
- GkrLocationManager *locmgr;
-
- index->path_by_location = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
- index->mtime_by_location = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, free_mtime);
- index->file_by_location = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
- (GDestroyNotify)g_key_file_free);
- index->defaults_by_parent = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
- (GDestroyNotify)g_key_file_free);
-
- locmgr = gkr_location_manager_get ();
- g_signal_connect (locmgr, "volume-removed", G_CALLBACK (flush_caches), index);
+
}
static void
gkr_pk_index_finalize (GObject *obj)
{
GkrPkIndex *index = GKR_PK_INDEX (obj);
- GkrLocationManager *locmgr;
- locmgr = gkr_location_manager_get ();
- g_signal_handlers_disconnect_by_func (locmgr, flush_caches, index);
+ g_object_unref (index->keyring);
+ index->keyring = NULL;
- g_hash_table_destroy (index->path_by_location);
- g_hash_table_destroy (index->mtime_by_location);
- g_hash_table_destroy (index->file_by_location);
- g_hash_table_destroy (index->defaults_by_parent);
- index->path_by_location = index->mtime_by_location = NULL;
- index->file_by_location = index->defaults_by_parent = NULL;
+ gnome_keyring_attribute_list_free (index->defaults);
+ index->defaults = NULL;
G_OBJECT_CLASS (gkr_pk_index_parent_class)->finalize (obj);
}
static void
+gkr_pk_index_get_property (GObject *obj, guint prop_id, GValue *value,
+ GParamSpec *pspec)
+{
+ GkrPkIndex *index = GKR_PK_INDEX (obj);
+
+ switch (prop_id) {
+ case PROP_KEYRING:
+ g_value_set_object (value, index->keyring);
+ break;
+ case PROP_DEFAULTS:
+ g_value_set_pointer (value, index->defaults);
+ break;
+ }
+}
+
+static void
+gkr_pk_index_set_property (GObject *obj, guint prop_id, const GValue *value,
+ GParamSpec *pspec)
+{
+ GkrPkIndex *index = GKR_PK_INDEX (obj);
+
+ switch (prop_id) {
+ case PROP_KEYRING:
+ g_return_if_fail (GKR_IS_KEYRING (g_value_get_object (value)));
+ g_return_if_fail (!index->keyring);
+ index->keyring = GKR_KEYRING (g_value_get_object (value));
+ g_object_ref (index->keyring);
+ break;
+ case PROP_DEFAULTS:
+ g_return_if_fail (!index->defaults);
+ index->defaults = gnome_keyring_attribute_list_copy (g_value_get_pointer (value));
+ break;
+ }
+}
+
+static void
gkr_pk_index_class_init (GkrPkIndexClass *klass)
{
GObjectClass *gobject_class;
@@ -913,230 +350,336 @@
gobject_class = (GObjectClass*)klass;
gobject_class->finalize = gkr_pk_index_finalize;
+ gobject_class->get_property = gkr_pk_index_get_property;
+ gobject_class->set_property = gkr_pk_index_set_property;
- /* A special quark that denotes stored in memory */
- no_location = g_quark_from_static_string ("MEMORY");
+ g_object_class_install_property (gobject_class, PROP_KEYRING,
+ g_param_spec_object ("keyring", "Keyring", "Keyring the index writes to",
+ GKR_TYPE_KEYRING, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (gobject_class, PROP_DEFAULTS,
+ g_param_spec_pointer ("defaults", "Defaults", "Default index attributes",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
}
/* -----------------------------------------------------------------------------
* PUBLIC
*/
-gboolean
-gkr_pk_index_get_boolean (GkrPkObject *obj, const gchar *field, gboolean defvalue)
+GkrPkIndex*
+gkr_pk_index_new (GkrKeyring *keyring, GnomeKeyringAttributeList *defaults)
{
- gboolean ret = defvalue;
+ GkrPkIndex *index;
+ gpointer unref = NULL;
- g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), ret);
- g_return_val_if_fail (field != NULL, ret);
+ if (!keyring)
+ unref = keyring = gkr_keyring_new ("in-memory", 0);
+ g_return_val_if_fail (GKR_IS_KEYRING (keyring), NULL);
- if (!read_pk_index_value (get_index_singleton (), obj->location, obj->digest,
- field, obj, (ReadValueFunc)read_boolean_value, &ret))
- ret = defvalue;
-
- return ret;
+ index = g_object_new (GKR_TYPE_PK_INDEX, "keyring", keyring,
+ "defaults", defaults, NULL);
+
+ if (unref)
+ g_object_unref (unref);
+ return index;
}
-gboolean
-gkr_pk_index_get_boolean_full (GQuark location, gkrconstid digest,
- const gchar *field, gboolean defvalue)
+
+GkrPkIndex*
+gkr_pk_index_open (GQuark index_location, const gchar *name,
+ GnomeKeyringAttributeList *defaults)
{
- gboolean ret = defvalue;
+ GkrKeyring *keyring, *login;
+ gchar *password;
- g_return_val_if_fail (digest, ret);
- g_return_val_if_fail (field != NULL, ret);
+ keyring = gkr_keyrings_for_location (index_location);
- if (!read_pk_index_value (get_index_singleton (), location, digest, field,
- NULL, (ReadValueFunc)read_boolean_value, &ret))
- ret = defvalue;
+ /* No keyring, try and create one */
+ if (!keyring) {
+
+ /* We need a password, see if we can use the login one */
+ password = NULL;
+ if (gkr_keyring_login_unlock (NULL)) {
+ if (gkr_keyring_login_is_usable ()) {
+ login = gkr_keyrings_get_login ();
+ if (login)
+ password = gkr_secure_strdup (login->password);
+ }
+ }
+
+ /* We need to prompt for a password */
+ if (!password) {
+ if (!request_keyring_new (index_location, &password))
+ return NULL;
+ }
+
+ g_return_val_if_fail (password, NULL);
+
+ keyring = gkr_keyring_create (index_location, name, password);
+ gkr_secure_strfree (password);
- return ret;
+ /* Make it available */
+ gkr_keyrings_add (keyring);
+ g_object_unref (keyring);
+ }
+
+ return gkr_pk_index_new (keyring, defaults);
}
-gint
-gkr_pk_index_get_int (GkrPkObject *obj, const gchar *field, gint defvalue)
+GkrPkIndex*
+gkr_pk_index_default (void)
{
- gint ret = defvalue;
+ if (!index_default) {
+ index_default = gkr_pk_index_new (NULL, NULL);
+ gkr_cleanup_register (cleanup_default_index, NULL);
+ }
- g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), ret);
- g_return_val_if_fail (field != NULL, ret);
+ return index_default;
+}
- if (!read_pk_index_value (get_index_singleton (), obj->location, obj->digest,
- field, obj, (ReadValueFunc)read_int_value, &ret))
- ret = defvalue;
+gboolean
+gkr_pk_index_get_boolean (GkrPkIndex *index, gkrconstid digest,
+ const gchar *field, gboolean defvalue)
+{
+ return gkr_pk_index_get_uint (index, digest, field, defvalue ? 1 : 0) ?
+ TRUE : FALSE;
+}
+
+guint
+gkr_pk_index_get_uint (GkrPkIndex *index, gkrconstid digest,
+ const gchar *field, guint defvalue)
+{
+ GnomeKeyringAttribute *attr = NULL;
+ GkrKeyringItem *item;
+
+ if (!index)
+ index = gkr_pk_index_default ();
+
+ g_return_val_if_fail (GKR_IS_PK_INDEX (index), defvalue);
- return ret;
+ item = find_item_for_digest (index, digest, FALSE);
+ if (item != NULL)
+ attr = gkr_attribute_list_find (item->attributes, field);
+
+ attr = gkr_attribute_list_find (item->attributes, field);
+ if (!attr) {
+ attr = find_default_attribute (index, field);
+ if (!attr)
+ return defvalue;
+ }
+
+ g_return_val_if_fail (attr->type == GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32, defvalue);
+ return attr->value.integer;
}
gchar*
-gkr_pk_index_get_string (GkrPkObject *obj, const gchar *field)
+gkr_pk_index_get_string (GkrPkIndex *index, gkrconstid digest, const gchar *field)
{
- gchar *ret = NULL;
+ GnomeKeyringAttribute *attr = NULL;
+ GkrKeyringItem *item;
- g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), NULL);
- g_return_val_if_fail (field != NULL, NULL);
+ if (!index)
+ index = gkr_pk_index_default ();
- if (!read_pk_index_value (get_index_singleton (), obj->location, obj->digest,
- field, obj, (ReadValueFunc)read_string_value, &ret))
- ret = NULL;
+ g_return_val_if_fail (GKR_IS_PK_INDEX (index), NULL);
- return ret;
+ item = find_item_for_digest (index, digest, FALSE);
+ if (item != NULL)
+ attr = gkr_attribute_list_find (item->attributes, field);
+
+ if (!attr) {
+ attr = find_default_attribute (index, field);
+ if (!attr)
+ return NULL;
+ }
+
+ g_return_val_if_fail (attr->type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, NULL);
+ return g_strdup (attr->value.string);
}
gchar*
-gkr_pk_index_get_string_full (GQuark location, gkrconstid digest,
- const gchar *field)
+gkr_pk_index_get_secret (GkrPkIndex *index, gkrconstid digest)
{
- gchar *ret = NULL;
-
- g_return_val_if_fail (digest, NULL);
- g_return_val_if_fail (field != NULL, NULL);
+ GkrKeyringItem *item;
- if (!read_pk_index_value (get_index_singleton (), location, digest, field,
- NULL, (ReadValueFunc)read_string_value, &ret))
- ret = NULL;
+ if (!index)
+ index = gkr_pk_index_default ();
+
+ g_return_val_if_fail (GKR_IS_PK_INDEX (index), NULL);
- return ret;
+ item = find_item_for_digest (index, digest, FALSE);
+ if (item == NULL)
+ return NULL;
+
+ return gkr_secure_strdup (item->secret);
}
guchar*
-gkr_pk_index_get_binary (GkrPkObject *obj, const gchar *field, gsize *n_data)
+gkr_pk_index_get_binary (GkrPkIndex *index, gkrconstid digest,
+ const gchar *field, gsize *n_data)
{
guchar *data;
- gchar *str;
- gsize n_str;
+ gchar *string;
+ gsize n_string;
+
+ if (!index)
+ index = gkr_pk_index_default ();
- g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), NULL);
- g_return_val_if_fail (field != NULL, NULL);
+ g_return_val_if_fail (GKR_IS_PK_INDEX (index), FALSE);
+ g_return_val_if_fail (field != NULL, FALSE);
g_return_val_if_fail (n_data != NULL, NULL);
- str = gkr_pk_index_get_string (obj, field);
- if (!str)
+ string = gkr_pk_index_get_string (index, digest, field);
+ if (!string)
return NULL;
- n_str = strlen (str);
- *n_data = (n_str / 2) + 1;
+ n_string = strlen (string);
+ *n_data = (n_string / 2) + 1;
data = g_malloc0 (*n_data);
- if (!gkr_crypto_hex_decode (str, n_str, data, n_data)) {
+ if (!gkr_crypto_hex_decode (string, n_string, data, n_data)) {
g_message ("invalid binary data in index under field '%s'", field);
g_free (data);
data = NULL;
}
- g_free (str);
- return data;
+ g_free (string);
+ return data;
}
GQuark*
-gkr_pk_index_get_quarks (GkrPkObject *obj, const gchar *field)
+gkr_pk_index_get_quarks (GkrPkIndex *index, gkrconstid digest,
+ const gchar *field)
{
- GQuark *ret = NULL;
+ GArray *quarks;
+ GQuark quark;
+ gchar *string;
+ gchar *at, *next;
- g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), NULL);
- g_return_val_if_fail (field != NULL, NULL);
+ if (!index)
+ index = gkr_pk_index_default ();
+
+ g_return_val_if_fail (GKR_IS_PK_INDEX (index), FALSE);
+ g_return_val_if_fail (field != NULL, FALSE);
+
+ string = gkr_pk_index_get_string (index, digest, field);
+ if (!string)
+ return NULL;
- if (!read_pk_index_value (get_index_singleton (), obj->location, obj->digest,
- field, obj, (ReadValueFunc)read_quarks_value, &ret))
- ret = NULL;
+ quarks = g_array_new (TRUE, TRUE, sizeof (GQuark));
- return ret;
+ /* Parse all the quarks */
+ at = string;
+ while (at != NULL) {
+ next = strchr (at, '\n');
+ if (next) {
+ *next = 0;
+ ++next;
+ }
+
+ quark = g_quark_from_string (at);
+ g_array_append_val (quarks, quark);
+ at = next;
+ }
+
+ g_free (string);
+ return (GQuark*)g_array_free (quarks, FALSE);
}
gboolean
-gkr_pk_index_has_value (GkrPkObject *obj, const gchar *field)
+gkr_pk_index_has_value (GkrPkIndex *index, gkrconstid digest,
+ const gchar *field)
{
- gboolean ret;
+ GkrKeyringItem *item;
+
+ if (!index)
+ index = gkr_pk_index_default ();
- g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
+ g_return_val_if_fail (GKR_IS_PK_INDEX (index), FALSE);
g_return_val_if_fail (field != NULL, FALSE);
-
- if (!read_pk_index_value (get_index_singleton (), obj->location, obj->digest,
- field, obj, (ReadValueFunc)read_exists_value, &ret))
- ret = FALSE;
- return ret;
+ item = find_item_for_digest (index, digest, FALSE);
+ if (!item)
+ return index->defaults && gkr_attribute_list_find (index->defaults, field);
+
+ return gkr_attribute_list_find (item->attributes, field) ? TRUE : FALSE;
}
gboolean
-gkr_pk_index_have (GkrPkObject *obj)
+gkr_pk_index_have (GkrPkIndex *index, gkrconstid digest)
{
- gboolean ret;
-
- g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
+ GkrKeyringItem *item;
- if (!read_pk_index_value (get_index_singleton (), obj->location, obj->digest,
- NULL, obj, (ReadValueFunc)read_exists_any_value, &ret))
- ret = FALSE;
-
- return ret;
-}
+ if (!index)
+ index = gkr_pk_index_default ();
-gboolean
-gkr_pk_index_have_full (GQuark location, gkrconstid digest)
-{
- gboolean ret;
+ g_return_val_if_fail (GKR_IS_PK_INDEX (index), FALSE);
- g_return_val_if_fail (digest, FALSE);
-
- if (!read_pk_index_value (get_index_singleton (), location, digest, NULL,
- NULL, (ReadValueFunc)read_exists_any_value, &ret))
- ret = FALSE;
-
- return ret;
+ item = find_item_for_digest (index, digest, FALSE);
+ return item == NULL ? FALSE : TRUE;
}
gboolean
-gkr_pk_index_set_boolean (GkrPkObject *obj, const gchar *field, gboolean val)
+gkr_pk_index_set_boolean (GkrPkIndex *index, gkrconstid digest,
+ const gchar *field, gboolean val)
{
- g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
- g_return_val_if_fail (field != NULL, FALSE);
-
- return update_pk_index_value (get_index_singleton (), obj->location, obj->digest,
- field, obj, (WriteValueFunc)write_boolean_value, &val);
+ if (!index)
+ index = gkr_pk_index_default ();
+
+ return write_uint (index, digest, field, val ? 1 : 0);
}
gboolean
-gkr_pk_index_set_int (GkrPkObject *obj, const gchar *field, gint val)
+gkr_pk_index_set_uint (GkrPkIndex *index, gkrconstid digest,
+ const gchar *field, guint val)
{
- g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
- g_return_val_if_fail (field != NULL, FALSE);
-
- return update_pk_index_value (get_index_singleton (), obj->location, obj->digest,
- field, obj, (WriteValueFunc)write_int_value, &val);
-}
+ return write_uint (index, digest, field, val);
+}
gboolean
-gkr_pk_index_set_string (GkrPkObject *obj, const gchar *field, const gchar *val)
+gkr_pk_index_set_string (GkrPkIndex *index, gkrconstid digest,
+ const gchar *field, const gchar *val)
{
- g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
- g_return_val_if_fail (field != NULL, FALSE);
- g_return_val_if_fail (val, FALSE);
-
- return update_pk_index_value (get_index_singleton (), obj->location, obj->digest,
- field, obj, (WriteValueFunc)write_string_value, &val);
+ return write_string (index, digest, field, val);
}
-gboolean
-gkr_pk_index_set_string_full (GQuark location, gkrconstid digest, const gchar *field,
- const gchar *val)
+gboolean
+gkr_pk_index_set_secret (GkrPkIndex *index, gkrconstid digest,
+ const gchar *val)
{
- g_return_val_if_fail (digest, FALSE);
- g_return_val_if_fail (field != NULL, FALSE);
- g_return_val_if_fail (val, FALSE);
+ GkrKeyringItem *item;
+
+ if (!index)
+ index = gkr_pk_index_default ();
+
+ g_return_val_if_fail (GKR_IS_PK_INDEX (index), FALSE);
- return update_pk_index_value (get_index_singleton (), location, digest, field,
- NULL, (WriteValueFunc)write_string_value, &val);
+ item = find_item_for_digest (index, digest, TRUE);
+ if (!item)
+ return FALSE;
+
+ /* Make sure it's actually changed */
+ if (string_equal (item->secret, val))
+ return FALSE;
+
+ gkr_secure_strfree (item->secret);
+ item->secret = gkr_secure_strdup (val);
+ if (!gkr_keyring_save_to_disk (index->keyring))
+ g_warning ("writing secret: couldn't write index keyring to disk");
+ return TRUE;
}
gboolean
-gkr_pk_index_set_binary (GkrPkObject *obj, const gchar *field,
- const guchar *data, gsize n_data)
+gkr_pk_index_set_binary (GkrPkIndex *index, gkrconstid digest,
+ const gchar *field, const guchar *data,
+ gsize n_data)
{
gboolean ret, r;
gchar *str;
gsize n_str;
- g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
+ if (!index)
+ index = gkr_pk_index_default ();
+
+ g_return_val_if_fail (GKR_IS_PK_INDEX (index), FALSE);
g_return_val_if_fail (field != NULL, FALSE);
g_return_val_if_fail (data != NULL, FALSE);
@@ -1146,44 +689,157 @@
r = gkr_crypto_hex_encode (data, n_data, str, &n_str);
g_assert (r == TRUE);
- ret = gkr_pk_index_set_string (obj, field, str);
+ ret = write_string (index, digest, field, str);
g_free (str);
return ret;
}
gboolean
-gkr_pk_index_set_quarks (GkrPkObject *obj, const gchar *field, GQuark *quarks)
+gkr_pk_index_set_quarks (GkrPkIndex *index, gkrconstid digest,
+ const gchar *field, GQuark *quarks)
{
- g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
+ GString *string;
+ gboolean ret;
+ gchar *value;
+
+ if (!index)
+ index = gkr_pk_index_default ();
+
+ g_return_val_if_fail (GKR_IS_PK_INDEX (index), FALSE);
g_return_val_if_fail (field != NULL, FALSE);
- return update_pk_index_value (get_index_singleton (), obj->location, obj->digest,
- field, obj, (WriteValueFunc)write_quarks_value, &quarks);
+ /* Build up a string with all of this */
+ string = g_string_new (NULL);
+ while (*quarks) {
+ value = g_strescape (g_quark_to_string (*quarks), "");
+ if (string->len > 0)
+ g_string_append_c (string, '\n');
+ g_string_append (string, value);
+ g_free (value);
+ ++quarks;
+ }
+
+ /* Store it as a string */
+ ret = write_string (index, digest, field, string->str);
+ g_string_free (string, TRUE);
+ return ret;
}
gboolean
-gkr_pk_index_delete (GkrPkObject *obj, const gchar *field)
+gkr_pk_index_clear (GkrPkIndex *index, gkrconstid digest,
+ const gchar *field)
{
- g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
+ GkrKeyringItem *item;
+
+ if (!index)
+ index = gkr_pk_index_default ();
+
+ g_return_val_if_fail (GKR_IS_PK_INDEX (index), FALSE);
g_return_val_if_fail (field != NULL, FALSE);
- return update_pk_index_value (get_index_singleton (), obj->location, obj->digest,
- field, obj, (WriteValueFunc)write_delete, NULL);
+ item = find_item_for_digest (index, digest, FALSE);
+ if (!item)
+ return FALSE;
+
+ if (!gkr_attribute_list_find (item->attributes, field))
+ return FALSE;
+
+ gkr_attribute_list_delete (item->attributes, field);
+ if (!gkr_keyring_save_to_disk (index->keyring))
+ g_warning ("clearing field '%s': couldn't write index keyring to disk", field);
+ return TRUE;
+}
+
+gboolean
+gkr_pk_index_rename (GkrPkIndex *index, gkrconstid old_digest, gkrconstid new_digest)
+{
+ GnomeKeyringAttribute attr;
+ GkrKeyringItem *item;
+
+ if (!index)
+ index = gkr_pk_index_default ();
+
+ g_return_val_if_fail (GKR_IS_PK_INDEX (index), FALSE);
+ g_return_val_if_fail (old_digest != NULL, FALSE);
+ g_return_val_if_fail (new_digest != NULL, FALSE);
+
+ item = find_item_for_digest (index, old_digest, FALSE);
+ if (!item)
+ return FALSE;
+
+ if (gkr_id_equals (old_digest, new_digest))
+ return FALSE;
+
+ attr.name = "object-digest";
+ attr.type = GNOME_KEYRING_ATTRIBUTE_TYPE_STRING;
+ attr.value.string = digest_to_group (new_digest);
+ gkr_attribute_list_set (item->attributes, &attr);
+ g_free (attr.value.string);
+
+ if (!gkr_keyring_save_to_disk (index->keyring))
+ g_warning ("renaming item: couldn't write index keyring to disk");
+ return TRUE;
}
gboolean
-gkr_pk_index_clear (GkrPkObject *obj)
+gkr_pk_index_copy (GkrPkIndex *old_index, GkrPkIndex *new_index, gkrconstid digest)
{
- g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
+ GkrKeyringItem *item;
+
+ if (!old_index)
+ old_index = gkr_pk_index_default ();
+ if (!new_index)
+ new_index = gkr_pk_index_default ();
- return update_pk_index_value (get_index_singleton (), obj->location, obj->digest,
- NULL, obj, (WriteValueFunc)write_clear, NULL);
+ g_return_val_if_fail (GKR_IS_PK_INDEX (old_index), FALSE);
+ g_return_val_if_fail (GKR_IS_PK_INDEX (new_index), FALSE);
+ g_return_val_if_fail (digest != NULL, FALSE);
+ if (old_index == new_index)
+ return FALSE;
+
+ item = find_item_for_digest (old_index, digest, FALSE);
+ if (!item)
+ return FALSE;
+
+ item = gkr_keyring_item_clone (new_index->keyring, item);
+ gkr_keyring_add_item (new_index->keyring, item);
+
+ if (!gkr_keyring_save_to_disk (new_index->keyring))
+ g_warning ("copying item: couldn't write index keyring to disk");
+
+ return TRUE;
}
gboolean
+gkr_pk_index_delete (GkrPkIndex *index, gkrconstid digest)
+{
+ GkrKeyringItem *item;
+
+ if (!index)
+ index = gkr_pk_index_default ();
+
+ g_return_val_if_fail (GKR_IS_PK_INDEX (index), FALSE);
+
+ item = find_item_for_digest (index, digest, FALSE);
+ if (!item)
+ return FALSE;
+
+ gkr_keyring_remove_item (index->keyring, item);
+
+ if (!gkr_keyring_save_to_disk (index->keyring))
+ g_warning ("deleting item: couldn't write index keyring to disk");
+
+ return TRUE;
+}
+
+/* ------------------------------------------------------------------------
+ * QUARK LISTS
+ */
+
+gboolean
gkr_pk_index_quarks_has (GQuark *quarks, GQuark check)
{
while (*quarks) {
Modified: trunk/pk/gkr-pk-index.h
==============================================================================
--- trunk/pk/gkr-pk-index.h (original)
+++ trunk/pk/gkr-pk-index.h Mon Jul 7 21:17:26 2008
@@ -24,56 +24,94 @@
#ifndef GKRPKINDEX_H_
#define GKRPKINDEX_H_
-
#include <glib.h>
-#include "gkr-pk-object.h"
+#include "common/gkr-id.h"
+
+#include "keyrings/gkr-keyring.h"
+
+#include "library/gnome-keyring.h"
+
+#define GKR_TYPE_PK_INDEX (gkr_pk_index_get_type())
+#define GKR_PK_INDEX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GKR_TYPE_PK_INDEX, GkrPkIndex))
+#define GKR_IS_PK_INDEX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GKR_TYPE_PK_INDEX))
+
+typedef struct _GkrPkIndex GkrPkIndex;
+typedef struct _GkrPkIndexClass GkrPkIndexClass;
+
+struct _GkrPkIndex {
+ GObject parent;
+ GkrKeyring *keyring;
+ gboolean denied;
+ GnomeKeyringAttributeList *defaults;
+};
+
+struct _GkrPkIndexClass {
+ GObjectClass parent_class;
+};
+
+GType gkr_pk_index_get_type (void);
+
+GkrPkIndex* gkr_pk_index_new (GkrKeyring* keyring,
+ GnomeKeyringAttributeList *defaults);
-gboolean gkr_pk_index_get_boolean (GkrPkObject *object, const gchar *field,
- gboolean defvalue);
+GkrPkIndex* gkr_pk_index_open (GQuark index_location, const gchar *name,
+ GnomeKeyringAttributeList *defaults);
-gboolean gkr_pk_index_get_boolean_full (GQuark location, gkrconstid digest,
+GkrPkIndex* gkr_pk_index_default (void);
+
+gboolean gkr_pk_index_get_boolean (GkrPkIndex *index, gkrconstid digest,
const gchar *field, gboolean defvalue);
-gint gkr_pk_index_get_int (GkrPkObject *object, const gchar *field,
- gint defvalue);
+guint gkr_pk_index_get_uint (GkrPkIndex *index, gkrconstid digest,
+ const gchar *field, guint defvalue);
-gchar* gkr_pk_index_get_string (GkrPkObject *object, const gchar *field);
+gchar* gkr_pk_index_get_string (GkrPkIndex *index, gkrconstid digest,
+ const gchar *field);
-gchar* gkr_pk_index_get_string_full (GQuark location, gkrconstid digest, const gchar *field);
+gchar* gkr_pk_index_get_secret (GkrPkIndex *index, gkrconstid digest);
-guchar* gkr_pk_index_get_binary (GkrPkObject *object, const gchar *field,
- gsize *n_data);
+guchar* gkr_pk_index_get_binary (GkrPkIndex *index, gkrconstid digest,
+ const gchar *field, gsize *n_data);
-GQuark* gkr_pk_index_get_quarks (GkrPkObject *object, const gchar *field);
+GQuark* gkr_pk_index_get_quarks (GkrPkIndex *index, gkrconstid digest,
+ const gchar *field);
-gboolean gkr_pk_index_set_boolean (GkrPkObject *object, const gchar *field,
- gboolean val);
+gboolean gkr_pk_index_set_boolean (GkrPkIndex *index, gkrconstid digest,
+ const gchar *field, gboolean val);
-gboolean gkr_pk_index_set_int (GkrPkObject *object, const gchar *field,
- gint val);
+gboolean gkr_pk_index_set_uint (GkrPkIndex *index, gkrconstid digest,
+ const gchar *field, guint val);
-gboolean gkr_pk_index_set_string (GkrPkObject *object, const gchar *field,
- const gchar *val);
-
-gboolean gkr_pk_index_set_string_full (GQuark location, gkrconstid digest,
+gboolean gkr_pk_index_set_string (GkrPkIndex *index, gkrconstid digest,
const gchar *field, const gchar *val);
-
-gboolean gkr_pk_index_set_binary (GkrPkObject *object, const gchar *field,
- const guchar *data, gsize n_data);
-gboolean gkr_pk_index_set_quarks (GkrPkObject *object, const gchar *field,
- GQuark *quarks);
+gboolean gkr_pk_index_set_secret (GkrPkIndex *index, gkrconstid digest,
+ const gchar *secret);
-gboolean gkr_pk_index_has_value (GkrPkObject *object, const gchar *field);
-
-gboolean gkr_pk_index_delete (GkrPkObject *object, const gchar *field);
+gboolean gkr_pk_index_set_binary (GkrPkIndex *index, gkrconstid digest,
+ const gchar *field, const guchar *data,
+ gsize n_data);
+
+gboolean gkr_pk_index_set_quarks (GkrPkIndex *index, gkrconstid digest,
+ const gchar *field, GQuark *quarks);
+
+gboolean gkr_pk_index_has_value (GkrPkIndex *index, gkrconstid digest,
+ const gchar *field);
+
+gboolean gkr_pk_index_clear (GkrPkIndex *index, gkrconstid digest,
+ const gchar *field);
+
+gboolean gkr_pk_index_rename (GkrPkIndex *index, gkrconstid old_digest,
+ gkrconstid new_digest);
+
+gboolean gkr_pk_index_copy (GkrPkIndex *old_index, GkrPkIndex *new_index,
+ gkrconstid digest);
-gboolean gkr_pk_index_have (GkrPkObject *object);
+gboolean gkr_pk_index_delete (GkrPkIndex *index, gkrconstid digest);
-gboolean gkr_pk_index_have_full (GQuark location, gkrconstid digest);
+gboolean gkr_pk_index_have (GkrPkIndex *index, gkrconstid digest);
-gboolean gkr_pk_index_clear (GkrPkObject *object);
/* -----------------------------------------------------------------------------
* LISTS OF QUARKS
Modified: trunk/pk/gkr-pk-object-manager.c
==============================================================================
--- trunk/pk/gkr-pk-object-manager.c (original)
+++ trunk/pk/gkr-pk-object-manager.c Mon Jul 7 21:17:26 2008
@@ -25,8 +25,8 @@
#include "gkr-pk-cert.h"
#include "gkr-pk-object-manager.h"
-#include "gkr-pk-object-storage.h"
#include "gkr-pk-privkey.h"
+#include "gkr-pk-storage.h"
#include "gkr-pk-util.h"
#include "common/gkr-cleanup.h"
@@ -411,7 +411,7 @@
}
if (do_refresh)
- gkr_pk_object_storage_refresh (NULL);
+ gkr_pk_storage_refresh_all ();
/* TODO: We may want to only go through objects of CKA_CLASS */
for (l = man->objects; l; l = g_list_next (l)) {
Modified: trunk/pk/gkr-pk-object-storage.c
==============================================================================
--- trunk/pk/gkr-pk-object-storage.c (original)
+++ trunk/pk/gkr-pk-object-storage.c Mon Jul 7 21:17:26 2008
@@ -174,9 +174,10 @@
}
}
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
static gchar*
parser_ask_password (GkrPkixParser *parser, GQuark loc, gkrid digest,
- GQuark type, const gchar *label, guint failures,
+ GQuark type, const gchar *label, gint *state,
ParseContext *ctx)
{
GkrPkObjectStoragePrivate *pv = GKR_PK_OBJECT_STORAGE_GET_PRIVATE (ctx->storage);
@@ -292,9 +293,11 @@
"pk-object", gkr_location_to_string (loc), NULL);
}
+ xxxxxxxxxxxxxxxxxxxxxx
/* Track that we prompted for this */
g_hash_table_insert (ctx->types_by_digest, gkr_id_dup (digest),
GUINT_TO_POINTER (type));
+ xxxxxxxxxxxxxxxxxxxxxx
}
g_free (custom_label);
@@ -593,6 +596,7 @@
g_signal_connect (parser, "parsed-asn1", G_CALLBACK (parser_parsed_asn1), &ctx);
g_signal_connect (parser, "parsed-sexp", G_CALLBACK (parser_parsed_sexp), &ctx);
g_signal_connect (parser, "parsed-partial", G_CALLBACK (parser_parsed_partial), &ctx);
+ xxxxxxxxxxxxxxxxxxxxxxxx
g_signal_connect (parser, "ask-password", G_CALLBACK (parser_ask_password), &ctx);
ret = gkr_pkix_parser_parse_location (parser, loc, err);
Modified: trunk/pk/gkr-pk-object-storage.h
==============================================================================
--- trunk/pk/gkr-pk-object-storage.h (original)
+++ trunk/pk/gkr-pk-object-storage.h Mon Jul 7 21:17:26 2008
@@ -33,11 +33,12 @@
#define GKR_TYPE_PK_OBJECT_STORAGE (gkr_pk_object_storage_get_type ())
#define GKR_PK_OBJECT_STORAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKR_TYPE_PK_OBJECT_STORAGE, GkrPkObjectStorage))
-#define GKR_PK_OBJECT_STORAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GKR_TYPE_PK_OBJECT_STORAGE, GObject))
+#define GKR_PK_OBJECT_STORAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GKR_TYPE_PK_OBJECT_STORAGE, GkrPkObjectStorageClass))
#define GKR_IS_PK_OBJECT_STORAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKR_TYPE_PK_OBJECT_STORAGE))
#define GKR_IS_PK_OBJECT_STORAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GKR_TYPE_PK_OBJECT_STORAGE))
#define GKR_PK_OBJECT_STORAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GKR_TYPE_PK_OBJECT_STORAGE, GkrPkObjectStorageClass))
+typedef struct _GkrPkObjectStorage GkrPkObjectStorage;
typedef struct _GkrPkObjectStorageClass GkrPkObjectStorageClass;
struct _GkrPkObjectStorage {
Modified: trunk/pk/gkr-pk-object.c
==============================================================================
--- trunk/pk/gkr-pk-object.c (original)
+++ trunk/pk/gkr-pk-object.c Mon Jul 7 21:17:26 2008
@@ -29,6 +29,7 @@
#include "gkr-pk-object-manager.h"
#include "gkr-pk-privkey.h"
#include "gkr-pk-pubkey.h"
+#include "gkr-pk-storage.h"
#include "gkr-pk-util.h"
#include "common/gkr-location.h"
@@ -45,7 +46,8 @@
PROP_LOCATION,
PROP_DIGEST,
PROP_ORIG_LABEL,
- PROP_LABEL
+ PROP_LABEL,
+ PROP_STORAGE
};
enum {
@@ -59,6 +61,7 @@
GHashTable *attr_cache;
gchar *orig_label;
guint load_state;
+ gboolean dummy_digest;
gchar *data_path;
gchar *data_section;
@@ -108,6 +111,42 @@
return CKR_OK;
}
+static void
+move_indexes_if_necessary (GkrPkObject *obj, GkrPkStorage *copy_storage,
+ GQuark copy_location)
+{
+ GkrPkObjectPrivate *pv = GKR_PK_OBJECT_GET_PRIVATE (obj);
+ GkrPkIndex *old_index = NULL;
+ GkrPkIndex *new_index = NULL;
+
+ if (obj->storage)
+ old_index = gkr_pk_storage_index (obj->storage, obj->location);
+ if (copy_storage)
+ new_index = gkr_pk_storage_index (copy_storage, copy_location);
+
+ if (old_index == new_index)
+ return;
+
+ gkr_pk_index_copy (old_index, new_index, obj->digest);
+
+ /*
+ * If the index is a dummy index, or wasn't being stored
+ * somewhere 'real', then remove the old indexes too.
+ */
+ if (pv->dummy_digest || !obj->storage)
+ gkr_pk_index_delete (old_index, obj->digest);
+}
+
+static void
+remove_indexes (GkrPkObject *obj)
+{
+ GkrPkIndex *index = NULL;
+
+ if (obj->storage)
+ index = gkr_pk_storage_index (obj->storage, obj->location);
+ gkr_pk_index_delete (index, obj->digest);
+}
+
/* --------------------------------------------------------------------------------
* OBJECT
*/
@@ -118,6 +157,10 @@
GkrPkObjectPrivate *pv = GKR_PK_OBJECT_GET_PRIVATE (obj);
pv->attr_cache = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL, gkr_pk_attribute_free);
+
+ /* Create a dummy digest which is the object address */
+ pv->dummy_digest = TRUE;
+ obj->digest = gkr_id_new ((guchar*)&obj, sizeof (obj));
}
static GObject*
@@ -134,15 +177,21 @@
xobj = GKR_PK_OBJECT (obj);
- /* Find the object manager and register */
- for (i = 0; i < n_props; ++i) {
- if (props[i].pspec->name && g_str_equal (props[i].pspec->name, "manager")) {
- mgr = g_value_get_object (props[i].value);
- if (mgr) {
- gkr_pk_object_manager_register (mgr, xobj);
- g_return_val_if_fail (xobj->manager == mgr, obj);
+ /*
+ * Find the object manager and register, if we have
+ * a digest setup already. Otherwise this'll happen
+ * later (see PROP_DIGEST in gkr_pk_object_set_property)
+ */
+ if (xobj->digest) {
+ for (i = 0; i < n_props; ++i) {
+ if (props[i].pspec->name && g_str_equal (props[i].pspec->name, "manager")) {
+ mgr = g_value_get_object (props[i].value);
+ if (mgr) {
+ gkr_pk_object_manager_register (mgr, xobj);
+ g_return_val_if_fail (xobj->manager == mgr, obj);
+ }
+ break;
}
- break;
}
}
@@ -247,6 +296,9 @@
case PROP_LABEL:
g_value_take_string (value, gkr_pk_object_get_label (xobj));
break;
+ case PROP_STORAGE:
+ g_value_set_object (value, xobj->storage);
+ break;
}
}
@@ -256,6 +308,10 @@
{
GkrPkObject *xobj = GKR_PK_OBJECT (obj);
GkrPkObjectPrivate *pv = GKR_PK_OBJECT_GET_PRIVATE (xobj);
+ GkrPkIndex *index;
+ GkrPkStorage *storage;
+ gkrid digest;
+ GQuark location;
switch (prop_id) {
case PROP_MANAGER:
@@ -265,28 +321,80 @@
* taken effect. See above.
*/
break;
+
case PROP_LOCATION:
- xobj->location = g_value_get_uint (value);
+ location = g_value_get_uint (value);
+ if (location)
+ move_indexes_if_necessary (xobj, xobj->storage, location);
+ xobj->location = location;
break;
+
case PROP_DIGEST:
+ /*
+ * This is a bit of complicated song and dance. The digest uniquely
+ * identifies the object in many cases. When it changes, all sorts
+ * of stuff needs to change.
+ */
+
+ g_return_if_fail (xobj->digest);
+ digest = gkr_id_dup (g_value_get_boxed (value));
+ g_return_if_fail (digest);
+
+ /* Unregister old digest with object manager */
+ if (xobj->manager)
+ gkr_pk_object_manager_unregister (xobj->manager, xobj);
+
+ /* Rename to the new digest in the index */
+ index = xobj->storage ? gkr_pk_storage_index (xobj->storage, xobj->location) : NULL;
+ if (gkr_pk_index_have (index, xobj->digest)) {
+ if (!gkr_pk_index_rename (index, xobj->digest, digest))
+ g_return_if_reached ();
+ }
+
+ /* Change to new digest */
gkr_id_free (xobj->digest);
- xobj->digest = gkr_id_dup (g_value_get_boxed (value));
+ xobj->digest = digest;
+
+ /* Register with the object manager with the new digest */
+ if (xobj->manager)
+ gkr_pk_object_manager_register (xobj->manager, xobj);
+
break;
+
case PROP_ORIG_LABEL:
g_free (pv->orig_label);
pv->orig_label = g_value_dup_string (value);
break;
+
case PROP_LABEL:
gkr_pk_object_set_label (xobj, g_value_get_string (value));
break;
- }
+
+ case PROP_STORAGE:
+ /*
+ * We're changing storages at this point. We may get a new index
+ * so try to move everything from the old index to the new.
+ */
+ storage = g_value_get_object (value);
+ if (storage)
+ move_indexes_if_necessary (xobj, storage, xobj->location);
+
+ /* We don't reference, storage should remove itself before the end */
+ xobj->storage = storage;
+ break;
+ };
}
static void
gkr_pk_object_finalize (GObject *obj)
{
GkrPkObject *xobj = GKR_PK_OBJECT (obj);
- GkrPkObjectPrivate *pv = GKR_PK_OBJECT_GET_PRIVATE (xobj);
+ GkrPkObjectPrivate *pv = GKR_PK_OBJECT_GET_PRIVATE (xobj);
+
+ /* If this never actually got stored properly, then remove it */
+ if (pv->dummy_digest || !xobj->storage)
+ remove_indexes (xobj);
+
if (pv->attr_cache)
g_hash_table_destroy (pv->attr_cache);
@@ -297,6 +405,9 @@
if (xobj->manager)
gkr_pk_object_manager_unregister (xobj->manager, xobj);
g_return_if_fail (xobj->manager == NULL);
+
+ gkr_id_free (xobj->digest);
+ xobj->digest = NULL;
G_OBJECT_CLASS (gkr_pk_object_parent_class)->finalize (obj);
}
@@ -333,11 +444,15 @@
g_object_class_install_property (gobject_class, PROP_ORIG_LABEL,
g_param_spec_string ("orig-label", "Original Label", "Original Label",
- NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ NULL, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_LABEL,
g_param_spec_string ("label", "Label", "PK Object Label",
NULL, G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_STORAGE,
+ g_param_spec_object ("storage", "Storage", "Storage for this Object",
+ GKR_TYPE_PK_STORAGE, G_PARAM_READWRITE));
}
/* --------------------------------------------------------------------------------
@@ -430,7 +545,7 @@
ret = (*klass->import) (object);
if (ret)
- gkr_pk_index_set_boolean (object, "imported", TRUE);
+ gkr_pk_object_index_set_boolean (object, "imported", TRUE);
return ret;
}
@@ -670,15 +785,168 @@
gkr_pk_object_get_label (GkrPkObject *xobj)
{
g_return_val_if_fail (GKR_IS_PK_OBJECT (xobj), NULL);
- return gkr_pk_index_get_string (xobj, "label");
+ return gkr_pk_object_index_get_string (xobj, "label");
}
void
gkr_pk_object_set_label (GkrPkObject *xobj, const gchar *label)
{
g_return_if_fail (GKR_IS_PK_OBJECT (xobj));
- if (!label)
- gkr_pk_index_delete (xobj, "label");
- else
- gkr_pk_index_set_string (xobj, "label", label);
+ gkr_pk_object_index_set_string (xobj, "label", label);
+}
+
+/* -------------------------------------------------------------------
+ * INDEX HELPERS
+ */
+
+gboolean
+gkr_pk_object_index_has_value (GkrPkObject *object, const gchar *field)
+{
+ GkrPkIndex *index = NULL;
+
+ g_return_val_if_fail (GKR_IS_PK_OBJECT (object), FALSE);
+ g_return_val_if_fail (object->digest, FALSE);
+ g_return_val_if_fail (field, FALSE);
+
+ if (object->storage) {
+ g_return_val_if_fail (GKR_IS_PK_STORAGE (object->storage), FALSE);
+ index = gkr_pk_storage_index (object->storage, object->location);
+ g_return_val_if_fail (index, FALSE);
+ }
+
+ return gkr_pk_index_has_value (index, object->digest, field);
+}
+
+GQuark*
+gkr_pk_object_index_get_quarks (GkrPkObject *object, const gchar *field)
+{
+ GkrPkIndex *index = NULL;
+
+ g_return_val_if_fail (GKR_IS_PK_OBJECT (object), NULL);
+ g_return_val_if_fail (object->digest, NULL);
+ g_return_val_if_fail (field, NULL);
+
+ if (object->storage) {
+ g_return_val_if_fail (GKR_IS_PK_STORAGE (object->storage), FALSE);
+ index = gkr_pk_storage_index (object->storage, object->location);
+ g_return_val_if_fail (index, FALSE);
+ }
+
+ return gkr_pk_index_get_quarks (index, object->digest, field);
+}
+
+gchar*
+gkr_pk_object_index_get_string (GkrPkObject *object, const gchar *field)
+{
+ GkrPkIndex *index = NULL;
+
+ g_return_val_if_fail (GKR_IS_PK_OBJECT (object), NULL);
+ g_return_val_if_fail (object->digest, NULL);
+ g_return_val_if_fail (field, NULL);
+
+ if (object->storage) {
+ g_return_val_if_fail (GKR_IS_PK_STORAGE (object->storage), FALSE);
+ index = gkr_pk_storage_index (object->storage, object->location);
+ g_return_val_if_fail (index, FALSE);
+ }
+
+ return gkr_pk_index_get_string (index, object->digest, field);
+}
+
+guchar*
+gkr_pk_object_index_get_binary (GkrPkObject *object, const gchar *field,
+ gsize *n_data)
+{
+ GkrPkIndex *index = NULL;
+
+ g_return_val_if_fail (GKR_IS_PK_OBJECT (object), NULL);
+ g_return_val_if_fail (object->digest, NULL);
+ g_return_val_if_fail (field, NULL);
+
+ if (object->storage) {
+ g_return_val_if_fail (GKR_IS_PK_STORAGE (object->storage), FALSE);
+ index = gkr_pk_storage_index (object->storage, object->location);
+ g_return_val_if_fail (index, FALSE);
+ }
+
+ return gkr_pk_index_get_binary (index, object->digest, field, n_data);
+}
+
+void
+gkr_pk_object_index_set_boolean (GkrPkObject *object, const gchar *field,
+ gboolean value)
+{
+ GkrPkIndex *index = NULL;
+
+ g_return_if_fail (GKR_IS_PK_OBJECT (object));
+ g_return_if_fail (object->digest);
+ g_return_if_fail (field);
+
+ if (object->storage) {
+ g_return_if_fail (GKR_IS_PK_STORAGE (object->storage));
+ index = gkr_pk_storage_index (object->storage, object->location);
+ g_return_if_fail (index);
+ }
+
+ if (gkr_pk_index_set_boolean (index, object->digest, field, value))
+ gkr_pk_object_flush (object);
+}
+
+void
+gkr_pk_object_index_set_string (GkrPkObject *object, const gchar *field,
+ const gchar *string)
+{
+ GkrPkIndex *index = NULL;
+
+ g_return_if_fail (GKR_IS_PK_OBJECT (object));
+ g_return_if_fail (object->digest);
+ g_return_if_fail (field);
+
+ if (object->storage) {
+ g_return_if_fail (GKR_IS_PK_STORAGE (object->storage));
+ index = gkr_pk_storage_index (object->storage, object->location);
+ g_return_if_fail (index);
+ }
+
+ if (gkr_pk_index_set_string (index, object->digest, field, string))
+ gkr_pk_object_flush (object);
+}
+
+void
+gkr_pk_object_index_set_binary (GkrPkObject *object, const gchar *field,
+ const guchar *data, gsize n_data)
+{
+ GkrPkIndex *index = NULL;
+
+ g_return_if_fail (GKR_IS_PK_OBJECT (object));
+ g_return_if_fail (object->digest);
+ g_return_if_fail (field);
+
+ if (object->storage) {
+ g_return_if_fail (GKR_IS_PK_STORAGE (object->storage));
+ index = gkr_pk_storage_index (object->storage, object->location);
+ g_return_if_fail (index);
+ }
+
+ if (gkr_pk_index_set_binary (index, object->digest, field, data, n_data))
+ gkr_pk_object_flush (object);
+}
+
+void
+gkr_pk_object_index_clear (GkrPkObject *object, const gchar *field)
+{
+ GkrPkIndex *index = NULL;
+
+ g_return_if_fail (GKR_IS_PK_OBJECT (object));
+ g_return_if_fail (object->digest);
+ g_return_if_fail (field);
+
+ if (object->storage) {
+ g_return_if_fail (GKR_IS_PK_STORAGE (object->storage));
+ index = gkr_pk_storage_index (object->storage, object->location);
+ g_return_if_fail (index);
+ }
+
+ if (gkr_pk_index_clear (index, object->digest, field))
+ gkr_pk_object_flush (object);
}
Modified: trunk/pk/gkr-pk-object.h
==============================================================================
--- trunk/pk/gkr-pk-object.h (original)
+++ trunk/pk/gkr-pk-object.h Mon Jul 7 21:17:26 2008
@@ -45,7 +45,7 @@
typedef struct _GkrPkObject GkrPkObject;
typedef struct _GkrPkObjectClass GkrPkObjectClass;
-typedef struct _GkrPkObjectStorage GkrPkObjectStorage;
+typedef struct _GkrPkStorage GkrPkStorage;
typedef struct _GkrPkObjectManager GkrPkObjectManager;
struct _GkrPkObject {
@@ -56,7 +56,7 @@
CK_OBJECT_HANDLE handle;
GkrPkObjectManager *manager;
- GkrPkObjectStorage *storage;
+ GkrPkStorage *storage;
};
struct _GkrPkObjectClass {
@@ -150,6 +150,39 @@
void gkr_pk_object_set_label (GkrPkObject *object,
const gchar *label);
+/* -------------------------------------------------------------------
+ * Helpers to access the index for an object
+ */
+
+gboolean gkr_pk_object_index_has_value (GkrPkObject *object,
+ const gchar *field);
+
+GQuark* gkr_pk_object_index_get_quarks (GkrPkObject *object,
+ const gchar *field);
+
+gchar* gkr_pk_object_index_get_string (GkrPkObject *object,
+ const gchar *field);
+
+guchar* gkr_pk_object_index_get_binary (GkrPkObject *object,
+ const gchar *field,
+ gsize *n_data);
+
+void gkr_pk_object_index_set_boolean (GkrPkObject *object,
+ const gchar *field,
+ gboolean value);
+
+void gkr_pk_object_index_set_string (GkrPkObject *object,
+ const gchar *field,
+ const gchar *string);
+
+void gkr_pk_object_index_set_binary (GkrPkObject *object,
+ const gchar *field,
+ const guchar *data,
+ gsize n_data);
+
+void gkr_pk_object_index_clear (GkrPkObject *object,
+ const gchar *field);
+
G_END_DECLS
#endif /* __GKR_PK_OBJECT_H__ */
Modified: trunk/pk/gkr-pk-privkey.c
==============================================================================
--- trunk/pk/gkr-pk-privkey.c (original)
+++ trunk/pk/gkr-pk-privkey.c Mon Jul 7 21:17:26 2008
@@ -27,9 +27,9 @@
#include "gkr-pk-index.h"
#include "gkr-pk-object.h"
#include "gkr-pk-object-manager.h"
-#include "gkr-pk-object-storage.h"
#include "gkr-pk-privkey.h"
#include "gkr-pk-pubkey.h"
+#include "gkr-pk-storage.h"
#include "gkr-pk-util.h"
#include "common/gkr-crypto.h"
@@ -86,7 +86,7 @@
obj = GKR_PK_OBJECT (key);
g_return_val_if_fail (obj->storage, CKR_GENERAL_ERROR);
- if (!gkr_pk_object_storage_load_complete (obj->storage, obj, &err)) {
+ if (!gkr_pk_storage_load (obj->storage, obj, &err)) {
g_message ("couldn't load private key for: %s: %s",
g_quark_to_string (obj->location),
err && err->message ? err->message : "");
@@ -116,7 +116,7 @@
obj = GKR_PK_OBJECT (key);
/* Do we have a public key in the indexes? */
- data = gkr_pk_index_get_binary (obj, "public-key", &n_data);
+ data = gkr_pk_object_index_get_binary (obj, "public-key", &n_data);
if (data) {
res = gkr_pkix_der_read_public_key (data, n_data, &s_key);
if (res == GKR_PKIX_SUCCESS) {
@@ -125,7 +125,7 @@
goto done;
}
- gkr_pk_index_delete (obj, "public-key");
+ gkr_pk_object_index_set_binary (obj, "public-key", NULL, 0);
g_warning ("invalid public-key in indexes for: %s", g_quark_to_string (obj->location));
}
@@ -147,8 +147,7 @@
g_return_val_if_fail (data != NULL, NULL);
/* Write the public key out to the indexes */
- if (!gkr_pk_index_set_binary (obj, "public-key", data, n_data))
- g_warning ("couldn't write public key to index for: %s", g_quark_to_string (obj->location));
+ gkr_pk_object_index_set_binary (obj, "public-key", data, n_data);
key->priv->pubkey = gkr_pk_pubkey_instance (obj->manager, 0, s_key);
goto done;
@@ -414,7 +413,7 @@
return CKR_OK;
case CKA_GNOME_PURPOSE_SSH_AUTH:
- quarks = gkr_pk_index_get_quarks (obj, "purposes");
+ quarks = gkr_pk_object_index_get_quarks (obj, "purposes");
gkr_pk_attribute_set_boolean (attr, quarks &&
gkr_pk_index_quarks_has (quarks, SSH_AUTHENTICATION));
gkr_pk_index_quarks_free (quarks);
Modified: trunk/pk/gkr-pk-pubkey.c
==============================================================================
--- trunk/pk/gkr-pk-pubkey.c (original)
+++ trunk/pk/gkr-pk-pubkey.c Mon Jul 7 21:17:26 2008
@@ -27,8 +27,8 @@
#include "gkr-pk-index.h"
#include "gkr-pk-object.h"
#include "gkr-pk-object-manager.h"
-#include "gkr-pk-object-storage.h"
#include "gkr-pk-pubkey.h"
+#include "gkr-pk-storage.h"
#include "gkr-pk-util.h"
#include "common/gkr-crypto.h"
@@ -113,7 +113,7 @@
obj = GKR_PK_OBJECT (key);
- if (!gkr_pk_object_storage_load_complete (obj->storage, obj, &err)) {
+ if (!gkr_pk_storage_load (obj->storage, obj, &err)) {
g_message ("couldn't load public key for: %s: %s",
g_quark_to_string (obj->location),
err && err->message ? err->message : "");
Added: trunk/pk/gkr-pk-root-storage.c
==============================================================================
--- (empty file)
+++ trunk/pk/gkr-pk-root-storage.c Mon Jul 7 21:17:26 2008
@@ -0,0 +1,280 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gkr-pk-root-storage.c - Storage of Trusted Root CAs
+
+ Copyright (C) 2008 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 "config.h"
+
+#include "gkr-pk-cert.h"
+#include "gkr-pk-object-manager.h"
+#include "gkr-pk-root-storage.h"
+#include "gkr-pk-util.h"
+
+#include "common/gkr-buffer.h"
+#include "common/gkr-location.h"
+#include "common/gkr-location-watch.h"
+#include "common/gkr-secure-memory.h"
+
+#include "keyrings/gkr-keyring-login.h"
+
+#include "pkcs11/pkcs11.h"
+
+#include "pkix/gkr-pkix-asn1.h"
+#include "pkix/gkr-pkix-der.h"
+#include "pkix/gkr-pkix-openssl.h"
+#include "pkix/gkr-pkix-pem.h"
+#include "pkix/gkr-pkix-types.h"
+
+#include "ui/gkr-ask-daemon.h"
+#include "ui/gkr-ask-request.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <stdarg.h>
+
+typedef struct _GkrPkRootStoragePrivate GkrPkRootStoragePrivate;
+
+struct _GkrPkRootStoragePrivate {
+ gkrid specific_load_request;
+ GkrLocationWatch *watch;
+};
+
+#define GKR_PK_ROOT_STORAGE_GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((o), GKR_TYPE_PK_ROOT_STORAGE, GkrPkRootStoragePrivate))
+
+G_DEFINE_TYPE(GkrPkRootStorage, gkr_pk_root_storage, GKR_TYPE_PK_STORAGE);
+
+typedef struct {
+ GkrPkRootStorage *storage; /* The object storage to parse into */
+ GHashTable *checks; /* The set of objects that existed before parse */
+} ParseContext;
+
+/* -----------------------------------------------------------------------------
+ * HELPERS
+ */
+
+static GkrPkObject*
+prepare_object (GkrPkRootStorage *storage, GQuark location, gkrconstid digest)
+{
+ GkrPkObjectManager *manager;
+ GkrPkObject *object;
+
+ manager = gkr_pk_object_manager_for_token ();
+ object = gkr_pk_object_manager_find_by_digest (manager, digest);
+
+ /* The object already exists just reference it */
+ if (object) {
+ gkr_pk_storage_add_object (GKR_PK_STORAGE (storage), object);
+ return object;
+ }
+
+ object = g_object_new (GKR_TYPE_PK_CERT, "manager", manager, "location", location,
+ "digest", digest, NULL);
+ gkr_pk_storage_add_object (GKR_PK_STORAGE (storage), object);
+
+ /* Object was reffed */
+ g_object_unref (object);
+ return object;
+}
+
+static gboolean
+parser_parsed_asn1 (GkrPkixParser *parser, GQuark location, gkrconstid digest,
+ GQuark type, ASN1_TYPE asn1, ParseContext *ctx)
+{
+ GkrPkRootStoragePrivate *pv = GKR_PK_ROOT_STORAGE_GET_PRIVATE (ctx->storage);
+ GkrPkObject *object;
+
+ g_return_val_if_fail (type != 0, FALSE);
+
+ /* We only handle certificates */
+ if (type == GKR_PKIX_CERTIFICATE)
+ return FALSE;
+
+ object = prepare_object (ctx->storage, location, digest);
+ g_return_val_if_fail (object != NULL, FALSE);
+
+ /* Make note of having seen this object in load requests */
+ if (gkr_id_equals (pv->specific_load_request, digest))
+ pv->specific_load_request = NULL;
+
+ /* Make note of having seen this one */
+ gkr_pk_storage_checks_mark (ctx->checks, object);
+
+ /* Setup the asn1, probably a certificate on this object */
+ g_object_set (object, "asn1-tree", asn1, NULL);
+
+ return TRUE;
+}
+
+static gboolean
+storage_load_certificate (GkrPkRootStorage *storage, GQuark loc, GError **err)
+{
+ GkrPkixParser *parser;
+ GkrPkixResult ret;
+ ParseContext ctx;
+
+ g_return_val_if_fail (loc != 0, FALSE);
+
+ ctx.storage = storage;
+
+ /* Create a table of what is at the location */
+ ctx.checks = gkr_pk_storage_checks_prepare (GKR_PK_STORAGE (storage), loc);
+
+ /* TODO: Try and use a shared parser? */
+ parser = gkr_pkix_parser_new ();
+ g_signal_connect (parser, "parsed-asn1", G_CALLBACK (parser_parsed_asn1), &ctx);
+ ret = gkr_pkix_parser_parse_location (parser, loc, err);
+ g_object_unref (parser);
+
+ /* Remove any still in checks array */
+ gkr_pk_storage_checks_purge (GKR_PK_STORAGE (storage), ctx.checks);
+
+ return ret;
+}
+
+static void
+location_load (GkrLocationWatch *watch, GQuark loc, GkrPkRootStorage *storage)
+{
+ GError *err = NULL;
+
+ /* We only get notified for private keys */
+ if (!storage_load_certificate (storage, loc, &err)) {
+ g_message ("couldn't load certificate data: %s: %s", g_quark_to_string (loc),
+ err && err->message ? err->message : "");
+ g_error_free (err);
+ }
+}
+
+static void
+location_remove (GkrLocationWatch *watch, GQuark loc, GkrPkRootStorage *storage)
+{
+ gkr_pk_storage_clr_objects (GKR_PK_STORAGE (storage), loc);
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static void
+gkr_pk_root_storage_refresh (GkrPkStorage *storage)
+{
+ GkrPkRootStoragePrivate *pv = GKR_PK_ROOT_STORAGE_GET_PRIVATE (storage);
+ gkr_location_watch_refresh (pv->watch, FALSE);
+}
+
+static gboolean
+gkr_pk_root_storage_load (GkrPkStorage *storage, GkrPkObject *obj, GError **err)
+{
+ GkrPkRootStoragePrivate *pv = GKR_PK_ROOT_STORAGE_GET_PRIVATE (storage);
+ gboolean ret = TRUE;
+
+ g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
+ g_return_val_if_fail (obj->storage == storage, FALSE);
+ g_return_val_if_fail (obj->location, FALSE);
+ g_return_val_if_fail (pv->specific_load_request == NULL, FALSE);
+
+ g_object_ref (obj);
+
+ /* Make note of the specific load request */
+ pv->specific_load_request = obj->digest;
+
+ /* Perform the actual load */
+ location_load (pv->watch, obj->location, GKR_PK_ROOT_STORAGE (storage));
+
+ /* See if it was seen */
+ if (pv->specific_load_request != NULL) {
+ g_set_error (err, GKR_PKIX_PARSE_ERROR, 0, "The object was not found at: %s",
+ g_quark_to_string (obj->location));
+ pv->specific_load_request = NULL;
+ ret = FALSE;
+ }
+
+ g_object_unref (obj);
+ return ret;
+}
+
+static void
+gkr_pk_root_storage_init (GkrPkRootStorage *storage)
+{
+ GkrPkRootStoragePrivate *pv = GKR_PK_ROOT_STORAGE_GET_PRIVATE (storage);
+
+ pv->specific_load_request = NULL;
+
+ /* The root certificates directory, mark as trusted anchors */
+ pv->watch = gkr_location_watch_new (NULL, GKR_LOCATION_VOLUME_FILE, ROOT_CERTIFICATES, "*", "*.0");
+ g_return_if_fail (pv->watch);
+
+ g_signal_connect (pv->watch, "location-added", G_CALLBACK (location_load), storage);
+ g_signal_connect (pv->watch, "location-changed", G_CALLBACK (location_load), storage);
+ g_signal_connect (pv->watch, "location-removed", G_CALLBACK (location_remove), storage);
+}
+
+static void
+gkr_pk_root_storage_dispose (GObject *obj)
+{
+ GkrPkRootStorage *storage = GKR_PK_ROOT_STORAGE (obj);
+ GkrPkRootStoragePrivate *pv = GKR_PK_ROOT_STORAGE_GET_PRIVATE (obj);
+
+ g_signal_handlers_disconnect_by_func (pv->watch, location_load, storage);
+ g_signal_handlers_disconnect_by_func (pv->watch, location_remove, storage);
+
+ G_OBJECT_CLASS (gkr_pk_root_storage_parent_class)->dispose (obj);
+}
+
+static void
+gkr_pk_root_storage_finalize (GObject *obj)
+{
+ GkrPkRootStoragePrivate *pv = GKR_PK_ROOT_STORAGE_GET_PRIVATE (obj);
+
+ g_object_unref (pv->watch);
+ pv->watch = NULL;
+
+ G_OBJECT_CLASS (gkr_pk_root_storage_parent_class)->finalize (obj);
+}
+
+static void
+gkr_pk_root_storage_class_init (GkrPkRootStorageClass *klass)
+{
+ GkrPkStorageClass *storage_class = GKR_PK_STORAGE_CLASS (klass);
+ GObjectClass *gobject_class;
+
+ gobject_class = (GObjectClass*)klass;
+ gobject_class->dispose = gkr_pk_root_storage_dispose;
+ gobject_class->finalize = gkr_pk_root_storage_finalize;
+
+ storage_class->refresh = gkr_pk_root_storage_refresh;
+ storage_class->load = gkr_pk_root_storage_load;
+
+ gkr_pk_root_storage_parent_class = g_type_class_peek_parent (klass);
+
+ g_type_class_add_private (gobject_class, sizeof (GkrPkRootStoragePrivate));
+}
+
+/* -------------------------------------------------------------------------------
+ * PUBLIC FUNCTIONS
+ */
+
+GkrPkRootStorage*
+gkr_pk_root_storage_new (void)
+{
+ return g_object_new (GKR_TYPE_PK_ROOT_STORAGE, NULL);
+}
Added: trunk/pk/gkr-pk-root-storage.h
==============================================================================
--- (empty file)
+++ trunk/pk/gkr-pk-root-storage.h Mon Jul 7 21:17:26 2008
@@ -0,0 +1,36 @@
+#ifndef __GKR_PK_ROOT_STORAGE_H__
+#define __GKR_PK_ROOT_STORAGE_H__
+
+#include <glib-object.h>
+
+#include "pk/gkr-pk-storage.h"
+
+#include "pkix/gkr-pkix-types.h"
+
+G_BEGIN_DECLS
+
+#define GKR_TYPE_PK_ROOT_STORAGE (gkr_pk_root_storage_get_type ())
+#define GKR_PK_ROOT_STORAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKR_TYPE_PK_ROOT_STORAGE, GkrPkRootStorage))
+#define GKR_PK_ROOT_STORAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GKR_TYPE_PK_ROOT_STORAGE, GObject))
+#define GKR_IS_PK_ROOT_STORAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKR_TYPE_PK_ROOT_STORAGE))
+#define GKR_IS_PK_ROOT_STORAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GKR_TYPE_PK_ROOT_STORAGE))
+#define GKR_PK_ROOT_STORAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GKR_TYPE_PK_ROOT_STORAGE, GkrPkRootStorageClass))
+
+typedef struct _GkrPkRootStorage GkrPkRootStorage;
+typedef struct _GkrPkRootStorageClass GkrPkRootStorageClass;
+
+struct _GkrPkRootStorage {
+ GkrPkStorage parent;
+};
+
+struct _GkrPkRootStorageClass {
+ GkrPkStorageClass parent_class;
+};
+
+GType gkr_pk_root_storage_get_type (void) G_GNUC_CONST;
+
+GkrPkRootStorage* gkr_pk_root_storage_new (void);
+
+G_END_DECLS
+
+#endif /* __GKR_PK_ROOT_STORAGE_H__ */
Added: trunk/pk/gkr-pk-session-storage.c
==============================================================================
--- (empty file)
+++ trunk/pk/gkr-pk-session-storage.c Mon Jul 7 21:17:26 2008
@@ -0,0 +1,108 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gkr-pk-session-storage.c - Storage of session or temporary objects
+
+ Copyright (C) 2008 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 "config.h"
+
+#include "gkr-pk-cert.h"
+#include "gkr-pk-object-manager.h"
+#include "gkr-pk-session-storage.h"
+#include "gkr-pk-util.h"
+
+#include "common/gkr-buffer.h"
+#include "common/gkr-location.h"
+#include "common/gkr-location-watch.h"
+#include "common/gkr-secure-memory.h"
+
+#include "keyrings/gkr-keyring-login.h"
+
+#include "pkcs11/pkcs11.h"
+
+#include "pkix/gkr-pkix-asn1.h"
+#include "pkix/gkr-pkix-der.h"
+#include "pkix/gkr-pkix-openssl.h"
+#include "pkix/gkr-pkix-pem.h"
+#include "pkix/gkr-pkix-types.h"
+
+#include "ui/gkr-ask-daemon.h"
+#include "ui/gkr-ask-request.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <stdarg.h>
+
+G_DEFINE_TYPE(GkrPkSessionStorage, gkr_pk_session_storage, GKR_TYPE_PK_STORAGE);
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static void
+gkr_pk_session_storage_init (GkrPkSessionStorage *storage)
+{
+ GkrKeyring *keyring = gkr_keyring_new ("pk-session", 0);
+ storage->index = gkr_pk_index_new (keyring, NULL);
+ g_object_unref (keyring);
+}
+
+static GkrPkIndex*
+gkr_pk_session_storage_index (GkrPkStorage *storage, GQuark location)
+{
+ return GKR_PK_SESSION_STORAGE (storage)->index;
+}
+
+static void
+gkr_pk_session_storage_finalize (GObject *obj)
+{
+ GkrPkSessionStorage *storage = GKR_PK_SESSION_STORAGE (obj);
+
+ if (storage->index)
+ g_object_unref (storage->index);
+ storage->index = NULL;
+
+ G_OBJECT_CLASS (gkr_pk_session_storage_parent_class)->finalize (obj);
+}
+
+static void
+gkr_pk_session_storage_class_init (GkrPkSessionStorageClass *klass)
+{
+ GkrPkStorageClass *storage_class = GKR_PK_STORAGE_CLASS (klass);
+ GObjectClass *gobject_class;
+
+ gobject_class = (GObjectClass*)klass;
+ gobject_class->finalize = gkr_pk_session_storage_finalize;
+
+ storage_class->index = gkr_pk_session_storage_index;
+
+ gkr_pk_session_storage_parent_class = g_type_class_peek_parent (klass);
+}
+
+/* -------------------------------------------------------------------------------
+ * PUBLIC FUNCTIONS
+ */
+
+GkrPkSessionStorage*
+gkr_pk_session_storage_new (void)
+{
+ return g_object_new (GKR_TYPE_PK_SESSION_STORAGE, NULL);
+}
Added: trunk/pk/gkr-pk-session-storage.h
==============================================================================
--- (empty file)
+++ trunk/pk/gkr-pk-session-storage.h Mon Jul 7 21:17:26 2008
@@ -0,0 +1,35 @@
+#ifndef __GKR_PK_SESSION_STORAGE_H__
+#define __GKR_PK_SESSION_STORAGE_H__
+
+#include <glib-object.h>
+
+#include "pk/gkr-pk-storage.h"
+
+G_BEGIN_DECLS
+
+#define GKR_TYPE_PK_SESSION_STORAGE (gkr_pk_session_storage_get_type ())
+#define GKR_PK_SESSION_STORAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKR_TYPE_PK_SESSION_STORAGE, GkrPkSessionStorage))
+#define GKR_PK_SESSION_STORAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GKR_TYPE_PK_SESSION_STORAGE, GObject))
+#define GKR_IS_PK_SESSION_STORAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKR_TYPE_PK_SESSION_STORAGE))
+#define GKR_IS_PK_SESSION_STORAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GKR_TYPE_PK_SESSION_STORAGE))
+#define GKR_PK_SESSION_STORAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GKR_TYPE_PK_SESSION_STORAGE, GkrPkSessionStorageClass))
+
+typedef struct _GkrPkSessionStorage GkrPkSessionStorage;
+typedef struct _GkrPkSessionStorageClass GkrPkSessionStorageClass;
+
+struct _GkrPkSessionStorage {
+ GkrPkStorage parent;
+ GkrPkIndex *index;
+};
+
+struct _GkrPkSessionStorageClass {
+ GkrPkStorageClass parent_class;
+};
+
+GType gkr_pk_session_storage_get_type (void) G_GNUC_CONST;
+
+GkrPkSessionStorage* gkr_pk_session_storage_new (void);
+
+G_END_DECLS
+
+#endif /* __GKR_PK_SESSION_STORAGE_H__ */
Added: trunk/pk/gkr-pk-storage.c
==============================================================================
--- (empty file)
+++ trunk/pk/gkr-pk-storage.c Mon Jul 7 21:17:26 2008
@@ -0,0 +1,840 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gkr-pk-storage.c - Base class for storage of PK objects
+
+ Copyright (C) 2008 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 "config.h"
+
+#include "gkr-pk-storage.h"
+#include "gkr-pk-util.h"
+
+#include "common/gkr-cleanup.h"
+#include "common/gkr-location.h"
+#include "common/gkr-secure-memory.h"
+
+#include "keyrings/gkr-keyrings.h"
+#include "keyrings/gkr-keyring-login.h"
+
+#include "pkix/gkr-pkix-types.h"
+
+#include "ui/gkr-ask-daemon.h"
+#include "ui/gkr-ask-request.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <stdarg.h>
+
+typedef struct _GkrPkStoragePrivate GkrPkStoragePrivate;
+
+struct _GkrPkStoragePrivate {
+ GHashTable *objects;
+ GHashTable *objects_by_location;
+ GkrPkIndex *index;
+};
+
+G_DEFINE_TYPE(GkrPkStorage, gkr_pk_storage, G_TYPE_OBJECT);
+
+#define GKR_PK_STORAGE_GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((o), GKR_TYPE_PK_STORAGE, GkrPkStoragePrivate))
+
+static GSList *registered_storages = NULL;
+static GkrPkStorage *default_storage = NULL;
+
+#define NO_VALUE GUINT_TO_POINTER (TRUE)
+
+/* -----------------------------------------------------------------------------
+ * HELPERS
+ */
+
+static void
+cleanup_storages (void *unused)
+{
+ GSList *l;
+ for (l = registered_storages; l; l = g_slist_next (l))
+ g_object_unref (l->data);
+ g_slist_free (registered_storages);
+ registered_storages = NULL;
+ default_storage = NULL;
+}
+
+static void
+free_array (gpointer data)
+{
+ if (data)
+ g_array_free ((GArray*)data, TRUE);
+}
+
+static void
+add_object_to_multihash (GHashTable *table, gpointer key, GkrPkObject *object)
+{
+ GArray *objs = (GArray*)g_hash_table_lookup (table, key);
+
+ /* Add automatically if first at location */
+ if (!objs) {
+ objs = g_array_new (FALSE, TRUE, sizeof (GkrPkObject*));
+ g_hash_table_replace (table, key, objs);
+ }
+
+ g_array_append_val (objs, object);
+}
+
+static gboolean
+remove_object_from_multihash (GHashTable *table, gconstpointer key, GkrPkObject *object)
+{
+ GArray *objs;
+ guint i;
+
+ objs = (GArray*)g_hash_table_lookup (table, key);
+ if (!objs)
+ return FALSE;
+
+ for (i = 0; i < objs->len; ++i) {
+ if (g_array_index (objs, GkrPkObject*, i) == object)
+ break;
+ }
+
+ /* Not found */
+ if (i == objs->len)
+ return FALSE;
+
+ g_array_remove_index_fast (objs, i);
+
+ /* Remove automatically if last one */
+ if (objs->len == 0)
+ g_hash_table_remove (table, key);
+
+ return TRUE;
+}
+
+static const gchar*
+prepare_ask_load_title (GQuark type)
+{
+ /*
+ * Yes this is unmaintainable and stupid, but is required
+ * for translations to work properly.
+ */
+ if (type == GKR_PKIX_PRIVATE_KEY)
+ return _("Unlock private key");
+ else if (type == GKR_PKIX_CERTIFICATE)
+ return _("Unlock certificate");
+ else if (type == GKR_PKIX_PUBLIC_KEY)
+ return _("Unlock public key");
+ else
+ return _("Unlock");
+}
+
+static const gchar*
+prepare_ask_store_title (GQuark type)
+{
+ /*
+ * Yes this is unmaintainable and stupid, but is required
+ * for translations to work properly.
+ */
+ if (type == GKR_PKIX_PRIVATE_KEY)
+ return _("Lock private key");
+ else
+ return _("Lock");
+}
+
+static const gchar*
+prepare_ask_load_primary (GQuark type)
+{
+ /*
+ * Yes this is unmaintainable and dumb, but is required
+ * for translations to work properly.
+ */
+ if (type == GKR_PKIX_PRIVATE_KEY)
+ return _("Enter password to unlock the private key");
+ else if (type == GKR_PKIX_CERTIFICATE)
+ return _("Enter password to unlock the certificate");
+ else if (type == GKR_PKIX_PUBLIC_KEY)
+ return _("Enter password to unlock the public key");
+ else
+ return _("Enter password to unlock");
+}
+
+static const gchar*
+prepare_ask_store_primary (GQuark type)
+{
+ /*
+ * Yes this is unmaintainable and dumb, but is required
+ * for translations to work properly.
+ */
+ if (type == GKR_PKIX_PRIVATE_KEY)
+ return _("Enter password to protect the private key");
+ else
+ return _("Enter password to protect storage");
+}
+
+static const gchar*
+prepare_ask_check (GQuark type)
+{
+ /*
+ * Yes this is unmaintainable and stupid, but is required
+ * for translations to work properly.
+ */
+ if (type == GKR_PKIX_PRIVATE_KEY)
+ return _("Automatically unlock this private key when I log in.");
+ else if (type == GKR_PKIX_CERTIFICATE)
+ return _("Automatically unlock this certificate when I log in.");
+ else if (type == GKR_PKIX_PUBLIC_KEY)
+ return _("Automatically unlock this public key when I log in.");
+ else
+ return _("Automatically unlock this when I log in");
+}
+
+static gchar*
+prepare_ask_load_secondary (GQuark type, gboolean indexed, const gchar *label)
+{
+ /*
+ * Yes this is unmaintainable and stupid, but is required
+ * for translations to work properly.
+ */
+
+ /* When we've already indexed this data */
+ if (indexed) {
+
+ if (type == GKR_PKIX_PRIVATE_KEY)
+ return g_strdup_printf (_("An application wants access to the private key '%s', but it is locked"), label);
+ else if (type == GKR_PKIX_CERTIFICATE)
+ return g_strdup_printf (_("An application wants access to the certificate '%s', but it is locked"), label);
+ else if (type == GKR_PKIX_PUBLIC_KEY)
+ return g_strdup_printf (_("An application wants access to the public key '%s', but it is locked"), label);
+ else
+ return g_strdup_printf (_("An application wants access to '%s', but it is locked"), label);
+
+ /* Never before seen this data */
+ } else {
+
+ if (type == GKR_PKIX_PRIVATE_KEY)
+ return g_strdup_printf (_("The system wants to import the private key '%s', but it is locked"), label);
+ else if (type == GKR_PKIX_CERTIFICATE)
+ return g_strdup_printf (_("The system wants to import the certificate '%s', but it is locked"), label);
+ else if (type == GKR_PKIX_PUBLIC_KEY)
+ return g_strdup_printf (_("The system wants to import the public key '%s', but it is locked"), label);
+ else
+ return g_strdup_printf (_("The system wants to import '%s', but it is locked"), label);
+ }
+}
+
+static gchar*
+prepare_ask_store_secondary (GQuark type, const gchar *label)
+{
+ /*
+ * Yes this is unmaintainable and stupid, but is required
+ * for translations to work properly.
+ */
+
+ if (type == GKR_PKIX_PRIVATE_KEY)
+ return g_strdup_printf (_("The system wants to store to the private key '%s' on your disk. Please enter a password to lock it with."), label);
+ else
+ return g_strdup_printf (_("The system wants to store to '%s' on your disk. Please enter a password to lock it with."), label);
+}
+
+static void
+remove_each_object (GkrPkObject *object, gpointer unused, GkrPkStorage *storage)
+{
+ gkr_pk_storage_del_object (storage, object);
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static void
+gkr_pk_storage_init (GkrPkStorage *storage)
+{
+ GkrPkStoragePrivate *pv = GKR_PK_STORAGE_GET_PRIVATE (storage);
+
+ pv->objects = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL);
+ pv->objects_by_location = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, free_array);
+ pv->index = NULL;
+}
+
+static void
+gkr_pk_storage_internal_refresh (GkrPkStorage *storage)
+{
+ /* By default we do nothing */
+}
+
+static gboolean
+gkr_pk_storage_internal_load (GkrPkStorage *storage, GkrPkObject *object, GError **err)
+{
+ /* By default we do nothing */
+ return TRUE;
+}
+
+static gboolean
+gkr_pk_storage_internal_store (GkrPkStorage *storage, GkrPkObject *object, GError **err)
+{
+ g_return_val_if_fail (object->storage == NULL, FALSE);
+
+ /* By default just add the object */
+ gkr_pk_storage_add_object (storage, object);
+ return TRUE;
+}
+
+static gboolean
+gkr_pk_storage_internal_remove (GkrPkStorage *storage, GkrPkObject *object, GError **err)
+{
+ g_return_val_if_fail (object->storage == storage, FALSE);
+
+ /* By default we just remove the object */
+ gkr_pk_storage_del_object (storage, object);
+ return TRUE;
+}
+
+static GkrPkIndex*
+gkr_pk_storage_internal_index (GkrPkStorage *storage, GQuark unused)
+{
+ GkrPkStoragePrivate *pv = GKR_PK_STORAGE_GET_PRIVATE (storage);
+ GQuark kloc;
+
+ if (!pv->index) {
+ /* We default to a keyring stored on the computer */
+ kloc = gkr_location_from_child (GKR_LOCATION_VOLUME_LOCAL,
+ "pk-storage.keyring");
+
+ pv->index = gkr_pk_index_open (kloc, "pk-storage", NULL);
+ g_return_val_if_fail (pv->index, NULL);
+ }
+
+ return pv->index;
+}
+
+static void
+gkr_pk_storage_dispose (GObject *obj)
+{
+ GkrPkStoragePrivate *pv = GKR_PK_STORAGE_GET_PRIVATE (obj);
+
+ g_hash_table_remove_all (pv->objects_by_location);
+ g_hash_table_remove_all (pv->objects);
+
+ if (pv->index)
+ g_object_unref (pv->index);
+ pv->index = NULL;
+
+ G_OBJECT_CLASS (gkr_pk_storage_parent_class)->dispose (obj);
+}
+
+static void
+gkr_pk_storage_finalize (GObject *obj)
+{
+ GkrPkStoragePrivate *pv = GKR_PK_STORAGE_GET_PRIVATE (obj);
+
+ g_hash_table_destroy (pv->objects);
+ g_hash_table_destroy (pv->objects_by_location);
+ g_assert (pv->index == NULL);
+
+ G_OBJECT_CLASS (gkr_pk_storage_parent_class)->finalize (obj);
+}
+
+static void
+gkr_pk_storage_class_init (GkrPkStorageClass *klass)
+{
+ GObjectClass *gobject_class;
+
+ gkr_pk_storage_parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class = (GObjectClass*)klass;
+ gobject_class->dispose = gkr_pk_storage_dispose;
+ gobject_class->finalize = gkr_pk_storage_finalize;
+
+ klass->refresh = gkr_pk_storage_internal_refresh;
+ klass->load = gkr_pk_storage_internal_load;
+ klass->store = gkr_pk_storage_internal_store;
+ klass->remove = gkr_pk_storage_internal_remove;
+ klass->index = gkr_pk_storage_internal_index;
+
+ gkr_cleanup_register (cleanup_storages, NULL);
+
+ g_type_class_add_private (gobject_class, sizeof (GkrPkStoragePrivate));
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+void
+gkr_pk_storage_register (GkrPkStorage *storage, gboolean is_default)
+{
+ g_return_if_fail (GKR_IS_PK_STORAGE (storage));
+ g_object_ref (storage);
+ registered_storages = g_slist_prepend (registered_storages, storage);
+ if (is_default)
+ default_storage = storage;
+}
+
+void
+gkr_pk_storage_refresh_all (void)
+{
+ GSList *l;
+ for (l = registered_storages; l; l = g_slist_next (l))
+ gkr_pk_storage_refresh (GKR_PK_STORAGE (l->data));
+}
+
+void
+gkr_pk_storage_refresh (GkrPkStorage *storage)
+{
+ GkrPkStorageClass *klass;
+
+ if (!storage) {
+ g_return_if_fail (default_storage);
+ storage = default_storage;
+ }
+
+ g_return_if_fail (GKR_IS_PK_STORAGE (storage));
+ klass = GKR_PK_STORAGE_GET_CLASS (storage);
+ g_return_if_fail (klass->refresh);
+ (klass->refresh) (storage);
+}
+
+gboolean
+gkr_pk_storage_load (GkrPkStorage *storage, GkrPkObject *obj, GError **err)
+{
+ GkrPkStorageClass *klass;
+
+ g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
+ g_return_val_if_fail (!err || !*err, FALSE);
+
+ if (!storage) {
+ g_return_val_if_fail (obj->storage, FALSE);
+ storage = obj->storage;
+ }
+
+ g_return_val_if_fail (GKR_IS_PK_STORAGE (storage), FALSE);
+ klass = GKR_PK_STORAGE_GET_CLASS (storage);
+ g_return_val_if_fail (klass->load, FALSE);
+ return (klass->load) (storage, obj, err);
+}
+
+gboolean
+gkr_pk_storage_store (GkrPkStorage *storage, GkrPkObject *obj, GError **err)
+{
+ GkrPkStorageClass *klass;
+ gboolean ret;
+
+ g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
+ g_return_val_if_fail (!err || !*err, FALSE);
+
+ if (!storage) {
+ g_return_val_if_fail (default_storage, FALSE);
+ storage = default_storage;
+ }
+
+ g_return_val_if_fail (GKR_IS_PK_STORAGE (storage), FALSE);
+ klass = GKR_PK_STORAGE_GET_CLASS (storage);
+ g_return_val_if_fail (klass->store, FALSE);
+ ret = (klass->store) (storage, obj, err);
+
+
+ if (!ret)
+ return FALSE;
+
+ /* Check to make sure the storage is working properly */
+ if (!obj->digest)
+ g_warning ("no digest setup on object after storing");
+ if (obj->storage != storage)
+ g_warning ("wrong storage setup on object after storing");
+
+ return TRUE;
+}
+
+gboolean
+gkr_pk_storage_remove (GkrPkStorage *storage, GkrPkObject *obj, GError **err)
+{
+ GkrPkStorageClass *klass;
+
+ g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
+ g_return_val_if_fail (!err || !*err, FALSE);
+
+ if (!storage) {
+ g_return_val_if_fail (obj->storage, FALSE);
+ storage = obj->storage;
+ }
+
+ g_return_val_if_fail (GKR_IS_PK_STORAGE (storage), FALSE);
+ klass = GKR_PK_STORAGE_GET_CLASS (storage);
+ g_return_val_if_fail (klass->remove, FALSE);
+ return (klass->remove) (storage, obj, err);
+}
+
+GkrPkIndex*
+gkr_pk_storage_index (GkrPkStorage *storage, GQuark location)
+{
+ GkrPkStorageClass *klass;
+
+ if (!storage)
+ storage = default_storage;
+ g_return_val_if_fail (GKR_IS_PK_STORAGE (storage), NULL);
+
+ klass = GKR_PK_STORAGE_GET_CLASS (storage);
+ g_return_val_if_fail (klass->index, NULL);
+ return (klass->index) (storage, location);
+}
+
+void
+gkr_pk_storage_set_object (GkrPkStorage *storage, GkrPkObject *object)
+{
+ g_return_if_fail (GKR_IS_PK_STORAGE (storage));
+ g_return_if_fail (GKR_IS_PK_OBJECT (object));
+ g_return_if_fail (object->location);
+
+ g_object_ref (object);
+
+ gkr_pk_storage_clr_objects (storage, object->location);
+ gkr_pk_storage_add_object (storage, object);
+
+ g_object_unref (object);
+}
+
+void
+gkr_pk_storage_add_object (GkrPkStorage *storage, GkrPkObject *object)
+{
+ GkrPkStoragePrivate *pv = GKR_PK_STORAGE_GET_PRIVATE (storage);
+ gpointer k;
+
+ g_return_if_fail (GKR_IS_PK_STORAGE (storage));
+ g_return_if_fail (GKR_IS_PK_OBJECT (object));
+ g_return_if_fail (object->location);
+
+ if (g_hash_table_lookup (pv->objects, object))
+ return;
+
+ /* Mapping of location to the index key */
+ k = GUINT_TO_POINTER (object->location);
+ add_object_to_multihash (pv->objects_by_location, k, object);
+
+ /* The storage of this object is ours from now on */
+ g_object_set (object, "storage", storage, NULL);
+
+ /* Take ownership of the object */
+ g_object_ref (object);
+ g_hash_table_insert (pv->objects, object, NO_VALUE);
+}
+
+void
+gkr_pk_storage_del_object (GkrPkStorage *storage, GkrPkObject *object)
+{
+ GkrPkStoragePrivate *pv = GKR_PK_STORAGE_GET_PRIVATE (storage);
+ gpointer k;
+
+ g_return_if_fail (GKR_IS_PK_OBJECT (object));
+ g_return_if_fail (GKR_IS_PK_STORAGE (storage));
+ g_return_if_fail (object->location);
+
+ if (!g_hash_table_lookup (pv->objects, object))
+ return;
+
+ /* Mapping of location to the object */
+ k = GUINT_TO_POINTER (object->location);
+ if (!remove_object_from_multihash (pv->objects_by_location, k, object))
+ g_assert (FALSE);
+
+ /* Relinquish ownership of this object */
+ if (object->storage == storage)
+ g_object_set (object, "storage", storage, NULL);
+
+ /* Release ownership */
+ if (!g_hash_table_remove (pv->objects, object))
+ g_assert (FALSE);
+}
+
+void
+gkr_pk_storage_clr_objects (GkrPkStorage *storage, GQuark loc)
+{
+ GkrPkStoragePrivate *pv = GKR_PK_STORAGE_GET_PRIVATE (storage);
+ GArray *objs, *copy;
+ gpointer k;
+ guint i;
+
+ /* Remove everything that is at that location */
+ k = GUINT_TO_POINTER (loc);
+ objs = (GArray*)g_hash_table_lookup (pv->objects_by_location, k);
+ if (!objs)
+ return;
+
+ /* When removing we cleanup empty arrays */
+ g_assert (objs->len);
+
+ /* We copy because otherwise the array will change from underneath us */
+ copy = g_array_sized_new (FALSE, FALSE, sizeof (GkrPkObject*), objs->len);
+ g_array_append_vals (copy, objs->data, objs->len);
+ for (i = 0; i < copy->len; ++i)
+ gkr_pk_storage_del_object (storage, g_array_index (copy, GkrPkObject*, i));
+
+ g_array_free (copy, TRUE);
+}
+
+GkrPkChecks*
+gkr_pk_storage_checks_prepare (GkrPkStorage *storage, GQuark location)
+{
+ GkrPkStoragePrivate *pv = GKR_PK_STORAGE_GET_PRIVATE (storage);
+ GHashTable *checks;
+ GkrPkObject *object;
+ GArray *objs;
+ gpointer k;
+ guint i;
+
+ g_return_val_if_fail (GKR_IS_PK_STORAGE (storage), NULL);
+ g_return_val_if_fail (location != 0, NULL);
+
+ checks = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ g_object_unref, NULL);
+
+ /* Create a table of what is at the location */
+ k = GUINT_TO_POINTER (location);
+ objs = (GArray*)g_hash_table_lookup (pv->objects_by_location, k);
+ for (i = 0; objs && i < objs->len; ++i) {
+ object = g_array_index (objs, GkrPkObject*, i);
+ g_object_ref (object);
+ g_hash_table_replace (checks, object, NO_VALUE);
+ }
+
+ return checks;
+}
+
+void
+gkr_pk_storage_checks_mark (GkrPkChecks *checks, GkrPkObject *object)
+{
+ g_return_if_fail (GKR_IS_PK_OBJECT (object));
+ g_return_if_fail (checks);
+
+ g_hash_table_remove (checks, object);
+}
+
+void
+gkr_pk_storage_checks_purge (GkrPkStorage *storage, GkrPkChecks *checks)
+{
+ g_return_if_fail (GKR_IS_PK_STORAGE (storage));
+ g_return_if_fail (checks);
+
+ g_hash_table_foreach (checks, (GHFunc)remove_each_object, storage);
+ g_hash_table_destroy (checks);
+}
+
+gboolean
+gkr_pk_storage_get_store_password (GkrPkStorage *storage, GQuark location,
+ GQuark type, const gchar *label, gboolean *save,
+ gchar **result)
+{
+ GkrAskRequest *ask;
+ gchar *custom_label = NULL;
+ gchar *secondary;
+ gchar *display = NULL;
+ gboolean ret;
+ guint flags;
+ GkrKeyring *login;
+
+ g_return_val_if_fail (GKR_IS_PK_STORAGE (storage), FALSE);
+ g_return_val_if_fail (result != NULL, FALSE);
+ g_return_val_if_fail (save != NULL, FALSE);
+
+ *save = FALSE;
+
+ /* See if we can just use the login keyring password for this */
+ if (gkr_keyring_login_is_usable ()) {
+ login = gkr_keyrings_get_login ();
+ g_return_val_if_fail (login, FALSE);
+ g_return_val_if_fail (login->password, FALSE);
+
+ *result = gkr_secure_strdup (login->password);
+
+ /*
+ * Always same a 'login' password used as a secret. So that
+ * the user can later change the login password, and this'll
+ * still work.
+ */
+ *save = TRUE;
+ return TRUE;
+ }
+
+ if (!label)
+ label = display = gkr_location_to_display (location);
+
+ /* Build up the prompt */
+ flags = GKR_ASK_REQUEST_NEW_PASSWORD;
+ ask = gkr_ask_request_new (prepare_ask_store_title (type),
+ prepare_ask_store_primary (type), flags);
+
+ secondary = prepare_ask_store_secondary (type, label);
+ gkr_ask_request_set_secondary (ask, secondary);
+ g_free (secondary);
+
+ gkr_ask_request_set_location (ask, location);
+
+ if (gkr_keyring_login_is_usable ())
+ gkr_ask_request_set_check_option (ask, prepare_ask_check (type));
+
+ /* Prompt the user */
+ gkr_ask_daemon_process (ask);
+
+ /* If the user denied ... */
+ if (ask->response == GKR_ASK_RESPONSE_DENY) {
+ ret = FALSE;
+
+ /* User cancelled or failure */
+ } else if (ask->response < GKR_ASK_RESPONSE_ALLOW) {
+ ret = FALSE;
+
+ /* Successful response */
+ } else {
+ *result = gkr_secure_strdup (ask->typed_password);
+ *save = ask->checked;
+ }
+
+ g_free (display);
+ g_free (custom_label);
+ g_object_unref (ask);
+ return ret;
+}
+
+gboolean
+gkr_pk_storage_get_load_password (GkrPkStorage *storage, GQuark location, gkrconstid digest,
+ GQuark type, const gchar *label, gint *state,
+ gchar **result)
+{
+ GkrAskRequest *ask;
+ gchar *custom_label = NULL;
+ gchar *stype, *secondary;
+ gchar *display = NULL;
+ gboolean ret;
+ GkrPkIndex *index;
+ gboolean importing = FALSE;
+ gint st;
+ guint flags;
+
+ g_return_val_if_fail (GKR_IS_PK_STORAGE (storage), FALSE);
+ g_return_val_if_fail (digest != NULL, FALSE);
+ g_return_val_if_fail (state != NULL, FALSE);
+ g_return_val_if_fail (result != NULL, FALSE);
+
+ st = *state;
+ (*state)++;
+
+ /*
+ * On the first pass always try a NULL and then an empty password.
+ * This helps with two things.
+ *
+ * 1. Often code will call this function, without actually parsing
+ * any data yet. So this prevents us prompting the user without
+ * knowing it will parse.
+ *
+ * 2. In case it is actually an empty password, we don't want to
+ * prompt the user, just 'decrypt' it. Note that some systems
+ * use the null password instead of empty, so we try both.
+ */
+
+ if (st == 0) {
+ *result = gkr_secure_strdup ("");
+ return TRUE;
+
+ } else if (st == 1) {
+ *result = NULL;
+ return TRUE;
+ }
+
+ index = gkr_pk_storage_index (storage, location);
+ g_return_val_if_fail (index, FALSE);
+
+ /*
+ * The password prompting is somewhat convoluted with the end goal of
+ * not prompting the user more than necessary.
+ *
+ * - Check and see if we have a password on record for this.
+ * - Don't prompt unless the user is specifically requesting
+ * this object *or* we've never seen it before.
+ * - Make note of everything we've prompted for so that later
+ * we can note having seen it.
+ */
+
+ /* See if we can find a valid password for this location */
+ if (st == 2) {
+ *result = gkr_pk_index_get_secret (index, digest);
+ if (*result != NULL)
+ return TRUE;
+
+ /* If we've already tried this password unsuccesfully, then clear */
+ } else {
+ gkr_pk_index_set_secret (index, digest, NULL);
+ }
+
+ /*
+ * If we've parsed this before, then we can lookup in our index as to what
+ * exactly this is we're talking about here.
+ */
+ stype = gkr_pk_index_get_string (index, digest, "parsed-type");
+ if (stype) {
+ if (!type && stype[0])
+ type = g_quark_from_string (stype);
+ g_free (stype);
+ }
+
+ /* TODO: Load a better label if we have one */
+ custom_label = NULL;
+
+ if (custom_label != NULL)
+ label = custom_label;
+
+ if (!label)
+ label = display = gkr_location_to_display (location);
+
+ /* Build up the prompt */
+ if (importing)
+ flags = GKR_ASK_REQUEST_PASSWORD | GKR_ASK_REQUEST_OK_CANCEL_BUTTONS;
+ else
+ flags = GKR_ASK_REQUEST_PASSWORD | GKR_ASK_REQUEST_OK_DENY_BUTTONS;
+ ask = gkr_ask_request_new (prepare_ask_load_title (type),
+ prepare_ask_load_primary (type), flags);
+
+ secondary = prepare_ask_load_secondary (type, !importing, label);
+ gkr_ask_request_set_secondary (ask, secondary);
+ g_free (secondary);
+
+ gkr_ask_request_set_location (ask, location);
+
+ if (gkr_keyring_login_is_usable ())
+ gkr_ask_request_set_check_option (ask, prepare_ask_check (type));
+
+ /* Prompt the user */
+ gkr_ask_daemon_process (ask);
+
+ /* If the user denied ... */
+ if (ask->response == GKR_ASK_RESPONSE_DENY) {
+ ret = FALSE;
+
+ /* User cancelled or failure */
+ } else if (ask->response < GKR_ASK_RESPONSE_ALLOW) {
+ ret = FALSE;
+
+ /* Successful response */
+ } else {
+ *result = gkr_secure_strdup (ask->typed_password);
+ if (ask->checked)
+ gkr_pk_index_set_secret (index, digest, ask->typed_password);
+ }
+
+ g_free (display);
+ g_free (custom_label);
+ g_object_unref (ask);
+ return ret;
+}
Added: trunk/pk/gkr-pk-storage.h
==============================================================================
--- (empty file)
+++ trunk/pk/gkr-pk-storage.h Mon Jul 7 21:17:26 2008
@@ -0,0 +1,123 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gkr-pk-storage.h - Base class for storage of PK objects
+
+ Copyright (C) 2008 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>
+*/
+
+#ifndef __GKR_PK_STORAGE_H__
+#define __GKR_PK_STORAGE_H__
+
+#include <gcrypt.h>
+#include <glib-object.h>
+
+#include "gkr-pk-index.h"
+#include "gkr-pk-object.h"
+
+G_BEGIN_DECLS
+
+#define GKR_TYPE_PK_STORAGE (gkr_pk_storage_get_type ())
+#define GKR_PK_STORAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKR_TYPE_PK_STORAGE, GkrPkStorage))
+#define GKR_PK_STORAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GKR_TYPE_PK_STORAGE, GkrPkStorageClass))
+#define GKR_IS_PK_STORAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKR_TYPE_PK_STORAGE))
+#define GKR_IS_PK_STORAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GKR_TYPE_PK_STORAGE))
+#define GKR_PK_STORAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GKR_TYPE_PK_STORAGE, GkrPkStorageClass))
+
+typedef struct _GkrPkStorageClass GkrPkStorageClass;
+
+struct _GkrPkStorage {
+ GObject parent;
+};
+
+struct _GkrPkStorageClass {
+ GObjectClass parent_class;
+
+ /* virtual methods */
+ void (*refresh) (GkrPkStorage *storage);
+ gboolean (*load) (GkrPkStorage *storage, GkrPkObject *object, GError **err);
+ gboolean (*store) (GkrPkStorage *storage, GkrPkObject *object, GError **err);
+ gboolean (*remove) (GkrPkStorage *storage, GkrPkObject *object, GError **err);
+ GkrPkIndex* (*index) (GkrPkStorage *storage, GQuark location);
+};
+
+GType gkr_pk_storage_get_type (void) G_GNUC_CONST;
+
+void gkr_pk_storage_register (GkrPkStorage *storage,
+ gboolean default_storage);
+
+void gkr_pk_storage_refresh_all (void);
+
+void gkr_pk_storage_refresh (GkrPkStorage *storage);
+
+gboolean gkr_pk_storage_load (GkrPkStorage *storage,
+ GkrPkObject *obj, GError **err);
+
+gboolean gkr_pk_storage_store (GkrPkStorage *storage,
+ GkrPkObject *obj, GError **err);
+
+gboolean gkr_pk_storage_remove (GkrPkStorage *storage,
+ GkrPkObject *obj, GError **err);
+
+GkrPkIndex* gkr_pk_storage_index (GkrPkStorage *storage,
+ GQuark location);
+
+/* For use by derived classes */
+
+GkrPkIndex* gkr_pk_storage_create_index (GkrPkStorage *storage,
+ GQuark index_location);
+
+void gkr_pk_storage_set_object (GkrPkStorage *storage,
+ GkrPkObject *obj);
+
+void gkr_pk_storage_add_object (GkrPkStorage *storage,
+ GkrPkObject *obj);
+
+void gkr_pk_storage_del_object (GkrPkStorage *storage,
+ GkrPkObject *obj);
+
+void gkr_pk_storage_clr_objects (GkrPkStorage *storage,
+ GQuark location);
+
+typedef GHashTable GkrPkChecks;
+
+GkrPkChecks* gkr_pk_storage_checks_prepare (GkrPkStorage *storage,
+ GQuark location);
+
+void gkr_pk_storage_checks_mark (GkrPkChecks *checks,
+ GkrPkObject *object);
+
+void gkr_pk_storage_checks_purge (GkrPkStorage *storage,
+ GkrPkChecks *checks);
+
+#define GKR_PK_STORAGE_PASSWD_STATE 0
+#define GKR_PK_STORAGE_PASSWD_PROMPT 2
+
+gboolean gkr_pk_storage_get_store_password (GkrPkStorage *storage,
+ GQuark location, GQuark type,
+ const gchar *label, gboolean *save,
+ gchar **passowrd);
+
+gboolean gkr_pk_storage_get_load_password (GkrPkStorage *storage,
+ GQuark location, gkrconstid digest,
+ GQuark type, const gchar *label,
+ gint *state, gchar **password);
+
+G_END_DECLS
+
+#endif /* __GKR_PK_STORAGE_H__ */
Modified: trunk/pk/tests/unit-test-pk-cert.c
==============================================================================
--- trunk/pk/tests/unit-test-pk-cert.c (original)
+++ trunk/pk/tests/unit-test-pk-cert.c Mon Jul 7 21:17:26 2008
@@ -58,11 +58,15 @@
static GkrPkCert *certificate_1 = NULL;
static GkrPkCert *certificate_2 = NULL;
static GkrPkObject *privkey_1 = NULL;
+static GkrPkIndex *pk_index = NULL;
void unit_setup_certificate (void)
{
/* Our own object manager */
- manager = gkr_pk_object_manager_instance_for_client (1231);
+ manager = gkr_pk_object_manager_instance_for_client (1231);
+
+ /* Our own pk_index */
+ pk_index = gkr_pk_index_default ();
}
void unit_test_create_certificate (CuTest* cu)
@@ -172,17 +176,17 @@
/* Mark as trusted */
/* TODO: Should do this via attribute once writable */
- gkr_pk_index_set_string (GKR_PK_OBJECT (certificate_2), "user-trust", "trusted");
+ gkr_pk_object_index_set_string (GKR_PK_OBJECT (certificate_2), "user-trust", "trusted");
CHECK_ULONG_ATTRIBUTE (cu, certificate_2, CKA_GNOME_USER_TRUST, CKT_GNOME_TRUSTED);
/* Should return to previous state */
/* TODO: Should do this via attribute once writable */
- gkr_pk_index_delete (GKR_PK_OBJECT (certificate_2), "user-trust");
+ gkr_pk_object_index_clear (GKR_PK_OBJECT (certificate_2), "user-trust");
CHECK_ULONG_ATTRIBUTE (cu, certificate_2, CKA_GNOME_USER_TRUST, CKT_GNOME_UNKNOWN);
/* Mark as untrusted */
/* TODO: Should do this via attribute once writable */
- gkr_pk_index_set_string (GKR_PK_OBJECT (certificate_1), "user-trust", "untrusted");
+ gkr_pk_object_index_set_string (GKR_PK_OBJECT (certificate_1), "user-trust", "untrusted");
CHECK_ULONG_ATTRIBUTE (cu, certificate_1, CKA_GNOME_USER_TRUST, CKT_GNOME_UNTRUSTED);
}
@@ -226,10 +230,9 @@
CHECK_BOOL_ATTRIBUTE (cu, certificate_2, CKA_GNOME_PURPOSE_IPSEC_USER, CK_TRUE);
CHECK_BOOL_ATTRIBUTE (cu, certificate_2, CKA_GNOME_PURPOSE_TIME_STAMPING, CK_TRUE);
-
/* Add a purpose */
/* TODO: Should do this via attribute once writable */
- gkr_pk_index_set_string (GKR_PK_OBJECT (certificate_2), "purposes", "some-purpose");
+ gkr_pk_object_index_set_string (GKR_PK_OBJECT (certificate_2), "purposes", "some-purpose");
CHECK_BOOL_ATTRIBUTE (cu, certificate_2, CKA_GNOME_PURPOSE_RESTRICTED, CK_TRUE);
memset (&attr, 0, sizeof (attr));
Modified: trunk/pk/tests/unit-test-pk-index.c
==============================================================================
--- trunk/pk/tests/unit-test-pk-index.c (original)
+++ trunk/pk/tests/unit-test-pk-index.c Mon Jul 7 21:17:26 2008
@@ -1,5 +1,5 @@
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-/* unit-test-pk-index.c: Test PK Indexes
+/* unit-test-pk-pk_index.c: Test PK Indexes
Copyright (C) 2007 Stefan Walter
@@ -51,17 +51,26 @@
#define DATA_L (strlen ((gchar*)DATA))
#define STR "a test string"
+#define DEFAULT "default-value"
static GkrPkObject *object = NULL;
+static GkrPkIndex *pk_index = NULL;
void unit_setup_index (void)
{
+ GnomeKeyringAttributeList *defaults;
+
/* This is just any arbitrary data */
gkrid id = gkr_id_new (DATA, DATA_L);
GQuark location = gkr_location_from_child (GKR_LOCATION_VOLUME_LOCAL, "woof");
+ defaults = gnome_keyring_attribute_list_new ();
+ gnome_keyring_attribute_list_append_string (defaults, "test-default", DEFAULT);
+
+ pk_index = gkr_pk_index_new (NULL, defaults);
+
object = g_object_new (GKR_TYPE_PK_OBJECT, "location", location, "digest", id, NULL);
- gkr_pk_index_clear (object);
+ gkr_pk_index_delete (pk_index, object->digest);
}
void unit_test_index_binary (CuTest* cu)
@@ -71,10 +80,10 @@
gsize n_data;
/* Test binary */
- ret = gkr_pk_index_set_binary (object, "field", DATA, DATA_L);
+ ret = gkr_pk_index_set_binary (pk_index, object->digest, "field", DATA, DATA_L);
CuAssert (cu, "set_binary returned false", ret);
- data = gkr_pk_index_get_binary (object, "field", &n_data);
+ data = gkr_pk_index_get_binary (pk_index, object->digest, "field", &n_data);
CuAssert (cu, "get_binary returned no data", data != NULL);
CuAssert (cu, "get_binary returned bad length data", n_data == DATA_L);
CuAssert (cu, "get_binary returned wrong data", memcmp (data, DATA, DATA_L) == 0);
@@ -86,26 +95,26 @@
gboolean ret;
/* Test strings */
- ret = gkr_pk_index_set_string (object, "string", STR);
+ ret = gkr_pk_index_set_string (pk_index, object->digest, "string", STR);
CuAssert (cu, "set_string returned false", ret);
- str = gkr_pk_index_get_string (object, "string");
+ str = gkr_pk_index_get_string (pk_index, object->digest, "string");
CuAssert (cu, "get_string returned no string", str != NULL);
CuAssert (cu, "get_string returned wrong string", strcmp (str, STR) == 0);
}
void unit_test_index_int (CuTest *cu)
{
- gint val;
+ guint val;
gboolean ret;
- ret = gkr_pk_index_set_int (object, "intval", 23423523);
+ ret = gkr_pk_index_set_uint (pk_index, object->digest, "intval", 23423523);
CuAssert (cu, "set_int returned false", ret);
- val = gkr_pk_index_get_int (object, "intval", 0);
+ val = gkr_pk_index_get_uint (pk_index, object->digest, "intval", 0);
CuAssert (cu, "get_int returned wrong value", val == 23423523);
- val = gkr_pk_index_get_int (object, "nonexistant", 35);
+ val = gkr_pk_index_get_uint (pk_index, object->digest, "nonexistant", 35);
CuAssert (cu, "get_int didn't return default", val == 35);
}
@@ -114,13 +123,13 @@
gboolean val;
gboolean ret;
- ret = gkr_pk_index_set_boolean (object, "boolval", TRUE);
+ ret = gkr_pk_index_set_boolean (pk_index, object->digest, "boolval", TRUE);
CuAssert (cu, "set_boolean returned false", ret);
- val = gkr_pk_index_get_boolean (object, "boolval", 0);
+ val = gkr_pk_index_get_boolean (pk_index, object->digest, "boolval", 0);
CuAssert (cu, "get_boolean returned wrong value", val == TRUE);
- val = gkr_pk_index_get_boolean (object, "nonexistant", TRUE);
+ val = gkr_pk_index_get_boolean (pk_index, object->digest, "nonexistant", TRUE);
CuAssert (cu, "get_boolean didn't return default", val == TRUE);
}
@@ -135,20 +144,20 @@
for (i = 0; i < 4; ++i)
quarks[i] = g_quark_from_static_string ("blah");
- ret = gkr_pk_index_set_quarks (object, "quarks", quarks);
+ ret = gkr_pk_index_set_quarks (pk_index, object->digest, "quarks", quarks);
CuAssert (cu, "set_quarks returned false", ret);
/* A second time which exercises internals to not write same value twice */
- ret = gkr_pk_index_set_quarks (object, "quarks", quarks);
- CuAssert (cu, "set_quarks returned false", ret);
+ ret = gkr_pk_index_set_quarks (pk_index, object->digest, "quarks", quarks);
+ CuAssert (cu, "set_quarks returned true, but shouldn't have written", !ret);
- output = gkr_pk_index_get_quarks (object, "quarks");
+ output = gkr_pk_index_get_quarks (pk_index, object->digest, "quarks");
CuAssert (cu, "get_quarks returned null", output != NULL);
for (i = 0; i < 4; ++i)
CuAssert (cu, "returned quark is different", quarks[i] == output[i]);
- output = gkr_pk_index_get_quarks (object, "nonexistant");
+ output = gkr_pk_index_get_quarks (pk_index, object->digest, "nonexistant");
CuAssert (cu, "get_quarks didn't return null", output == NULL);
}
@@ -157,25 +166,34 @@
gboolean ret;
gboolean val;
- ret = gkr_pk_index_delete (object, "boolval");
+ ret = gkr_pk_index_clear (pk_index, object->digest, "boolval");
CuAssert (cu, "delete returned false", ret);
- val = gkr_pk_index_get_boolean (object, "boolval", FALSE);
+ val = gkr_pk_index_get_boolean (pk_index, object->digest, "boolval", FALSE);
CuAssert (cu, "delete didn't work", val == FALSE);
- ret = gkr_pk_index_delete (object, "nonexistant");
- CuAssert (cu, "delete returned false", ret);
+ ret = gkr_pk_index_clear (pk_index, object->digest, "nonexistant");
+ CuAssert (cu, "delete return true but should already be gone", !ret);
}
void unit_test_index_all (CuTest *cu)
{
gboolean ret;
- ret = gkr_pk_index_have (object);
+ ret = gkr_pk_index_have (pk_index, object->digest);
CuAssert (cu, "didn't find anything for object", ret);
- gkr_pk_index_clear (object);
+ gkr_pk_index_delete (pk_index, object->digest);
- ret = gkr_pk_index_have (object);
+ ret = gkr_pk_index_have (pk_index, object->digest);
CuAssert (cu, "clear didn't work", !ret);
}
+
+void unit_test_index_defaults (CuTest* cu)
+{
+ gchar *str;
+
+ str = gkr_pk_index_get_string (pk_index, object->digest, "test-default");
+ CuAssert (cu, "couldn't find default value", str != NULL);
+ CuAssert (cu, "returned wrong default value", strcmp (DEFAULT, str) == 0);
+}
Modified: trunk/pk/tests/unit-test-pk-netscape-trust.c
==============================================================================
--- trunk/pk/tests/unit-test-pk-netscape-trust.c (original)
+++ trunk/pk/tests/unit-test-pk-netscape-trust.c Mon Jul 7 21:17:26 2008
@@ -57,11 +57,14 @@
static GkrPkCert *certificate_2 = NULL;
static GkrPkObject *trust_1 = NULL;
static GkrPkObject *trust_2 = NULL;
+static GkrPkIndex *pk_index = NULL;
void unit_setup_trust (void)
{
/* Our own object manager */
- manager = gkr_pk_object_manager_instance_for_client (12333);
+ manager = gkr_pk_object_manager_instance_for_client (12333);
+
+ pk_index = gkr_pk_index_default ();
}
void unit_test_create_trust (CuTest* cu)
@@ -80,8 +83,8 @@
CuAssert (cu, "gkr_pk_cert_new returned bad object", GKR_IS_PK_CERT (certificate_1));
/* Make sure this is trusted */
- gkr_pk_index_set_string (GKR_PK_OBJECT (certificate_1), "user-trust", "trusted");
- gkr_pk_index_delete (GKR_PK_OBJECT (certificate_1), "purposes");
+ gkr_pk_object_index_set_string (GKR_PK_OBJECT (certificate_1), "user-trust", "trusted");
+ gkr_pk_object_index_clear (GKR_PK_OBJECT (certificate_1), "purposes");
/* Should have created netscape trust companion object */
keyid = gkr_pk_cert_get_keyid (certificate_1);
@@ -96,8 +99,8 @@
CuAssert (cu, "gkr_pk_cert_new returned bad object", GKR_IS_PK_CERT (certificate_2));
/* Make sure this is not trusted */
- gkr_pk_index_delete (GKR_PK_OBJECT (certificate_2), "user-trust");
- gkr_pk_index_delete (GKR_PK_OBJECT (certificate_2), "purposes");
+ gkr_pk_object_index_clear (GKR_PK_OBJECT (certificate_2), "user-trust");
+ gkr_pk_object_index_clear (GKR_PK_OBJECT (certificate_2), "purposes");
/* Should have created netscape trust companion object */
keyid = gkr_pk_cert_get_keyid (certificate_2);
Modified: trunk/pkcs11/gkr-pkcs11-daemon-session.c
==============================================================================
--- trunk/pkcs11/gkr-pkcs11-daemon-session.c (original)
+++ trunk/pkcs11/gkr-pkcs11-daemon-session.c Mon Jul 7 21:17:26 2008
@@ -41,7 +41,8 @@
#include "pk/gkr-pk-object.h"
#include "pk/gkr-pk-object-manager.h"
-#include "pk/gkr-pk-object-storage.h"
+#include "pk/gkr-pk-session-storage.h"
+#include "pk/gkr-pk-storage.h"
#include "pk/gkr-pk-util.h"
#include <stdlib.h>
@@ -76,7 +77,7 @@
guint deverror; /* The 'device' error code */
GkrPkObjectManager *manager; /* The object manager for this session */
- GHashTable *objects; /* Objects owned by the session */
+ GkrPkStorage *storage; /* Objects owned by the session */
};
/*
@@ -86,24 +87,6 @@
#define PROTOCOL_ERROR CKR_DEVICE_ERROR
/* -----------------------------------------------------------------------------
- * SESSION OBJECTS
- */
-
-static void
-session_add_object (SessionInfo *sinfo, GkrPkObject *object)
-{
- g_assert (sinfo);
-
- g_return_if_fail (object->handle != 0);
- g_return_if_fail (object->location == 0);
- g_return_if_fail (object->manager == sinfo->manager);
-
- /* We assume the ownership */
- g_object_ref (object);
- g_hash_table_insert (sinfo->objects, GUINT_TO_POINTER (object->handle), object);
-}
-
-/* -----------------------------------------------------------------------------
* HELPERS
*/
@@ -492,22 +475,22 @@
goto done;
g_return_val_if_fail (object, CKR_GENERAL_ERROR);
-
+ g_return_val_if_fail (object->storage == NULL, CKR_GENERAL_ERROR);
+
/* Token objects get stored in the main object storage */
- if (token) {
- g_return_val_if_fail (object->storage != NULL, CKR_GENERAL_ERROR);
- res = gkr_pk_object_storage_add (gkr_pk_object_storage_get (), object, &err);
- if (!res) {
- g_warning ("couldn't write created object to disk: %s",
- err && err->message ? err->message : "");
- g_clear_error (&err);
- ret = CKR_GENERAL_ERROR;
- goto done;
- }
-
+ if (token)
+ res = gkr_pk_storage_store (NULL, object, &err);
+
/* Session objects are owned by the session */
- } else {
- session_add_object (sinfo, object);
+ else
+ res = gkr_pk_storage_store (sinfo->storage, object, &err);
+
+ if (!res) {
+ g_warning ("couldn't write created object to disk: %s",
+ err && err->message ? err->message : "");
+ g_clear_error (&err);
+ ret = CKR_GENERAL_ERROR;
+ goto done;
}
gkr_pkcs11_message_write_uint32 (resp, object->handle);
@@ -572,7 +555,7 @@
return CKR_SESSION_READ_ONLY;
g_return_val_if_fail (object->storage, CKR_GENERAL_ERROR);
- res = gkr_pk_object_storage_remove (object->storage, object, &err);
+ res = gkr_pk_storage_remove (object->storage, object, &err);
if (!res) {
g_warning ("couldn't remove object from disk: %s",
err && err->message ? err->message : "");
@@ -1381,17 +1364,20 @@
session_info_new ()
{
SessionInfo *sinfo = g_new0 (SessionInfo, 1);
- sinfo->objects = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
+ sinfo->storage = GKR_PK_STORAGE (gkr_pk_session_storage_new ());
return sinfo;
}
static void
session_info_free (SessionInfo *sinfo)
{
- if (sinfo->manager)
- g_object_unref (sinfo->manager);
- g_hash_table_destroy (sinfo->objects);
- g_free (sinfo);
+ if (sinfo) {
+ if (sinfo->manager)
+ g_object_unref (sinfo->manager);
+ if (sinfo->storage)
+ g_object_unref (sinfo->storage);
+ g_free (sinfo);
+ }
}
static gboolean
Modified: trunk/pkix/gkr-pkix-marshal.list
==============================================================================
--- trunk/pkix/gkr-pkix-marshal.list (original)
+++ trunk/pkix/gkr-pkix-marshal.list Mon Jul 7 21:17:26 2008
@@ -1,3 +1,3 @@
BOOLEAN:UINT,POINTER,UINT
BOOLEAN:UINT,POINTER,UINT,POINTER
-POINTER:UINT,POINTER,UINT,STRING,UINT
+BOOLEAN:UINT,POINTER,UINT,STRING,POINTER,POINTER
Modified: trunk/pkix/gkr-pkix-openssl.c
==============================================================================
--- trunk/pkix/gkr-pkix-openssl.c (original)
+++ trunk/pkix/gkr-pkix-openssl.c Mon Jul 7 21:17:26 2008
@@ -257,3 +257,121 @@
return GKR_PKIX_SUCCESS;
}
+
+gboolean
+gkr_pkix_openssl_encrypt_block (const gchar *dekinfo, const gchar *password,
+ const guchar *data, gsize n_data,
+ guchar **encrypted, gsize *n_encrypted)
+{
+ gsize n_overflow, n_batch, n_padding;
+ gcry_cipher_hd_t ch;
+ guchar *key = NULL;
+ guchar *iv = NULL;
+ guchar *padded = NULL;
+ int gcry, ivlen;
+ int algo = 0;
+ int mode = 0;
+
+ if (!parse_dekinfo (dekinfo, &algo, &mode, &iv))
+ g_return_val_if_reached (FALSE);
+
+ ivlen = gcry_cipher_get_algo_blklen (algo);
+
+ /* We assume the iv is at least as long as at 8 byte salt */
+ g_return_val_if_fail (ivlen >= 8, FALSE);
+
+ /* IV is already set from the DEK info */
+ if (!gkr_crypto_generate_symkey_simple (algo, GCRY_MD_MD5, password,
+ iv, 8, 1, &key, NULL))
+ g_return_val_if_reached (FALSE);
+
+ gcry = gcry_cipher_open (&ch, algo, mode, 0);
+ g_return_val_if_fail (!gcry, FALSE);
+
+ gcry = gcry_cipher_setkey (ch, key, gcry_cipher_get_algo_keylen (algo));
+ g_return_val_if_fail (!gcry, FALSE);
+ gkr_secure_free (key);
+
+ /* 16 = 128 bits */
+ gcry = gcry_cipher_setiv (ch, iv, ivlen);
+ g_return_val_if_fail (!gcry, FALSE);
+ g_free (iv);
+
+ /* Allocate output area */
+ n_overflow = (n_data % ivlen);
+ n_padding = n_overflow ? (ivlen - n_overflow) : 0;
+ n_batch = n_data - n_overflow;
+ *n_encrypted = n_data + n_padding;
+ *encrypted = g_malloc0 (*n_encrypted);
+
+ g_assert (*n_encrypted % ivlen == 0);
+ g_assert (*n_encrypted >= n_data);
+ g_assert (*n_encrypted == n_batch + n_overflow + n_padding);
+
+ /* Encrypt everything but the last bit */
+ gcry = gcry_cipher_encrypt (ch, *encrypted, n_batch, (void*)data, n_batch);
+ if (gcry) {
+ g_free (*encrypted);
+ g_return_val_if_reached (FALSE);
+ }
+
+ /* Encrypt the padded block */
+ if (n_overflow) {
+ padded = gkr_secure_alloc (ivlen);
+ memset (padded, 0, ivlen);
+ memcpy (padded, data + n_batch, n_overflow);
+ gcry = gcry_cipher_encrypt (ch, *encrypted + n_batch, ivlen, padded, ivlen);
+ gkr_secure_free (padded);
+ if (gcry) {
+ g_free (*encrypted);
+ g_return_val_if_reached (FALSE);
+ }
+ }
+
+ gcry_cipher_close (ch);
+ return TRUE;
+}
+
+const gchar*
+gkr_pkix_openssl_get_dekinfo (GHashTable *headers)
+{
+ const gchar *val;
+ if (!headers)
+ return NULL;
+ val = g_hash_table_lookup (headers, "Proc-Type");
+ if (!val || strcmp (val, "4,ENCRYPTED") != 0)
+ return NULL;
+ val = g_hash_table_lookup (headers, "DEK-Info");
+ g_return_val_if_fail (val, NULL);
+ return val;
+}
+
+const gchar*
+gkr_pkix_openssl_prep_dekinfo (GHashTable *headers)
+{
+ gsize ivlen, len, n_encoded;
+ gchar buf[256];
+ guchar *iv;
+ const gchar *dekinfo;
+
+ strcpy (buf, "DES-EDE3-CBC,");
+
+ /* Create the iv */
+ ivlen = gcry_cipher_get_algo_blklen (GCRY_CIPHER_3DES);
+ g_return_val_if_fail (ivlen, NULL);
+ iv = g_malloc (ivlen);
+ gcry_create_nonce (iv, ivlen);
+
+ /* And encode it into the string */
+ len = strlen (buf);
+ g_return_val_if_fail (sizeof (buf) - len > ivlen * 2, NULL);
+ n_encoded = (ivlen * 2) + 1;
+ if (!gkr_crypto_hex_encode (iv, ivlen, buf + len, &n_encoded))
+ g_return_val_if_reached (NULL);
+
+ dekinfo = g_strdup (buf);
+ g_hash_table_insert (headers, g_strdup ("DEK-Info"), (void*)dekinfo);
+ g_hash_table_insert (headers, g_strdup ("Proc-Type"), g_strdup ("4,ENCRYPTED"));
+
+ return dekinfo;
+}
Modified: trunk/pkix/gkr-pkix-openssl.h
==============================================================================
--- trunk/pkix/gkr-pkix-openssl.h (original)
+++ trunk/pkix/gkr-pkix-openssl.h Mon Jul 7 21:17:26 2008
@@ -28,10 +28,18 @@
#include "gkr-pkix-parser.h"
-int gkr_pkix_openssl_parse_algo (const gchar *name, int *mode);
+int gkr_pkix_openssl_parse_algo (const gchar *name, int *mode);
-GkrPkixResult gkr_pkix_openssl_decrypt_block (const gchar *dekinfo, const gchar *password,
+gboolean gkr_pkix_openssl_encrypt_block (const gchar *dekinfo, const gchar *password,
+ const guchar *data, gsize n_data,
+ guchar **encrypted, gsize *n_encrypted);
+
+GkrPkixResult gkr_pkix_openssl_decrypt_block (const gchar *dekinfo, const gchar *password,
const guchar *data, gsize n_data,
guchar **decrypted, gsize *n_decrypted);
+const gchar* gkr_pkix_openssl_get_dekinfo (GHashTable *headers);
+
+const gchar* gkr_pkix_openssl_prep_dekinfo (GHashTable *headers);
+
#endif /*GKRPKIOPENSSL_H_*/
Modified: trunk/pkix/gkr-pkix-parser.c
==============================================================================
--- trunk/pkix/gkr-pkix-parser.c (original)
+++ trunk/pkix/gkr-pkix-parser.c Mon Jul 7 21:17:26 2008
@@ -111,12 +111,11 @@
typedef struct {
GQuark location;
- guint n_prompts;
- guint n_passes;
+ gint ask_state;
GSList *seen;
} PasswordState;
-#define PASSWORD_STATE_INIT { 0, 0, 0, NULL}
+#define PASSWORD_STATE_INIT { 0, 0, NULL}
typedef struct {
GSList *seen_passwords;
@@ -149,8 +148,8 @@
GkrPkixParserPrivate *pv = GKR_PKIX_PARSER_GET_PRIVATE (parser);
gboolean first = FALSE;
gchar *display = NULL;
- guint passes;
gchar *prompted;
+ gboolean result;
GSList *l;
if (gkr_async_is_stopping ())
@@ -159,36 +158,10 @@
/* Is it a new location, reset stuff */
if (loc != state->location) {
state->seen = NULL;
- state->n_prompts = 0;
- state->n_passes = 0;
+ state->ask_state = 0;
state->location = loc;
}
-
- passes = state->n_passes;
- ++state->n_passes;
-
- /*
- * On the first pass always try a NULL and then an empty password.
- * This helps with two things.
- *
- * 1. Often code will call this function, without actually parsing
- * any data yet. So this prevents us prompting the user without
- * knowing it will parse.
- *
- * 2. In case it is actually an empty password, we don't want to
- * prompt the user, just 'decrypt' it. Note that some systems
- * use the null password instead of empty, so we try both.
- */
- if (passes == 0) {
- *password = "";
- return TRUE;
- }
-
- if (passes == 1) {
- *password = NULL;
- return TRUE;
- }
-
+
/*
* Next passes we look through all the passwords that the parser
* has seen so far. This is because different parts of a encrypted
@@ -225,19 +198,19 @@
* And lastly we actually prompt for a password. This prompt might
* also lookup saved passwords for this location.
*/
-
if (!label)
label = display = gkr_location_to_display (loc);
g_signal_emit (parser, signals[ASK_PASSWORD], 0,
- loc, digest, type, label, state->n_prompts, &prompted);
+ loc, digest, type, label, &state->ask_state,
+ &prompted, &result);
- ++state->n_prompts;
g_free (display);
/* Stash away any password */
- if (prompted) {
- pv->seen_passwords = g_slist_prepend (pv->seen_passwords, prompted);
+ if (result) {
+ if (prompted)
+ pv->seen_passwords = g_slist_prepend (pv->seen_passwords, prompted);
*password = prompted;
return TRUE;
}
@@ -287,21 +260,6 @@
asn1_delete_structure (&asn1);
}
-static gboolean
-accumulate_password (GSignalInvocationHint *ihint, GValue *return_accu,
- const GValue *handler_return, gpointer data)
-{
- gchar *password;
-
- password = g_value_get_pointer (handler_return);
- if (!password)
- return TRUE;
-
- /* Choose the first password returned by a handler */
- g_value_set_pointer (return_accu, password);
- return FALSE;
-}
-
/* -----------------------------------------------------------------------------
* OBJECT
*/
@@ -337,11 +295,13 @@
return FALSE;
}
-static gchar*
+static gboolean
gkr_pkix_parser_ask_password (GkrPkixParser *parser, GQuark loc, gkrconstid digest,
- GQuark type, const gchar *details, guint n_prompts)
+ GQuark type, const gchar *details, gint *state,
+ gchar **password)
{
- return NULL;
+ *password = NULL;
+ return FALSE;
}
static void
@@ -392,8 +352,8 @@
/* Due to our use of secure memory, we use a pointer as the signal return type */
signals[ASK_PASSWORD] = g_signal_new ("ask-password", GKR_TYPE_PKIX_PARSER,
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GkrPkixParserClass, ask_password),
- accumulate_password, NULL, gkr_pkix_marshal_POINTER__UINT_POINTER_UINT_STRING_UINT,
- G_TYPE_POINTER, 5, G_TYPE_UINT, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_UINT);
+ g_signal_accumulator_true_handled, NULL, gkr_pkix_marshal_BOOLEAN__UINT_POINTER_UINT_STRING_POINTER_POINTER,
+ G_TYPE_BOOLEAN, 6, G_TYPE_UINT, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER);
g_type_class_add_private (klass, sizeof (GkrPkixParserPrivate));
}
Modified: trunk/pkix/gkr-pkix-parser.h
==============================================================================
--- trunk/pkix/gkr-pkix-parser.h (original)
+++ trunk/pkix/gkr-pkix-parser.h Mon Jul 7 21:17:26 2008
@@ -70,9 +70,10 @@
gcry_sexp_t sexp);
/* A callback for each password needed */
- gchar* (*ask_password) (GkrPkixParser *parser, GQuark location,
- gkrconstid digest, GQuark type,
- const gchar *orig_label, guint failed);
+ gboolean (*ask_password) (GkrPkixParser *parser, GQuark location,
+ gkrconstid digest, GQuark type,
+ const gchar *orig_label, gint *state,
+ gchar **password);
};
GType gkr_pkix_parser_get_type (void) G_GNUC_CONST;
Modified: trunk/pkix/gkr-pkix-pem.c
==============================================================================
--- trunk/pkix/gkr-pkix-pem.c (original)
+++ trunk/pkix/gkr-pkix-pem.c Mon Jul 7 21:17:26 2008
@@ -82,7 +82,7 @@
g_strstrip (name);
if (!*result)
- *result = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+ *result = gkr_pkix_pem_headers_new ();
g_hash_table_replace (*result, name, value);
}
@@ -225,6 +225,12 @@
return TRUE;
}
+GHashTable*
+gkr_pkix_pem_headers_new (void)
+{
+ return g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+}
+
guint
gkr_pkix_pem_parse (const guchar *data, gsize n_data,
GkrPkixPemCallback callback, gpointer user_data)
@@ -279,3 +285,61 @@
return nfound;
}
+static void
+append_each_header (gpointer key, gpointer value, gpointer user_data)
+{
+ GString *string = (GString*)user_data;
+
+ g_string_append (string, (gchar*)key);
+ g_string_append (string, ": ");
+ g_string_append (string, (gchar*)value);
+ g_string_append_c (string, '\n');
+}
+
+guchar*
+gkr_pkix_pem_write (const guchar *data, gsize n_data, GQuark type,
+ GHashTable *headers, gsize *n_result)
+{
+ GString *string;
+ gint state, save;
+ gsize length, n_prefix;
+
+ g_return_val_if_fail (data || !n_data, NULL);
+ g_return_val_if_fail (type, NULL);
+ g_return_val_if_fail (n_result, NULL);
+
+ string = g_string_sized_new (4096);
+
+ /* The prefix */
+ g_string_append_len (string, PEM_PREF_BEGIN, PEM_PREF_BEGIN_L);
+ g_string_append (string, g_quark_to_string (type));
+ g_string_append_len (string, PEM_SUFF, PEM_SUFF_L);
+ g_string_append_c (string, '\n');
+
+ /* The headers */
+ if (headers && g_hash_table_size (headers) > 0) {
+ g_hash_table_foreach (headers, append_each_header, string);
+ g_string_append_c (string, '\n');
+ }
+
+ /* Resize string to fit the base64 data. Algorithm from Glib reference */
+ length = n_data * 4 / 3 + n_data * 4 / (3 * 72) + 7;
+ n_prefix = string->len;
+ g_string_set_size (string, n_prefix + length);
+
+ /* The actual base64 data */
+ state = save = 0;
+ length = g_base64_encode_step (data, n_data, TRUE,
+ string->str + string->len, &state, &save);
+ g_string_set_size (string, n_prefix + length);
+
+ /* The suffix */
+ g_string_append_c (string, '\n');
+ g_string_append_len (string, PEM_PREF_END, PEM_PREF_END_L);
+ g_string_append (string, g_quark_to_string (type));
+ g_string_append_len (string, PEM_SUFF, PEM_SUFF_L);
+ g_string_append_c (string, '\n');
+
+ *n_result = string->len;
+ return (guchar*)g_string_free (string, FALSE);
+}
Modified: trunk/pkix/gkr-pkix-pem.h
==============================================================================
--- trunk/pkix/gkr-pkix-pem.h (original)
+++ trunk/pkix/gkr-pkix-pem.h Mon Jul 7 21:17:26 2008
@@ -29,8 +29,14 @@
typedef void (*GkrPkixPemCallback) (GQuark type, const guchar *data, gsize n_data,
GHashTable *headers, gpointer user_data);
+GHashTable* gkr_pkix_pem_headers_new (void);
+
guint gkr_pkix_pem_parse (const guchar *data, gsize n_data,
GkrPkixPemCallback callback,
gpointer user_data);
+guchar* gkr_pkix_pem_write (const guchar *data, gsize n_data,
+ GQuark type, GHashTable *headers,
+ gsize *n_result);
+
#endif /*GKRPKIPEM_H_*/
Modified: trunk/pkix/tests/Makefile.am
==============================================================================
--- trunk/pkix/tests/Makefile.am (original)
+++ trunk/pkix/tests/Makefile.am Mon Jul 7 21:17:26 2008
@@ -9,6 +9,7 @@
unit-test-gcrypt-setup.c \
unit-test-pkix-asn1.c \
unit-test-pkix-der.c \
+ unit-test-pkix-openssl.c \
unit-test-pkix-parser.c \
unit-test-pkix-serialize.c \
$(BUILT_SOURCES)
Added: trunk/pkix/tests/unit-test-pkix-openssl.c
==============================================================================
--- (empty file)
+++ trunk/pkix/tests/unit-test-pkix-openssl.c Mon Jul 7 21:17:26 2008
@@ -0,0 +1,168 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-pkix-openssl.c: Test PKIX openssl
+
+ Copyright (C) 2008 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 "config.h"
+
+#include "run-auto-test.h"
+
+#include "common/gkr-location.h"
+#include "common/gkr-crypto.h"
+#include "common/gkr-secure-memory.h"
+
+#include "pkix/gkr-pkix-openssl.h"
+#include "pkix/gkr-pkix-pem.h"
+
+#include <glib.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.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
+read_file (CuTest *cu, const gchar *filename, guchar **contents, gsize *len)
+{
+ gchar *path;
+ gboolean ret;
+
+ path = g_build_filename (g_get_current_dir (), "test-data", filename, NULL);
+ ret = g_file_get_contents (path, (gchar**)contents, len, NULL);
+ CuAssert (cu, "couldn't read in file", ret);
+
+ g_free (path);
+}
+
+guchar *refenc = NULL;
+guchar *refdata = NULL;
+gsize n_refenc = 0;
+gsize n_refdata = 0;
+GHashTable *refheaders = NULL;
+
+static void
+copy_each_key_value (gpointer key, gpointer value, gpointer user_data)
+{
+ g_hash_table_insert ((GHashTable*)user_data, g_strdup ((gchar*)key), g_strdup ((gchar*)value));
+}
+
+static void
+parse_reference (GQuark type, const guchar *data, gsize n_data,
+ GHashTable *headers, gpointer user_data)
+{
+ CuTest *cu = (CuTest*)user_data;
+ GkrPkixResult res;
+ const gchar *dekinfo;
+
+ CuAssert (cu, "no data in PEM callback", data != NULL);
+ CuAssert (cu, "no data in PEM callback", n_data > 0);
+ refenc = g_memdup (data, n_data);
+ n_refenc = n_data;
+
+ CuAssert (cu, "no headers present in file", headers != NULL);
+ refheaders = gkr_pkix_pem_headers_new ();
+ g_hash_table_foreach (headers, copy_each_key_value, refheaders);
+ dekinfo = gkr_pkix_openssl_get_dekinfo (headers);
+ CuAssert (cu, "no dekinfo in headers", dekinfo != NULL);
+
+ res = gkr_pkix_openssl_decrypt_block (dekinfo, "booo", data, n_data, &refdata, &n_refdata);
+ CuAssert (cu, "couldn't openssl decrypt block", res == GKR_PKIX_SUCCESS);
+ CuAssert (cu, "no data returned from openssl decrypt", refdata != NULL);
+ CuAssert (cu, "invalid amount of data returned from openssl decrypt", n_refdata == n_data);
+}
+
+void unit_test_openssl_parse_reference (CuTest* cu)
+{
+ guchar *input;
+ gsize n_input;
+ guint num;
+
+ read_file (cu, "pem-rsa-enc.key", &input, &n_input);
+
+ num = gkr_pkix_pem_parse (input, n_input, parse_reference, NULL);
+ CuAssert (cu, "couldn't PEM block in reference data", num == 1);
+
+ CuAssert (cu, "parse_reference() wasn't called", refdata != NULL);
+}
+
+void unit_test_openssl_write_reference (CuTest* cu)
+{
+ const gchar *dekinfo;
+ guchar *encrypted;
+ gsize n_encrypted;
+ gboolean ret;
+
+ dekinfo = gkr_pkix_openssl_get_dekinfo (refheaders);
+ CuAssert (cu, "no dekinfo in headers", dekinfo != NULL);
+
+ ret = gkr_pkix_openssl_encrypt_block (dekinfo, "booo", refdata, n_refdata, &encrypted, &n_encrypted);
+ CuAssert (cu, "couldn't openssl encrypt block", ret == TRUE);
+ CuAssert (cu, "no data returned from openssl encrypt", encrypted != NULL);
+ CuAssert (cu, "invalid amount of data returned from openssl encrypt", n_refdata <= n_encrypted);
+
+ CuAssert (cu, "data length doesn't match input length", n_encrypted == n_refenc);
+ CuAssert (cu, "data doesn't match input", memcmp (encrypted, refenc, n_encrypted) == 0);
+}
+
+/* 29 bytes (prime number, so block length has bad chance of matching */
+const static guchar *TEST_DATA = (guchar*)"ABCDEFGHIJKLMNOPQRSTUVWXYZ123";
+const gsize TEST_DATA_L = 29;
+
+void unit_test_openssl_roundtrip (CuTest* cu)
+{
+ const gchar *dekinfo;
+ GkrPkixResult res;
+ gboolean ret;
+ guchar *encrypted, *decrypted;
+ gsize n_encrypted, n_decrypted;
+ int i;
+
+ dekinfo = gkr_pkix_openssl_prep_dekinfo (refheaders);
+
+ ret = gkr_pkix_openssl_encrypt_block (dekinfo, "password", TEST_DATA, TEST_DATA_L, &encrypted, &n_encrypted);
+ CuAssert (cu, "couldn't openssl encrypt block", ret == TRUE);
+ CuAssert (cu, "no data returned from openssl encrypt", encrypted != NULL);
+ CuAssert (cu, "invalid amount of data returned from openssl encrypt", TEST_DATA_L <= n_encrypted);
+
+ res = gkr_pkix_openssl_decrypt_block (dekinfo, "password", encrypted, n_encrypted, &decrypted, &n_decrypted);
+ CuAssert (cu, "couldn't openssl decrypt block", res == GKR_PKIX_SUCCESS);
+ CuAssert (cu, "no data returned from openssl decrypt", decrypted != NULL);
+
+ /* Check that the data was decrypted properly */
+ CuAssert (cu, "decrypted data doesn't match length", n_decrypted >= TEST_DATA_L);
+ CuAssert (cu, "decrypted data doesn't match", memcmp (TEST_DATA, decrypted, TEST_DATA_L) == 0);
+
+ /* Check that the remainder is all zeros */
+ for (i = TEST_DATA_L; i < n_decrypted; ++i)
+ CuAssert (cu, "non null byte in padding", decrypted[i] == 0);
+}
Modified: trunk/pkix/tests/unit-test-pkix-parser.c
==============================================================================
--- trunk/pkix/tests/unit-test-pkix-parser.c (original)
+++ trunk/pkix/tests/unit-test-pkix-parser.c Mon Jul 7 21:17:26 2008
@@ -125,30 +125,43 @@
return TRUE;
}
-static gchar*
+static gboolean
ask_password (GkrPkixParser *parser, GQuark loc, gkrconstid digest,
- GQuark type, const gchar *details, guint n_prompts,
- gpointer user_data)
+ GQuark type, const gchar *details, gint *state,
+ gchar **password, gpointer user_data)
{
CuTest *cu = the_cu;
- g_assert (cu);
-
gchar *msg;
+ gint st;
- /* Should only be asking once per location */
- if (n_prompts > 0) {
- msg = g_strdup_printf ("decryption didn't work for: %s", g_quark_to_string (loc));
- CuAssert (cu, msg, FALSE);
- return NULL;
- }
-
+ g_assert (cu);
+ CuAssert (cu, "state is null", state != NULL);
+ CuAssert (cu, "state is bad", *state >= 0 && *state < 3);
+
+ st = *state;
+ (*state)++;
+
CuAssert (cu, "location is empty", loc != 0);
CuAssert (cu, "details is null", details != NULL);
- g_print ("getting password 'booo' for: %s\n", details);
-
- /* All our test encrypted stuff use this password */
- return gkr_secure_strdup ("booo");
+ /* Return "", null, and "booo" in that order */
+ switch (st) {
+ case 0:
+ *password = gkr_secure_strdup ("");
+ return TRUE;
+ case 1:
+ *password = NULL;
+ return TRUE;
+ case 2:
+ /* Most of our test encrypted stuff use this password */
+ g_print ("getting password 'booo' for: %s\n", details);
+ *password = gkr_secure_strdup ("booo");
+ return TRUE;
+ default:
+ msg = g_strdup_printf ("decryption didn't work for: %s", g_quark_to_string (loc));
+ CuAssert (cu, msg, FALSE);
+ return FALSE;
+ };
}
static void
Modified: trunk/pkix/tests/unit-test-pkix-serialize.c
==============================================================================
--- trunk/pkix/tests/unit-test-pkix-serialize.c (original)
+++ trunk/pkix/tests/unit-test-pkix-serialize.c Mon Jul 7 21:17:26 2008
@@ -67,28 +67,31 @@
g_free (path);
}
-static gchar*
+static gboolean
ask_password (GkrPkixParser *parser, GQuark loc, gkrconstid unique,
- GQuark type, const gchar *details, guint n_prompts,
- gpointer user_data)
+ GQuark type, const gchar *details, gint *state,
+ gchar **password, gpointer user_data)
{
CuTest *cu = (CuTest*)user_data;
gchar *msg;
/* Should only be asking once per location */
- if (n_prompts > 0) {
+ if (*state > 0) {
msg = g_strdup_printf ("decryption didn't work for: %s", g_quark_to_string (loc));
CuAssert (cu, msg, FALSE);
- return NULL;
+ return FALSE;
}
+ (*state)++;
+
CuAssert (cu, "type is zero", type != 0);
CuAssert (cu, "details is null", details != NULL);
g_print ("getting password 'booo' for: %s\n", details);
/* All our test encrypted stuff use this password */
- return gkr_secure_strdup ("booo");
+ *password = gkr_secure_strdup ("booo");
+ return TRUE;
}
void unit_test_serialize_certificate (CuTest* cu)
Modified: trunk/po/POTFILES.in
==============================================================================
--- trunk/po/POTFILES.in (original)
+++ trunk/po/POTFILES.in Mon Jul 7 21:17:26 2008
@@ -5,7 +5,10 @@
data/gnome-keyring.schemas.in
library/gnome-keyring-utils.c
keyrings/gkr-keyring-login.c
-pk/gkr-pk-object-storage.c
+keyrings/gkr-keyring.c
+pk/gkr-pk-index.c
+pk/gkr-pk-storage.c
pkix/gkr-pkix-parser.c
pkix/gkr-pkix-serialize.c
+ssh/gkr-ssh-storage.c
ui/gkr-ask-tool.c
Modified: trunk/reference/tmpl/gnome-keyring-item-info.sgml
==============================================================================
--- trunk/reference/tmpl/gnome-keyring-item-info.sgml (original)
+++ trunk/reference/tmpl/gnome-keyring-item-info.sgml Mon Jul 7 21:17:26 2008
@@ -26,6 +26,7 @@
@GNOME_KEYRING_ITEM_NOTE:
@GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD:
@GNOME_KEYRING_ITEM_ENCRYPTION_KEY_PASSWORD:
+ GNOME_KEYRING_ITEM_PK_STORAGE:
@GNOME_KEYRING_ITEM_LAST_TYPE:
<!-- ##### TYPEDEF GnomeKeyringItemInfo ##### -->
Modified: trunk/ssh/Makefile.am
==============================================================================
--- trunk/ssh/Makefile.am (original)
+++ trunk/ssh/Makefile.am Mon Jul 7 21:17:26 2008
@@ -16,8 +16,17 @@
gkr-ssh-daemon-io.c \
gkr-ssh-daemon-ops.c \
gkr-ssh-private.h \
- gkr-ssh-proto.c
+ gkr-ssh-proto.c \
+ gkr-ssh-storage.c gkr-ssh-storage.h
libgkr_ssh_la_LIBADD = \
$(GLIB_LIBS) \
$(GOBJECT_LIBS)
+
+if WITH_TESTS
+TESTS_DIR = tests
+else
+TESTS_DIR =
+endif
+
+SUBDIRS = . $(TESTS_DIR)
Modified: trunk/ssh/gkr-ssh-daemon-io.c
==============================================================================
--- trunk/ssh/gkr-ssh-daemon-io.c (original)
+++ trunk/ssh/gkr-ssh-daemon-io.c Mon Jul 7 21:17:26 2008
@@ -42,7 +42,7 @@
#include "common/gkr-daemon-util.h"
#include "common/gkr-secure-memory.h"
-#include "pk/gkr-pk-object-storage.h"
+#include "pk/gkr-pk-storage.h"
#ifndef HAVE_SOCKLEN_T
#define socklen_t int
@@ -175,7 +175,7 @@
gkr_async_register_cancel (close_fd, &client->sock);
/* Make sure everything is in sync for this connection */
- gkr_pk_object_storage_refresh (NULL);
+ gkr_pk_storage_refresh_all ();
while (!gkr_async_is_stopping ()) {
Modified: trunk/ssh/gkr-ssh-daemon-ops.c
==============================================================================
--- trunk/ssh/gkr-ssh-daemon-ops.c (original)
+++ trunk/ssh/gkr-ssh-daemon-ops.c Mon Jul 7 21:17:26 2008
@@ -264,6 +264,7 @@
{
GList *objects, *pubkeys, *l;
GkrPkPubkey *pub;
+ gsize blobpos;
const gchar *label;
/* Only find the keys that have usage = ssh */
@@ -285,10 +286,17 @@
pub = GKR_PK_PUBKEY (l->data);
g_return_val_if_fail (GKR_IS_PK_PUBKEY (pub), FALSE);
+ /* Add a space for the key blob length */
+ blobpos = resp->len;
+ gkr_buffer_add_uint32 (resp, 0);
+
if (!gkr_ssh_proto_write_public (resp, gkr_pk_pubkey_get_algorithm (pub),
gkr_pk_pubkey_get_key (pub)))
return FALSE;
+ /* Write back the blob length */
+ gkr_buffer_set_uint32 (resp, blobpos, (resp->len - blobpos) - 4);
+
/* And now a per key comment */
label = gkr_pk_object_get_label (GKR_PK_OBJECT (pub));
gkr_buffer_add_string (resp, label ? label : "");
@@ -387,12 +395,18 @@
gsize offset;
gcry_error_t gcry;
gboolean ret;
- guint blobpos;
+ guint blobpos, sz;
guchar *hash;
int algo;
int halgo, n_algo;
offset = 5;
+
+ /* The key packet size */
+ if (!gkr_buffer_get_uint32 (req, offset, &offset, &sz))
+ return FALSE;
+
+ /* The key itself */
if (!gkr_ssh_proto_read_public (req, &offset, &s_key, &algo))
return FALSE;
@@ -624,8 +638,15 @@
GkrPkObject *obj;
gcry_sexp_t skey;
gsize offset;
+ guint sz;
offset = 5;
+
+ /* The key packet size */
+ if (!gkr_buffer_get_uint32 (req, offset, &offset, &sz))
+ return FALSE;
+
+ /* The public key itself */
if (!gkr_ssh_proto_read_public (req, &offset, &skey, NULL))
return FALSE;
Modified: trunk/ssh/gkr-ssh-proto.c
==============================================================================
--- trunk/ssh/gkr-ssh-proto.c (original)
+++ trunk/ssh/gkr-ssh-proto.c Mon Jul 7 21:17:26 2008
@@ -161,13 +161,8 @@
{
gboolean ret;
gchar *stype;
- guint sz;
int alg;
- /* The key packet size */
- if (!gkr_buffer_get_uint32 (req, *offset, offset, &sz))
- return FALSE;
-
/* The string algorithm */
if (!gkr_buffer_get_string (req, *offset, offset, &stype, (GkrBufferAllocator)g_realloc))
return FALSE;
@@ -425,13 +420,8 @@
gkr_ssh_proto_write_public (GkrBuffer *resp, int algo, gcry_sexp_t key)
{
gboolean ret = FALSE;
- gsize blobpos;
const gchar *salgo;
- /* Add a space for the key blob length */
- blobpos = resp->len;
- gkr_buffer_add_uint32 (resp, 0);
-
salgo = gkr_ssh_proto_algo_to_keytype (algo);
g_assert (salgo);
gkr_buffer_add_string (resp, salgo);
@@ -449,9 +439,6 @@
g_return_val_if_reached (FALSE);
break;
}
-
- /* Write back the blob length */
- gkr_buffer_set_uint32 (resp, blobpos, (resp->len - blobpos) - 4);
return ret;
}
Added: trunk/ssh/gkr-ssh-storage.c
==============================================================================
--- (empty file)
+++ trunk/ssh/gkr-ssh-storage.c Mon Jul 7 21:17:26 2008
@@ -0,0 +1,934 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gkr-ssh-storage.c - Storage of SSH keys
+
+ Copyright (C) 2008 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 "config.h"
+
+#include "gkr-ssh-private.h"
+#include "gkr-ssh-storage.h"
+
+#include "common/gkr-buffer.h"
+#include "common/gkr-crypto.h"
+#include "common/gkr-location.h"
+#include "common/gkr-location-watch.h"
+#include "common/gkr-secure-memory.h"
+
+#include "keyrings/gkr-keyring-login.h"
+
+#include "pkcs11/pkcs11.h"
+
+#include "pk/gkr-pk-privkey.h"
+#include "pk/gkr-pk-object-manager.h"
+#include "pk/gkr-pk-util.h"
+
+#include "pkix/gkr-pkix-asn1.h"
+#include "pkix/gkr-pkix-der.h"
+#include "pkix/gkr-pkix-openssl.h"
+#include "pkix/gkr-pkix-pem.h"
+#include "pkix/gkr-pkix-types.h"
+
+#include "ui/gkr-ask-daemon.h"
+#include "ui/gkr-ask-request.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <stdarg.h>
+
+typedef struct _GkrSshStoragePrivate GkrSshStoragePrivate;
+
+struct _GkrSshStoragePrivate {
+ gkrid specific_load_request;
+ GQuark home_location;
+ GkrPkIndex *index;
+ GkrLocationWatch *watch;
+};
+
+#define GKR_SSH_STORAGE_GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((o), GKR_TYPE_SSH_STORAGE, GkrSshStoragePrivate))
+
+G_DEFINE_TYPE(GkrSshStorage, gkr_ssh_storage, GKR_TYPE_PK_STORAGE);
+
+static GQuark PEM_RSA_PRIVATE_KEY;
+static GQuark PEM_DSA_PRIVATE_KEY;
+
+#define NO_VALUE GUINT_TO_POINTER (TRUE)
+
+/* -----------------------------------------------------------------------------
+ * HELPERS
+ */
+
+static GQuark
+location_for_storing_private_key (GkrSshStorage *storage, gcry_sexp_t sexp)
+{
+ GkrSshStoragePrivate *pv = GKR_SSH_STORAGE_GET_PRIVATE (storage);
+ const gchar *pref;
+ gchar *name;
+ GQuark loc = 0;
+ int algo, i;
+
+ /* What kind of key is it? */
+ algo = gkr_crypto_skey_parse (sexp, &algo, NULL, NULL);
+ switch (algo) {
+ case GCRY_PK_RSA:
+ pref = "id_rsa";
+ break;
+ case GCRY_PK_DSA:
+ pref = "id_dsa";
+ break;
+ default:
+ pref = "id_xsa";
+ break;
+ };
+
+ /* Find a file that's unique */
+ for (i = 0; i < ~0; i++) {
+ name = (i == 0) ? g_strdup (pref) : g_strdup_printf ("%s.%d", pref, i);
+ loc = gkr_location_from_child (pv->home_location, name);
+ if (!gkr_location_test_file(loc, G_FILE_TEST_EXISTS))
+ break;
+ g_free (name);
+ loc = 0;
+ }
+
+ return loc;
+}
+
+static GkrPkObject*
+prepare_object (GkrSshStorage *storage, GQuark location,
+ gkrconstid digest, gboolean is_public)
+{
+ GkrPkObjectManager *manager;
+ GkrPkObject *object;
+ GType gtype;
+
+ manager = gkr_pk_object_manager_for_token ();
+ object = gkr_pk_object_manager_find_by_digest (manager, digest);
+
+ /* The object already exists just reference it */
+ if (object) {
+ gkr_pk_storage_add_object (GKR_PK_STORAGE (storage), object);
+ return object;
+ }
+
+ if (is_public)
+ gtype = GKR_TYPE_PK_PUBKEY;
+ else
+ gtype = GKR_TYPE_PK_PRIVKEY;
+
+ object = g_object_new (gtype, "manager", manager, "location", location,
+ "digest", digest, NULL);
+ gkr_pk_storage_add_object (GKR_PK_STORAGE (storage), object);
+
+ /* Object was reffed */
+ g_object_unref (object);
+ return object;
+}
+
+static GQuark
+public_location_for_private (GQuark loc)
+{
+ gchar *pstr;
+ GQuark ploc;
+
+ pstr = g_strdup_printf ("%s.pub", gkr_location_to_string (loc));
+ ploc = gkr_location_from_string (pstr);
+ g_free (pstr);
+
+ return ploc;
+}
+
+static gboolean
+storage_load_public_key (GkrSshStorage *storage, GQuark loc, GError **err)
+{
+ GkrPkObject *object;
+ GkrPkixResult res;
+ gcry_sexp_t sexp;
+ gkrid digest;
+ gchar *comment;
+ guchar *data;
+ gsize n_data;
+
+ g_return_val_if_fail (loc, FALSE);
+ g_return_val_if_fail (!err || !*err, FALSE);
+
+ if (!gkr_location_read_file (loc, &data, &n_data, err))
+ return FALSE;
+
+ res = gkr_ssh_storage_load_public_key (data, n_data, &sexp, &comment);
+ if (res == GKR_PKIX_FAILURE) {
+ g_set_error (err, GKR_SSH_STORAGE_ERROR, 0, _("Couldn't read secure shell key public key: %s"),
+ g_quark_to_string (loc));
+ return FALSE;
+ } else if (res == GKR_PKIX_UNRECOGNIZED) {
+ g_set_error (err, GKR_SSH_STORAGE_ERROR, 0, _("Invalid secure shell public key at: %s"),
+ g_quark_to_string (loc));
+ return FALSE;
+ }
+
+ digest = gkr_id_new_digest (data, n_data);
+
+ /* Prepare and setup the object */
+ object = prepare_object (storage, loc, digest, TRUE);
+ g_object_set (object, "orig-label", comment, NULL);
+ g_object_set (object, "gcrypt-sexp", sexp, NULL);
+
+
+ gkr_id_free (digest);
+ g_free (comment);
+ return TRUE;
+}
+
+static gboolean
+storage_write_public_key (GkrSshStorage *storage, gcry_sexp_t sexp,
+ GQuark loc, GError **err)
+{
+ guchar *data;
+ gsize n_data;
+ gboolean ret;
+
+ g_return_val_if_fail (loc, FALSE);
+ g_return_val_if_fail (!err || !*err, FALSE);
+
+ /* TODO: What about the comment? */
+ data = gkr_ssh_storage_write_public_key(sexp, NULL, &n_data);
+ if (!data) {
+ g_set_error (err, GKR_SSH_STORAGE_ERROR, 0, _("Couldn't encode secure shell public key."));
+ return FALSE;
+ }
+
+ /* And write that to disk */
+ ret = gkr_location_write_file (loc, data, n_data, err);
+ g_free (data);
+ return ret;
+}
+
+static gboolean
+store_public_key_for_private (GkrSshStorage *storage, GkrPkObject *priv, GError **err)
+{
+ gcry_sexp_t sexp, psexp;
+ gboolean ret;
+ GQuark ploc;
+
+ g_return_val_if_fail (GKR_IS_PK_PRIVKEY (priv), FALSE);
+ g_return_val_if_fail (priv->location, FALSE);
+
+ /* Don't have a key to write out :( */
+ g_object_get (priv, "gcrypt-sexp", &sexp, NULL);
+ if (!sexp)
+ return TRUE;
+
+ /* Convert to a public key */
+ if (!gkr_crypto_skey_private_to_public (sexp, &psexp))
+ g_return_val_if_reached (FALSE);
+
+ /* And then store that public key next to the private */
+ ploc = public_location_for_private (priv->location);
+ ret = storage_write_public_key (storage, psexp, ploc, err);
+ gcry_sexp_release (psexp);
+
+ return ret;
+}
+
+static GkrPkixResult
+load_encrypted_key (GkrSshStorage *storage, gkrid digest, GQuark location,
+ const gchar *dekinfo, const guchar *data, gsize n_data,
+ gcry_sexp_t *skey)
+{
+ GkrPkixResult ret;
+ gchar *password;
+ guchar *decrypted;
+ gsize n_decrypted;
+ gboolean res;
+ gint l, state;
+
+ state = GKR_PK_STORAGE_PASSWD_STATE;
+ while (!gkr_async_is_stopping ()) {
+
+ /* Get the password to try */
+ if (!gkr_pk_storage_get_load_password (GKR_PK_STORAGE (storage), location,
+ digest, GKR_PKIX_PRIVATE_KEY, NULL,
+ &state, &password))
+ return GKR_PKIX_SUCCESS;
+
+ decrypted = NULL;
+ n_decrypted = 0;
+
+ /* Decrypt, this will result in garble if invalid password */
+ res = gkr_pkix_openssl_decrypt_block (dekinfo, password, data, n_data,
+ &decrypted, &n_decrypted);
+ gkr_secure_free (password);
+
+ if (!res)
+ return GKR_PKIX_UNRECOGNIZED;
+
+ g_assert (decrypted);
+
+ /* Unpad the DER data */
+ l = gkr_pkix_asn1_element_length (decrypted, n_decrypted);
+ if (l > 0)
+ n_decrypted = l;
+
+ /* Try to parse */
+ ret = gkr_pkix_der_read_private_key (decrypted, n_decrypted, skey);
+ gkr_secure_free (decrypted);
+
+ if (ret != GKR_PKIX_UNRECOGNIZED)
+ return ret;
+ }
+
+ return GKR_PKIX_FAILURE;
+}
+
+
+static void
+add_corresponding_public (GkrSshStorage *storage, GQuark loc)
+{
+ GError *err = NULL;
+ GQuark ploc;
+
+ g_return_if_fail (loc);
+ ploc = public_location_for_private (loc);
+
+ if (gkr_location_test_file (ploc, G_FILE_TEST_IS_REGULAR)) {
+ if (!storage_load_public_key (storage, ploc, &err)) {
+ g_message ("couldn't parse public key: %s: %s", g_quark_to_string (ploc),
+ err && err->message ? err->message : "");
+ g_clear_error (&err);
+ }
+ }
+}
+
+typedef struct _Load {
+ GkrSshStorage *storage;
+ GQuark location;
+ gboolean seen;
+ GkrPkixResult result;
+} Load;
+
+static void
+parsed_pem_block (GQuark type, const guchar *data, gsize n_data,
+ GHashTable *headers, gpointer user_data)
+{
+ Load *ctx = (Load*)user_data;
+ GkrSshStoragePrivate *pv = GKR_SSH_STORAGE_GET_PRIVATE (ctx->storage);
+ gcry_sexp_t sexp;
+ GkrPkObject *object;
+ const gchar *dekinfo;
+ gkrid digest;
+
+ /* Only handle SSHv2 private keys */
+ if (type != PEM_RSA_PRIVATE_KEY && type != PEM_DSA_PRIVATE_KEY)
+ return;
+
+ /* Only parse first key in the file */
+ if (ctx->seen)
+ return;
+
+ digest = gkr_id_new_digest (data, n_data);
+ ctx->seen = TRUE;
+
+ /* If it's encrypted ... */
+ dekinfo = gkr_pkix_openssl_get_dekinfo (headers);
+ if (dekinfo) {
+ /* This key was specifically requested to be loaded */
+ if (gkr_id_equals (digest, pv->specific_load_request)) {
+ ctx->result = load_encrypted_key (ctx->storage, digest, ctx->location,
+ dekinfo, data, n_data, &sexp);
+
+ /* Nobody's asking us to load this key just yet */
+ } else {
+ ctx->result = GKR_PKIX_SUCCESS;
+ sexp = NULL;
+ }
+
+ /* not encryted, just load the data */
+ } else {
+ ctx->result = gkr_pkix_der_read_private_key (data, n_data, &sexp);
+ }
+
+ if (ctx->result == GKR_PKIX_SUCCESS) {
+ if (gkr_id_equals (pv->specific_load_request, digest))
+ pv->specific_load_request = NULL;
+
+ /* Prepare and setup the object */
+ object = prepare_object (ctx->storage, ctx->location, digest, FALSE);
+ if (sexp)
+ g_object_set (object, "gcrypt-sexp", sexp, NULL);
+
+ gkr_id_free (digest);
+ }
+}
+
+static gboolean
+storage_load_private_key (GkrSshStorage *storage, GQuark loc, GError **err)
+{
+ Load ctx;
+ guchar *data;
+ gsize n_data;
+ guint num;
+
+ g_return_val_if_fail (loc, FALSE);
+ g_return_val_if_fail (!err || !*err, FALSE);
+
+ if (!gkr_location_read_file (loc, &data, &n_data, err))
+ return FALSE;
+
+ memset (&ctx, 0, sizeof (ctx));
+ ctx.storage = storage;
+ ctx.location = loc;
+
+ num = gkr_pkix_pem_parse (data, n_data, parsed_pem_block, &ctx);
+
+ /* Didn't find any private key there */
+ if (num == 0)
+ return TRUE;
+
+ if (ctx.result == GKR_PKIX_FAILURE) {
+ g_set_error (err, GKR_SSH_STORAGE_ERROR, 0, _("Couldn't read secure shell key private key: %s"),
+ g_quark_to_string (loc));
+ return FALSE;
+ } else if (ctx.result == GKR_PKIX_UNRECOGNIZED) {
+ g_set_error (err, GKR_SSH_STORAGE_ERROR, 0, _("Invalid secure shell private key at: %s"),
+ g_quark_to_string (loc));
+ return FALSE;
+ }
+
+ /* Load the corresponding public key */
+ add_corresponding_public (storage, loc);
+
+ return TRUE;
+}
+
+static gkrid
+storage_write_private_key (GkrSshStorage *storage, gcry_sexp_t sexp,
+ GQuark loc, const gchar *password, GError **err)
+{
+ GHashTable *headers;
+ const gchar *dekinfo;
+ GQuark type;
+ guchar *data, *encrypted, *result;
+ gsize n_data, n_encrypted, n_result;
+ gboolean is_priv;
+ gkrid digest = NULL;
+ int algo;
+
+ data = encrypted = result = NULL;
+ headers = NULL;
+
+ /* What kind of key is it? */
+ algo = gkr_crypto_skey_parse (sexp, &algo, &is_priv, NULL);
+ g_return_val_if_fail (is_priv == TRUE, NULL);
+ g_return_val_if_fail (algo != 0, NULL);
+
+ /* Figure out what kind of BEGIN/END PEM we need */
+ if (algo == GCRY_PK_RSA)
+ type = PEM_RSA_PRIVATE_KEY;
+ else if (algo == GCRY_PK_DSA)
+ type = PEM_DSA_PRIVATE_KEY;
+ else
+ g_return_val_if_reached (NULL);
+
+ /* Write out the raw key to memory */
+ data = gkr_pkix_der_write_private_key (sexp, &n_data);
+ g_return_val_if_fail (data, NULL);
+
+ /* Write an encrypted private key */
+ if (password) {
+ headers = gkr_pkix_pem_headers_new ();
+ dekinfo = gkr_pkix_openssl_prep_dekinfo (headers);
+
+ if (!gkr_pkix_openssl_encrypt_block (dekinfo, password, data, n_data,
+ &encrypted, &n_encrypted)) {
+ g_set_error (err, GKR_SSH_STORAGE_ERROR, 0,
+ _("Couldn't encrypt the SSH key to store it."));
+ goto done;
+ }
+ digest = gkr_id_new_digest (encrypted, n_encrypted);
+ result = gkr_pkix_pem_write (encrypted, n_encrypted, type, headers, &n_result);
+ g_free (encrypted);
+
+ /* Write a non-encrypted private key */
+ } else {
+ digest = gkr_id_new_digest (data, n_data);
+ result = gkr_pkix_pem_write (data, n_data, type, headers, &n_result);
+ }
+
+ /* Make sure it worked */
+ if (!result) {
+ g_set_error (err, GKR_SSH_STORAGE_ERROR, 0,
+ _("Couldn't encode the SSH key to store it."));
+ gkr_id_free (digest);
+ digest = NULL;
+ goto done;
+ }
+
+ /* Now write it to the file */
+ if (gkr_location_write_file (loc, result, n_result, err)) {
+ gkr_id_free (digest);
+ digest = NULL;
+ }
+
+done:
+ if (headers)
+ g_hash_table_destroy (headers);
+ gkr_secure_free (data);
+ g_free (result);
+ g_free (encrypted);
+
+ return digest;
+}
+
+static void
+location_load (GkrLocationWatch *watch, GQuark loc, GkrSshStorage *storage)
+{
+ GError *err = NULL;
+
+ /* We only get notified for private keys */
+ if (!storage_load_private_key (storage, loc, &err)) {
+ g_message ("couldn't parse data: %s: %s", g_quark_to_string (loc),
+ err && err->message ? err->message : "");
+ g_clear_error (&err);
+ }
+}
+
+static void
+location_remove (GkrLocationWatch *watch, GQuark loc, GkrSshStorage *storage)
+{
+ /* Remove key that is at that location */
+ gkr_pk_storage_clr_objects (GKR_PK_STORAGE (storage), loc);
+
+ /* We only watch private keys, so try and clear out the public */
+ gkr_pk_storage_clr_objects (GKR_PK_STORAGE (storage),
+ public_location_for_private (loc));
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static void
+gkr_ssh_storage_refresh (GkrPkStorage *storage)
+{
+ GkrSshStoragePrivate *pv = GKR_SSH_STORAGE_GET_PRIVATE (storage);
+ gkr_location_watch_refresh (pv->watch, FALSE);
+}
+
+static gboolean
+gkr_ssh_storage_load (GkrPkStorage *storage, GkrPkObject *obj, GError **err)
+{
+ GkrSshStoragePrivate *pv = GKR_SSH_STORAGE_GET_PRIVATE (storage);
+ gboolean ret = FALSE;
+
+ g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
+ g_return_val_if_fail (obj->storage == storage, FALSE);
+ g_return_val_if_fail (obj->location, FALSE);
+ g_return_val_if_fail (pv->specific_load_request == NULL, FALSE);
+
+ g_object_ref (obj);
+
+ /* Make note of the specific load request */
+ pv->specific_load_request = obj->digest;
+
+ /* Load a private key from this location */
+ if (GKR_IS_PK_PRIVKEY (obj))
+ storage_load_private_key (GKR_SSH_STORAGE (storage), obj->location, err);
+
+ /* Load a private key from this location */
+ else if (GKR_IS_PK_PUBKEY (obj))
+ storage_load_public_key (GKR_SSH_STORAGE (storage), obj->location, err);
+
+ else
+ g_return_val_if_reached (FALSE);
+
+ /* See if it was seen */
+ if (pv->specific_load_request != NULL) {
+ g_set_error (err, GKR_SSH_STORAGE_ERROR, 0, "The object was not found at: %s",
+ g_quark_to_string (obj->location));
+ pv->specific_load_request = NULL;
+ goto done;
+ }
+
+ /*
+ * At this point, if we were loading a public key, it should be all loaded,
+ * including encrypted parts. Write out the public key if needed.
+ */
+ if (GKR_IS_PK_PRIVKEY (obj))
+ store_public_key_for_private (GKR_SSH_STORAGE (storage), obj, NULL);
+
+ ret = TRUE;
+
+done:
+ g_object_unref (obj);
+ return ret;
+}
+
+static gboolean
+gkr_ssh_storage_store (GkrPkStorage *stor, GkrPkObject *obj, GError **err)
+{
+ GkrSshStorage *storage;
+ gcry_sexp_t sexp;
+ gchar *password;
+ gchar *label;
+ gkrid digest;
+ gboolean save, ret;
+ GQuark loc;
+
+ g_return_val_if_fail (!err || !*err, FALSE);
+ g_return_val_if_fail (GKR_IS_SSH_STORAGE (stor), FALSE);
+ g_return_val_if_fail (obj->storage == NULL, FALSE);
+ g_return_val_if_fail (obj->location == 0, FALSE);
+
+ storage = GKR_SSH_STORAGE (stor);
+
+ /* We don't yet support storing arbitrary public keys */
+ if (GKR_IS_PK_PUBKEY (obj))
+ return TRUE;
+
+ g_return_val_if_fail (GKR_IS_PK_PRIVKEY (obj), FALSE);
+
+ /* Pull out the actual part of the key */
+ g_object_get (obj, "gcrypt-sexp", &sexp, NULL);
+ g_return_val_if_fail (sexp, FALSE);
+
+ /* Find a good location to store this key */
+ loc = location_for_storing_private_key (storage, sexp);
+ g_return_val_if_fail (loc, FALSE);
+
+ /* Get a password for this key, determines whether encrypted or not */
+ label = gkr_pk_object_get_label (obj);
+ ret = gkr_pk_storage_get_store_password (stor, loc, GKR_PKIX_PRIVATE_KEY,
+ label, &save, &password);
+ g_free (label);
+
+ /* Prompt for a password was denied */
+ if (!ret)
+ return TRUE;
+
+ /* Store the private key */
+ digest = storage_write_private_key (storage, sexp, loc, password, err);
+ gkr_secure_strfree (password);
+
+ if (!digest)
+ return FALSE;
+
+ /* The object now has a (possibly new) location */
+ g_object_set (obj, "location", loc, "storage", stor, "digest", digest, NULL);
+ gkr_id_free (digest);
+
+ /* Now store the public key in place if possible */
+ return store_public_key_for_private (storage, obj, err);
+}
+
+static gboolean
+gkr_ssh_storage_remove (GkrPkStorage *storage, GkrPkObject *obj, GError **err)
+{
+ GQuark ploc;
+
+ g_return_val_if_fail (!err || !*err, FALSE);
+ g_return_val_if_fail (GKR_IS_SSH_STORAGE (storage), FALSE);
+ g_return_val_if_fail (obj->storage == storage, FALSE);
+ g_return_val_if_fail (obj->location, FALSE);
+
+ /* Delete the public key along with the private */
+ if (GKR_IS_PK_PRIVKEY (obj)) {
+ ploc = public_location_for_private (obj->location);
+ if (!gkr_location_delete_file (ploc, err))
+ return FALSE;
+ }
+
+ /* Delete the object itself */
+ if (!gkr_location_delete_file (obj->location, err))
+ return FALSE;
+
+ gkr_ssh_storage_refresh (storage);
+ return TRUE;
+}
+
+static GkrPkIndex*
+gkr_ssh_storage_index (GkrPkStorage *storage, GQuark unused)
+{
+ GkrSshStoragePrivate *pv = GKR_SSH_STORAGE_GET_PRIVATE (storage);
+ GnomeKeyringAttributeList *attrs;
+ GQuark kloc;
+
+ if (!pv->index) {
+ /* We default to a keyring stored on the computer */
+ kloc = gkr_location_from_child (GKR_LOCATION_VOLUME_LOCAL,
+ "pk-storage.keyring");
+
+ /* Default attributes for our index */
+ attrs = gnome_keyring_attribute_list_new ();
+ gnome_keyring_attribute_list_append_string (attrs, "purposes", "ssh-authentication");
+
+ pv->index = gkr_pk_index_open (kloc, "pk-storage", attrs);
+ gnome_keyring_attribute_list_free (attrs);
+
+ g_return_val_if_fail (pv->index, NULL);
+ }
+
+ return pv->index;
+}
+
+
+static void
+gkr_ssh_storage_init (GkrSshStorage *storage)
+{
+ GkrSshStoragePrivate *pv = GKR_SSH_STORAGE_GET_PRIVATE (storage);
+
+ pv->specific_load_request = NULL;
+ pv->home_location = gkr_location_from_child (GKR_LOCATION_VOLUME_HOME, ".ssh/");
+
+ /* Watch all ~/.ssh/id_?sa* except for *.pub files */
+ pv->watch = gkr_location_watch_new (NULL, GKR_LOCATION_VOLUME_HOME, ".ssh",
+ "id_?sa*", "*.pub");
+ g_return_if_fail (pv->watch);
+
+ g_signal_connect (pv->watch, "location-added", G_CALLBACK (location_load), storage);
+ g_signal_connect (pv->watch, "location-changed", G_CALLBACK (location_load), storage);
+ g_signal_connect (pv->watch, "location-removed", G_CALLBACK (location_remove), storage);
+}
+
+static void
+gkr_ssh_storage_dispose (GObject *obj)
+{
+ GkrSshStorage *storage = GKR_SSH_STORAGE (obj);
+ GkrSshStoragePrivate *pv = GKR_SSH_STORAGE_GET_PRIVATE (obj);
+
+ g_signal_handlers_disconnect_by_func (pv->watch, location_load, storage);
+ g_signal_handlers_disconnect_by_func (pv->watch, location_remove, storage);
+
+ if (pv->index)
+ g_object_unref (pv->index);
+ pv->index = NULL;
+
+ G_OBJECT_CLASS (gkr_ssh_storage_parent_class)->dispose (obj);
+}
+
+static void
+gkr_ssh_storage_finalize (GObject *obj)
+{
+ GkrSshStoragePrivate *pv = GKR_SSH_STORAGE_GET_PRIVATE (obj);
+
+ g_object_unref (pv->watch);
+ pv->watch = NULL;
+
+ g_assert (pv->index == NULL);
+
+ G_OBJECT_CLASS (gkr_ssh_storage_parent_class)->finalize (obj);
+}
+
+static void
+gkr_ssh_storage_class_init (GkrSshStorageClass *klass)
+{
+ GkrPkStorageClass *storage_class = GKR_PK_STORAGE_CLASS (klass);
+ GObjectClass *gobject_class;
+
+ gobject_class = (GObjectClass*)klass;
+ gobject_class->dispose = gkr_ssh_storage_dispose;
+ gobject_class->finalize = gkr_ssh_storage_finalize;
+
+ storage_class->refresh = gkr_ssh_storage_refresh;
+ storage_class->load = gkr_ssh_storage_load;
+ storage_class->store = gkr_ssh_storage_store;
+ storage_class->remove = gkr_ssh_storage_remove;
+ storage_class->index = gkr_ssh_storage_index;
+
+ gkr_ssh_storage_parent_class = g_type_class_peek_parent (klass);
+
+ PEM_RSA_PRIVATE_KEY = g_quark_from_static_string ("RSA PRIVATE KEY");
+ PEM_DSA_PRIVATE_KEY = g_quark_from_static_string ("DSA PRIVATE KEY");
+
+ g_type_class_add_private (gobject_class, sizeof (GkrSshStoragePrivate));
+}
+
+/* -------------------------------------------------------------------------------
+ * PUBLIC FUNCTIONS
+ */
+
+GQuark
+gkr_ssh_storage_get_error_domain (void)
+{
+ static GQuark domain = 0;
+ if (domain == 0)
+ domain = g_quark_from_static_string ("gkr-ssh-storage-error");
+ return domain;
+}
+
+gboolean
+gkr_ssh_storage_initialize (void)
+{
+ GkrPkStorage *storage;
+
+ storage = g_object_new (GKR_TYPE_SSH_STORAGE, NULL);
+ gkr_pk_storage_register (storage, FALSE);
+ g_object_unref (storage);
+
+ return TRUE;
+}
+
+GkrPkixResult
+gkr_ssh_storage_load_public_key (const guchar *data, gsize n_data,
+ gcry_sexp_t *sexp, gchar **comment)
+{
+ GkrBuffer buf;
+ const guchar *at;
+ guchar *decoded;
+ gsize n_decoded;
+ gsize offset;
+ gchar *val;
+ gboolean ret;
+ gint state, algo;
+ guint save;
+
+ g_return_val_if_fail (data, GKR_PKIX_FAILURE);
+ g_return_val_if_fail (sexp, GKR_PKIX_FAILURE);
+
+ /* Look for a key line */
+ for (;;) {
+ /* Eat space at the front */
+ while (n_data > 0 && g_ascii_isspace (data[0])) {
+ ++data;
+ --n_data;
+ }
+
+ /* Not a comment or blank line? Then parse... */
+ if (data[0] != '#')
+ break;
+
+ /* Skip to the next line */
+ at = memchr (data, '\n', n_data);
+ if (!at)
+ return GKR_PKIX_UNRECOGNIZED;
+ at += 1;
+ n_data -= (at - data);
+ data = at;
+ }
+
+ /* Limit to use only the first line */
+ at = memchr (data, '\n', n_data);
+ if (at != NULL)
+ n_data = at - data;
+
+ /* Find the first space */
+ at = memchr (data, ' ', n_data);
+ if (!at) {
+ g_message ("SSH public key missing space");
+ return GKR_PKIX_UNRECOGNIZED;
+ }
+
+ /* Parse the key type */
+ val = g_strndup ((gchar*)data, at - data);
+ algo = gkr_ssh_proto_keytype_to_algo (val);
+ if (!algo)
+ g_message ("Unsupported or unknown SSH key algorithm: %s", val);
+ g_free (val);
+ if (!algo)
+ return GKR_PKIX_UNRECOGNIZED;
+
+ /* Skip more whitespace */
+ n_data -= (at - data);
+ data = at;
+ while (n_data > 0 && (data[0] == ' ' || data[0] == '\t')) {
+ ++data;
+ --n_data;
+ }
+
+ /* Find the next whitespace, or the end */
+ at = memchr (data, ' ', n_data);
+ if (at == NULL)
+ at = data + n_data;
+
+ /* Decode the base64 key */
+ save = state = 0;
+ decoded = g_malloc (n_data * 3 / 4);
+ n_decoded = g_base64_decode_step ((gchar*)data, n_data, decoded, &state, &save);
+
+ /* Parse the actual key */
+ gkr_buffer_init_static (&buf, decoded, n_decoded);
+ offset = 0;
+ ret = gkr_ssh_proto_read_public (&buf, &offset, sexp, NULL);
+ g_free (decoded);
+ if (!ret) {
+ g_message ("failed to parse base64 part of SSH key");
+ return GKR_PKIX_FAILURE;
+ }
+
+ /* Skip more whitespace */
+ n_data -= (at - data);
+ data = at;
+ while (n_data > 0 && (data[0] == ' ' || data[0] == '\t')) {
+ ++data;
+ --n_data;
+ }
+
+ /* If there's data left, its the comment */
+ if (comment && n_data)
+ *comment = g_strndup ((gchar*)data, n_data);
+
+ return GKR_PKIX_SUCCESS;
+}
+
+guchar*
+gkr_ssh_storage_write_public_key (gcry_sexp_t sexp, gchar *comment,
+ gsize *n_data)
+{
+ GString *result;
+ GkrBuffer buffer;
+ const gchar *type;
+ gchar *encoded;
+ gboolean is_priv;
+ int algo;
+
+ g_return_val_if_fail (n_data, NULL);
+ g_return_val_if_fail (sexp, NULL);
+
+ result = g_string_sized_new (4096);
+
+ if (!gkr_crypto_skey_parse (sexp, &algo, &is_priv, NULL))
+ g_return_val_if_reached (NULL);
+ g_return_val_if_fail (is_priv == FALSE, NULL);
+ g_return_val_if_fail (algo != 0, NULL);
+
+ type = gkr_ssh_proto_algo_to_keytype (algo);
+ g_return_val_if_fail (type, NULL);
+
+ g_string_append (result, type);
+ g_string_append_c (result, ' ');
+
+ gkr_buffer_init_full (&buffer, 4096, (GkrBufferAllocator)g_realloc);
+ gkr_ssh_proto_write_public (&buffer, algo, sexp);
+
+ encoded = g_base64_encode (buffer.buf, buffer.len);
+ gkr_buffer_uninit (&buffer);
+
+ g_return_val_if_fail (encoded, NULL);
+ g_string_append (result, encoded);
+
+ if (comment) {
+ g_string_append_c (result, ' ');
+ g_string_append (result, comment);
+ }
+
+ *n_data = result->len;
+ return (guchar*)g_string_free (result, FALSE);
+}
Added: trunk/ssh/gkr-ssh-storage.h
==============================================================================
--- (empty file)
+++ trunk/ssh/gkr-ssh-storage.h Mon Jul 7 21:17:26 2008
@@ -0,0 +1,46 @@
+#ifndef __GKR_SSH_STORAGE_H__
+#define __GKR_SSH_STORAGE_H__
+
+#include <glib-object.h>
+
+#include "pk/gkr-pk-storage.h"
+
+#include "pkix/gkr-pkix-types.h"
+
+G_BEGIN_DECLS
+
+#define GKR_SSH_STORAGE_ERROR (gkr_ssh_storage_get_error_domain ())
+
+#define GKR_TYPE_SSH_STORAGE (gkr_ssh_storage_get_type ())
+#define GKR_SSH_STORAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKR_TYPE_SSH_STORAGE, GkrSshStorage))
+#define GKR_SSH_STORAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GKR_TYPE_SSH_STORAGE, GObject))
+#define GKR_IS_SSH_STORAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKR_TYPE_SSH_STORAGE))
+#define GKR_IS_SSH_STORAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GKR_TYPE_SSH_STORAGE))
+#define GKR_SSH_STORAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GKR_TYPE_SSH_STORAGE, GkrSshStorageClass))
+
+typedef struct _GkrSshStorage GkrSshStorage;
+typedef struct _GkrSshStorageClass GkrSshStorageClass;
+
+struct _GkrSshStorage {
+ GkrPkStorage parent;
+};
+
+struct _GkrSshStorageClass {
+ GkrPkStorageClass parent_class;
+};
+
+GType gkr_ssh_storage_get_type (void) G_GNUC_CONST;
+
+GQuark gkr_ssh_storage_get_error_domain (void) G_GNUC_CONST;
+
+gboolean gkr_ssh_storage_initialize (void);
+
+GkrPkixResult gkr_ssh_storage_load_public_key (const guchar *data, gsize n_data,
+ gcry_sexp_t *sexp, gchar **comment);
+
+guchar* gkr_ssh_storage_write_public_key (gcry_sexp_t sexp, gchar *comment,
+ gsize *n_data);
+
+G_END_DECLS
+
+#endif /* __GKR_SSH_STORAGE_H__ */
Added: trunk/ssh/tests/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/ssh/tests/Makefile.am Mon Jul 7 21:17:26 2008
@@ -0,0 +1,16 @@
+
+UNIT_AUTO = \
+ unit-test-ssh-storage.c
+
+UNIT_PROMPT =
+
+UNIT_LIBS = \
+ $(top_builddir)/ssh/libgkr-ssh.la \
+ $(top_builddir)/pk/libgkr-pk.la \
+ $(top_builddir)/keyrings/libgkr-keyrings.la \
+ $(top_builddir)/library/libgnome-keyring-common.la \
+ $(top_builddir)/pkix/libgkr-pkix.la \
+ $(top_builddir)/common/libgkr-common.la
+
+include $(top_srcdir)/tests/test.make
+
Added: trunk/ssh/tests/unit-test-ssh-storage.c
==============================================================================
--- (empty file)
+++ trunk/ssh/tests/unit-test-ssh-storage.c Mon Jul 7 21:17:26 2008
@@ -0,0 +1,122 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-ssh-storage.c: Test SSH storage
+
+ Copyright (C) 2008 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 "config.h"
+
+#include "run-auto-test.h"
+
+#include "common/gkr-location.h"
+#include "common/gkr-crypto.h"
+#include "common/gkr-secure-memory.h"
+
+#include "ssh/gkr-ssh-storage.h"
+
+#include <glib.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.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 const gchar *TEST_DSA_KEY = "ssh-dss AAAAB3NzaC1kc3MAAACBAJhgJycWojhw+UkvgFTdrBnCyVAZZPbbGCJ9bvoVb8N75MAmsPZugNInz6j6Iz+sa1nsYlBZnrhg4mXfxeWOTiI6/YDbPdA65P/q4oNDjKIjgBiC135un40+Qz8JGq2JPrU5pElH4jb8NYA4PymuIL7vingUvFK3XJiWSb2ZepNXAAAAFQCWBBXsX/Vi3GpSlG88Z+P8NQqmQQAAAIB0JOhEstQgJKic5Vx+C1MtBS2DX8dQ1TLo4bgzDTbYU4mbqJDUkhhYP2IGFEpuWFxLaCGsWoBfWi98Wz9o1P9TYkbmCiDd8mt7Px5bUR09orMUvHiNaLM9kH0KxUxAifGcrAsATloLJ8ReNJkypB9frjjbN1b/7YDyEP0zSiwDwwAAAIA9syAP6aY0kIdv7yqC5biGJqY170cpJYOE/vFHDVUXrXaTgPsoEQuRMFwHZbhgrVcUTKLJsmIyrpqWZ41PxDHgk1SC9GYDLmb65Pn23NvUDAZKft6E09KGL49LNpitfzLxvZAMLcU+YVCrUJwT/NgPTJ70GFrLs3z8UsKeFFxEUA== Test Comment";
+static const gchar *TEST_RSA_KEY = "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAz8Ji7Z1/NK7tvHETqSuLWPyn4l0fF6lTTbYf9Jx21RtaNwmaCi9u1Id3wVQMtuuR+0NLoBPyVdDrWi6ap9TkKdNQnnqW4Ang+GZc+9sXzbgWmgXnjKTXo+EcpMJLqpTLXPcaxYtwGIL/K/BE7NJ9i43HPqUG5z8ezE1/iHkfHMk= stef memberwebs com";
+static const gchar *TEST_COMMENT_KEY = "# a line that shouldn't be parsed \n\nssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAz8Ji7Z1/NK7tvHETqSuLWPyn4l0fF6lTTbYf9Jx21RtaNwmaCi9u1Id3wVQMtuuR+0NLoBPyVdDrWi6ap9TkKdNQnnqW4Ang+GZc+9sXzbgWmgXnjKTXo+EcpMJLqpTLXPcaxYtwGIL/K/BE7NJ9i43HPqUG5z8ezE1/iHkfHMk= stef memberwebs com\n# \n";
+
+void unit_test_ssh_public_dsa (CuTest* cu)
+{
+ GkrPkixResult res;
+ gcry_sexp_t sexp;
+ gchar *comment;
+ int algo;
+ guchar *data;
+ gsize n_data;
+ gboolean ret, is_priv;
+
+ res = gkr_ssh_storage_load_public_key ((guchar*)TEST_DSA_KEY, strlen (TEST_DSA_KEY), &sexp, &comment);
+ CuAssert (cu, "couldn't parse public SSH DSA key", res == GKR_PKIX_SUCCESS);
+ CuAssert (cu, "Bad comment on public SSH DSA key", comment && strcmp (comment, "Test Comment") == 0);
+
+ ret = gkr_crypto_skey_parse (sexp, &algo, &is_priv, NULL);
+ CuAssert (cu, "bad SSH DSA key parsed", ret == TRUE);
+ CuAssert (cu, "wrong algorithm in SSH DSA key parsed", algo == GCRY_PK_DSA);
+ CuAssert (cu, "bad key type in SSH DSA key parsed", is_priv == FALSE);
+
+ gkr_crypto_sexp_dump (sexp);
+
+ data = gkr_ssh_storage_write_public_key (sexp, comment, &n_data);
+ CuAssert (cu, "Couldn't write SSH DSA key", data != NULL);
+ CuAssert (cu, "Written SSH key invalid length", n_data == strlen (TEST_DSA_KEY));
+ CuAssert (cu, "Wrote invalid SSH DSA key", strncmp (TEST_DSA_KEY, (gchar*)data, n_data) == 0);
+}
+
+void unit_test_ssh_public_rsa (CuTest *cu)
+{
+ GkrPkixResult res;
+ gcry_sexp_t sexp;
+ gchar *comment;
+ int algo;
+ guchar *data, *data2;
+ gsize n_data, n_data2;
+ gboolean ret, is_priv;
+
+ /* RSA */
+
+ res = gkr_ssh_storage_load_public_key ((guchar*)TEST_RSA_KEY, strlen (TEST_RSA_KEY), &sexp, &comment);
+ CuAssert (cu, "couldn't parse public SSH RSA key", res == GKR_PKIX_SUCCESS);
+ CuAssert (cu, "Bad comment on public SSH RSA key", comment && strcmp (comment, "stef memberwebs com") == 0);
+
+ ret = gkr_crypto_skey_parse (sexp, &algo, &is_priv, NULL);
+ CuAssert (cu, "bad SSH RSA key parsed", ret == TRUE);
+ CuAssert (cu, "wrong algorithm in SSH RSA key parsed", algo == GCRY_PK_RSA);
+ CuAssert (cu, "bad key type in SSH RSA key parsed", is_priv == FALSE);
+
+ gkr_crypto_sexp_dump (sexp);
+
+ data = gkr_ssh_storage_write_public_key (sexp, comment, &n_data);
+ CuAssert (cu, "Couldn't write SSH RSA key", data != NULL);
+ CuAssert (cu, "Written SSH key invalid length", n_data == strlen (TEST_RSA_KEY));
+ CuAssert (cu, "Wrote invalid SSH RSA key", memcmp (TEST_RSA_KEY, data, n_data) == 0);
+
+ /* The same RSA key with comments */
+
+ res = gkr_ssh_storage_load_public_key ((guchar*)TEST_COMMENT_KEY, strlen (TEST_COMMENT_KEY), &sexp, &comment);
+ CuAssert (cu, "couldn't parse public SSH RSA key", res == GKR_PKIX_SUCCESS);
+
+ gkr_crypto_sexp_dump (sexp);
+
+ data2 = gkr_ssh_storage_write_public_key (sexp, comment, &n_data2);
+ CuAssert (cu, "Couldn't write SSH RSA key", data != NULL);
+ CuAssert (cu, "Written SSH key invalid length", n_data == n_data2);
+ CuAssert (cu, "Wrote invalid SSH RSA key", memcmp (data, data2, n_data) == 0);
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]