gnome-keyring r1417 - in trunk: . pkcs11/gck pkcs11/gck/tests pkcs11/gck/tests/test-data pkcs11/roots pkcs11/ssh-keys tests



Author: nnielsen
Date: Sat Jan  3 19:30:08 2009
New Revision: 1417
URL: http://svn.gnome.org/viewvc/gnome-keyring?rev=1417&view=rev

Log:
	* pkcs11/gck/gck-attributes.c: (added)
	* pkcs11/gck/gck-attributes.h: (added)
	* pkcs11/gck/gck-certificate.c:
	* pkcs11/gck/gck-certificate.h:
	* pkcs11/gck/gck-certificate-key.c:
	* pkcs11/gck/gck-certificate-key.h:
	* pkcs11/gck/gck-factory.c: (added)
	* pkcs11/gck/gck-factory.h: (added)
	* pkcs11/gck/gck-file-store.c: (added)
	* pkcs11/gck/gck-file-store.h: (added)
	* pkcs11/gck/gck-key.c:
	* pkcs11/gck/gck-key.h:
	* pkcs11/gck/gck-manager.c:
	* pkcs11/gck/gck-manager.h:
	* pkcs11/gck/gck-marshal.list: (added)
	* pkcs11/gck/gck-memory-store.c: (added)
	* pkcs11/gck/gck-memory-store.h: (added)
	* pkcs11/gck/gck-module.c:
	* pkcs11/gck/gck-module.h:
	* pkcs11/gck/gck-object.c:
	* pkcs11/gck/gck-object.h:
	* pkcs11/gck/gck-private-key.c:
	* pkcs11/gck/gck-private-key.h:
	* pkcs11/gck/gck-public-key.c:
	* pkcs11/gck/gck-public-key.h:
	* pkcs11/gck/gck-session.c:
	* pkcs11/gck/gck-sexp.h:
	* pkcs11/gck/gck-store.c: (added)
	* pkcs11/gck/gck-store.h: (added)
	* pkcs11/gck/gck-transaction.c: (added)
	* pkcs11/gck/gck-transaction.h: (added)
	* pkcs11/gck/gck-types.h: (added)
	* pkcs11/gck/gck-util.c:
	* pkcs11/gck/gck-util.h: 
	* pkcs11/gck/Makefile.am:
	* pkcs11/gck/tests/Makefile.am:
	* pkcs11/gck/tests/unit-test-file-store.c: (added)
	* pkcs11/gck/tests/unit-test-memory-store.c: (added)
	* pkcs11/gck/tests/unit-test-store.c: (added)
	* pkcs11/gck/tests/unit-test-transaction.c: (added)
	* pkcs11/gck/tests/test-data/test-file-store.store: (added)
	* pkcs11/roots/gck-roots-certificate.c:
	* pkcs11/ssh-keys/gck-ssh-private-key.c:
	* pkcs11/ssh-keys/gck-ssh-public-key.c:
	* tests/gtest-helpers.c:
	* tests/gtest-helpers.h: Added support for creating, deleting and setting
	attributes on session objects. Framework for general modification of objects.


Added:
   trunk/pkcs11/gck/gck-attributes.c
   trunk/pkcs11/gck/gck-attributes.h
   trunk/pkcs11/gck/gck-factory.c
   trunk/pkcs11/gck/gck-factory.h
   trunk/pkcs11/gck/gck-file-store.c
   trunk/pkcs11/gck/gck-file-store.h
   trunk/pkcs11/gck/gck-marshal.list
   trunk/pkcs11/gck/gck-memory-store.c
   trunk/pkcs11/gck/gck-memory-store.h
   trunk/pkcs11/gck/gck-store.c
   trunk/pkcs11/gck/gck-store.h
   trunk/pkcs11/gck/gck-transaction.c
   trunk/pkcs11/gck/gck-transaction.h
   trunk/pkcs11/gck/gck-types.h
   trunk/pkcs11/gck/tests/test-data/test-file-store.store   (contents, props changed)
   trunk/pkcs11/gck/tests/unit-test-file-store.c
   trunk/pkcs11/gck/tests/unit-test-memory-store.c
   trunk/pkcs11/gck/tests/unit-test-store.c
   trunk/pkcs11/gck/tests/unit-test-transaction.c
Modified:
   trunk/ChangeLog
   trunk/pkcs11/gck/   (props changed)
   trunk/pkcs11/gck/Makefile.am
   trunk/pkcs11/gck/gck-certificate-key.c
   trunk/pkcs11/gck/gck-certificate-key.h
   trunk/pkcs11/gck/gck-certificate.c
   trunk/pkcs11/gck/gck-certificate.h
   trunk/pkcs11/gck/gck-key.c
   trunk/pkcs11/gck/gck-key.h
   trunk/pkcs11/gck/gck-manager.c
   trunk/pkcs11/gck/gck-manager.h
   trunk/pkcs11/gck/gck-module.c
   trunk/pkcs11/gck/gck-module.h
   trunk/pkcs11/gck/gck-object.c
   trunk/pkcs11/gck/gck-object.h
   trunk/pkcs11/gck/gck-private-key.c
   trunk/pkcs11/gck/gck-private-key.h
   trunk/pkcs11/gck/gck-public-key.c
   trunk/pkcs11/gck/gck-public-key.h
   trunk/pkcs11/gck/gck-session.c
   trunk/pkcs11/gck/gck-sexp.h
   trunk/pkcs11/gck/gck-util.c
   trunk/pkcs11/gck/gck-util.h
   trunk/pkcs11/gck/tests/Makefile.am
   trunk/pkcs11/roots/gck-roots-certificate.c
   trunk/pkcs11/ssh-keys/gck-ssh-private-key.c
   trunk/pkcs11/ssh-keys/gck-ssh-public-key.c
   trunk/tests/gtest-helpers.c
   trunk/tests/gtest-helpers.h

Modified: trunk/pkcs11/gck/Makefile.am
==============================================================================
--- trunk/pkcs11/gck/Makefile.am	(original)
+++ trunk/pkcs11/gck/Makefile.am	Sat Jan  3 19:30:08 2009
@@ -13,9 +13,11 @@
 	libgck.la	
 
 BUILT_SOURCES = \
+	gck-marshal.c gck-marshal.h \
 	asn1-def-pk.h asn1-def-pkix.h
 
 libgck_la_SOURCES = \
+	gck-attributes.c gck-attributes.h \
 	gck-certificate.c gck-certificate.h \
 	gck-certificate-key.c gck-certificate-key.h \
 	gck-crypto.c gck-crypto.h \
@@ -24,16 +26,23 @@
 	gck-data-openssl.c gck-data-openssl.h \
 	gck-data-pem.c gck-data-pem.h \
 	gck-data-types.h \
+	gck-factory.c gck-factory.h \
+	gck-file-store.c gck-file-store.h \
 	gck-file-tracker.c gck-file-tracker.h \
 	gck-key.c gck-key.h \
 	gck-manager.c gck-manager.h \
+	gck-memory-store.c gck-memory-store.h \
 	gck-module.c gck-module.h gck-module-ep.h \
 	gck-object.c gck-object.h \
 	gck-private-key.c gck-private-key.h \
 	gck-public-key.c gck-public-key.h \
 	gck-session.c gck-session.h \
 	gck-sexp.c gck-sexp.h \
-	gck-util.c gck-util.h 
+	gck-store.c gck-store.h \
+	gck-transaction.c gck-transaction.h \
+	gck-types.h \
+	gck-util.c gck-util.h \
+	$(BUILT_SOURCES)
 
 libgck_la_CFLAGS = \
 	$(GOBJECT_CFLAGS) \
@@ -46,6 +55,13 @@
     	$(LIBGCRYPT_LIBS) \
 	$(GLIB_LIBS) 
 	
+gck-marshal.h: gck-marshal.list $(GLIB_GENMARSHAL)
+	$(GLIB_GENMARSHAL) $< --header --prefix=gck_marshal > $@
+
+gck-marshal.c: gck-marshal.list $(GLIB_GENMARSHAL)
+	echo "#include \"gck-marshal.h\"" > $@ && \
+	$(GLIB_GENMARSHAL) $< --body --prefix=gck_marshal >> $@
+
 asn1-def-pk.h: pk.asn
 	asn1Parser -o asn1-def-pk.h pk.asn 
 	
@@ -53,6 +69,7 @@
 	asn1Parser -o asn1-def-pkix.h pkix.asn 
 
 EXTRA_DIST = \
+	gck-marshal.list \
 	pkix.asn \
 	pk.asn
 

Added: trunk/pkcs11/gck/gck-attributes.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-attributes.c	Sat Jan  3 19:30:08 2009
@@ -0,0 +1,292 @@
+/* 
+ * gnome-keyring
+ * 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General  License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program 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
+ * Lesser General  License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General 
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include "config.h"
+
+#include "gck-attributes.h"
+#include "gck-util.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+CK_RV
+gck_attribute_set_bool (CK_ATTRIBUTE_PTR attr, CK_BBOOL value)
+{
+	return gck_attribute_set_data (attr, &value, sizeof (CK_BBOOL));
+}
+
+CK_RV
+gck_attribute_set_ulong (CK_ATTRIBUTE_PTR attr, CK_ULONG value)
+{
+	return gck_attribute_set_data (attr, &value, sizeof (CK_ULONG));
+}
+
+CK_RV
+gck_attribute_set_string (CK_ATTRIBUTE_PTR attr, const gchar* string)
+{
+	g_return_val_if_fail (string, CKR_GENERAL_ERROR);
+	return gck_attribute_set_data (attr, (CK_VOID_PTR)string, strlen (string));
+}
+
+CK_RV
+gck_attribute_set_date (CK_ATTRIBUTE_PTR attr, time_t time)
+{
+	CK_DATE date;
+	struct tm tm;
+	gchar buf[16];
+	
+	/* 'Empty' date as defined in PKCS#11 */
+	if (time == (time_t)-1)
+		return gck_attribute_set_data (attr, NULL, 0);
+	
+	if (!attr->pValue) {
+		attr->ulValueLen = sizeof (CK_DATE);
+		return CKR_OK;
+	}
+
+	if (!gmtime_r (&time, &tm))
+		g_return_val_if_reached (CKR_GENERAL_ERROR);
+		
+	g_assert (sizeof (date.year) == 4);
+	snprintf ((char*)buf, 5, "%04d", 1900 + tm.tm_year);
+	memcpy (date.year, buf, 4);
+	 
+	g_assert (sizeof (date.month) == 2);
+	snprintf ((char*)buf, 3, "%02d", tm.tm_mon + 1);
+	memcpy (date.month, buf, 2);
+	
+	g_assert (sizeof (date.day) == 2);
+	snprintf ((char*)buf, 3, "%02d", tm.tm_mday);
+	memcpy (date.day, buf, 2);
+		
+	return gck_attribute_set_data (attr, &date, sizeof (date));
+}
+CK_RV
+gck_attribute_set_data (CK_ATTRIBUTE_PTR attr, gconstpointer value, gsize n_value)
+{
+	return gck_util_return_data (attr->pValue, &(attr->ulValueLen), value, n_value);
+}
+
+CK_RV
+gck_attribute_set_mpi (CK_ATTRIBUTE_PTR attr, gcry_mpi_t mpi)
+{
+	gsize len;
+  	gcry_error_t gcry;
+
+	g_assert (attr);
+	g_assert (mpi);
+	
+	/* Get the size */
+	gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &len, mpi);
+	g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
+
+	if (!attr->pValue) {
+		attr->ulValueLen = len;
+		return CKR_OK;
+	}
+	
+	if (len > attr->ulValueLen) {
+		attr->ulValueLen = len;
+		return CKR_BUFFER_TOO_SMALL;
+	}
+
+	/* Write in directly to attribute */
+	gcry = gcry_mpi_print (GCRYMPI_FMT_USG, attr->pValue, len, &len, mpi);	
+	g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
+	
+	attr->ulValueLen = len;
+	return CKR_OK;
+}
+
+gboolean
+gck_attribute_equal (gconstpointer v1, gconstpointer v2)
+{
+	const CK_ATTRIBUTE *a1 = v1;
+	const CK_ATTRIBUTE *a2 = v2;
+	
+	g_assert (a1);
+	g_assert (a2);
+	
+	if (a1 == a2)
+		return TRUE;
+	if (a1->type != a2->type)
+		return FALSE;
+	if (a1->ulValueLen != a2->ulValueLen)
+		return FALSE;
+	if (a1->pValue == a2->pValue)
+		return TRUE;
+	
+	g_assert (a1->pValue);
+	g_assert (a2->pValue);
+	
+	return memcmp (a1->pValue, a2->pValue, a1->ulValueLen) == 0;
+}
+
+guint
+gck_attribute_hash (gconstpointer v)
+{
+	const CK_ATTRIBUTE *a = v;
+	const signed char *p;
+	guint i, h;
+	
+	g_assert (a);
+	
+	p = (const signed char*)&(a->type);
+	h = *p;
+	for(i = 0; i < sizeof (CK_ATTRIBUTE_PTR); ++i)
+		h = (h << 5) - h + *(p++);
+	
+	p = a->pValue;
+	for(i = 0; i < a->ulValueLen; ++i)
+		h = (h << 5) - h + *(p++);
+	
+	return h;
+}
+
+gboolean
+gck_attribute_consumed (CK_ATTRIBUTE_PTR attr)
+{
+	g_return_val_if_fail (attr, FALSE);
+	return attr->type == (CK_ULONG)-1;
+}
+
+void
+gck_attributes_consume (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, ...)
+{
+	CK_ATTRIBUTE_TYPE type;
+	GArray *types;
+	guint i, j;
+	va_list va;
+
+	/* Convert the var args into an array */
+	types = g_array_new (FALSE, TRUE, sizeof (CK_ATTRIBUTE_TYPE));
+	va_start (va, n_attrs);
+	while ((type = va_arg (va, CK_ATTRIBUTE_TYPE)) != (CK_ULONG)-1)
+		 g_array_append_val (types, type);
+	va_end (va);
+	
+	/* Consume each attribute whose type was in the var args */
+	for (i = 0; i < n_attrs; ++i) {
+		if (gck_attribute_consumed (&attrs[i]))
+			continue;
+		for (j = 0; j < types->len; ++j) {
+			if (attrs[i].type == g_array_index (types, CK_ATTRIBUTE_TYPE, j)) {
+				attrs[i].type = (CK_ULONG)-1;
+				break;
+			}
+		}
+	}
+	
+	g_array_free (types, TRUE);
+}
+
+gboolean
+gck_attributes_contains (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, CK_ATTRIBUTE_PTR attr)
+{
+	CK_ULONG i;
+	
+	g_assert (attrs || !n_attrs);
+	g_assert (attr);
+	
+	for (i = 0; i < n_attrs; ++i) {
+		if (gck_attribute_equal (attr, &attrs[i]))
+			return TRUE;
+	}
+	
+	return FALSE;
+}
+
+CK_ATTRIBUTE_PTR
+gck_attributes_find (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, CK_ATTRIBUTE_TYPE type)
+{
+	CK_ULONG i;
+	
+	g_assert (attrs || !n_attrs);
+	
+	for (i = 0; i < n_attrs; ++i) {
+		if(attrs[i].type == type)
+			return &attrs[i];
+	}
+	
+	return NULL;
+}
+
+gboolean
+gck_attributes_find_boolean (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, CK_ATTRIBUTE_TYPE type, gboolean *value)
+{
+	CK_ATTRIBUTE_PTR attr;
+	
+	g_assert (attrs || !n_attrs);
+	
+	attr = gck_attributes_find (attrs, n_attrs, type);
+	if (attr == NULL)
+		return FALSE;
+	
+	if (attr->ulValueLen != sizeof (CK_BBOOL))
+		return FALSE;
+	
+	if (value != NULL)
+		*value = *((CK_BBOOL*)attr->pValue) == CK_TRUE ? TRUE : FALSE;
+
+	return TRUE;
+}
+
+gboolean
+gck_attributes_find_ulong (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, CK_ATTRIBUTE_TYPE type, gulong *value)
+{
+	CK_ATTRIBUTE_PTR attr;
+	
+	g_assert (attrs || !n_attrs);
+	
+	attr = gck_attributes_find (attrs, n_attrs, type);
+	if (attr == NULL)
+		return FALSE;
+	
+	if (attr->ulValueLen != sizeof (CK_ULONG))
+		return FALSE;
+	
+	if (value != NULL)
+		*value = *((CK_ULONG*)attr->pValue);
+
+	return TRUE;
+}
+
+gboolean
+gck_attributes_find_mpi (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, CK_ATTRIBUTE_TYPE type, gcry_mpi_t *value)
+{
+	CK_ATTRIBUTE_PTR attr;
+	gcry_error_t gcry;
+	
+	g_assert (attrs || !n_attrs);
+	
+	attr = gck_attributes_find (attrs, n_attrs, type);
+	if (attr == NULL)
+		return FALSE;
+	
+	if (value != NULL) {
+		gcry = gcry_mpi_scan (value, GCRYMPI_FMT_USG, attr->pValue, attr->ulValueLen, NULL);
+		if (gcry != 0)
+			return FALSE;
+	}
+	
+	return TRUE;
+}

Added: trunk/pkcs11/gck/gck-attributes.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-attributes.h	Sat Jan  3 19:30:08 2009
@@ -0,0 +1,90 @@
+/* 
+ * gnome-keyring
+ * 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General  License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program 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
+ * Lesser General  License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General 
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef GCK_ATTRIBUTE_H_
+#define GCK_ATTRIBUTE_H_
+
+#include <glib.h>
+
+#include <gcrypt.h>
+
+#include "pkcs11/pkcs11.h"
+
+CK_RV                 gck_attribute_set_bool                           (CK_ATTRIBUTE_PTR attr,
+                                                                        CK_BBOOL value);
+
+CK_RV                 gck_attribute_set_ulong                          (CK_ATTRIBUTE_PTR attr, 
+                                                                        CK_ULONG value);
+
+CK_RV                 gck_attribute_set_string                         (CK_ATTRIBUTE_PTR attr, 
+                                                                        const gchar* string);
+
+CK_RV                 gck_attribute_set_date                           (CK_ATTRIBUTE_PTR attr,
+                                                                        time_t when);
+
+CK_RV                 gck_attribute_set_data                           (CK_ATTRIBUTE_PTR attr,
+                                                                        gconstpointer value,
+                                                                        gsize n_value);
+
+CK_RV                 gck_attribute_return_data                        (CK_VOID_PTR output,
+                                                                        CK_ULONG_PTR n_output,
+                                                                        gconstpointer input,
+                                                                        gsize n_input);
+
+CK_RV                 gck_attribute_set_mpi                            (CK_ATTRIBUTE_PTR attr, 
+                                                                        gcry_mpi_t mpi);
+
+guint                 gck_attribute_hash                               (gconstpointer v);
+
+gboolean              gck_attribute_equal                              (gconstpointer a,
+                                                                        gconstpointer b);
+
+gboolean              gck_attribute_consumed                           (CK_ATTRIBUTE_PTR attr);
+
+
+
+gboolean              gck_attributes_contains                          (CK_ATTRIBUTE_PTR attrs,
+                                                                        CK_ULONG n_attrs,
+                                                                        CK_ATTRIBUTE_PTR attr);
+
+void                  gck_attributes_consume                           (CK_ATTRIBUTE_PTR attrs, 
+                                                                        CK_ULONG n_attrs, ...);
+
+CK_ATTRIBUTE_PTR      gck_attributes_find                              (CK_ATTRIBUTE_PTR attrs,
+                                                                        CK_ULONG n_attrs,
+                                                                        CK_ATTRIBUTE_TYPE type);
+
+gboolean              gck_attributes_find_boolean                      (CK_ATTRIBUTE_PTR attrs,
+                                                                        CK_ULONG n_attrs,
+                                                                        CK_ATTRIBUTE_TYPE type,
+                                                                        gboolean *value);
+
+gboolean              gck_attributes_find_ulong                        (CK_ATTRIBUTE_PTR attrs,
+                                                                        CK_ULONG n_attrs,
+                                                                        CK_ATTRIBUTE_TYPE type,
+                                                                        gulong *value);
+
+gboolean              gck_attributes_find_mpi                          (CK_ATTRIBUTE_PTR attrs,
+                                                                        CK_ULONG n_attrs,
+                                                                        CK_ATTRIBUTE_TYPE type,
+                                                                        gcry_mpi_t *mpi);
+
+#endif /* GCK_ATTRIBUTE_H_ */

Modified: trunk/pkcs11/gck/gck-certificate-key.c
==============================================================================
--- trunk/pkcs11/gck/gck-certificate-key.c	(original)
+++ trunk/pkcs11/gck/gck-certificate-key.c	Sat Jan  3 19:30:08 2009
@@ -21,6 +21,8 @@
 
 #include "config.h"
 
+#include "gck-attributes.h"
+#include "gck-certificate.h"
 #include "gck-certificate-key.h"
 
 #include "gck-object.h"
@@ -52,7 +54,7 @@
 	case CKA_LABEL:
 		if (self->pv->certificate)
 			return gck_object_get_attribute (GCK_OBJECT (self->pv->certificate), attr);
-		return gck_util_set_string (attr, "");
+		return gck_attribute_set_string (attr, "");
 	}
 	
 	return GCK_OBJECT_CLASS (gck_certificate_key_parent_class)->get_attribute (base, attr);

Modified: trunk/pkcs11/gck/gck-certificate-key.h
==============================================================================
--- trunk/pkcs11/gck/gck-certificate-key.h	(original)
+++ trunk/pkcs11/gck/gck-certificate-key.h	Sat Jan  3 19:30:08 2009
@@ -25,7 +25,7 @@
 #include <glib-object.h>
 
 #include "gck-public-key.h"
-#include "gck-certificate.h"
+#include "gck-types.h"
 
 #define GCK_TYPE_CERTIFICATE_KEY               (gck_certificate_key_get_type ())
 #define GCK_CERTIFICATE_KEY(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_CERTIFICATE_KEY, GckCertificateKey))

Modified: trunk/pkcs11/gck/gck-certificate.c
==============================================================================
--- trunk/pkcs11/gck/gck-certificate.c	(original)
+++ trunk/pkcs11/gck/gck-certificate.c	Sat Jan  3 19:30:08 2009
@@ -23,6 +23,8 @@
 
 #include "pkcs11/pkcs11.h"
 
+#include "gck-attributes.h"
+#include "gck-certificate.h"
 #include "gck-certificate-key.h"
 #include "gck-crypto.h"
 #include "gck-data-asn1.h"
@@ -127,24 +129,24 @@
 	switch (attr->type) {
 	
 	case CKA_CLASS:
-		return gck_util_set_ulong (attr, CKO_CERTIFICATE);
+		return gck_attribute_set_ulong (attr, CKO_CERTIFICATE);
 		
 	case CKA_PRIVATE:
-		return gck_util_set_bool (attr, FALSE);
+		return gck_attribute_set_bool (attr, FALSE);
 		
 	case CKA_LABEL:
-		return gck_util_set_string (attr, gck_certificate_get_label (self)); 
+		return gck_attribute_set_string (attr, gck_certificate_get_label (self)); 
 		
 	case CKA_CERTIFICATE_TYPE:
-		return gck_util_set_ulong (attr, CKC_X_509);
+		return gck_attribute_set_ulong (attr, CKC_X_509);
 		
 	case CKA_TRUSTED:
-		return gck_util_set_bool (attr, FALSE);
+		return gck_attribute_set_bool (attr, FALSE);
 		
 	case CKA_CERTIFICATE_CATEGORY:
 		if (!gck_certificate_calc_category (self, &category))
 			return CKR_FUNCTION_FAILED;
-		return gck_util_set_ulong (attr, category);
+		return gck_attribute_set_ulong (attr, category);
 		
 	case CKA_CHECK_VALUE:
 		g_return_val_if_fail (self->pv->data, CKR_GENERAL_ERROR);
@@ -152,7 +154,7 @@
 		g_return_val_if_fail (n_data && n_data > 3, CKR_GENERAL_ERROR);
 		data = g_new0 (guchar, n_data);
 		gcry_md_hash_buffer (GCRY_MD_SHA1, data, self->pv->data, self->pv->n_data);
-		rv = gck_util_set_data (attr, data, 3);
+		rv = gck_attribute_set_data (attr, data, 3);
 		g_free (data);
 		return rv;
 	
@@ -165,14 +167,14 @@
 		                                       "tbsCertificate.validity.notAfter",
 		                              &when))
 			return CKR_FUNCTION_FAILED;
-		return gck_util_set_date (attr, when);
+		return gck_attribute_set_date (attr, when);
 
 	case CKA_SUBJECT:
 		g_return_val_if_fail (self->pv->asn1, CKR_GENERAL_ERROR);
 		cdata = gck_data_asn1_read_element (self->pv->asn1, self->pv->data, self->pv->n_data, 
 		                                    "tbsCertificate.subject", &n_data);
 		g_return_val_if_fail (cdata, CKR_GENERAL_ERROR);
-		return gck_util_set_data (attr, cdata, n_data);
+		return gck_attribute_set_data (attr, cdata, n_data);
 
 	case CKA_ID:
 		g_return_val_if_fail (self->pv->key, CKR_GENERAL_ERROR);
@@ -183,28 +185,28 @@
 		cdata = gck_data_asn1_read_element (self->pv->asn1, self->pv->data, self->pv->n_data, 
 		                                    "tbsCertificate.issuer", &n_data);
 		g_return_val_if_fail (cdata, CKR_GENERAL_ERROR);
-		return gck_util_set_data (attr, cdata, n_data);
+		return gck_attribute_set_data (attr, cdata, n_data);
 		
 	case CKA_SERIAL_NUMBER:
 		g_return_val_if_fail (self->pv->asn1, CKR_GENERAL_ERROR);
 		cdata = gck_data_asn1_read_element (self->pv->asn1, self->pv->data, self->pv->n_data, 
 		                                    "tbsCertificate.serialNumber", &n_data);
 		g_return_val_if_fail (cdata, CKR_GENERAL_ERROR);
-		return gck_util_set_data (attr, cdata, n_data);		
+		return gck_attribute_set_data (attr, cdata, n_data);		
 		
 	case CKA_VALUE:
 		g_return_val_if_fail (self->pv->data, CKR_GENERAL_ERROR);
-		return gck_util_set_data (attr, self->pv->data, self->pv->n_data);
+		return gck_attribute_set_data (attr, self->pv->data, self->pv->n_data);
 
 	/* These are only used for strange online certificates which we don't support */	
 	case CKA_URL:
 	case CKA_HASH_OF_SUBJECT_PUBLIC_KEY:
 	case CKA_HASH_OF_ISSUER_PUBLIC_KEY:
-		return gck_util_set_data (attr, "", 0);
+		return gck_attribute_set_data (attr, "", 0);
 	
 	/* What in the world is this doing in the spec? */
 	case CKA_JAVA_MIDP_SECURITY_DOMAIN:
-		return gck_util_set_ulong (attr, 0); /* 0 = unspecified */
+		return gck_attribute_set_ulong (attr, 0); /* 0 = unspecified */
 	};
 
 	return GCK_OBJECT_CLASS (gck_certificate_parent_class)->get_attribute (base, attr);

Modified: trunk/pkcs11/gck/gck-certificate.h
==============================================================================
--- trunk/pkcs11/gck/gck-certificate.h	(original)
+++ trunk/pkcs11/gck/gck-certificate.h	Sat Jan  3 19:30:08 2009
@@ -25,6 +25,7 @@
 #include <glib-object.h>
 
 #include "gck-object.h"
+#include "gck-types.h"
 
 #define GCK_TYPE_CERTIFICATE               (gck_certificate_get_type ())
 #define GCK_CERTIFICATE(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_CERTIFICATE, GckCertificate))
@@ -33,8 +34,6 @@
 #define GCK_IS_CERTIFICATE_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_CERTIFICATE))
 #define GCK_CERTIFICATE_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_CERTIFICATE, GckCertificateClass))
 
-typedef struct _GckCertificate GckCertificate;
-typedef struct _GckCertificateKey GckCertificateKey;
 typedef struct _GckCertificateClass GckCertificateClass;
 typedef struct _GckCertificatePrivate GckCertificatePrivate;
     

Added: trunk/pkcs11/gck/gck-factory.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-factory.c	Sat Jan  3 19:30:08 2009
@@ -0,0 +1,25 @@
+/* 
+ * gnome-keyring
+ * 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program 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
+ * Lesser General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include "config.h"
+
+#include "gck-factory.h"
+

Added: trunk/pkcs11/gck/gck-factory.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-factory.h	Sat Jan  3 19:30:08 2009
@@ -0,0 +1,40 @@
+/* 
+ * gnome-keyring
+ * 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program 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
+ * Lesser General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef __GCK_FACTORY_H__
+#define __GCK_FACTORY_H__
+
+#include <glib-object.h>
+
+#include "pkcs11/pkcs11.h"
+
+#include "gck-types.h"
+
+typedef void (*GckFactory) (GckSession *session, GckTransaction *transaction, 
+                            CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **object);
+
+struct _GckFactoryInfo {
+	CK_ATTRIBUTE_PTR attrs;
+	CK_ULONG n_attrs;
+	GckFactory factory;
+};
+
+#endif /* __GCK_FACTORY_H__ */

Added: trunk/pkcs11/gck/gck-file-store.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-file-store.c	Sat Jan  3 19:30:08 2009
@@ -0,0 +1,1513 @@
+/* 
+ * gnome-keyring
+ * 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program 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
+ * Lesser General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include "config.h"
+
+#include "gck-attributes.h"
+#include "gck-crypto.h"
+#include "gck-file-store.h"
+#include "gck-object.h"
+#include "gck-transaction.h"
+#include "gck-util.h"
+
+#include "common/gkr-buffer.h"
+#include "common/gkr-secure-memory.h"
+
+#include <glib/gstdio.h>
+
+#include <sys/file.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h> 
+
+#include <gcrypt.h>
+
+enum {
+	PROP_0,
+	PROP_FILENAME,
+	PROP_LOCKED
+};
+
+
+enum {
+	ENTRY_CREATED,
+	ENTRY_DESTROYED,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+struct _GckFileStore {
+	GckStore parent;
+	
+	GHashTable *privates;
+	GHashTable *publics;
+	GHashTable *object_by_unique;
+	GHashTable *unique_by_object;
+	
+	gchar *filename;
+	time_t last_mtime;
+	gboolean locked;
+	guchar *password;
+	gsize n_password;
+	gboolean unlock_failures;
+	
+	/* Valid when in a transaction */
+	GckTransaction *transaction;
+	int previous_fd;
+	int transaction_fd;
+	gchar *transaction_path;
+};
+
+G_DEFINE_TYPE (GckFileStore, gck_file_store, GCK_TYPE_STORE);
+
+#define PUBLIC_ALLOC (GkrBufferAllocator)g_realloc
+#define PRIVATE_ALLOC (GkrBufferAllocator)gkr_secure_realloc
+
+typedef gboolean (*BlockFunc) (guint block, GkrBuffer *buffer, gpointer user_data);
+
+#define FILE_HEADER ((const guchar*)"Gnome Keyring Store 2\n\r\0")
+#define FILE_HEADER_LEN 24
+
+#define FILE_BLOCK_PRIVATE  0x70727632  /* ie: "prv2" */
+#define FILE_BLOCK_PUBLIC   0x70756232  /* ie: "pub2" */
+
+#define MAX_LOCK_TRIES 20
+
+/* -----------------------------------------------------------------------------
+ * HELPERS 
+ */
+
+static void
+attribute_free (gpointer data)
+{
+	CK_ATTRIBUTE_PTR attr = data;
+	if (attr) {
+		g_free (attr->pValue);
+		g_slice_free (CK_ATTRIBUTE, attr);
+	}
+}
+
+static CK_ATTRIBUTE_PTR
+attribute_dup (CK_ATTRIBUTE_PTR attr)
+{
+	CK_ATTRIBUTE_PTR copy;
+	g_assert (attr);
+	copy = g_slice_new (CK_ATTRIBUTE);
+	copy->ulValueLen = attr->ulValueLen;
+	copy->pValue = g_memdup (attr->pValue, copy->ulValueLen);
+	copy->type = attr->type;
+	return copy;
+}
+
+static gboolean
+read_all_bytes (int fd, guchar *buf, gsize len)
+{
+	gsize all = len;
+	int res;
+	
+	while (len > 0) {
+		
+		res = read (fd, buf, len);
+		if (res <= 0) {
+			if (errno == EAGAIN && errno == EINTR)
+				continue;
+			if (res < 0 || len != all)
+				g_warning ("couldn't read %u bytes from store file: %s", all, 
+				           g_strerror (errno));
+			return FALSE;
+		} else  {
+			len -= res;
+			buf += res;
+		}
+	}
+	
+	return TRUE;
+}
+
+static gboolean
+write_all_bytes (int fd, const guchar *buf, gsize len)
+{
+	gsize all = len;
+	int res;
+	
+	while (len > 0) {
+		
+		res = write (fd, buf, len);
+
+		if (res <= 0) {
+			if (errno == EAGAIN && errno == EINTR)
+				continue;
+			g_warning ("couldn't write %u bytes to store file: %s", all, 
+			           res < 0 ? g_strerror (errno) : "");
+			return FALSE;
+		} else  {
+			len -= res;
+			buf += res;
+		}
+	}
+	
+	return TRUE;
+}
+
+static gboolean
+parse_file_blocks (int file, BlockFunc block_func, gpointer user_data)
+{
+	gchar header[FILE_HEADER_LEN];
+	GkrBuffer buffer;
+	gboolean ret;
+	guint32 block;
+	guint32 length;
+	gsize offset;
+	
+	g_assert (file != -1);
+	g_assert (block_func);
+	
+	/* Zero length file is valid */
+	if (!read_all_bytes (file, (guchar*)header, FILE_HEADER_LEN))
+		return TRUE;
+	
+	/* Check the header */
+	if (memcmp (header, FILE_HEADER, FILE_HEADER_LEN) != 0) {
+		g_message ("invalid header in store file");
+		return FALSE;
+	}
+
+	gkr_buffer_init_full (&buffer, 1024, (GkrBufferAllocator)g_realloc);
+
+	ret = FALSE;
+	for (;;) {
+
+		gkr_buffer_reset (&buffer);
+		gkr_buffer_resize (&buffer, 8);
+		offset = 0;
+
+		/* Read in a set of bytes */
+		if (!read_all_bytes (file, buffer.buf, 8)) {
+			ret = TRUE;
+			break;
+		}
+		
+		/* Decode it as the number of bytes in the next section */
+		if (!gkr_buffer_get_uint32 (&buffer, offset, &offset, &length) ||
+		    !gkr_buffer_get_uint32 (&buffer, offset, &offset, &block) || 
+		    length < 8) {
+			g_message ("invalid block size or length in store file");
+			break;
+		}
+		
+		/* Read in that amount of bytes */
+		gkr_buffer_resize (&buffer, length - 8);
+		if (!read_all_bytes (file, buffer.buf, length - 8)) 
+			break;
+
+		if (!(block_func) (block, &buffer, user_data))
+			break;
+	}
+	
+	gkr_buffer_uninit (&buffer);
+	return ret;
+}
+
+static gboolean
+write_file_block (int file, guint block, GkrBuffer *buffer)
+{
+	GkrBuffer header;
+	gboolean ret;
+	
+	g_assert (file != -1);
+	g_assert (buffer);
+	
+	/* Write out the 8 bytes of header */
+	gkr_buffer_init_full (&header, 8, (GkrBufferAllocator)g_realloc);
+	gkr_buffer_add_uint32 (&header, buffer->len + 8);
+	gkr_buffer_add_uint32 (&header, block);
+	g_assert (!gkr_buffer_has_error (&header));
+	g_assert (header.len == 8);
+	ret = write_all_bytes (file, header.buf, header.len);
+	gkr_buffer_uninit (&header);
+	
+	if (ret != TRUE)
+		return FALSE;
+	
+	/* Now write out the remainder of the data */
+	return write_all_bytes (file, buffer->buf, buffer->len);
+}
+
+static gboolean
+hash_buffer (GkrBuffer *buffer)
+{
+	const gchar *salgo;
+	gsize length;
+	guchar *hash;
+	gsize n_hash;
+	int algo;
+	
+	/* The length needs to be the first thing in the buffer */
+	g_assert (buffer->len > 4);
+	g_assert (gkr_buffer_decode_uint32 (buffer->buf) == buffer->len);
+	
+	length = buffer->len;
+	
+	algo = GCRY_MD_SHA256;
+	salgo = gcry_md_algo_name (algo);
+	g_return_val_if_fail (salgo, FALSE);
+	n_hash = gcry_md_get_algo_dlen (algo);
+	g_return_val_if_fail (n_hash > 0, FALSE);
+	
+	gkr_buffer_add_string (buffer, salgo);
+	hash = gkr_buffer_add_byte_array_empty (buffer, n_hash);
+	g_return_val_if_fail (hash, FALSE);
+	
+	gcry_md_hash_buffer (algo, hash, buffer->buf, length);
+	return TRUE;
+}
+
+static gboolean
+validate_buffer (GkrBuffer *buffer, gsize *offset)
+{
+	const guchar *hash;
+	gchar *salgo, *check;
+	gsize n_hash, hash_offset;
+	guint32 length;
+	int algo;
+	
+	g_assert (buffer);
+	g_assert (offset);
+	
+	*offset = 0;
+	
+	if (!gkr_buffer_get_uint32 (buffer, *offset, offset, &length) || 
+	    !gkr_buffer_get_string (buffer, length, &hash_offset, &salgo, PUBLIC_ALLOC))
+		return FALSE;
+	
+	algo = gcry_md_map_name (salgo);
+	if (algo == 0) {
+		g_warning ("unsupported hash algorithm: %s", salgo);
+		g_free (salgo);
+		return FALSE;
+	}
+	g_free (salgo);
+	
+	if (!gkr_buffer_get_byte_array (buffer, hash_offset, &hash_offset, &hash, &n_hash))
+		return FALSE;
+	
+	if (n_hash != gcry_md_get_algo_dlen (algo)) {
+		g_warning ("invalid hash length in store file");
+		return FALSE;
+	}
+	
+	check = g_malloc0 (n_hash);
+	gcry_md_hash_buffer (algo, check, buffer->buf, length);
+	if (memcmp (check, hash, n_hash) != 0)
+		return FALSE;
+	
+	return TRUE;
+}
+
+static gboolean
+create_cipher (int calgo, int halgo, const guchar *password, gsize n_password, 
+               const guchar *salt, gsize n_salt, guint iterations, gcry_cipher_hd_t *cipher)
+{
+	gsize n_key, n_block;
+	guchar *key, *iv;
+	gcry_error_t gcry;
+	
+	g_assert (salt);
+	g_assert (cipher);
+
+	n_key = gcry_cipher_get_algo_keylen (calgo);
+	g_return_val_if_fail (n_key, FALSE);
+	n_block = gcry_cipher_get_algo_blklen (calgo);
+	g_return_val_if_fail (n_block, FALSE);
+
+	/* Allocate memory for the keys */
+	key = gcry_malloc_secure (n_key);
+	g_return_val_if_fail (key, FALSE);
+	iv = g_malloc0 (n_block);
+	
+	if (!gck_crypto_symkey_generate_simple (calgo, halgo, (const gchar*)password, 
+	                                        n_password, salt, n_salt, iterations, &key, &iv)) {
+		gcry_free (key);
+		g_free (iv);
+		return FALSE;
+	}
+	
+	gcry = gcry_cipher_open (cipher, calgo, GCRY_CIPHER_MODE_CBC, 0);
+	if (gcry) {
+		g_warning ("couldn't create cipher context: %s", gcry_strerror (gcry));
+		gcry_free (key);
+		g_free (iv);
+		return FALSE;
+	}
+
+	gcry = gcry_cipher_setkey (*cipher, key, n_key);
+	g_return_val_if_fail (!gcry, FALSE);
+	gcry_free (key);
+
+	gcry = gcry_cipher_setiv (*cipher, iv, n_block);
+	g_return_val_if_fail (!gcry, FALSE);
+	g_free (iv);
+	
+	return TRUE;
+}
+
+static gboolean
+encrypt_buffer (GkrBuffer *input, const guchar *password, 
+                gsize n_password, GkrBuffer *output)
+{
+	gcry_cipher_hd_t cipher;
+	gcry_error_t gcry;
+	guchar salt[8];
+	guint32 iterations;
+	int calgo, halgo;
+	const gchar *salgo;
+	guchar *dest;
+	gsize n_block;
+	
+	g_assert (input);
+	g_assert (output);
+	
+	/* The algorithms we're going to use */
+	calgo = GCRY_CIPHER_AES128;
+	halgo = GCRY_MD_SHA256;
+	
+	/* Prepare us some salt */
+	gcry_create_nonce (salt, sizeof (salt));
+	
+	/* Prepare us the iterations */
+	iterations = 1000 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
+	
+	/* Write out crypto algorithm */
+	salgo = gcry_cipher_algo_name (calgo);
+	g_return_val_if_fail (salgo, FALSE);
+	gkr_buffer_add_string (output, salgo);
+	
+	/* Write out the hash algorithm */
+	salgo = gcry_md_algo_name (halgo);
+	g_return_val_if_fail (halgo, FALSE);
+	gkr_buffer_add_string (output, salgo);
+	
+	/* Write out the iterations */
+	gkr_buffer_add_uint32 (output, iterations);
+	
+	/* And write out the salt */
+	gkr_buffer_add_byte_array (output, salt, sizeof (salt));
+	
+	/* Okay now use the above info to create our cipher context */
+	if (!create_cipher (calgo, halgo, password, n_password, salt,
+	                    sizeof (salt), iterations, &cipher))
+		return FALSE;
+	
+	/* Significant block sizes */
+	n_block = gcry_cipher_get_algo_blklen (calgo);
+	g_return_val_if_fail (n_block, FALSE);
+	
+	/* Pad the buffer to a multiple of block length */
+	while (input->len % n_block != 0)
+		gkr_buffer_add_byte (input, 0);
+	
+	/* Now reserve space for it in the output block, and encrypt */
+	dest = gkr_buffer_add_byte_array_empty (output, input->len);
+	g_return_val_if_fail (dest, FALSE);
+
+	gcry = gcry_cipher_encrypt (cipher, dest, input->len, input->buf, input->len);
+	g_return_val_if_fail (!gcry, FALSE);
+	
+	gcry_cipher_close (cipher);
+
+	return TRUE;
+}
+
+static gboolean
+decrypt_buffer (GkrBuffer *input, gsize *offset, const guchar *password, 
+                gsize n_password, GkrBuffer *output)
+{
+	gcry_cipher_hd_t cipher;
+	gcry_error_t gcry;
+	const guchar *salt, *data;
+	gsize n_block, n_salt, n_data;
+	guint32 iterations;
+	int calgo, halgo;
+	gchar *salgo;
+
+	g_assert (input);
+	g_assert (output);
+	g_assert (offset);
+
+	/* Read in and interpret the cipher algorithm */
+	if (!gkr_buffer_get_string (input, *offset, offset, &salgo, NULL))
+		return FALSE;
+	calgo = gcry_cipher_map_name (salgo); 
+	if (!calgo) {
+		g_warning ("unsupported crypto algorithm: %s", salgo);
+		g_free (salgo);
+		return FALSE;
+	}
+	g_free (salgo);
+		
+	/* Read in and interpret the hash algorithm */
+	if (!gkr_buffer_get_string (input, *offset, offset, &salgo, NULL))
+		return FALSE;
+	halgo = gcry_md_map_name (salgo);
+	if (!halgo) {
+		g_warning ("unsupported crypto algorithm: %s", salgo);
+		g_free (salgo);
+		return FALSE;
+	}
+	g_free (salgo);
+		
+	/* Read in the iterations, salt, and encrypted data */
+	if (!gkr_buffer_get_uint32 (input, *offset, offset, &iterations) ||
+	    !gkr_buffer_get_byte_array (input, *offset, offset, &salt, &n_salt) ||
+	    !gkr_buffer_get_byte_array (input, *offset, offset, &data, &n_data))
+		return FALSE;
+
+	/* Significant block sizes */
+	n_block = gcry_cipher_get_algo_blklen (calgo);
+	g_return_val_if_fail (n_block, FALSE);
+	
+	/* Make sure the encrypted data is of a good length */
+	if (n_data % n_block != 0) {
+		g_warning ("encrypted data in file store is of an invalid length for algorithm");
+		return FALSE;
+	}
+
+	/* Create the cipher context */
+	if (!create_cipher (calgo, halgo, password, n_password, 
+	                    salt, n_salt, iterations, &cipher))
+		return FALSE;
+
+	/* Now reserve space for it in the output block, and encrypt */
+	gkr_buffer_reset (output);
+	gkr_buffer_resize (output, n_data);
+
+	gcry = gcry_cipher_decrypt (cipher, output->buf, output->len, data, n_data);
+	g_return_val_if_fail (!gcry, FALSE);
+	
+	gcry_cipher_close (cipher);
+
+	return TRUE;
+}
+
+/* ----------------------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static GHashTable*
+add_entry (GHashTable *entries, gchar *unique)
+{
+	GHashTable *attributes;
+	
+	g_assert (entries);
+	g_assert (unique);
+	
+	attributes = g_hash_table_new_full (gck_util_ulong_hash, gck_util_ulong_equal, NULL, attribute_free);
+	g_hash_table_replace (entries, unique, attributes);
+
+	return attributes;
+}
+
+static const gchar*
+read_entry (GckFileStore *self, GHashTable *entries, 
+            GkrBuffer *buffer, gsize *offset)
+{
+	gboolean added = FALSE;
+	CK_ATTRIBUTE attr;
+	CK_ATTRIBUTE_PTR at;
+	gpointer key, value;
+	GHashTable *attributes;
+	gchar *unique, *str;
+	const guchar *data;
+	GckObject *object;
+	gsize n_data;
+	guint64 type;
+	guint32 count, i;
+	
+	g_assert (GCK_IS_FILE_STORE (self));
+	g_assert (buffer);
+	g_assert (offset);
+	g_assert (attributes);
+	
+	if (!gkr_buffer_get_string (buffer, *offset, offset, &str, (GkrBufferAllocator)g_realloc))
+		return NULL;
+	
+	if (g_hash_table_lookup_extended (entries, str, &key, &value)) {
+		unique = key;
+		attributes = value;
+		g_free (str);
+
+		/* Any object that's associated with this */
+		object = g_hash_table_lookup (self->object_by_unique, unique);
+		added = FALSE;
+
+	} else {
+		unique = str;
+		attributes = add_entry (entries, unique);
+		
+		/* No object should yet be associated */
+		object = NULL;
+		added = TRUE;
+	} 
+	
+	if (!gkr_buffer_get_uint32 (buffer, *offset, offset, &count))
+		return NULL;
+	
+	for (i = 0; i < count; ++i) {
+		if (!gkr_buffer_get_uint64 (buffer, *offset, offset, &type) ||
+		    !gkr_buffer_get_byte_array (buffer, *offset, offset, &data, &n_data))
+			return NULL;
+		
+		attr.type = type;
+		attr.pValue = (CK_VOID_PTR)data;
+		attr.ulValueLen = n_data;
+		
+		at = g_hash_table_lookup (attributes, &attr.type);
+		if (at != NULL && gck_attribute_equal (&attr, at))
+			continue;
+		
+		at = attribute_dup (&attr);
+		g_hash_table_replace (attributes, &(at->type), at);
+		
+		if (object != NULL) 
+			gck_object_notify_attribute (object, at->type);
+	}
+	
+	if (added) {
+		g_assert (!object);
+		g_signal_emit (self, signals[ENTRY_CREATED], 0, unique);
+	}
+	
+	g_assert (unique);
+	return unique;
+}
+
+static void
+clear_each_entry (gpointer key, gpointer value, gpointer data)
+{
+	GHashTable *attributes = value;
+	g_hash_table_remove_all (attributes);
+}
+
+static void
+copy_each_unique_id (gpointer key, gpointer value, gpointer data)
+{
+	g_hash_table_insert (data, g_strdup (key), GUINT_TO_POINTER (1));
+}
+
+static void
+destroy_each_unique_id (gpointer key, gpointer value, gpointer data)
+{
+	/* Our default handler does the actual remove */
+	g_signal_emit (data, signals[ENTRY_DESTROYED], 0, key);
+}
+
+static gboolean
+read_entries (GckFileStore *self, GHashTable *entries, GkrBuffer *buffer, gsize *offset)
+{
+	GHashTable *checks;
+	const gchar *unique;
+	guint32 count, i;
+	
+	g_assert (GCK_IS_FILE_STORE (self));
+	g_assert (entries);
+	g_assert (buffer);
+	g_assert (offset);
+	
+	/* The number of entries */
+	if (!gkr_buffer_get_uint32 (buffer, *offset, offset, &count))
+		return FALSE;
+
+	checks = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+	g_hash_table_foreach (entries, copy_each_unique_id, checks);
+	
+	for (i = 0; i < count; ++i) {
+		unique = read_entry (self, entries, buffer, offset);
+		if (!unique) {
+			g_hash_table_destroy (checks);
+			return FALSE;
+		}
+		
+		g_hash_table_remove (checks, unique);
+	}
+
+	g_hash_table_foreach (checks, destroy_each_unique_id, self);
+	g_hash_table_destroy (checks);
+	return TRUE;
+}
+
+static gboolean
+read_from_block (guint block, GkrBuffer *buffer, gpointer user_data)
+{
+	GckFileStore *self;
+	gsize offset;
+	GkrBuffer custom;
+	GHashTable *attributes;
+	gboolean ret = FALSE;
+	
+	g_assert (GCK_IS_FILE_STORE (user_data));
+	g_assert (buffer);
+
+	self = GCK_FILE_STORE (user_data);
+	
+	switch (block) {
+	case FILE_BLOCK_PRIVATE:
+		/* Skip private blocks when not unlocked */
+		if (self->locked)
+			return TRUE;
+
+		attributes = self->privates;
+		gkr_buffer_init_full (&custom, 1024, gkr_secure_realloc);
+
+		offset = 0;
+		if (!decrypt_buffer (buffer, &offset, self->password, self->n_password, &custom)) {
+			g_warning ("couldn't decrypt private attributes in store file");
+			gkr_buffer_uninit (&custom);
+			return FALSE;
+		}
+		
+		buffer = &custom;
+		break;
+		
+	case FILE_BLOCK_PUBLIC:
+		attributes = self->publics;
+		gkr_buffer_init_static (&custom, NULL, 0);
+		break;
+		
+	default:
+		return TRUE;
+	}
+	
+	offset = 0;
+
+	/* Validate the buffer hash, failure is usually a bad password */
+	if (!validate_buffer (buffer, &offset)) {
+		if (block == FILE_BLOCK_PRIVATE)
+			++self->unlock_failures;
+		ret = FALSE;
+	} else {
+		ret = read_entries (self, attributes, buffer, &offset);
+	}
+	
+	gkr_buffer_uninit (&custom);
+	return ret;	
+}
+
+static void
+write_each_attribute (gpointer key, gpointer value, gpointer data)
+{
+	CK_ATTRIBUTE_PTR attr = value;
+	GkrBuffer *buffer = data;
+	gkr_buffer_add_uint64 (buffer, attr->type);
+	g_assert (attr->ulValueLen != (gulong)-1);
+	gkr_buffer_add_byte_array (buffer, attr->pValue, attr->ulValueLen);
+}
+
+static void
+write_each_entry (gpointer key, gpointer value, gpointer data)
+{
+	GkrBuffer *buffer = data;
+	const gchar *unique = key;
+	GHashTable *attributes = value;
+	
+	gkr_buffer_add_string (buffer, unique);
+	gkr_buffer_add_uint32 (buffer, g_hash_table_size (attributes));
+	g_hash_table_foreach (attributes, write_each_attribute, buffer);
+}
+
+static gboolean
+write_entries (GckFileStore *self, GkrBuffer *output, GHashTable *entries, gboolean is_private)
+{
+	GkrBuffer secure;
+	GkrBuffer *buffer;
+	gsize offset;
+	
+	g_assert (GCK_FILE_STORE (self));
+	g_assert (output);
+	
+	if (is_private) {
+		gkr_buffer_init_full (&secure, 1024, PRIVATE_ALLOC);
+		buffer = &secure;
+	} else {
+		gkr_buffer_init_static (&secure, NULL, 0);
+		buffer = output;
+	}
+	
+	/* Reserve space for the length */
+	offset = buffer->len;
+	gkr_buffer_add_uint32 (buffer, 0);
+	
+	/* The number of attributes we'll be encountering */
+	gkr_buffer_add_uint32 (buffer, g_hash_table_size (entries));
+	
+	/* Fill in the attributes */
+	g_hash_table_foreach (entries, write_each_entry, buffer);
+	
+	g_return_val_if_fail (!gkr_buffer_has_error (buffer), FALSE);
+	
+	/* Fill in the length */
+	gkr_buffer_set_uint32 (buffer, offset, buffer->len);
+	
+	/* Hash the entire dealio */
+	if (!hash_buffer (buffer)) {
+		gkr_buffer_uninit (&secure);
+		return FALSE;
+	}
+	
+	if (is_private) {
+		if (!encrypt_buffer (buffer, self->password, self->n_password, output)) {
+			gkr_buffer_uninit (&secure);
+			return FALSE;
+		}
+	}
+
+	gkr_buffer_uninit (&secure);
+	return TRUE;
+}
+
+static gboolean
+write_entries_block (GckFileStore *self, GHashTable *entries)
+{
+	GkrBuffer buffer;
+	gboolean is_private;
+	gboolean ret;
+	guint32 block;
+	
+	g_assert (GCK_IS_FILE_STORE (self));
+	g_assert (self->transaction_fd != -1);
+	g_assert (entries);
+	
+	if (entries == self->privates) {
+		is_private = TRUE;
+		block = FILE_BLOCK_PRIVATE;
+	} else {
+		is_private = FALSE;
+		block = FILE_BLOCK_PUBLIC;
+	}
+
+	g_assert (!is_private || !self->locked);
+	gkr_buffer_init_full (&buffer, 1024, PUBLIC_ALLOC);
+
+	ret = write_entries (self, &buffer, entries, is_private);
+	if (ret == TRUE && gkr_buffer_has_error (&buffer)) {
+		g_warning ("couldn't prepare file store buffer for writing");
+		g_return_val_if_reached (FALSE);
+	}
+	
+	ret = write_file_block (self->transaction_fd, block, &buffer);
+	gkr_buffer_uninit (&buffer);
+	return ret;
+}
+
+static gboolean
+write_extraneous_block (guint block, GkrBuffer *buffer, gpointer user_data)
+{
+	GckFileStore *self = GCK_FILE_STORE (user_data);
+	
+	g_assert (GCK_IS_FILE_STORE (user_data));
+	g_assert (self->transaction_fd != -1);
+	g_assert (buffer);
+	
+	self = GCK_FILE_STORE (user_data);
+	
+	switch (block) {
+	
+	/* We can always write public attribute blocks, skip. */
+	case FILE_BLOCK_PUBLIC:
+		return TRUE;
+		
+	/* We can write private attribute blocks when not locked, skip. */
+	case FILE_BLOCK_PRIVATE:
+		if (!self->locked)
+			return TRUE;
+		break;
+		
+	default:
+		break;
+	};
+	
+	/* Write out the block we don't or can't write */
+	if (!write_file_block (self->transaction_fd, block, buffer))
+		return FALSE;
+	
+	return TRUE;
+}
+
+static void
+cleanup_transaction (GckFileStore *self, GckTransaction *transaction)
+{
+	g_assert (GCK_IS_FILE_STORE (self));
+	g_assert (GCK_IS_TRANSACTION (transaction));
+	g_assert (self->transaction == transaction);
+	
+	if (self->previous_fd != -1)
+		close (self->previous_fd);
+	self->previous_fd = -1;
+	
+	if (self->transaction_fd != -1)
+		close (self->transaction_fd);
+	self->transaction_fd = -1;
+	
+	if (self->transaction_path) {
+		g_unlink (self->transaction_path);
+		g_free (self->transaction_path);
+		self->transaction_path = NULL;
+	}
+	
+	g_object_unref (self->transaction);
+	self->transaction = NULL;
+}
+
+static void
+fail_transaction (GckFileStore *self, GckTransaction *transaction)
+{
+	gck_transaction_fail (transaction, CKR_FUNCTION_FAILED);
+	cleanup_transaction (self, transaction);
+}
+
+static gboolean
+complete_transaction (GckTransaction *transaction, GckFileStore *self, gpointer unused)
+{
+	struct stat sb;
+	
+	g_return_val_if_fail (GCK_IS_FILE_STORE (self), FALSE);
+	g_return_val_if_fail (GCK_IS_TRANSACTION (transaction), FALSE);
+	g_return_val_if_fail (self->transaction == transaction, FALSE);
+	
+	if (!gck_transaction_get_failed (transaction)) {
+
+		if (!self->locked) {
+			if (!write_entries_block (self, self->privates))
+				return FALSE;
+		}
+			
+		if (!write_entries_block (self, self->publics))
+			return FALSE;
+		
+		/* Move the file into place */
+		if (g_rename (self->transaction_path, self->filename) == -1) {
+			g_warning ("couldn't rename temporary store file: %s", self->transaction_path);
+			return FALSE;
+		}
+		
+		/* Stat the file and save away the last mtime */
+		if (stat (self->filename, &sb) >= 0)
+			self->last_mtime = sb.st_mtime;
+		
+	} else {
+		
+		/* Transaction failed, load the old stuff again */
+		gck_file_store_refresh (self);
+	}
+	
+	/* And we're all done */
+	cleanup_transaction (self, transaction);
+	return TRUE;
+}
+
+#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 /* !HAVE_FLOCK */ 
+
+static gboolean
+prepare_transaction (GckFileStore *self, GckTransaction *transaction)
+{
+	struct stat sb;
+	guint tries = 0;
+	
+	g_assert (GCK_IS_FILE_STORE (self));
+	g_assert (GCK_IS_TRANSACTION (transaction));
+
+	if (self->transaction) {
+		g_return_val_if_fail (self->transaction == transaction, FALSE);
+		return TRUE;
+	}
+	
+	g_return_val_if_fail (self->filename, FALSE);
+	g_assert (self->previous_fd == -1);
+	
+	self->transaction = g_object_ref (transaction);
+
+	/* File lock retry loop */
+	for (tries = 0; TRUE; ++tries) {
+		if (tries > MAX_LOCK_TRIES) {
+			g_message ("couldn't write to store file: %s: file is locked", self->filename);
+			fail_transaction (self, transaction);
+			return FALSE;
+		}
+
+		self->previous_fd = open (self->filename, O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR);
+		if (self->previous_fd == -1) {
+			g_message ("couldn't open store file: %s: %s", self->filename, g_strerror (errno));
+			fail_transaction (self, transaction);
+			return FALSE;
+		}
+	
+		if (flock (self->previous_fd, LOCK_EX | LOCK_NB) < 0) {
+
+			if (errno != EWOULDBLOCK) {
+				g_message ("couldn't lock store file: %s: %s", self->filename, g_strerror (errno));
+				fail_transaction (self, transaction);
+				return FALSE;
+			}
+				
+			close (self->previous_fd);
+			self->previous_fd = -1;
+			g_usleep (200000);
+			continue;
+		}
+
+		/* Successfully opened file */;
+		break;
+	}
+
+	/* See if file needs updating */
+	if (fstat (self->previous_fd, &sb) >= 0 && sb.st_mtime != self->last_mtime) {
+		if (!parse_file_blocks (self->previous_fd, read_from_block, self) || 
+		    lseek (self->previous_fd, 0, SEEK_SET) != 0) {
+			g_message ("couldn't update store from file: %s", self->filename);
+			fail_transaction (self, transaction);
+			return FALSE;
+		}
+			
+		self->last_mtime = sb.st_mtime;
+	}
+	
+	/* Open the new file */
+	g_assert (self->transaction_fd == -1);
+	self->transaction_path = g_strdup_printf ("%s.XXXXXX", self->filename);
+	self->transaction_fd = g_mkstemp (self->transaction_path);
+	if (self->transaction_fd == -1) {
+		g_message ("couldn't open new temporary store file: %s: %s", self->filename, g_strerror (errno));
+		fail_transaction (self, transaction);
+		return FALSE;
+	}
+	
+	/* Now write out everything that we don't understand from previous one into the new */
+	if (!write_all_bytes (self->transaction_fd, FILE_HEADER, FILE_HEADER_LEN) ||
+	    !parse_file_blocks (self->previous_fd, write_extraneous_block, self)) {
+		fail_transaction (self, transaction);
+		return FALSE;
+	}
+	
+	/* And we're ready for changes. */
+	gck_transaction_add (transaction, self, (GckTransactionFunc)complete_transaction, NULL);
+	return TRUE;
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT 
+ */
+
+static void 
+gck_file_store_real_entry_created (GckFileStore *self, const gchar *unique_id)
+{
+	/* Actual action happens elsewhere */
+	g_return_if_fail (g_hash_table_lookup (self->publics, unique_id) || 
+	                  g_hash_table_lookup (self->privates, unique_id));
+}
+
+static void 
+gck_file_store_real_entry_destroyed (GckFileStore *self, const gchar *unique_id)
+{
+	/* 
+	 * Note we don't remove the object -> unique mapping, we 
+	 * keep that unrelated.
+	 */
+	
+	/* Actual action happens here */
+	if (!g_hash_table_remove (self->publics, unique_id)) {
+		g_return_if_fail (self->locked);
+		if (!g_hash_table_remove (self->privates, unique_id))
+			g_return_if_reached ();
+	}
+}
+
+static CK_RV
+gck_file_store_real_read_value (GckStore *base, GckObject *object, CK_ATTRIBUTE_PTR attr)
+{
+	GckFileStore *self = GCK_FILE_STORE (base);
+	CK_ATTRIBUTE_PTR at;
+	GHashTable *attributes;
+	const gchar *unique;
+
+	g_return_val_if_fail (GCK_IS_FILE_STORE (self), CKR_GENERAL_ERROR);
+	g_return_val_if_fail (GCK_IS_OBJECT (object), CKR_GENERAL_ERROR);
+	g_return_val_if_fail (attr, CKR_GENERAL_ERROR);
+
+	unique = g_hash_table_lookup (self->unique_by_object, object);
+	if (!unique)
+		return CKR_ATTRIBUTE_TYPE_INVALID;
+	
+	if (self->last_mtime == 0) {
+		if (!gck_file_store_refresh (self))
+			return CKR_FUNCTION_FAILED;
+	}
+	
+	attributes = g_hash_table_lookup (self->publics, unique);
+	if (attributes == NULL) { 
+		attributes = g_hash_table_lookup (self->privates, unique);
+		if (attributes && self->locked)
+			return CKR_USER_NOT_LOGGED_IN;
+	}
+	
+	if (!attributes)
+		return CKR_ATTRIBUTE_TYPE_INVALID;
+	
+	at = g_hash_table_lookup (attributes, &(attr->type));
+	if (at == NULL)
+		return CKR_ATTRIBUTE_TYPE_INVALID;
+	
+	g_assert (at->type == attr->type);
+	
+	/* Yes, we don't fill a buffer, just return pointer */
+	attr->pValue = at->pValue;
+	attr->ulValueLen = at->ulValueLen;
+	
+	return CKR_OK;
+}
+
+static void
+gck_file_store_real_write_value (GckStore *base, GckTransaction *transaction, 
+                                 GckObject *object, CK_ATTRIBUTE_PTR attr)
+{
+	GckFileStore *self = GCK_FILE_STORE (base);
+	CK_ATTRIBUTE_PTR at;
+	GHashTable *attributes;
+	const gchar *unique;
+	
+	g_return_if_fail (GCK_IS_FILE_STORE (self));
+	g_return_if_fail (GCK_IS_OBJECT (object));
+	g_return_if_fail (GCK_IS_TRANSACTION (transaction));
+	g_return_if_fail (!gck_transaction_get_failed (transaction));
+	g_return_if_fail (attr);
+
+	unique = g_hash_table_lookup (self->unique_by_object, object);
+	if (!unique) {
+		gck_transaction_fail (transaction, CKR_ATTRIBUTE_READ_ONLY);
+		return;
+	}
+	
+	if (self->last_mtime == 0) {
+		if (!gck_file_store_refresh (self))
+			gck_transaction_fail (transaction, CKR_FUNCTION_FAILED);
+	}
+
+	attributes = g_hash_table_lookup (self->publics, unique);
+	if (attributes == NULL) {
+		attributes = g_hash_table_lookup (self->privates, unique);
+		if (attributes && self->locked) {
+			gck_transaction_fail (transaction, CKR_USER_NOT_LOGGED_IN);
+			return;
+		}
+	}
+
+	if (!attributes) {
+		gck_transaction_fail (transaction, CKR_ATTRIBUTE_READ_ONLY);
+		return;
+	}
+	
+	/* No need to go any further if no change */
+	at = g_hash_table_lookup (attributes, &(attr->type));
+	if (at != NULL && gck_attribute_equal (at, attr))
+		return;
+
+	if (!prepare_transaction (self, transaction))
+		return;
+
+	attr = attribute_dup (attr);
+	g_hash_table_replace (attributes, &(attr->type), attr);
+	gck_object_notify_attribute (object, attr->type);
+}
+
+static GObject* 
+gck_file_store_constructor (GType type, guint n_props, GObjectConstructParam *props) 
+{
+	GckFileStore *self = GCK_FILE_STORE (G_OBJECT_CLASS (gck_file_store_parent_class)->constructor(type, n_props, props));
+	g_return_val_if_fail (self, NULL);	
+
+	g_return_val_if_fail (self->filename, NULL);
+	
+	return G_OBJECT (self);
+}
+
+static void
+gck_file_store_init (GckFileStore *self)
+{
+	self->object_by_unique = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+	self->unique_by_object = g_hash_table_new (g_direct_hash, g_direct_equal);
+	self->publics = g_hash_table_new_full (g_str_hash, g_str_equal, 
+	                                       NULL, (GDestroyNotify)g_hash_table_unref);
+	self->privates = g_hash_table_new_full (g_str_hash, g_str_equal, 
+	                                        NULL, (GDestroyNotify)g_hash_table_unref);
+	self->previous_fd = -1;
+	self->transaction_fd = -1;
+	self->locked = TRUE;
+}
+
+static void
+gck_file_store_dispose (GObject *obj)
+{
+	GckFileStore *self = GCK_FILE_STORE (obj);
+
+	g_hash_table_remove_all (self->unique_by_object);
+	g_hash_table_remove_all (self->object_by_unique);
+	
+	G_OBJECT_CLASS (gck_file_store_parent_class)->dispose (obj);
+}
+
+static void
+gck_file_store_finalize (GObject *obj)
+{
+	GckFileStore *self = GCK_FILE_STORE (obj);
+
+	g_free (self->filename);
+	self->filename = NULL;
+	
+	g_hash_table_destroy (self->object_by_unique);
+	self->object_by_unique = NULL;
+	g_hash_table_destroy (self->unique_by_object);
+	self->unique_by_object = NULL;
+	
+	g_hash_table_destroy (self->publics);
+	g_hash_table_destroy (self->privates);
+
+	gkr_secure_free (self->password);
+	self->password = NULL;
+	self->n_password = 0;
+	
+	G_OBJECT_CLASS (gck_file_store_parent_class)->finalize (obj);
+}
+
+static void
+gck_file_store_set_property (GObject *obj, guint prop_id, const GValue *value, 
+                             GParamSpec *pspec)
+{
+	GckFileStore *self = GCK_FILE_STORE (obj);
+	
+	switch (prop_id) {
+	case PROP_FILENAME:
+		g_return_if_fail (!self->filename);
+		self->filename = g_value_dup_string (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gck_file_store_get_property (GObject *obj, guint prop_id, GValue *value, 
+                             GParamSpec *pspec)
+{
+	GckFileStore *self = GCK_FILE_STORE (obj);
+	
+	switch (prop_id) {
+	case PROP_FILENAME:
+		g_value_set_string (value, gck_file_store_get_filename (self));
+		break;
+	case PROP_LOCKED:
+		g_value_set_boolean (value, gck_file_store_get_locked (self));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gck_file_store_class_init (GckFileStoreClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GckStoreClass *store_class = GCK_STORE_CLASS (klass);
+    
+	gobject_class->constructor = gck_file_store_constructor;
+	gobject_class->dispose = gck_file_store_dispose;
+	gobject_class->finalize = gck_file_store_finalize;
+	gobject_class->set_property = gck_file_store_set_property;
+	gobject_class->get_property = gck_file_store_get_property;
+
+	store_class->read_value = gck_file_store_real_read_value;
+	store_class->write_value = gck_file_store_real_write_value;
+	
+	klass->entry_created = gck_file_store_real_entry_created;
+	klass->entry_destroyed = gck_file_store_real_entry_destroyed;
+	
+	g_object_class_install_property (gobject_class, PROP_FILENAME,
+	           g_param_spec_string ("filename", "File Name", "File name of the store", 
+	                                NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+	g_object_class_install_property (gobject_class, PROP_LOCKED,
+	           g_param_spec_boolean ("locked", "Locked", "Whether store is locked", 
+	                                 TRUE, G_PARAM_READABLE));
+    
+	signals[ENTRY_CREATED] = g_signal_new ("entry-created", GCK_TYPE_FILE_STORE, 
+	                                G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GckFileStoreClass, entry_created),
+	                                NULL, NULL, g_cclosure_marshal_VOID__STRING, 
+	                                G_TYPE_NONE, 1, G_TYPE_STRING);
+	
+	signals[ENTRY_DESTROYED] = g_signal_new ("entry-destroyed", GCK_TYPE_FILE_STORE, 
+	                                G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GckFileStoreClass, entry_destroyed),
+	                                NULL, NULL, g_cclosure_marshal_VOID__STRING, 
+	                                G_TYPE_NONE, 1, G_TYPE_STRING);
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC 
+ */
+
+GckFileStore*
+gck_file_store_new (const gchar *filename)
+{
+	g_return_val_if_fail (filename, NULL);
+	g_return_val_if_fail (filename[0], NULL);
+	return g_object_new (GCK_TYPE_FILE_STORE, "filename", filename, NULL);
+}
+
+gboolean
+gck_file_store_have_entry (GckFileStore *self, const gchar *unique_id)
+{
+	g_return_val_if_fail (GCK_IS_FILE_STORE (self), FALSE);
+	g_return_val_if_fail (unique_id, FALSE);
+
+	return (g_hash_table_lookup (self->publics, unique_id) || 
+	        g_hash_table_lookup (self->privates, unique_id));
+}
+
+void
+gck_file_store_create_entry (GckFileStore *self, GckTransaction *transaction,
+                             const gchar *unique_id, gboolean is_private)
+{
+	GHashTable *entries;
+	gchar *unique;
+	
+	g_return_if_fail (GCK_IS_FILE_STORE (self));
+	g_return_if_fail (GCK_IS_TRANSACTION (transaction));
+	g_return_if_fail (unique_id);
+	
+	/* We can't add an entry twice */
+	if (is_private) {
+		g_return_if_fail (!self->locked);
+		entries = self->privates;
+	} else {
+		entries = self->publics;
+	}
+
+	g_return_if_fail (g_hash_table_lookup (entries, unique_id) == NULL);
+	
+	if (!prepare_transaction (self, transaction))
+		return;
+	
+	unique = g_strdup (unique_id);
+	add_entry (entries, unique);
+	g_signal_emit (self, signals[ENTRY_CREATED], 0, unique);
+}
+
+void
+gck_file_store_connect_entry (GckFileStore *self, const gchar *unique_id, GckObject *object)
+{
+	gchar *unique;
+	
+	g_return_if_fail (GCK_IS_FILE_STORE (self));
+	g_return_if_fail (GCK_IS_OBJECT (object));
+	g_return_if_fail (unique_id);
+	
+	g_return_if_fail (g_hash_table_lookup (self->object_by_unique, unique_id) == NULL);
+	g_return_if_fail (g_hash_table_lookup (self->unique_by_object, object) == NULL);
+
+	unique = g_strdup (unique_id);
+	g_hash_table_replace (self->object_by_unique, unique, object);
+	g_hash_table_replace (self->unique_by_object, object, unique);
+}
+
+void
+gck_file_store_disconnect_entry (GckFileStore *self, const gchar *unique_id, GckObject *object)
+{
+	const gchar *unique;
+	g_return_if_fail (GCK_IS_FILE_STORE (self));
+	g_return_if_fail (GCK_IS_OBJECT (object));
+	g_return_if_fail (unique_id);
+	
+	g_return_if_fail (g_hash_table_lookup (self->object_by_unique, unique_id) == object);
+	unique = g_hash_table_lookup (self->unique_by_object, object);
+	g_return_if_fail (unique && g_str_equal (unique, unique_id));
+
+	g_hash_table_remove (self->unique_by_object, object);
+	g_hash_table_remove (self->object_by_unique, unique);
+}
+
+void
+gck_file_store_destroy_entry (GckFileStore *self, GckTransaction *transaction,
+                              const gchar *unique_id)
+{
+	g_return_if_fail (GCK_IS_FILE_STORE (self));
+	g_return_if_fail (GCK_IS_TRANSACTION (transaction));
+	g_return_if_fail (unique_id);
+
+	/* Can't destroy something that doesn't exist */
+	if (!g_hash_table_lookup (self->publics, unique_id) && 
+	    !g_hash_table_lookup (self->privates, unique_id)) {
+		g_return_if_reached ();
+	}
+	
+	if (!prepare_transaction (self, transaction))
+		return;
+
+	/* The default handler actually does the deed */
+	g_signal_emit (self, signals[ENTRY_DESTROYED], 0, unique_id);
+}
+
+const gchar*
+gck_file_store_get_filename (GckFileStore *self)
+{
+	g_return_val_if_fail (GCK_IS_FILE_STORE (self), NULL);
+	return self->filename;
+}
+
+gboolean
+gck_file_store_refresh (GckFileStore *self)
+{
+	struct stat sb;
+	gboolean ret;
+	int file;
+	
+	g_return_val_if_fail (GCK_IS_FILE_STORE (self), FALSE);
+	
+	/* Open the file for reading */
+	file = open (self->filename, O_RDONLY, 0);
+	if (file == -1) {
+		/* No file, no worries */
+		if (errno == ENOENT)
+			return TRUE;
+		g_message ("couldn't open store file: %s: %s", self->filename, g_strerror (errno));
+		return FALSE;
+	}
+
+	/* Try and update the last read time */
+	if (fstat (file, &sb) >= 0) 
+		self->last_mtime = sb.st_mtime;
+
+	ret = parse_file_blocks (file, read_from_block, self);
+
+	/* Force a reread on next write */
+	if (ret == FALSE)
+		self->last_mtime = 0;
+	
+	close (file);
+	return ret;
+}
+
+CK_RV
+gck_file_store_unlock (GckFileStore *self, guchar *password,
+                       gsize n_password)
+{
+	g_return_val_if_fail (GCK_IS_FILE_STORE (self), CKR_GENERAL_ERROR);
+	
+	if (!self->locked)
+		return CKR_USER_ALREADY_LOGGED_IN;
+	
+	/* Don't copy until we're sure it worked */
+	g_assert (!self->password);
+	self->password = password;
+	self->n_password = n_password;
+	self->unlock_failures = 0;
+	self->locked = FALSE;
+	
+	if (!gck_file_store_refresh (self)) {
+		self->locked = TRUE;
+		self->password = NULL;
+		self->n_password = 0;
+		if (self->unlock_failures)
+			return CKR_PIN_INCORRECT;
+		else
+			return CKR_FUNCTION_FAILED;
+	}
+	
+	if (self->password) {
+		self->password = gkr_secure_alloc (n_password);
+		memcpy (self->password, password, n_password);
+		self->n_password = n_password;
+	}
+	
+	self->locked = FALSE;
+	g_object_notify (G_OBJECT (self), "locked");
+	return CKR_OK;
+}
+
+CK_RV
+gck_file_store_lock (GckFileStore *self)
+{
+	g_return_val_if_fail (GCK_IS_FILE_STORE (self), CKR_GENERAL_ERROR);
+	
+	if (self->locked)
+		return CKR_USER_NOT_LOGGED_IN;
+
+	/* Remove all data for each private one */
+	g_hash_table_foreach (self->privates, clear_each_entry, NULL);
+	
+	gkr_secure_free (self->password);
+	self->password = NULL;
+	self->n_password = 0;
+	self->locked = TRUE;
+	g_object_notify (G_OBJECT (self), "locked");
+	
+	return CKR_OK;
+}
+
+gboolean
+gck_file_store_get_locked (GckFileStore *self)
+{
+	g_return_val_if_fail (GCK_IS_FILE_STORE (self), TRUE);
+	return self->locked;
+}

Added: trunk/pkcs11/gck/gck-file-store.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-file-store.h	Sat Jan  3 19:30:08 2009
@@ -0,0 +1,86 @@
+/* 
+ * gnome-keyring
+ * 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program 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
+ * Lesser General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef __GCK_FILE_STORE_H__
+#define __GCK_FILE_STORE_H__
+
+#include <glib-object.h>
+
+#include "gck-store.h"
+#include "gck-types.h"
+
+#define GCK_TYPE_FILE_STORE               (gck_file_store_get_type ())
+#define GCK_FILE_STORE(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_FILE_STORE, GckFileStore))
+#define GCK_FILE_STORE_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCK_TYPE_FILE_STORE, GckFileStoreClass))
+#define GCK_IS_FILE_STORE(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCK_TYPE_FILE_STORE))
+#define GCK_IS_FILE_STORE_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_FILE_STORE))
+#define GCK_FILE_STORE_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_FILE_STORE, GckFileStoreClass))
+
+typedef struct _GckFileStore GckFileStore;
+typedef struct _GckFileStoreClass GckFileStoreClass;
+    
+struct _GckFileStoreClass {
+	GckStoreClass parent_class;
+	
+	/* signals */
+	
+	void (*entry_created) (GckFileStore *store, const gchar *unique_id);
+	
+	void (*entry_destroyed) (GckFileStore *store, const gchar *unique_id);
+};
+
+GType                     gck_file_store_get_type               (void);
+
+GckFileStore*             gck_file_store_new                    (const gchar *filename);
+
+const gchar*              gck_file_store_get_filename           (GckFileStore *self);
+
+gboolean                  gck_file_store_refresh                (GckFileStore *self);
+
+CK_RV                     gck_file_store_unlock                 (GckFileStore *self,
+                                                                 guchar *password,
+                                                                 gsize n_password);
+
+CK_RV                     gck_file_store_lock                   (GckFileStore *self);
+
+gboolean                  gck_file_store_get_locked             (GckFileStore *self);
+
+gboolean                  gck_file_store_have_entry             (GckFileStore *self,
+                                                                 const gchar *unique_id);
+
+void                      gck_file_store_create_entry           (GckFileStore *self, 
+                                                                 GckTransaction *transaction,
+                                                                 const gchar *unique_id,
+                                                                 gboolean is_private);
+
+void                      gck_file_store_connect_entry          (GckFileStore *self, 
+                                                                 const gchar *unique_id,
+                                                                 GckObject *object);
+
+void                      gck_file_store_disconnect_entry       (GckFileStore *self, 
+                                                                 const gchar *unique_id,
+                                                                 GckObject *object);
+
+void                      gck_file_store_destroy_entry          (GckFileStore *self, 
+                                                                 GckTransaction *transaction,
+                                                                 const gchar *unique_id);
+
+#endif /* __GCK_FILE_STORE_H__ */

Modified: trunk/pkcs11/gck/gck-key.c
==============================================================================
--- trunk/pkcs11/gck/gck-key.c	(original)
+++ trunk/pkcs11/gck/gck-key.c	Sat Jan  3 19:30:08 2009
@@ -23,6 +23,7 @@
 
 #include "pkcs11/pkcs11.h"
 
+#include "gck-attributes.h"
 #include "gck-crypto.h"
 #include "gck-key.h"
 #include "gck-util.h"
@@ -57,9 +58,9 @@
 		{
 			switch (gck_key_get_algorithm (self)) {
 			case GCRY_PK_RSA:
-				return gck_util_set_ulong (attr, CKK_RSA);
+				return gck_attribute_set_ulong (attr, CKK_RSA);
 			case GCRY_PK_DSA:
-				return gck_util_set_ulong (attr, CKK_DSA);
+				return gck_attribute_set_ulong (attr, CKK_DSA);
 			default:
 				g_return_val_if_reached (CKR_GENERAL_ERROR);
 			};
@@ -72,30 +73,30 @@
 			g_return_val_if_fail (self->pv->base_sexp, CKR_GENERAL_ERROR);
 			if (!gcry_pk_get_keygrip (gck_sexp_get (self->pv->base_sexp), hash))
 				g_return_val_if_reached (CKR_GENERAL_ERROR);
-			return gck_util_set_data (attr, hash, sizeof (hash));
+			return gck_attribute_set_data (attr, hash, sizeof (hash));
 		}
 		break;
 		
 	case CKA_START_DATE:
 	case CKA_END_DATE:
-		return gck_util_set_data (attr, "", 0);
+		return gck_attribute_set_data (attr, "", 0);
 	
 	case CKA_DERIVE:
-		return gck_util_set_bool (attr, FALSE);
+		return gck_attribute_set_bool (attr, FALSE);
 		
 	case CKA_LOCAL:
-		return gck_util_set_bool (attr, FALSE);
+		return gck_attribute_set_bool (attr, FALSE);
 		
 	case CKA_KEY_GEN_MECHANISM:
-		return gck_util_set_ulong (attr, CK_UNAVAILABLE_INFORMATION);
+		return gck_attribute_set_ulong (attr, CK_UNAVAILABLE_INFORMATION);
 		
 	case CKA_ALLOWED_MECHANISMS:
 		switch (gck_key_get_algorithm (self)) {
 		case GCRY_PK_RSA:
-			return gck_util_set_data (attr, (CK_VOID_PTR)GCK_CRYPTO_RSA_MECHANISMS, 
+			return gck_attribute_set_data (attr, (CK_VOID_PTR)GCK_CRYPTO_RSA_MECHANISMS, 
 			                          sizeof (GCK_CRYPTO_RSA_MECHANISMS));
 		case GCRY_PK_DSA:
-			return gck_util_set_data (attr, (CK_VOID_PTR)GCK_CRYPTO_DSA_MECHANISMS, 
+			return gck_attribute_set_data (attr, (CK_VOID_PTR)GCK_CRYPTO_DSA_MECHANISMS, 
 			                          sizeof (GCK_CRYPTO_DSA_MECHANISMS));
 		default:
 			g_return_val_if_reached (CKR_GENERAL_ERROR);
@@ -104,7 +105,7 @@
 	/* Lookup the certificate subject */
 	case CKA_SUBJECT:
 		/* TODO: When we have certificates, implement this */
-		return gck_util_set_data (attr, "", 0);
+		return gck_attribute_set_data (attr, "", 0);
 	};
 
 	return GCK_OBJECT_CLASS (gck_key_parent_class)->get_attribute (base, attr);
@@ -274,7 +275,7 @@
 	
 	if (!gck_crypto_sexp_extract_mpi (numbers, &mpi, part, NULL))
 		g_return_val_if_reached (CKR_GENERAL_ERROR);
-	rv = gck_util_set_mpi (attr, mpi);
+	rv = gck_attribute_set_mpi (attr, mpi);
 	gcry_sexp_release (numbers);
 	gcry_mpi_release (mpi);
 	

Modified: trunk/pkcs11/gck/gck-key.h
==============================================================================
--- trunk/pkcs11/gck/gck-key.h	(original)
+++ trunk/pkcs11/gck/gck-key.h	Sat Jan  3 19:30:08 2009
@@ -26,6 +26,7 @@
 
 #include "gck-sexp.h"
 #include "gck-object.h"
+#include "gck-types.h"
 
 #define GCK_TYPE_KEY               (gck_key_get_type ())
 #define GCK_KEY(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_KEY, GckKey))
@@ -34,7 +35,6 @@
 #define GCK_IS_KEY_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_KEY))
 #define GCK_KEY_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_KEY, GckKeyClass))
 
-typedef struct _GckKey GckKey;
 typedef struct _GckKeyClass GckKeyClass;
 typedef struct _GckKeyPrivate GckKeyPrivate;
     

Modified: trunk/pkcs11/gck/gck-manager.c
==============================================================================
--- trunk/pkcs11/gck/gck-manager.c	(original)
+++ trunk/pkcs11/gck/gck-manager.c	Sat Jan  3 19:30:08 2009
@@ -21,6 +21,7 @@
 
 #include "config.h"
 
+#include "gck-attributes.h"
 #include "gck-manager.h"
 #include "gck-util.h"
 
@@ -73,51 +74,6 @@
 	}
 }
 
-static gboolean
-attribute_equal (gconstpointer v1, gconstpointer v2)
-{
-	const CK_ATTRIBUTE *a1 = v1;
-	const CK_ATTRIBUTE *a2 = v2;
-	
-	g_assert (a1);
-	g_assert (a2);
-	
-	if (a1 == a2)
-		return TRUE;
-	if (a1->type != a2->type)
-		return FALSE;
-	if (a1->ulValueLen != a2->ulValueLen)
-		return FALSE;
-	if (a1->pValue == a2->pValue)
-		return TRUE;
-	
-	g_assert (a1->pValue);
-	g_assert (a2->pValue);
-	
-	return memcmp (a1->pValue, a2->pValue, a1->ulValueLen) == 0;
-}
-
-static guint
-attribute_hash (gconstpointer v)
-{
-	const CK_ATTRIBUTE *a = v;
-	const signed char *p;
-	guint i, h;
-	
-	g_assert (a);
-	
-	p = (const signed char*)&(a->type);
-	h = *p;
-	for(i = 0; i < sizeof (CK_ATTRIBUTE_PTR); ++i)
-		h = (h << 5) - h + *(p++);
-	
-	p = a->pValue;
-	for(i = 0; i < a->ulValueLen; ++i)
-		h = (h << 5) - h + *(p++);
-	
-	return h;
-}
-
 static Index*
 index_new (gboolean unique)
 {
@@ -125,9 +81,9 @@
 	index->unique = unique;
 	
 	if (unique)
-		index->values = g_hash_table_new_full (attribute_hash, attribute_equal, attribute_free, NULL);
+		index->values = g_hash_table_new_full (gck_attribute_hash, gck_attribute_equal, attribute_free, NULL);
 	else
-		index->values = g_hash_table_new_full (attribute_hash, attribute_equal, attribute_free,
+		index->values = g_hash_table_new_full (gck_attribute_hash, gck_attribute_equal, attribute_free,
 		                                       (GDestroyNotify)g_hash_table_destroy);
 	
 	index->objects = g_hash_table_new (g_direct_hash, g_direct_equal);
@@ -267,9 +223,58 @@
 }
 
 static void
-index_update (Index *index, GckObject *object)
+index_remove_attr (Index *index, gpointer object, CK_ATTRIBUTE_PTR attr)
+{
+	GHashTable *objects;
+
+	g_assert (index);
+	g_assert (object);
+	g_assert (attr);
+	
+	if (index->unique) {
+		if (!g_hash_table_remove (index->values, attr))
+			g_assert_not_reached ();
+	} else {
+		objects = g_hash_table_lookup (index->values, attr);
+		g_assert (objects);
+		if (!g_hash_table_remove (objects, object))
+			g_assert_not_reached ();
+		if (g_hash_table_size (objects) == 0)
+			if (!g_hash_table_remove (index->values, attr))
+				g_assert_not_reached ();
+	}
+}
+
+static void
+index_remove (Index *index, gpointer object)
 {
 	CK_ATTRIBUTE_PTR attr;
+
+	/* 
+	 * We don't actually access the object. We want to be able to 
+	 * handle objects that have been destroyed as well.
+	 */
+	
+	g_assert (object);
+	g_assert (index);
+	
+	attr = g_hash_table_lookup (index->objects, object);
+	
+	/* Object not in this index */
+	if (attr == NULL) 
+		return;
+
+	/* Remove the actual value */
+	index_remove_attr (index, object, attr);
+	
+	if (!g_hash_table_remove (index->objects, object))
+		g_assert_not_reached ();
+}
+
+static void
+index_update (Index *index, GckObject *object)
+{
+	CK_ATTRIBUTE_PTR attr, prev;
 	GHashTable *objects;
 	gboolean ret;
 
@@ -286,7 +291,20 @@
 	/* No such attribute/property on object */
 	if (attr == NULL)
 		return;
-	
+
+	prev = g_hash_table_lookup (index->objects, object);
+	if (prev != NULL) {
+		
+		/* The previous one is same, ignore */
+		if (gck_attribute_equal (prev, attr)) {
+			attribute_free (attr);
+			return;
+		}
+		
+		/* Remove the previous one */
+		index_remove_attr (index, object, prev);
+	} 
+
 	/* In this case values is a direct pointer to the object */
 	if (index->unique) {
 		g_return_if_fail (g_hash_table_lookup (index->values, attr) == NULL);
@@ -310,43 +328,6 @@
 	}
 }
 
-static void
-index_remove (Index *index, gpointer object)
-{
-	CK_ATTRIBUTE_PTR attr;
-	GHashTable *objects;
-
-	/* 
-	 * We don't actually access the object. We want to be able to 
-	 * handle objects that have been destroyed as well.
-	 */
-	
-	g_assert (object);
-	g_assert (index);
-	
-	attr = g_hash_table_lookup (index->objects, object);
-	
-	/* Object not in this index */
-	if (attr == NULL) 
-		return;
-	
-	if (index->unique) {
-		if (!g_hash_table_remove (index->values, attr))
-			g_assert_not_reached ();
-	} else {
-		objects = g_hash_table_lookup (index->values, attr);
-		g_assert (objects);
-		if (!g_hash_table_remove (objects, object))
-			g_assert_not_reached ();
-		if (g_hash_table_size (objects) == 0)
-			if (!g_hash_table_remove (index->values, attr))
-				g_assert_not_reached ();
-	}
-	
-	if (!g_hash_table_remove (index->objects, object))
-		g_assert_not_reached ();
-}
-
 static gboolean
 index_contains (Index *index, GckObject *object, CK_ATTRIBUTE_PTR attr)
 {
@@ -377,6 +358,34 @@
 }
 
 static void
+notify_attribute (GckObject *object, CK_ATTRIBUTE_TYPE attr_type, GckManager *self)
+{
+	Index *index;
+	
+	g_return_if_fail (GCK_IS_OBJECT (object));
+	g_return_if_fail (GCK_IS_MANAGER (self));
+	g_return_if_fail (gck_object_get_manager (object) == self);
+	
+	index = g_hash_table_lookup (self->pv->index_by_attribute, &attr_type);
+	if (index != NULL) 
+		index_update (index, object);
+}
+
+static void
+notify_property (GckObject *object, GParamSpec *spec, GckManager *self)
+{
+	Index *index;
+	
+	g_return_if_fail (GCK_IS_OBJECT (object));
+	g_return_if_fail (GCK_IS_MANAGER (self));
+	g_return_if_fail (gck_object_get_manager (object) == self);
+	
+	index = g_hash_table_lookup (self->pv->index_by_property, spec->name);
+	if (index != NULL)
+		index_update (index, object);
+}
+
+static void
 add_object (GckManager *self, GckObject *object)
 {
 	CK_OBJECT_HANDLE handle;
@@ -406,6 +415,8 @@
 	/* Now index the object properly */
 	g_hash_table_foreach (self->pv->index_by_attribute, index_object_each, object);
 	g_hash_table_foreach (self->pv->index_by_property, index_object_each, object);
+	g_signal_connect (object, "notify-attribute", G_CALLBACK (notify_attribute), self);
+	g_signal_connect (object, "notify", G_CALLBACK (notify_property), self);
 }
 
 static void
@@ -420,16 +431,17 @@
 	handle = gck_object_get_handle (object);
 	g_assert (handle);
 	
-	/* Release object management */		
-	self->pv->objects = g_list_remove (self->pv->objects, object);
-	g_object_set (object, "manager", NULL, NULL);
-	
 	/* Remove from all indexes */
+	g_signal_handlers_disconnect_by_func (object, G_CALLBACK (notify_attribute), self);
+	g_signal_handlers_disconnect_by_func (object, G_CALLBACK (notify_property), self);
 	g_hash_table_foreach (self->pv->index_by_attribute, index_remove_each, object);
 	g_hash_table_foreach (self->pv->index_by_property, index_remove_each, object);
+	
+	/* Release object management */		
+	self->pv->objects = g_list_remove (self->pv->objects, object);
+	g_object_set (object, "manager", NULL, NULL);
 }
 
-
 static void
 find_each_object (gpointer unused, gpointer object, gpointer user_data)
 {

Modified: trunk/pkcs11/gck/gck-manager.h
==============================================================================
--- trunk/pkcs11/gck/gck-manager.h	(original)
+++ trunk/pkcs11/gck/gck-manager.h	Sat Jan  3 19:30:08 2009
@@ -48,7 +48,9 @@
 
 G_BEGIN_DECLS
 
-#include "gck-object.h"
+#include <glib-object.h>
+
+#include "gck-types.h"
 
 #include "pkcs11/pkcs11.h"
 

Added: trunk/pkcs11/gck/gck-marshal.list
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-marshal.list	Sat Jan  3 19:30:08 2009
@@ -0,0 +1 @@
+BOOLEAN:VOID

Added: trunk/pkcs11/gck/gck-memory-store.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-memory-store.c	Sat Jan  3 19:30:08 2009
@@ -0,0 +1,261 @@
+/* 
+ * gnome-keyring
+ * 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program 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
+ * Lesser General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include "config.h"
+
+#include "gck-attributes.h"
+#include "gck-object.h"
+#include "gck-memory-store.h"
+#include "gck-transaction.h"
+#include "gck-util.h"
+
+struct _GckMemoryStore {
+	GckStore parent;
+	GHashTable *entries;
+};
+
+typedef struct _Revert {
+	GHashTable *attributes;
+	CK_ATTRIBUTE_TYPE type;
+	CK_ATTRIBUTE_PTR attr;
+} Revert;
+
+G_DEFINE_TYPE (GckMemoryStore, gck_memory_store, GCK_TYPE_STORE);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL 
+ */
+
+static void
+attribute_free (gpointer data)
+{
+	CK_ATTRIBUTE_PTR attr = data;
+	if (attr) {
+		g_free (attr->pValue);
+		g_slice_free (CK_ATTRIBUTE, attr);
+	}
+}
+
+static CK_ATTRIBUTE_PTR
+attribute_dup (CK_ATTRIBUTE_PTR attr)
+{
+	CK_ATTRIBUTE_PTR copy;
+	g_assert (attr);
+	copy = g_slice_new (CK_ATTRIBUTE);
+	copy->ulValueLen = attr->ulValueLen;
+	copy->pValue = g_memdup (attr->pValue, copy->ulValueLen);
+	copy->type = attr->type;
+	return copy;
+}
+
+static void
+object_gone (gpointer data, GObject *was_object)
+{
+	GckMemoryStore *self;
+	
+	g_assert (GCK_IS_MEMORY_STORE (data));
+	self = GCK_MEMORY_STORE (data);
+	
+	if (!g_hash_table_remove (self->entries, was_object))
+		g_return_if_reached ();
+}
+
+static gboolean
+remove_each_object (gpointer key, gpointer value, gpointer user_data)
+{
+	g_assert (GCK_IS_OBJECT (key));
+	g_assert (GCK_IS_MEMORY_STORE (user_data));
+	
+	g_object_weak_unref (key, object_gone, user_data);
+	return TRUE;
+}
+
+static gboolean
+complete_set (GckTransaction *transaction, GckObject *object, Revert *revert)
+{
+	g_assert (GCK_IS_OBJECT (object));
+
+	if (gck_transaction_get_failed (transaction)) {
+		if (revert->attr)
+			g_hash_table_replace (revert->attributes, &(revert->attr->type), revert->attr);
+		else
+			g_hash_table_remove (revert->attributes, &(revert->type));
+		
+		gck_object_notify_attribute (object, revert->type);
+
+		revert->attr = NULL;
+		revert->type = 0;
+	}
+		
+	g_hash_table_unref (revert->attributes);
+	attribute_free (revert->attr);
+	g_slice_free (Revert, revert);
+	return TRUE;
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT 
+ */
+
+static CK_RV
+gck_memory_store_real_read_value (GckStore *base, GckObject *object, CK_ATTRIBUTE_PTR attr)
+{
+	GckMemoryStore *self = GCK_MEMORY_STORE (base);
+	GHashTable *attributes;
+	CK_ATTRIBUTE_PTR at;
+	
+	attributes = g_hash_table_lookup (self->entries, object);
+	if (attributes == NULL)
+		return CKR_ATTRIBUTE_TYPE_INVALID;
+	
+	at = g_hash_table_lookup (attributes, &(attr->type));
+	if (at == NULL)
+		return CKR_ATTRIBUTE_TYPE_INVALID;
+	
+	g_assert (at->type == attr->type);
+	
+	/* Yes, we don't fill a buffer, just return pointer */
+	attr->pValue = at->pValue;
+	attr->ulValueLen = at->ulValueLen;
+	
+	return CKR_OK;
+}
+
+static void
+gck_memory_store_real_write_value (GckStore *base, GckTransaction *transaction,
+                                   GckObject *object, CK_ATTRIBUTE_PTR attr)
+{
+	GckMemoryStore *self = GCK_MEMORY_STORE (base);
+	GHashTable *attributes;
+	CK_ATTRIBUTE_PTR at;
+	Revert *revert;
+	
+	g_return_if_fail (!gck_transaction_get_failed (transaction));
+	
+	attributes = g_hash_table_lookup (self->entries, object);
+	if (attributes == NULL) {
+		g_object_weak_ref (G_OBJECT (object), object_gone, self);
+		attributes = g_hash_table_new_full (gck_util_ulong_hash, gck_util_ulong_equal, 
+		                                    NULL, attribute_free);
+		g_hash_table_replace (self->entries, object, attributes);
+	}
+	
+	/* No need to go any further if no change */
+	at = g_hash_table_lookup (attributes, &(attr->type));
+	if (at != NULL && gck_attribute_equal (at, attr))
+		return;
+
+	revert = g_new0 (Revert, 1);
+	revert->attributes = g_hash_table_ref (attributes);
+	revert->type = attr->type;
+	revert->attr = at;
+	g_hash_table_steal (attributes, &(attr->type));
+	gck_transaction_add (transaction, object, (GckTransactionFunc)complete_set, revert);
+
+	attr = attribute_dup (attr);
+	g_hash_table_replace (attributes, &(attr->type), attr);
+	gck_object_notify_attribute (object, attr->type);
+}
+
+static GObject* 
+gck_memory_store_constructor (GType type, guint n_props, GObjectConstructParam *props) 
+{
+	GckMemoryStore *self = GCK_MEMORY_STORE (G_OBJECT_CLASS (gck_memory_store_parent_class)->constructor(type, n_props, props));
+	g_return_val_if_fail (self, NULL);	
+
+	return G_OBJECT (self);
+}
+
+static void
+gck_memory_store_init (GckMemoryStore *self)
+{
+	self->entries = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)g_hash_table_unref);
+}
+
+static void
+gck_memory_store_dispose (GObject *obj)
+{
+	GckMemoryStore *self = GCK_MEMORY_STORE (obj);
+	
+	g_hash_table_foreach_remove (self->entries, remove_each_object, self);
+    
+	G_OBJECT_CLASS (gck_memory_store_parent_class)->dispose (obj);
+}
+
+static void
+gck_memory_store_finalize (GObject *obj)
+{
+	GckMemoryStore *self = GCK_MEMORY_STORE (obj);
+
+	g_assert (g_hash_table_size (self->entries) == 0);
+	g_hash_table_destroy (self->entries);
+	self->entries = NULL;
+
+	G_OBJECT_CLASS (gck_memory_store_parent_class)->finalize (obj);
+}
+
+static void
+gck_memory_store_set_property (GObject *obj, guint prop_id, const GValue *value, 
+                               GParamSpec *pspec)
+{
+	switch (prop_id) {
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gck_memory_store_get_property (GObject *obj, guint prop_id, GValue *value, 
+                               GParamSpec *pspec)
+{
+	switch (prop_id) {
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gck_memory_store_class_init (GckMemoryStoreClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GckStoreClass *store_class = GCK_STORE_CLASS (klass);
+    
+	gobject_class->constructor = gck_memory_store_constructor;
+	gobject_class->dispose = gck_memory_store_dispose;
+	gobject_class->finalize = gck_memory_store_finalize;
+	gobject_class->set_property = gck_memory_store_set_property;
+	gobject_class->get_property = gck_memory_store_get_property;
+	
+	store_class->read_value = gck_memory_store_real_read_value;
+	store_class->write_value = gck_memory_store_real_write_value;
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC 
+ */
+
+GckMemoryStore*
+gck_memory_store_new (void)
+{
+	return g_object_new (GCK_TYPE_MEMORY_STORE, NULL);
+}

Added: trunk/pkcs11/gck/gck-memory-store.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-memory-store.h	Sat Jan  3 19:30:08 2009
@@ -0,0 +1,48 @@
+/* 
+ * gnome-keyring
+ * 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program 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
+ * Lesser General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef __GCK_MEMORY_STORE_H__
+#define __GCK_MEMORY_STORE_H__
+
+#include <glib-object.h>
+
+#include "gck-store.h"
+#include "gck-types.h"
+
+#define GCK_TYPE_MEMORY_STORE               (gck_memory_store_get_type ())
+#define GCK_MEMORY_STORE(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_MEMORY_STORE, GckMemoryStore))
+#define GCK_MEMORY_STORE_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCK_TYPE_MEMORY_STORE, GckMemoryStoreClass))
+#define GCK_IS_MEMORY_STORE(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCK_TYPE_MEMORY_STORE))
+#define GCK_IS_MEMORY_STORE_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_MEMORY_STORE))
+#define GCK_MEMORY_STORE_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_MEMORY_STORE, GckMemoryStoreClass))
+
+typedef struct _GckMemoryStore GckMemoryStore;
+typedef struct _GckMemoryStoreClass GckMemoryStoreClass;
+    
+struct _GckMemoryStoreClass {
+	GckStoreClass parent_class;
+};
+
+GType                 gck_memory_store_get_type               (void);
+
+GckMemoryStore*       gck_memory_store_new                    (void);
+
+#endif /* __GCK_MEMORY_STORE_H__ */

Modified: trunk/pkcs11/gck/gck-module.c
==============================================================================
--- trunk/pkcs11/gck/gck-module.c	(original)
+++ trunk/pkcs11/gck/gck-module.c	Sat Jan  3 19:30:08 2009
@@ -23,12 +23,16 @@
 
 #include "pkcs11/pkcs11.h"
 
+#include "gck-attributes.h"
+#include "gck-factory.h"
 #include "gck-manager.h"
 #include "gck-module.h"
+#include "gck-private-key.h"
+#include "gck-public-key.h"
 #include "gck-session.h"
+#include "gck-transaction.h"
 #include "gck-util.h"
 
-
 enum {
 	PROP_0,
 	PROP_MANAGER,
@@ -41,6 +45,8 @@
 	GHashTable *virtual_slots_by_id;        /* Various slot partitions by their ID */
 	GHashTable *sessions_by_handle;         /* Mapping of handle to all open sessions */
 	gint handle_counter;                    /* Constantly incrementing counter for handles and the like */
+	GArray *factories;                      /* Various registered object factories */
+	gboolean factories_sorted;              /* Whether we need to sort the object factories */
 };
 
 typedef struct _VirtualSlot {
@@ -120,6 +126,21 @@
  * INTERNAL 
  */
 
+static gint
+sort_factory_by_n_attrs (gconstpointer a, gconstpointer b)
+{
+	const GckFactoryInfo *fa = a;
+	const GckFactoryInfo *fb = b;
+	
+	g_assert (a);
+	g_assert (b);
+	
+	/* Note we're sorting in reverse order */
+	if (fa->n_attrs < fb->n_attrs)
+		return 1;
+	return (fa->n_attrs == fb->n_attrs) ? 0 : -1;
+}
+
 static void
 extend_space_string (CK_UTF8CHAR_PTR string, gsize length)
 {
@@ -310,6 +331,20 @@
 	return CKR_OK;
 }
 
+static void
+gck_module_real_store_token_object (GckModule *self, GckTransaction *transaction, GckObject *object)
+{
+	/* Derived classes should do something interesting */
+	gck_transaction_fail (transaction, CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static void
+gck_module_real_remove_token_object (GckModule *self, GckTransaction *transaction, GckObject *object)
+{
+	/* Derived classes should do something interesting */
+	gck_transaction_fail (transaction, CKR_FUNCTION_NOT_SUPPORTED);
+}
+
 static CK_RV
 gck_module_real_login_user (GckModule *self, CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
 {
@@ -366,8 +401,13 @@
 	                                                      gck_util_ulong_free, g_object_unref);
 	self->pv->virtual_slots_by_id = g_hash_table_new_full (gck_util_ulong_hash, gck_util_ulong_equal, 
 	                                                       gck_util_ulong_free, virtual_slot_free);
+	self->pv->factories = g_array_new (FALSE, TRUE, sizeof (GckFactoryInfo));
 	
 	g_atomic_int_set (&(self->pv->handle_counter), 1);
+	
+	/* Register session object factories */
+	gck_module_register_factory (self, GCK_FACTORY_PRIVATE_KEY);
+	gck_module_register_factory (self, GCK_FACTORY_PUBLIC_KEY);
 }
 
 static void
@@ -381,6 +421,8 @@
 	
 	g_hash_table_remove_all (self->pv->virtual_slots_by_id);
 	g_hash_table_remove_all (self->pv->sessions_by_handle);
+	
+	g_array_set_size (self->pv->factories, 0);
     
 	G_OBJECT_CLASS (gck_module_parent_class)->dispose (obj);
 }
@@ -399,6 +441,9 @@
 	g_assert (g_hash_table_size (self->pv->sessions_by_handle) == 0);
 	g_hash_table_destroy (self->pv->sessions_by_handle);
 	self->pv->sessions_by_handle = NULL;
+	
+	g_array_free (self->pv->factories, TRUE);
+	self->pv->factories = NULL;
 
 	G_OBJECT_CLASS (gck_module_parent_class)->finalize (obj);
 }
@@ -463,6 +508,8 @@
 	
 	klass->parse_argument = gck_module_real_parse_argument;
 	klass->refresh_token = gck_module_real_refresh_token;
+	klass->store_token_object = gck_module_real_store_token_object;
+	klass->remove_token_object = gck_module_real_remove_token_object;
 	klass->login_user = gck_module_real_login_user;
 	klass->logout_user = gck_module_real_logout_user;
 	
@@ -477,13 +524,6 @@
 	g_object_class_install_property (gobject_class, PROP_INITIALIZE_ARGS,
 	           g_param_spec_pointer ("initialize-args", "Initialize Args", "Arguments passed to C_Initialize", 
 	                                 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
-
-#if 0
-	signals[SIGNAL] = g_signal_new ("signal", GCK_TYPE_MODULE, 
-	                                G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GckModuleClass, signal),
-	                                NULL, NULL, g_cclosure_marshal_VOID__OBJECT, 
-	                                G_TYPE_NONE, 0);
-#endif
 }
 
 /* -----------------------------------------------------------------------------
@@ -553,6 +593,70 @@
 	return GCK_MODULE_GET_CLASS (self)->refresh_token (self);	
 }
 
+void
+gck_module_store_token_object (GckModule *self, GckTransaction *transaction, GckObject *object)
+{
+	g_return_if_fail (GCK_IS_MODULE (self));
+	g_return_if_fail (GCK_IS_OBJECT (object));
+	g_assert (GCK_MODULE_GET_CLASS (self)->store_token_object);
+	GCK_MODULE_GET_CLASS (self)->store_token_object (self, transaction, object);
+}
+
+void
+gck_module_remove_token_object (GckModule *self, GckTransaction *transaction, GckObject *object)
+{
+	g_return_if_fail (GCK_IS_MODULE (self));
+	g_return_if_fail (GCK_IS_OBJECT (object));
+	g_assert (GCK_MODULE_GET_CLASS (self)->remove_token_object);
+	GCK_MODULE_GET_CLASS (self)->remove_token_object (self, transaction, object);
+}
+
+void
+gck_module_register_factory (GckModule *self, GckFactoryInfo *factory)
+{
+	g_return_if_fail (GCK_IS_MODULE (self));
+	g_return_if_fail (factory);
+	g_return_if_fail (factory->attrs || !factory->n_attrs);
+	g_return_if_fail (factory->factory);
+	
+	g_array_append_val (self->pv->factories, *factory);
+	self->pv->factories_sorted = FALSE;
+}
+
+GckFactory
+gck_module_find_factory (GckModule *self, CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
+{
+	GckFactoryInfo *factory;
+	gboolean matched;
+	gulong j;
+	gsize i;
+	
+	g_return_val_if_fail (GCK_IS_MODULE (self), NULL);
+	g_return_val_if_fail (attrs || !n_attrs, NULL);
+	
+	if (!self->pv->factories_sorted) {
+		g_array_sort (self->pv->factories, sort_factory_by_n_attrs);
+		self->pv->factories_sorted = TRUE;
+	}
+	
+	for (i = 0; i < self->pv->factories->len; ++i) {
+		factory = &(g_array_index (self->pv->factories, GckFactoryInfo, i));
+		
+		matched = TRUE;
+		for (j = 0; j < factory->n_attrs; ++j) {
+			if (!gck_attributes_contains (attrs, n_attrs, &factory->attrs[j])) {
+				matched = FALSE;
+				break;
+			}
+		}
+		
+		if (matched)
+			return factory->factory;
+	}
+	
+	return NULL;
+}
+
 /* -----------------------------------------------------------------------------
  * PKCS#11
  */

Modified: trunk/pkcs11/gck/gck-module.h
==============================================================================
--- trunk/pkcs11/gck/gck-module.h	(original)
+++ trunk/pkcs11/gck/gck-module.h	Sat Jan  3 19:30:08 2009
@@ -26,9 +26,8 @@
 
 #include "pkcs11/pkcs11.h"
 
-#include "gck-manager.h"
-
-typedef struct _GckSession GckSession;
+#include "gck-factory.h"
+#include "gck-types.h"
 
 #define GCK_TYPE_MODULE               (gck_module_get_type ())
 #define GCK_MODULE(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_MODULE, GckModule))
@@ -37,7 +36,6 @@
 #define GCK_IS_MODULE_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_MODULE))
 #define GCK_MODULE_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_MODULE, GckModuleClass))
 
-typedef struct _GckModule GckModule;
 typedef struct _GckModuleClass GckModuleClass;
 typedef struct _GckModulePrivate GckModulePrivate;
     
@@ -63,6 +61,10 @@
 
 	CK_RV (*refresh_token) (GckModule *self);
 	
+	void (*store_token_object) (GckModule *self, GckTransaction *transaction, GckObject *object);
+	
+	void (*remove_token_object) (GckModule *self, GckTransaction *transaction, GckObject *object);
+	
 	CK_RV (*login_user) (GckModule *self, CK_SLOT_ID slot_id, 
 	                     CK_UTF8CHAR_PTR pin, CK_ULONG n_pin);
 	
@@ -111,7 +113,20 @@
 
 CK_RV                  gck_module_refresh_token                   (GckModule *self);
 
+void                   gck_module_store_token_object              (GckModule *self,
+                                                                   GckTransaction *transaction,
+                                                                   GckObject *object);
+
+void                   gck_module_remove_token_object             (GckModule *self,
+                                                                   GckTransaction *transaction,
+                                                                   GckObject *object);
+
+GckFactory             gck_module_find_factory                    (GckModule *self,
+                                                                   CK_ATTRIBUTE_PTR attrs,
+                                                                   CK_ULONG n_attrs);
 
+void                   gck_module_register_factory                (GckModule *self, 
+                                                                   GckFactoryInfo *factory);
 
 CK_RV                  gck_module_C_GetInfo                       (GckModule *self, 
                                                                    CK_INFO_PTR info);

Modified: trunk/pkcs11/gck/gck-object.c
==============================================================================
--- trunk/pkcs11/gck/gck-object.c	(original)
+++ trunk/pkcs11/gck/gck-object.c	Sat Jan  3 19:30:08 2009
@@ -23,19 +23,31 @@
 
 #include "pkcs11/pkcs11.h"
 
+#include "gck-attributes.h"
 #include "gck-manager.h"
 #include "gck-object.h"
+#include "gck-transaction.h"
+#include "gck-store.h"
 #include "gck-util.h"
 
 enum {
 	PROP_0,
 	PROP_HANDLE,
-	PROP_MANAGER
+	PROP_MANAGER,
+	PROP_STORE
 };
 
+enum {
+	NOTIFY_ATTRIBUTE,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
 struct _GckObjectPrivate {
 	CK_OBJECT_HANDLE handle;
 	GckManager *manager;
+	GckStore *store;
 };
 
 G_DEFINE_TYPE (GckObject, gck_object, G_TYPE_OBJECT);
@@ -51,44 +63,64 @@
 static CK_RV 
 gck_object_real_get_attribute (GckObject *self, CK_ATTRIBUTE* attr)
 {
+	CK_RV rv;
+	
 	switch (attr->type)
 	{
 	case CKA_CLASS:
 		g_warning ("Derived class should have overridden CKA_CLASS");
 		return CKR_GENERAL_ERROR;
-	case CKA_LABEL:
-		g_warning ("Derived class should have overridden CKA_LABEL");
-		return gck_util_set_data (attr, "", 0);
 	case CKA_MODIFIABLE:
+		return gck_attribute_set_bool (attr, self->pv->store ? TRUE : FALSE);
 	case CKA_PRIVATE:
-		return gck_util_set_bool (attr, FALSE);
+		return gck_attribute_set_bool (attr, FALSE);
 	case CKA_TOKEN:
-		return gck_util_set_bool (attr, (self->pv->handle & GCK_OBJECT_IS_PERMANENT) ? TRUE : FALSE);
+		return gck_attribute_set_bool (attr, (self->pv->handle & GCK_OBJECT_IS_PERMANENT) ? TRUE : FALSE);
 	};
+
+	/* Give store a shot */
+	if (self->pv->store) {
+		rv = gck_store_get_attribute (self->pv->store, self, attr);
+		if (rv != CKR_ATTRIBUTE_TYPE_INVALID)
+			return rv;
+	}
+
+	/* Now some more defaults */
+	switch (attr->type) {
+	case CKA_LABEL:
+		return gck_attribute_set_data (attr, "", 0);
+	}
 	
 	return CKR_ATTRIBUTE_TYPE_INVALID;
 }
 
-#if 0
-static CK_RV 
-gck_object_real_set_attribute (GckObject *self, const CK_ATTRIBUTE* attr)
+static void 
+gck_object_real_set_attribute (GckObject *self, GckTransaction* transaction, CK_ATTRIBUTE* attr)
 {
 	switch (attr->type) {
-	case CKA_LABEL:
-		g_warning ("Derived class should have overridden CKA_LABEL");
-		return CKR_ATTRIBUTE_READ_ONLY;
 	case CKA_TOKEN:
 	case CKA_PRIVATE:
 	case CKA_MODIFIABLE:
-		return CKR_ATTRIBUTE_READ_ONLY;
-		
 	case CKA_CLASS:
-		return CKR_ATTRIBUTE_READ_ONLY;
+		gck_transaction_fail (transaction, CKR_ATTRIBUTE_READ_ONLY);
+		return;
 	};
-	
-	return CKR_ATTRIBUTE_TYPE_INVALID;
+
+	/* Give store a shot */
+	if (self->pv->store) {
+		gck_store_set_attribute (self->pv->store, transaction, self, attr);
+		return;
+	}
+
+	/* Now some more defaults */
+	switch (attr->type) {
+	case CKA_LABEL:
+		gck_transaction_fail (transaction, CKR_ATTRIBUTE_READ_ONLY);
+		return;
+	}	
+
+	gck_transaction_fail (transaction, CKR_ATTRIBUTE_TYPE_INVALID);
 }
-#endif
 
 static CK_RV
 gck_object_real_unlock (GckObject *self, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
@@ -152,6 +184,7 @@
 {
 	GckObject *self = GCK_OBJECT (obj);
 	GckManager *manager;
+	GckStore *store;
 	
 	switch (prop_id) {
 	case PROP_HANDLE:
@@ -171,6 +204,20 @@
 		
 		g_object_notify (G_OBJECT (self), "manager");
 		break;
+	case PROP_STORE:
+		store = g_value_get_object (value);
+		if (self->pv->store) {
+			g_return_if_fail (!store);
+			g_object_remove_weak_pointer (G_OBJECT (self->pv->store), 
+			                              (gpointer*)&(self->pv->store));
+		}
+		self->pv->store = store;
+		if (self->pv->store)
+			g_object_add_weak_pointer (G_OBJECT (self->pv->store), 
+			                           (gpointer*)&(self->pv->store));
+		
+		g_object_notify (G_OBJECT (self), "store");
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
 		break;
@@ -190,6 +237,9 @@
 	case PROP_MANAGER:
 		g_value_set_object (value, gck_object_get_manager (self));
 		break;
+	case PROP_STORE:
+		g_value_set_object (value, self->pv->store);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
 		break;
@@ -212,9 +262,7 @@
 	
 	klass->unlock = gck_object_real_unlock;
 	klass->get_attribute = gck_object_real_get_attribute;
-#if 0
 	klass->set_attribute = gck_object_real_set_attribute;
-#endif
 	
 	g_object_class_install_property (gobject_class, PROP_HANDLE,
 	           g_param_spec_ulong ("handle", "Handle", "Object handle",
@@ -224,12 +272,14 @@
 	           g_param_spec_object ("manager", "Manager", "Object manager", 
 	                                GCK_TYPE_MANAGER, G_PARAM_READWRITE));
 	
-#if 0
-	signals[SIGNAL] = g_signal_new ("signal", GCK_TYPE_OBJECT, 
-	                                G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GckObjectClass, signal),
-	                                NULL, NULL, g_cclosure_marshal_VOID__OBJECT, 
-	                                G_TYPE_NONE, 0);
-#endif
+	g_object_class_install_property (gobject_class, PROP_STORE,
+	           g_param_spec_object ("store", "Store", "Object store", 
+	                                GCK_TYPE_STORE, G_PARAM_READWRITE));
+	
+	signals[NOTIFY_ATTRIBUTE] = g_signal_new ("notify-attribute", GCK_TYPE_OBJECT, 
+	                                G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GckObjectClass, notify_attribute),
+	                                NULL, NULL, g_cclosure_marshal_VOID__ULONG, 
+	                                G_TYPE_NONE, 1, G_TYPE_ULONG);
 }
 
 /* -----------------------------------------------------------------------------
@@ -245,6 +295,42 @@
 	return GCK_OBJECT_GET_CLASS (self)->get_attribute (self, attr);
 }
 
+void
+gck_object_set_attribute (GckObject *self, GckTransaction *transaction,
+                          CK_ATTRIBUTE_PTR attr)
+{
+	CK_ATTRIBUTE check;
+	CK_RV rv;
+	
+	g_return_if_fail (GCK_IS_OBJECT (self));
+	g_return_if_fail (GCK_IS_TRANSACTION (transaction));
+	g_return_if_fail (!gck_transaction_get_failed (transaction));
+	g_return_if_fail (attr);
+
+	g_assert (GCK_OBJECT_GET_CLASS (self)->set_attribute);
+
+	/* Check if this attribute exists */
+	check.type = attr->type;
+	check.pValue = 0;
+	check.ulValueLen = 0;
+	rv = gck_object_get_attribute (self, &check);
+	if (rv != CKR_OK && rv != CKR_ATTRIBUTE_SENSITIVE) {
+		gck_transaction_fail (transaction, rv);
+		return;
+	}
+	
+	/* Check that the value will actually change */
+	if (rv == CKR_ATTRIBUTE_SENSITIVE || !gck_object_match (self, attr))
+		GCK_OBJECT_GET_CLASS (self)->set_attribute (self, transaction, attr);
+}
+
+void
+gck_object_notify_attribute  (GckObject *self, CK_ATTRIBUTE_TYPE attr_type)
+{
+	g_return_if_fail (GCK_IS_OBJECT (self));
+	g_signal_emit (self, signals[NOTIFY_ATTRIBUTE], 0, attr_type);
+}
+
 gboolean
 gck_object_match (GckObject *self, CK_ATTRIBUTE_PTR match)
 {

Modified: trunk/pkcs11/gck/gck-object.h
==============================================================================
--- trunk/pkcs11/gck/gck-object.h	(original)
+++ trunk/pkcs11/gck/gck-object.h	Sat Jan  3 19:30:08 2009
@@ -26,6 +26,8 @@
 
 #include "pkcs11/pkcs11.h"
 
+#include "gck-types.h"
+
 #define GCK_OBJECT_HANDLE_MASK  0x0FFFFFFF
 #define GCK_OBJECT_IS_PERMANENT	0x10000000
 #define GCK_OBJECT_IS_TEMPORARY	0x00000000
@@ -37,12 +39,9 @@
 #define GCK_IS_OBJECT_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_OBJECT))
 #define GCK_OBJECT_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_OBJECT, GckObjectClass))
 
-typedef struct _GckObject GckObject;
 typedef struct _GckObjectClass GckObjectClass;
 typedef struct _GckObjectPrivate GckObjectPrivate;
 
-typedef struct _GckManager GckManager;
-
 struct _GckObject {
 	GObject parent;
 	GckObjectPrivate *pv;
@@ -51,12 +50,15 @@
 struct _GckObjectClass {
 	GObjectClass parent_class;
 	
-	/* properties --------------------------------------------------------------- */
+	/* signals ------------------------------------------------------------------ */
 	
+	void (*notify_attribute) (GckObject *object, CK_ATTRIBUTE_TYPE attr_type);
 	
 	/* virtual methods  --------------------------------------------------------- */
     
-	CK_RV (*get_attribute) (GckObject *object, CK_ATTRIBUTE* attr);
+	CK_RV (*get_attribute) (GckObject *object, CK_ATTRIBUTE *attr);
+	
+	void (*set_attribute) (GckObject *object, GckTransaction *transaction, CK_ATTRIBUTE *attr);
 	
 	CK_RV (*unlock) (GckObject *self, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin);
 };
@@ -84,9 +86,13 @@
 CK_RV                  gck_object_get_attribute          (GckObject *self,
                                                           CK_ATTRIBUTE_PTR attr);
 
-void                   gck_object_cache_attribute        (GckObject *self,
+void                   gck_object_set_attribute          (GckObject *self,
+                                                          GckTransaction *transaction,
                                                           CK_ATTRIBUTE_PTR attr);
 
+void                   gck_object_notify_attribute       (GckObject *self,
+                                                          CK_ATTRIBUTE_TYPE attr_type);
+
 gboolean               gck_object_get_attribute_boolean  (GckObject *self,
                                                           CK_ATTRIBUTE_TYPE type,
                                                           gboolean *value);

Modified: trunk/pkcs11/gck/gck-private-key.c
==============================================================================
--- trunk/pkcs11/gck/gck-private-key.c	(original)
+++ trunk/pkcs11/gck/gck-private-key.c	Sat Jan  3 19:30:08 2009
@@ -23,15 +23,12 @@
 
 #include "pkcs11/pkcs11.h"
 
+#include "gck-attributes.h"
+#include "gck-factory.h"
 #include "gck-private-key.h"
+#include "gck-transaction.h"
 #include "gck-util.h"
 
-#if 0
-enum {
-	PROP_0
-};
-#endif
-
 struct _GckPrivateKeyPrivate {
 	guint sexp_uses;
 	GckSexp *sexp;
@@ -43,6 +40,108 @@
  * INTERNAL 
  */
 
+
+static CK_RV
+create_rsa_private (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, gcry_sexp_t *skey)
+{
+	gcry_error_t gcry;
+	gcry_mpi_t n = NULL;
+	gcry_mpi_t e = NULL;
+	gcry_mpi_t d = NULL;
+	gcry_mpi_t p = NULL;
+	gcry_mpi_t q = NULL;
+	gcry_mpi_t u = NULL;
+	CK_RV ret;
+	
+	if (!gck_attributes_find_mpi (attrs, n_attrs, CKA_MODULUS, &n) ||
+	    !gck_attributes_find_mpi (attrs, n_attrs, CKA_PUBLIC_EXPONENT, &e) || 
+	    !gck_attributes_find_mpi (attrs, n_attrs, CKA_PRIVATE_EXPONENT, &d) || 
+	    !gck_attributes_find_mpi (attrs, n_attrs, CKA_PRIME_1, &p) || 
+	    !gck_attributes_find_mpi (attrs, n_attrs, CKA_PRIME_2, &q)) {
+	    	ret = CKR_TEMPLATE_INCOMPLETE;
+	    	goto done;
+	}
+	
+	/* Fix up the incoming key so gcrypt likes it */    	
+	if (gcry_mpi_cmp (p, q) > 0)
+		gcry_mpi_swap (p, q);
+
+	/* Compute U.  */
+	u = gcry_mpi_snew (gcry_mpi_get_nbits (n));
+	gcry_mpi_invm (u, p, q);
+	
+	gcry = gcry_sexp_build (skey, NULL, 
+	                        "(private-key (rsa (n %m) (e %m) (d %m) (p %m) (q %m) (u %m)))", 
+	                        n, e, d, p, q, u);
+
+	if (gcry != 0) {
+		g_message ("couldn't create RSA key from passed attributes: %s", gcry_strerror (gcry));
+		ret = CKR_FUNCTION_FAILED;
+		goto done;
+	}
+	
+	gck_attributes_consume (attrs, n_attrs, CKA_MODULUS, CKA_PUBLIC_EXPONENT, 
+	                        CKA_PRIVATE_EXPONENT, CKA_PRIME_1, CKA_PRIME_2, 
+	                        CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT, -1);
+	ret = CKR_OK;
+
+done:
+	gcry_mpi_release (n);
+	gcry_mpi_release (e);
+	gcry_mpi_release (d);
+	gcry_mpi_release (p);
+	gcry_mpi_release (q);
+	gcry_mpi_release (u);
+	return ret;	
+}
+
+static CK_RV
+create_dsa_private (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, gcry_sexp_t *skey)
+{
+	gcry_error_t gcry;
+	gcry_mpi_t p = NULL;
+	gcry_mpi_t q = NULL;
+	gcry_mpi_t g = NULL;
+	gcry_mpi_t y = NULL;
+	gcry_mpi_t value = NULL;
+	CK_RV ret;
+	
+	if (!gck_attributes_find_mpi (attrs, n_attrs, CKA_PRIME, &p) ||
+	    !gck_attributes_find_mpi (attrs, n_attrs, CKA_SUBPRIME, &q) || 
+	    !gck_attributes_find_mpi (attrs, n_attrs, CKA_BASE, &g) ||
+	    !gck_attributes_find_mpi (attrs, n_attrs, CKA_VALUE, &value)) {
+	    	ret = CKR_TEMPLATE_INCOMPLETE;
+	    	goto done;
+	}
+	
+	/* Calculate the public part from the private */
+	y = gcry_mpi_snew (gcry_mpi_get_nbits (value));
+	g_return_val_if_fail (y, CKR_GENERAL_ERROR);
+  	gcry_mpi_powm (y, g, value, p);
+
+	gcry = gcry_sexp_build (skey, NULL, 
+	                        "(private-key (dsa (p %m) (q %m) (g %m) (y %m) (x %m)))",
+	                        p, q, g, y, value);
+
+	if (gcry != 0) {
+		g_message ("couldn't create DSA key from passed attributes: %s", gcry_strerror (gcry));
+		ret = CKR_FUNCTION_FAILED;
+		goto done;
+	}
+
+	gck_attributes_consume (attrs, n_attrs, CKA_PRIME, CKA_SUBPRIME, 
+	                        CKA_BASE, CKA_VALUE, -1);
+	ret = CKR_OK;
+
+done:
+	gcry_mpi_release (p);
+	gcry_mpi_release (q);
+	gcry_mpi_release (g);
+	gcry_mpi_release (y);
+	gcry_mpi_release (value);
+	return ret;
+}
+
 /* -----------------------------------------------------------------------------
  * PRIVATE_KEY 
  */
@@ -54,43 +153,43 @@
 	
 	switch (attr->type) {
 	case CKA_CLASS:
-		return gck_util_set_ulong (attr, CKO_PRIVATE_KEY);
+		return gck_attribute_set_ulong (attr, CKO_PRIVATE_KEY);
 		
 	case CKA_PRIVATE:
-		return gck_util_set_bool (attr, TRUE);
+		return gck_attribute_set_bool (attr, TRUE);
 
 	case CKA_SENSITIVE:
-		return gck_util_set_bool (attr, TRUE);
+		return gck_attribute_set_bool (attr, TRUE);
 		
 	case CKA_DECRYPT:
-		return gck_util_set_bool (attr, gck_key_get_algorithm (GCK_KEY (self)) == GCRY_PK_RSA); 
+		return gck_attribute_set_bool (attr, gck_key_get_algorithm (GCK_KEY (self)) == GCRY_PK_RSA); 
 		
 	case CKA_SIGN:
-		return gck_util_set_bool (attr, TRUE);
+		return gck_attribute_set_bool (attr, TRUE);
 		
 	case CKA_SIGN_RECOVER:
-		return gck_util_set_bool (attr, FALSE);
+		return gck_attribute_set_bool (attr, FALSE);
 		
 	case CKA_UNWRAP:
-		return gck_util_set_bool (attr, FALSE);
+		return gck_attribute_set_bool (attr, FALSE);
 		
 	case CKA_EXTRACTABLE:
-		return gck_util_set_bool (attr, FALSE);
+		return gck_attribute_set_bool (attr, FALSE);
 		
 	case CKA_ALWAYS_SENSITIVE:
-		return gck_util_set_bool (attr, FALSE);
+		return gck_attribute_set_bool (attr, FALSE);
 		
 	case CKA_NEVER_EXTRACTABLE:
-		return gck_util_set_bool (attr, FALSE);
+		return gck_attribute_set_bool (attr, FALSE);
 		
 	case CKA_WRAP_WITH_TRUSTED:
-		return gck_util_set_bool (attr, FALSE);
+		return gck_attribute_set_bool (attr, FALSE);
 		
 	case CKA_UNWRAP_TEMPLATE:
 		return CKR_ATTRIBUTE_TYPE_INVALID;
 		
 	case CKA_ALWAYS_AUTHENTICATE:
-		return gck_util_set_bool (attr, self->pv->sexp_uses <= 1);
+		return gck_attribute_set_bool (attr, self->pv->sexp_uses <= 1);
 		
 	case CKA_MODULUS:
 		return gck_key_set_key_part (GCK_KEY (self), GCRY_PK_RSA, "n", attr);
@@ -124,26 +223,6 @@
 	return GCK_OBJECT_CLASS (gck_private_key_parent_class)->get_attribute (base, attr);
 }
 
-#if 0
-static CK_RV 
-gck_private_key_real_set_attribute (GckPrivateKey *private_key, const CK_ATTRIBUTE* attr)
-{
-	switch (attr->type) {
-	/* TODO: CKA_LABEL */
-
-	case CKA_TOKEN:
-	case CKA_PRIVATE:
-	case CKA_MODIFIABLE:
-		return CKR_ATTRIBUTE_READ_ONLY;
-		
-	case CKA_CLASS:
-		return CKR_ATTRIBUTE_READ_ONLY;
-	};
-	
-xxx
-}
-#endif
-
 static GckSexp*
 gck_private_key_real_acquire_crypto_sexp (GckKey *base)
 {
@@ -212,10 +291,6 @@
 gck_private_key_set_property (GObject *obj, guint prop_id, const GValue *value, 
                               GParamSpec *pspec)
 {
-#if 0
-	GckPrivateKey *self = GCK_PRIVATE_KEY (obj);
-#endif
-	
 	switch (prop_id) {
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
@@ -227,10 +302,6 @@
 gck_private_key_get_property (GObject *obj, guint prop_id, GValue *value, 
                               GParamSpec *pspec)
 {
-#if 0
-	GckPrivateKey *self = GCK_PRIVATE_KEY (obj);
-#endif
-	
 	switch (prop_id) {
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
@@ -255,21 +326,8 @@
 	gobject_class->get_property = gck_private_key_get_property;
 	
 	gck_class->get_attribute = gck_private_key_real_get_attribute;
-#if 0
-	gck_class->set_attribute = gck_private_key_real_set_attribute;
-#endif
-	
+
 	key_class->acquire_crypto_sexp = gck_private_key_real_acquire_crypto_sexp;
-    
-#if 0
-	g_private_key_class_install_property (gprivate_key_class, PROP_PRIVATE_KEY,
-	           g_param_spec_pointer ("private_key", "PrivateKey", "PrivateKey.", G_PARAM_READWRITE));
-    
-	signals[SIGNAL] = g_signal_new ("signal", GCK_TYPE_PRIVATE_KEY, 
-	                                G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GckPrivateKeyClass, signal),
-	                                NULL, NULL, g_cclosure_marshal_VOID__OBJECT, 
-	                                G_TYPE_NONE, 0);
-#endif
 }
 
 /* -----------------------------------------------------------------------------
@@ -289,3 +347,71 @@
 	self->pv->sexp = sexp;
 	self->pv->sexp_uses = num_uses;
 }
+
+
+void
+gck_private_key_create (GckSession *session, GckTransaction *transaction, 
+                        CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **object)
+{
+ 	CK_KEY_TYPE type;
+ 	GckSexp *wrapper;
+ 	gcry_sexp_t sexp;
+ 	CK_RV ret;
+ 	
+	g_return_if_fail (GCK_IS_TRANSACTION (transaction));
+	g_return_if_fail (attrs || !n_attrs);
+	g_return_if_fail (object);
+	
+	*object = NULL;
+	
+	if (!gck_attributes_find_ulong (attrs, n_attrs, CKA_KEY_TYPE, &type)) {
+		gck_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
+		return;
+	}
+		
+ 	gck_attributes_consume (attrs, n_attrs, CKA_KEY_TYPE, CKA_CLASS, -1);
+
+ 	switch (type) {
+	case CKK_RSA:
+		ret = create_rsa_private (attrs, n_attrs, &sexp);
+		break;
+	case CKK_DSA:
+		ret = create_dsa_private (attrs, n_attrs, &sexp);
+		break;
+	default:
+		ret = CKR_ATTRIBUTE_VALUE_INVALID;
+		break;
+ 	};
+
+ 	
+	if (ret != CKR_OK) {
+		gck_transaction_fail (transaction, ret);
+		return;
+	}
+	
+	g_return_if_fail (sexp);
+	wrapper = gck_sexp_new (sexp);
+	*object = g_object_new (GCK_TYPE_PRIVATE_KEY, "base-sexp", wrapper, NULL);
+	gck_private_key_store_private (GCK_PRIVATE_KEY (*object), wrapper, G_MAXUINT);
+	gck_sexp_unref (wrapper);
+}
+
+GckFactoryInfo*
+gck_private_key_get_factory (void)
+{
+	static CK_OBJECT_CLASS klass = CKO_PRIVATE_KEY;
+	static CK_BBOOL token = CK_FALSE;
+
+	static CK_ATTRIBUTE attributes[] = {
+		{ CKA_CLASS, &klass, sizeof (klass) },
+		{ CKA_TOKEN, &token, sizeof (token) }, 
+	};
+
+	static GckFactoryInfo factory = {
+		attributes,
+		G_N_ELEMENTS (attributes),
+		gck_private_key_create
+	};
+	
+	return &factory;
+}

Modified: trunk/pkcs11/gck/gck-private-key.h
==============================================================================
--- trunk/pkcs11/gck/gck-private-key.h	(original)
+++ trunk/pkcs11/gck/gck-private-key.h	Sat Jan  3 19:30:08 2009
@@ -25,7 +25,9 @@
 #include <glib-object.h>
 
 #include "gck-key.h"
-#include "gck-sexp.h"
+#include "gck-types.h"
+
+#define GCK_FACTORY_PRIVATE_KEY            (gck_private_key_get_factory ())
 
 #define GCK_TYPE_PRIVATE_KEY               (gck_private_key_get_type ())
 #define GCK_PRIVATE_KEY(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_PRIVATE_KEY, GckPrivateKey))
@@ -34,7 +36,6 @@
 #define GCK_IS_PRIVATE_KEY_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_PRIVATE_KEY))
 #define GCK_PRIVATE_KEY_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_PRIVATE_KEY, GckPrivateKeyClass))
 
-typedef struct _GckPrivateKey GckPrivateKey;
 typedef struct _GckPrivateKeyClass GckPrivateKeyClass;
 typedef struct _GckPrivateKeyPrivate GckPrivateKeyPrivate;
     
@@ -49,10 +50,16 @@
 
 GType                      gck_private_key_get_type               (void);
 
-GckPrivateKey*             gck_private_key_new                    (void);
-
 void                       gck_private_key_store_private          (GckPrivateKey *self, 
                                                                    GckSexp *sexp, 
                                                                    guint num_uses);               
 
+GckFactoryInfo*            gck_private_key_get_factory            (void);
+
+void                       gck_private_key_create                 (GckSession *session, 
+                                                                   GckTransaction *transaction, 
+                                                                   CK_ATTRIBUTE_PTR attrs, 
+                                                                   CK_ULONG n_attrs, 
+                                                                   GckObject **object);
+
 #endif /* __GCK_PRIVATE_KEY_H__ */

Modified: trunk/pkcs11/gck/gck-public-key.c
==============================================================================
--- trunk/pkcs11/gck/gck-public-key.c	(original)
+++ trunk/pkcs11/gck/gck-public-key.c	Sat Jan  3 19:30:08 2009
@@ -23,20 +23,13 @@
 
 #include "pkcs11/pkcs11.h"
 
+#include "gck-attributes.h"
 #include "gck-crypto.h"
+#include "gck-factory.h"
 #include "gck-public-key.h"
+#include "gck-transaction.h"
 #include "gck-util.h"
 
-#if 0
-enum {
-	PROP_0,
-	PROP_PUBLIC_KEY
-};
-
-struct _GckPublicKeyPrivate {
-};
-#endif
-
 G_DEFINE_TYPE (GckPublicKey, gck_public_key, GCK_TYPE_KEY);
 
 /* -----------------------------------------------------------------------------
@@ -65,12 +58,85 @@
 		g_return_val_if_reached (CKR_GENERAL_ERROR);
 
 	gcry_sexp_release (numbers);
-	rv = gck_util_set_ulong (attr, gcry_mpi_get_nbits (mpi));
+	rv = gck_attribute_set_ulong (attr, gcry_mpi_get_nbits (mpi));
 	gcry_mpi_release (mpi);
 
 	return rv;
 }
 
+static CK_RV
+create_rsa_public (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, gcry_sexp_t *skey)
+{
+	gcry_error_t gcry;
+	gcry_mpi_t n = NULL;
+	gcry_mpi_t e = NULL;
+	CK_RV ret;
+	
+	if (!gck_attributes_find_mpi (attrs, n_attrs, CKA_MODULUS, &n) ||
+	    !gck_attributes_find_mpi (attrs, n_attrs, CKA_PUBLIC_EXPONENT, &e)) { 
+	    	ret = CKR_TEMPLATE_INCOMPLETE;
+	    	goto done;
+	}
+	
+	gcry = gcry_sexp_build (skey, NULL, 
+	                        "(public-key (rsa (n %m) (e %m)))", 
+	                        n, e);
+
+	if (gcry != 0) {
+		g_message ("couldn't create RSA key from passed attributes: %s", gcry_strerror (gcry));
+		ret = CKR_FUNCTION_FAILED;
+		goto done;
+	}
+	
+	gck_attributes_consume (attrs, n_attrs, CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKA_MODULUS_BITS, -1); 
+	ret = CKR_OK;
+
+done:
+	gcry_mpi_release (n);
+	gcry_mpi_release (e);
+	return ret;	
+}
+
+static CK_RV
+create_dsa_public (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, gcry_sexp_t *skey)
+{
+	gcry_error_t gcry;
+	gcry_mpi_t p = NULL;
+	gcry_mpi_t q = NULL;
+	gcry_mpi_t g = NULL;
+	gcry_mpi_t y = NULL;
+	CK_RV ret;
+	
+	if (!gck_attributes_find_mpi (attrs, n_attrs, CKA_PRIME, &p) ||
+	    !gck_attributes_find_mpi (attrs, n_attrs, CKA_SUBPRIME, &q) || 
+	    !gck_attributes_find_mpi (attrs, n_attrs, CKA_BASE, &g) ||
+	    !gck_attributes_find_mpi (attrs, n_attrs, CKA_VALUE, &y)) {
+	    	ret = CKR_TEMPLATE_INCOMPLETE;
+	    	goto done;
+	}
+	
+	gcry = gcry_sexp_build (skey, NULL, 
+	                        "(public-key (dsa (p %m) (q %m) (g %m) (y %m)))",
+	                        p, q, g, y);
+
+	if (gcry != 0) {
+		g_message ("couldn't create DSA key from passed attributes: %s", gcry_strerror (gcry));
+		ret = CKR_FUNCTION_FAILED;
+		goto done;
+	}
+
+	gck_attributes_consume (attrs, n_attrs, CKA_PRIME, CKA_SUBPRIME, 
+	                        CKA_BASE, CKA_VALUE, -1);
+	ret = CKR_OK;
+
+done:
+	gcry_mpi_release (p);
+	gcry_mpi_release (q);
+	gcry_mpi_release (g);
+	gcry_mpi_release (y);
+	return ret;
+}
+
 /* -----------------------------------------------------------------------------
  * PUBLIC_KEY 
  */
@@ -84,22 +150,22 @@
 	{
 	
 	case CKA_CLASS:
-		return gck_util_set_ulong (attr, CKO_PUBLIC_KEY);
+		return gck_attribute_set_ulong (attr, CKO_PUBLIC_KEY);
 	
 	case CKA_ENCRYPT:
-		return gck_util_set_bool (attr, gck_key_get_algorithm (GCK_KEY (self)) == GCRY_PK_RSA);
+		return gck_attribute_set_bool (attr, gck_key_get_algorithm (GCK_KEY (self)) == GCRY_PK_RSA);
 		
 	case CKA_VERIFY:
-		return gck_util_set_bool (attr, TRUE);
+		return gck_attribute_set_bool (attr, TRUE);
 		
 	case CKA_VERIFY_RECOVER:
-		return gck_util_set_bool (attr, FALSE);
+		return gck_attribute_set_bool (attr, FALSE);
 		
 	case CKA_WRAP:
-		return gck_util_set_bool (attr, FALSE);
+		return gck_attribute_set_bool (attr, FALSE);
 		
 	case CKA_TRUSTED:
-		return gck_util_set_bool (attr, FALSE);
+		return gck_attribute_set_bool (attr, FALSE);
 		
 	case CKA_WRAP_TEMPLATE:
 		return CKR_ATTRIBUTE_TYPE_INVALID;
@@ -130,26 +196,6 @@
 	return GCK_OBJECT_CLASS (gck_public_key_parent_class)->get_attribute (base, attr);
 }
 
-#if 0
-static CK_RV 
-gck_public_key_real_set_attribute (GckPublicKey *public_key, const CK_ATTRIBUTE* attr)
-{
-	switch (attr->type) {
-	/* TODO: CKA_LABEL */
-
-	case CKA_TOKEN:
-	case CKA_PRIVATE:
-	case CKA_MODIFIABLE:
-		return CKR_ATTRIBUTE_READ_ONLY;
-		
-	case CKA_CLASS:
-		return CKR_ATTRIBUTE_READ_ONLY;
-	};
-	
-	return CKA_ATTRIBUTE_TYPE_INVALID;
-}
-#endif
-
 static GckSexp*
 gck_public_key_acquire_crypto_sexp (GckKey *self)
 {
@@ -174,26 +220,18 @@
 static void
 gck_public_key_init (GckPublicKey *self)
 {
-#if 0
-	self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCK_TYPE_PUBLIC_KEY, GckPublicKeyPrivate);
-#endif
+
 }
 
 static void
 gck_public_key_dispose (GObject *obj)
 {
-#if 0
-	GckPublicKey *self = GCK_PUBLIC_KEY (obj);
-#endif
 	G_OBJECT_CLASS (gck_public_key_parent_class)->dispose (obj);
 }
 
 static void
 gck_public_key_finalize (GObject *obj)
 {
-#if 0
-	GckPublicKey *self = GCK_PUBLIC_KEY (obj);
-#endif
 	G_OBJECT_CLASS (gck_public_key_parent_class)->finalize (obj);
 }
 
@@ -201,10 +239,6 @@
 gck_public_key_set_property (GObject *obj, guint prop_id, const GValue *value, 
                            GParamSpec *pspec)
 {
-#if 0
-	GckPublicKey *self = GCK_PUBLIC_KEY (obj);
-#endif
-	
 	switch (prop_id) {
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
@@ -216,10 +250,6 @@
 gck_public_key_get_property (GObject *obj, guint prop_id, GValue *value, 
                            GParamSpec *pspec)
 {
-#if 0
-	GckPublicKey *self = GCK_PUBLIC_KEY (obj);
-#endif
-	
 	switch (prop_id) {
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
@@ -235,9 +265,6 @@
 	GckKeyClass *key_class = GCK_KEY_CLASS (klass);
 	
 	gck_public_key_parent_class = g_type_class_peek_parent (klass);
-#if 0
-	g_type_class_add_private (klass, sizeof (GckPublicKeyPrivate));
-#endif
 	
 	gobject_class->constructor = gck_public_key_constructor;
 	gobject_class->dispose = gck_public_key_dispose;
@@ -246,23 +273,75 @@
 	gobject_class->get_property = gck_public_key_get_property;
 	
 	gck_class->get_attribute = gck_public_key_real_get_attribute;
-#if 0
-	gck_class->set_attribute = gck_public_key_real_set_attribute;
-#endif
 	
 	key_class->acquire_crypto_sexp = gck_public_key_acquire_crypto_sexp;
-	
-#if 0
-	g_public_key_class_install_property (gobject_class, PROP_PUBLIC_KEY,
-	           g_param_spec_pointer ("public_key", "PublicKey", "PublicKey.", G_PARAM_READWRITE));
-    
-	signals[SIGNAL] = g_signal_new ("signal", GCK_TYPE_PUBLIC_KEY, 
-	                                G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GckPublicKeyClass, signal),
-	                                NULL, NULL, g_cclosure_marshal_VOID__OBJECT, 
-	                                G_TYPE_NONE, 0);
-#endif
 }
 
 /* -----------------------------------------------------------------------------
  * PUBLIC 
  */
+
+void
+gck_public_key_create (GckSession *session, GckTransaction *transaction, 
+                       CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **object)
+{
+ 	CK_KEY_TYPE type;
+ 	GckSexp *wrapper;
+ 	gcry_sexp_t sexp;
+ 	CK_RV ret;
+ 
+	g_return_if_fail (GCK_IS_TRANSACTION (transaction));
+	g_return_if_fail (attrs || !n_attrs);
+	g_return_if_fail (object);
+	
+	*object = NULL;
+	
+	if (!gck_attributes_find_ulong (attrs, n_attrs, CKA_KEY_TYPE, &type)) {
+		gck_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
+		return;
+	}
+		
+ 	gck_attributes_consume (attrs, n_attrs, CKA_KEY_TYPE, CKA_CLASS, -1);
+
+ 	switch (type) {
+	case CKK_RSA:
+		ret = create_rsa_public (attrs, n_attrs, &sexp);
+		break;
+	case CKK_DSA:
+		ret = create_dsa_public (attrs, n_attrs, &sexp);
+		break;
+	default:
+		ret = CKR_ATTRIBUTE_VALUE_INVALID;
+		break;
+ 	};
+
+	if (ret != CKR_OK) {
+		gck_transaction_fail (transaction, ret);
+		return;
+	}
+	
+	g_return_if_fail (sexp);
+	wrapper = gck_sexp_new (sexp);
+	*object = g_object_new (GCK_TYPE_PUBLIC_KEY, "base-sexp", wrapper, NULL);
+	gck_sexp_unref (wrapper);
+}
+
+GckFactoryInfo*
+gck_public_key_get_factory (void)
+{
+	static CK_OBJECT_CLASS klass = CKO_PUBLIC_KEY;
+	static CK_BBOOL token = CK_FALSE;
+
+	static CK_ATTRIBUTE attributes[] = {
+		{ CKA_CLASS, &klass, sizeof (klass) },
+		{ CKA_TOKEN, &token, sizeof (token) }, 
+	};
+
+	static GckFactoryInfo factory = {
+		attributes,
+		G_N_ELEMENTS (attributes),
+		gck_public_key_create
+	};
+	
+	return &factory;
+}

Modified: trunk/pkcs11/gck/gck-public-key.h
==============================================================================
--- trunk/pkcs11/gck/gck-public-key.h	(original)
+++ trunk/pkcs11/gck/gck-public-key.h	Sat Jan  3 19:30:08 2009
@@ -25,6 +25,9 @@
 #include <glib-object.h>
 
 #include "gck-key.h"
+#include "gck-types.h"
+
+#define GCK_FACTORY_PUBLIC_KEY            (gck_public_key_get_factory ())
 
 #define GCK_TYPE_PUBLIC_KEY               (gck_public_key_get_type ())
 #define GCK_PUBLIC_KEY(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_PUBLIC_KEY, GckPublicKey))
@@ -33,7 +36,6 @@
 #define GCK_IS_PUBLIC_KEY_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_PUBLIC_KEY))
 #define GCK_PUBLIC_KEY_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_PUBLIC_KEY, GckPublicKeyClass))
 
-typedef struct _GckPublicKey GckPublicKey;
 typedef struct _GckPublicKeyClass GckPublicKeyClass;
 typedef struct _GckPublicKeyPrivate GckPublicKeyPrivate;
     
@@ -48,4 +50,11 @@
 
 GType                     gck_public_key_get_type               (void);
 
+GckFactoryInfo*           gck_public_key_get_factory            (void);
+
+void                      gck_public_key_create                 (GckSession *session, 
+                                                                 GckTransaction *transaction, 
+                                                                 CK_ATTRIBUTE_PTR attrs, 
+                                                                 CK_ULONG n_attrs, 
+                                                                 GckObject **object);
 #endif /* __GCK_PUBLIC_KEY_H__ */

Modified: trunk/pkcs11/gck/gck-session.c
==============================================================================
--- trunk/pkcs11/gck/gck-session.c	(original)
+++ trunk/pkcs11/gck/gck-session.c	Sat Jan  3 19:30:08 2009
@@ -23,11 +23,15 @@
 
 #include "pkcs11/pkcs11.h"
 
+#include "gck-attributes.h"
 #include "gck-crypto.h"
 #include "gck-key.h"
+#include "gck-factory.h"
 #include "gck-manager.h"
+#include "gck-memory-store.h"
 #include "gck-session.h"
 #include "gck-sexp.h"
+#include "gck-transaction.h"
 
 enum {
 	PROP_0,
@@ -39,16 +43,6 @@
 	PROP_LOGGED_IN
 };
 
-#if 0
-enum {
-	SIGNAL,
-	LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-#endif 
-
-
 struct _GckSessionPrivate {
 
 	CK_SESSION_HANDLE handle;
@@ -56,12 +50,16 @@
 	
 	GckModule *module;
 	GckManager *manager;
+	GckStore *store;
 
 	gboolean logged_in;
 	gboolean read_only;
 
 	CK_NOTIFY notify_callback;
 	CK_VOID_PTR application_ptr;
+	
+	/* Objects owned by this session */
+	GHashTable *objects;
 
 	/* Used for context specific logins */
 	void (*current_operation) (GckSession *self);
@@ -78,6 +76,9 @@
 
 G_DEFINE_TYPE (GckSession, gck_session, G_TYPE_OBJECT);
 
+static void add_object (GckSession *self, GckTransaction *transaction, GckObject *object);
+static void remove_object (GckSession *self, GckTransaction *transaction, GckObject *object);
+
 /* -----------------------------------------------------------------------------
  * INTERNAL 
  */
@@ -115,9 +116,12 @@
 	CK_RV rv;
 	
 	g_assert (GCK_IS_SESSION (self));
-	
-	if (self->pv->current_operation)
-		return CKR_OPERATION_ACTIVE;
+
+	/* Cancel any current operation */
+	if (self->pv->current_operation) {
+		(self->pv->current_operation) (self);
+		g_assert (!self->pv->current_operation);
+	}
 	
 	g_assert (!self->pv->crypto_sexp);
 	
@@ -259,11 +263,13 @@
 	 * If we're going to write to this object check that we're in a 
 	 * writable session and object is modifiable.
 	 */
-	if (writable && !is_token) {
-		if (gck_module_get_write_protected (self->pv->module))
-			return CKR_TOKEN_WRITE_PROTECTED;
-		if (self->pv->read_only && !is_token)
-			return CKR_SESSION_READ_ONLY;
+	if (writable) {
+		if (is_token) {
+			if (gck_module_get_write_protected (self->pv->module))
+				return CKR_TOKEN_WRITE_PROTECTED;
+			if (self->pv->read_only)
+				return CKR_SESSION_READ_ONLY;
+		}
 		if (!gck_object_get_attribute_boolean (object, CKA_MODIFIABLE, &is_modifiable))
 			is_modifiable = FALSE;
 		if (!is_modifiable) /* What's a better return code in this case? */
@@ -274,6 +280,74 @@
 	return CKR_OK;
 }
 
+
+static gboolean
+complete_remove (GckTransaction *transaction, GckSession *self, GckObject *object)
+{
+	if (gck_transaction_get_failed (transaction))
+		add_object (self, NULL, object);
+	g_object_unref (object);
+	return TRUE;
+}
+
+static void
+remove_object (GckSession *self, GckTransaction *transaction, GckObject *object)
+{
+	g_assert (GCK_IS_SESSION (self));
+	g_assert (GCK_IS_OBJECT (object));
+	
+	g_object_ref (object);
+	
+	gck_manager_unregister_object (self->pv->manager, object);
+	if (!g_hash_table_remove (self->pv->objects, object))
+		g_return_if_reached ();
+	g_object_set (object, "store", NULL, NULL);
+	
+	if (transaction)
+		gck_transaction_add (transaction, self, (GckTransactionFunc)complete_remove, 
+		                     g_object_ref (object));
+	
+	g_object_unref (object);
+}
+
+static gboolean
+complete_add (GckTransaction *transaction, GckSession *self, GckObject *object)
+{
+	if (gck_transaction_get_failed (transaction))
+		remove_object (self, NULL, object);
+	g_object_unref (object);
+	return TRUE;
+}
+
+static void
+add_object (GckSession *self, GckTransaction *transaction, GckObject *object)
+{
+	g_assert (GCK_IS_SESSION (self));
+	g_assert (GCK_IS_OBJECT (object));
+	
+	/* Must not already be associated with a session or manager */
+	g_return_if_fail (gck_object_get_manager (object) == NULL);
+	g_return_if_fail (g_object_get_data (G_OBJECT (object), "owned-by-session") == NULL);
+	g_return_if_fail (g_hash_table_lookup (self->pv->objects, object) == NULL);
+	
+	g_hash_table_insert (self->pv->objects, object, g_object_ref (object));
+	g_object_set_data (G_OBJECT (object), "owned-by-session", self);
+	gck_manager_register_object (self->pv->manager, object);
+	g_object_set (object, "store", self->pv->store, NULL);
+
+	if (transaction)
+		gck_transaction_add (transaction, self, (GckTransactionFunc)complete_add, 
+		                     g_object_ref (object));
+}
+
+static void
+dispose_unref_object (gpointer obj)
+{
+	g_assert (G_IS_OBJECT (obj));
+	g_object_run_dispose (obj);
+	g_object_unref (obj);
+}
+
 static gboolean
 attributes_find_boolean (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, 
                          CK_ATTRIBUTE_TYPE type, CK_BBOOL *value)
@@ -304,9 +378,15 @@
 gck_session_constructor (GType type, guint n_props, GObjectConstructParam *props) 
 {
 	GckSession *self = GCK_SESSION (G_OBJECT_CLASS (gck_session_parent_class)->constructor(type, n_props, props));
-	g_return_val_if_fail (self, NULL);	
+	CK_ATTRIBUTE attr;
 
+	g_return_val_if_fail (self, NULL);	
 
+	/* Register store attributes */
+	attr.type = CKA_LABEL;
+	attr.pValue = "";
+	attr.ulValueLen = 0;
+	gck_store_register_schema (self->pv->store, &attr, NULL, 0);
 	
 	return G_OBJECT (self);
 }
@@ -315,7 +395,11 @@
 gck_session_init (GckSession *self)
 {
 	self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCK_TYPE_SESSION, GckSessionPrivate);
+	self->pv->objects = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, dispose_unref_object);
 	self->pv->read_only = TRUE;
+	
+	/* Create the store and register attributes */
+	self->pv->store = GCK_STORE (gck_memory_store_new ());
 }
 
 static void
@@ -326,15 +410,18 @@
 	/* Cleanup any current operation */
 	if (self->pv->current_operation)
 		(self->pv->current_operation) (self);
+	g_assert (!self->pv->current_operation);
 
-	g_return_if_fail (self->pv->module);
-	g_object_unref (self->pv->module);
+	if (self->pv->module)
+		g_object_unref (self->pv->module);
 	self->pv->module = NULL;
 
-	g_return_if_fail (self->pv->manager);
-	g_object_unref (self->pv->manager);
+	if (self->pv->manager)
+		g_object_unref (self->pv->manager);
 	self->pv->manager = NULL;
 	
+	g_hash_table_remove_all (self->pv->objects);
+	
 	G_OBJECT_CLASS (gck_session_parent_class)->dispose (obj);
 }
 
@@ -346,6 +433,12 @@
 	g_assert (self->pv->module == NULL);
 	g_assert (self->pv->manager == NULL);
 	
+	g_hash_table_destroy (self->pv->objects);
+	self->pv->objects = NULL;
+	
+	g_object_unref (self->pv->store);
+	self->pv->store = NULL;
+	
 	G_OBJECT_CLASS (gck_session_parent_class)->finalize (obj);
 }
 
@@ -455,13 +548,6 @@
 	g_object_class_install_property (gobject_class, PROP_LOGGED_IN,
 	         g_param_spec_boolean ("logged-in", "Logged in", "Whether this session is logged in or not", 
 	                               FALSE, G_PARAM_READWRITE));
-
-#if 0
-	signals[SIGNAL] = g_signal_new ("signal", GCK_TYPE_SESSION, 
-	                                G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GckSessionClass, signal),
-	                                NULL, NULL, g_cclosure_marshal_VOID__OBJECT, 
-	                                G_TYPE_NONE, 0);
-#endif
 }
 
 /* -----------------------------------------------------------------------------
@@ -640,8 +726,90 @@
 gck_session_C_CreateObject (GckSession* self, CK_ATTRIBUTE_PTR template,
                             CK_ULONG count, CK_OBJECT_HANDLE_PTR new_object)
 {
-	/* TODO: Need to implement this */
- 	return CKR_FUNCTION_NOT_SUPPORTED;
+	GckObject *object = NULL;
+	GckTransaction *transaction;
+	CK_ATTRIBUTE_PTR attrs;
+	CK_ULONG n_attrs, i;
+	GckFactory factory;
+	gboolean is_token;
+	gboolean is_private;
+	CK_RV rv;
+
+	g_return_val_if_fail (GCK_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
+	if (!new_object)
+		return CKR_ARGUMENTS_BAD;
+	if (!(!count || template))
+		return CKR_ARGUMENTS_BAD;
+
+	/* Find out if we can create such an object */
+	factory = gck_module_find_factory (gck_session_get_module (self), template, count);
+	if (!factory)
+		return CKR_TEMPLATE_INCOMPLETE;
+	
+	/* Find out where we'll be creating this */
+	if (!gck_attributes_find_boolean (template, count, CKA_TOKEN, &is_token))
+		is_token = CK_FALSE;
+		
+	/* See if we can create due to read-only */
+	if (is_token) {
+		if (gck_module_get_write_protected (self->pv->module))
+			return CKR_TOKEN_WRITE_PROTECTED;
+		if (self->pv->read_only)
+			return CKR_SESSION_READ_ONLY;
+	}
+	
+	/* The transaction for this whole dealio */
+	transaction = gck_transaction_new ();
+	
+	/* 
+	 * Duplicate the memory for the attributes (but not values) so we 
+	 * can 'consume' in the factory function 
+	 */
+	attrs = g_memdup (template, count * sizeof (CK_ATTRIBUTE));
+	n_attrs = count;
+	
+	/* Actually create the object */
+	object = NULL;
+	(factory) (self, transaction, attrs, n_attrs, &object);
+
+	if (!gck_transaction_get_failed (transaction)) {
+		g_return_val_if_fail (object, CKR_GENERAL_ERROR);
+
+		/* Can only create public objects unless logged in */
+		if (!gck_session_get_logged_in (self) &&
+		    gck_object_get_attribute_boolean (object, CKA_PRIVATE, &is_private) && 
+		    is_private == TRUE) {
+			gck_transaction_fail (transaction, CKR_USER_NOT_LOGGED_IN);
+		}
+	}
+	
+	/* Find somewhere to store the object */
+	if (!gck_transaction_get_failed (transaction)) {
+		if (is_token) 
+			gck_module_store_token_object (self->pv->module, transaction, object); 
+		else
+			add_object (self, transaction, object);
+	}
+
+	/* Next go through and set all attributes that weren't used initially */
+	gck_attributes_consume (attrs, n_attrs, CKA_TOKEN, -1);
+	for (i = 0; i < n_attrs && !gck_transaction_get_failed (transaction); ++i) {
+		if (!gck_attribute_consumed (&attrs[i]))
+			gck_object_set_attribute (object, transaction, &attrs[i]);
+	}
+
+	gck_transaction_complete (transaction);
+	rv = gck_transaction_get_result (transaction);
+	g_object_unref (transaction);
+	if (rv == CKR_OK) {
+		g_assert (object);
+		*new_object = gck_object_get_handle (object);
+	}
+	if (object) 
+		g_object_unref (object);
+	g_free (attrs);
+	
+	return rv;
 }
 
 CK_RV
@@ -712,10 +880,39 @@
 }
 
 CK_RV
-gck_session_C_DestroyObject (GckSession* self, CK_OBJECT_HANDLE object)
+gck_session_C_DestroyObject (GckSession* self, CK_OBJECT_HANDLE handle)
 {
-	/* TODO: Need to implement this */
-	return CKR_FUNCTION_NOT_SUPPORTED;
+	GckObject *object;
+	GckSession *session;
+	GckTransaction *transaction;
+	CK_RV rv;
+	
+	g_return_val_if_fail (GCK_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
+	
+	rv = gck_session_lookup_writable_object (self, handle, &object);
+	if (rv != CKR_OK)
+		return rv;
+	
+	transaction = gck_transaction_new ();
+
+	/* Lookup the actual session that owns this object, if no session, then a token object */
+	session = g_object_get_data (G_OBJECT (object), "owned-by-session");
+	if (session != NULL)
+		remove_object (session, transaction, object);
+	else
+		gck_module_remove_token_object (self->pv->module, transaction, object);
+	
+	gck_transaction_complete (transaction);
+	rv = gck_transaction_get_result (transaction);
+	g_object_unref (transaction);
+	
+	if (rv == CKR_OK) {
+		/* Check that it's really gone */
+		g_return_val_if_fail (gck_session_lookup_readable_object (self, handle, &object) == 
+		                      CKR_OBJECT_HANDLE_INVALID, CKR_GENERAL_ERROR);
+	}
+	
+	return rv;
 }
 
 CK_RV
@@ -732,8 +929,11 @@
 	if (!(template || !count))
 		return CKR_ARGUMENTS_BAD;
 	
-	if (self->pv->current_operation)
-		return CKR_OPERATION_ACTIVE;
+	/* Cancel any current operation */
+	if (self->pv->current_operation) {
+		(self->pv->current_operation) (self);
+		g_assert (!self->pv->current_operation);
+	}
 
 	/* See whether this is token or not */
 	all = !attributes_find_boolean (template, count, CKA_TOKEN, &token);

Modified: trunk/pkcs11/gck/gck-sexp.h
==============================================================================
--- trunk/pkcs11/gck/gck-sexp.h	(original)
+++ trunk/pkcs11/gck/gck-sexp.h	Sat Jan  3 19:30:08 2009
@@ -26,8 +26,7 @@
 
 #include <glib-object.h>
 
-struct _GckSexp;
-typedef struct _GckSexp GckSexp;
+#include "gck-types.h"
 
 GckSexp*       gck_sexp_new           (gcry_sexp_t sexp);
 

Added: trunk/pkcs11/gck/gck-store.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-store.c	Sat Jan  3 19:30:08 2009
@@ -0,0 +1,328 @@
+/* 
+ * gnome-keyring
+ * 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program 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
+ * Lesser General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include "config.h"
+
+#include "gck-attributes.h"
+#include "gck-object.h"
+#include "gck-store.h"
+#include "gck-transaction.h"
+#include "gck-util.h"
+
+typedef struct _Schema {
+	CK_ATTRIBUTE_TYPE type;
+	gpointer default_value;
+	gsize default_length;
+	GckStoreValidator validator;
+	guint flags;
+} Schema;
+
+struct _GckStorePrivate {
+	GHashTable *schemas;
+};
+
+G_DEFINE_TYPE (GckStore, gck_store, G_TYPE_OBJECT);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL 
+ */
+
+static void
+schema_free (gpointer data)
+{
+	Schema *schema;
+	
+	if (data == NULL)
+		return;
+	
+	schema = data;
+	g_free (schema->default_value);
+	g_slice_free (Schema, schema);
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT 
+ */
+
+static GObject* 
+gck_store_constructor (GType type, guint n_props, GObjectConstructParam *props) 
+{
+	GckStore *self = GCK_STORE (G_OBJECT_CLASS (gck_store_parent_class)->constructor(type, n_props, props));
+	g_return_val_if_fail (self, NULL);	
+
+	return G_OBJECT (self);
+}
+
+static void
+gck_store_init (GckStore *self)
+{
+	self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCK_TYPE_STORE, GckStorePrivate);
+	self->pv->schemas = g_hash_table_new_full (gck_util_ulong_hash, gck_util_ulong_equal, 
+	                                           NULL, schema_free);
+}
+
+static void
+gck_store_dispose (GObject *obj)
+{
+	GckStore *self = GCK_STORE (obj);
+
+	g_hash_table_remove_all (self->pv->schemas);
+	
+	G_OBJECT_CLASS (gck_store_parent_class)->dispose (obj);
+}
+
+static void
+gck_store_finalize (GObject *obj)
+{
+	GckStore *self = GCK_STORE (obj);
+
+	g_hash_table_destroy (self->pv->schemas);
+
+	G_OBJECT_CLASS (gck_store_parent_class)->finalize (obj);
+}
+
+static void
+gck_store_set_property (GObject *obj, guint prop_id, const GValue *value, 
+                           GParamSpec *pspec)
+{
+	switch (prop_id) {
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gck_store_get_property (GObject *obj, guint prop_id, GValue *value, 
+                           GParamSpec *pspec)
+{
+	switch (prop_id) {
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gck_store_class_init (GckStoreClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+    
+	gobject_class->constructor = gck_store_constructor;
+	gobject_class->dispose = gck_store_dispose;
+	gobject_class->finalize = gck_store_finalize;
+	gobject_class->set_property = gck_store_set_property;
+	gobject_class->get_property = gck_store_get_property;
+	
+	g_type_class_add_private (klass, sizeof (GckStorePrivate));
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC 
+ */
+
+gconstpointer
+gck_store_read_value (GckStore *self, GckObject *object, 
+                      CK_ATTRIBUTE_TYPE type, gsize *n_value)
+{
+	CK_ATTRIBUTE at;
+	Schema *schema;
+	CK_RV rv;
+	
+	g_return_val_if_fail (GCK_IS_STORE (self), NULL);
+	g_return_val_if_fail (GCK_IS_OBJECT (object), NULL);
+	g_return_val_if_fail (n_value, NULL);
+
+	g_assert (GCK_STORE_GET_CLASS (self)->read_value);
+
+	schema = g_hash_table_lookup (self->pv->schemas, &type);
+	if (schema == NULL)
+		return NULL;
+
+	at.type = type;
+	at.pValue = NULL;
+	at.ulValueLen = 0;
+	
+	rv = GCK_STORE_GET_CLASS (self)->read_value (self, object, &at);
+	if (rv == CKR_ATTRIBUTE_TYPE_INVALID || rv == CKR_USER_NOT_LOGGED_IN) {
+		at.pValue = schema->default_value;
+		at.ulValueLen = schema->default_length;
+	} else if (rv != CKR_OK) {
+		g_return_val_if_reached (NULL);
+	}
+	
+	*n_value = at.ulValueLen;
+	return at.pValue;
+}
+
+gchar*
+gck_store_read_string (GckStore *self, GckObject *object, CK_ATTRIBUTE_TYPE type)
+{
+	gconstpointer value;
+	gsize n_value;
+	
+	g_return_val_if_fail (GCK_IS_STORE (self), NULL);
+	g_return_val_if_fail (GCK_IS_OBJECT (object), NULL);
+	
+	value = gck_store_read_value (self, object, type, &n_value);
+	if (!value)
+		return NULL;
+	
+	return g_strndup (value, n_value);
+}
+
+CK_RV
+gck_store_get_attribute (GckStore *self, GckObject *object, CK_ATTRIBUTE_PTR attr)
+{
+	CK_ATTRIBUTE at;
+	Schema *schema;
+	CK_RV rv;
+	
+	g_return_val_if_fail (GCK_IS_STORE (self), CKR_GENERAL_ERROR);
+	g_return_val_if_fail (GCK_IS_OBJECT (object), CKR_GENERAL_ERROR);
+	g_return_val_if_fail (attr, CKR_GENERAL_ERROR);
+
+	g_assert (GCK_STORE_GET_CLASS (self)->read_value);
+
+	schema = g_hash_table_lookup (self->pv->schemas, &(attr->type));
+	if (schema == NULL)
+		return CKR_ATTRIBUTE_TYPE_INVALID;
+	
+	if (schema->flags & GCK_STORE_IS_INTERNAL)
+		return CKR_ATTRIBUTE_TYPE_INVALID;
+
+	if (schema->flags & GCK_STORE_IS_SENSITIVE)
+		return CKR_ATTRIBUTE_SENSITIVE;
+	
+	at.type = attr->type;
+	at.pValue = NULL;
+	at.ulValueLen = 0;
+
+	rv = GCK_STORE_GET_CLASS (self)->read_value (self, object, &at);
+	if (rv == CKR_ATTRIBUTE_TYPE_INVALID) {
+		at.pValue = schema->default_value;
+		at.ulValueLen = schema->default_length;
+	} else if (rv != CKR_OK) {
+		return rv;
+	}
+	
+	/* 
+	 * If we get an assert here, then the derived class is probably 
+	 * trying to fill the  buffer in the attribute passed. It should
+	 * actually just be setting the pValue to its own buffers.
+	 */ 
+	g_assert (at.pValue || !at.ulValueLen);
+	
+	return gck_attribute_set_data (attr, at.pValue, at.ulValueLen);
+}
+
+void
+gck_store_write_value (GckStore *self, GckTransaction *transaction,
+                       GckObject *object, CK_ATTRIBUTE_PTR attr)
+{
+	Schema *schema;
+
+	g_return_if_fail (GCK_IS_STORE (self));
+	g_return_if_fail (GCK_IS_TRANSACTION (transaction));
+	g_return_if_fail (GCK_IS_OBJECT (object));
+	g_return_if_fail (attr);
+
+	g_return_if_fail (!gck_transaction_get_failed (transaction));
+	g_assert (GCK_STORE_GET_CLASS (self)->write_value);
+	
+	schema = g_hash_table_lookup (self->pv->schemas, &(attr->type));
+	if (schema == NULL) {
+		gck_transaction_fail (transaction, CKR_ATTRIBUTE_TYPE_INVALID);
+		return;
+	}
+
+	GCK_STORE_GET_CLASS (self)->write_value (self, transaction, object, attr);
+}
+
+void
+gck_store_set_attribute (GckStore *self, GckTransaction *transaction,
+                         GckObject *object, CK_ATTRIBUTE_PTR attr)
+{
+	Schema *schema;
+	CK_RV rv = CKR_OK;
+
+	g_return_if_fail (GCK_IS_STORE (self));
+	g_return_if_fail (GCK_IS_TRANSACTION (transaction));
+	g_return_if_fail (GCK_IS_OBJECT (object));
+	g_return_if_fail (attr);
+
+	g_return_if_fail (!gck_transaction_get_failed (transaction));
+	g_assert (GCK_STORE_GET_CLASS (self)->write_value);
+	
+	schema = g_hash_table_lookup (self->pv->schemas, &(attr->type));
+	if (schema == NULL)
+		rv = CKR_ATTRIBUTE_TYPE_INVALID;
+	else if (schema->flags & GCK_STORE_IS_INTERNAL)
+		rv = CKR_ATTRIBUTE_TYPE_INVALID;
+	else if (schema->validator)
+		rv = (schema->validator) (object, attr);
+
+	if (rv != CKR_OK) {
+		gck_transaction_fail (transaction, rv);
+		return;
+	}
+
+	GCK_STORE_GET_CLASS (self)->write_value (self, transaction, object, attr);
+}
+
+void
+gck_store_register_schema (GckStore *self, CK_ATTRIBUTE_PTR attr, 
+                           GckStoreValidator validator, guint flags)
+{
+	Schema *schema;
+	
+	g_return_if_fail (GCK_IS_STORE (self));
+	g_return_if_fail (g_hash_table_lookup (self->pv->schemas, &(attr->type)) == NULL);
+	g_return_if_fail (!attr->ulValueLen || attr->pValue);
+	g_return_if_fail (attr->ulValueLen != (CK_ULONG)-1);
+	
+	schema = g_slice_new0 (Schema);
+	schema->type = attr->type;
+	schema->flags = flags;
+	schema->validator = validator;
+	schema->default_value = attr->pValue;
+	schema->default_length = attr->ulValueLen;
+	if (schema->default_value) 
+		schema->default_value = g_memdup (schema->default_value, 
+		                                  schema->default_length);
+	
+	g_hash_table_insert (self->pv->schemas, &(schema->type), schema);
+}
+
+gboolean
+gck_store_lookup_schema (GckStore *self, CK_ATTRIBUTE_TYPE type, guint *flags)
+{
+	Schema *schema;
+	
+	g_return_val_if_fail (GCK_IS_STORE (self), FALSE);
+
+	schema = g_hash_table_lookup (self->pv->schemas, &type);
+	if (!schema)
+		return FALSE;
+	if (flags)
+		*flags = schema->flags;
+	return TRUE;
+}

Added: trunk/pkcs11/gck/gck-store.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-store.h	Sat Jan  3 19:30:08 2009
@@ -0,0 +1,101 @@
+/* 
+ * gnome-keyring
+ * 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program 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
+ * Lesser General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef __GCK_STORE_H__
+#define __GCK_STORE_H__
+
+#include <glib-object.h>
+
+#include "gck-types.h"
+
+#include "pkcs11/pkcs11.h"
+
+enum {
+	GCK_STORE_IS_INTERNAL = 0x01,
+	GCK_STORE_IS_SENSITIVE = 0x02
+};
+
+#define GCK_TYPE_STORE               (gck_store_get_type ())
+#define GCK_STORE(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_STORE, GckStore))
+#define GCK_STORE_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCK_TYPE_STORE, GckStoreClass))
+#define GCK_IS_STORE(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCK_TYPE_STORE))
+#define GCK_IS_STORE_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_STORE))
+#define GCK_STORE_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_STORE, GckStoreClass))
+
+typedef struct _GckStoreClass GckStoreClass;
+typedef struct _GckStorePrivate GckStorePrivate;
+
+struct _GckStore {
+	GObject parent;
+	GckStorePrivate *pv;
+};
+
+struct _GckStoreClass {
+	GObjectClass parent_class;
+	
+	/* Virtual methods */
+    
+	CK_RV (*read_value) (GckStore *self, GckObject *object, CK_ATTRIBUTE_PTR attr);
+	void (*write_value) (GckStore *self, GckTransaction *transaction, GckObject *object, CK_ATTRIBUTE_PTR attr); 
+};
+
+typedef CK_RV         (*GckStoreValidator)                (GckObject *object,
+                                                           CK_ATTRIBUTE_PTR attr);
+
+GType                 gck_store_get_type                  (void);
+
+gboolean              gck_store_lookup_schema             (GckStore *self,
+                                                           CK_ATTRIBUTE_TYPE type,
+                                                           guint *flags);
+
+void                  gck_store_register_schema           (GckStore *self,
+                                                           CK_ATTRIBUTE_PTR type_and_default,
+                                                           GckStoreValidator validator,
+                                                           guint flags);
+
+void                  gck_store_set_attribute             (GckStore *self,
+                                                           GckTransaction *transaction,
+                                                           GckObject *object,
+                                                           CK_ATTRIBUTE_PTR attr);
+
+void                  gck_store_write_value               (GckStore *self,
+                                                           GckTransaction *transaction,
+                                                           GckObject *object,
+                                                           CK_ATTRIBUTE_PTR attr);
+
+CK_RV                 gck_store_get_attribute             (GckStore *self,
+                                                           GckObject *object,
+                                                           CK_ATTRIBUTE_PTR attr);
+
+gconstpointer         gck_store_read_value                (GckStore *self,
+                                                           GckObject *object,
+                                                           CK_ATTRIBUTE_TYPE type,
+                                                           gsize *n_value);
+
+gchar*                gck_store_read_string               (GckStore *self,
+                                                           GckObject *object,
+                                                           CK_ATTRIBUTE_TYPE type);
+
+void                  gck_store_notify_attribute          (GckStore *self,
+                                                           GckObject *object,
+                                                           CK_ATTRIBUTE_TYPE type);
+
+#endif /* __GCK_STORE_H__ */

Added: trunk/pkcs11/gck/gck-transaction.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-transaction.c	Sat Jan  3 19:30:08 2009
@@ -0,0 +1,291 @@
+/* 
+ * gnome-keyring
+ * 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program 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
+ * Lesser General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include "config.h"
+
+#include "gck-marshal.h"
+#include "gck-transaction.h"
+
+enum {
+	PROP_0,
+	PROP_COMPLETED,
+	PROP_FAILED,
+	PROP_RESULT
+};
+
+enum {
+	COMPLETE,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+struct _GckTransaction {
+	GObject parent;
+	GList *completes;
+	gboolean failed;
+	gboolean completed;
+	CK_RV result;
+};
+
+typedef struct _Complete {
+	GObject *object;
+	GckTransactionFunc func;
+	gpointer user_data;
+} Complete;
+
+G_DEFINE_TYPE (GckTransaction, gck_transaction, G_TYPE_OBJECT);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL 
+ */
+
+static gboolean
+complete_invoke (GckTransaction *transaction, Complete *complete)
+{
+	g_assert (complete);
+	g_assert (complete->func);
+	g_assert (complete->object);
+	
+	return (complete->func) (transaction, complete->object, complete->user_data);
+}
+
+static void
+complete_destroy (Complete *complete)
+{
+	g_assert (complete->func);
+	g_assert (G_IS_OBJECT (complete->object));
+	g_object_unref (complete->object);
+	g_slice_free (Complete, complete);
+}
+
+static gboolean
+complete_accumulator (GSignalInvocationHint *ihint, GValue *return_accu, 
+                      const GValue *handler_return, gpointer data)
+{
+	gboolean result;
+	
+	/* If any of them return false, then the result is false */
+	result = g_value_get_boolean (handler_return);
+	if (result == FALSE)
+		g_value_set_boolean (return_accu, FALSE);
+	
+	/* Continue signal invocations */
+	return TRUE;
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT 
+ */
+
+static gboolean
+gck_transaction_real_complete (GckTransaction *self)
+{
+	GList *l;
+	
+	g_return_val_if_fail (!self->completed, FALSE);
+	self->completed = TRUE;
+	g_object_notify (G_OBJECT (self), "completed");
+	
+	for (l = self->completes; l; l = g_list_next (l)) {
+		complete_invoke (self, l->data);
+		complete_destroy (l->data);
+	}
+	
+	g_list_free (self->completes);
+	self->completes = NULL;
+	
+	return TRUE;
+}
+
+static void
+gck_transaction_init (GckTransaction *self)
+{
+
+}
+
+static void
+gck_transaction_dispose (GObject *obj)
+{
+	GckTransaction *self = GCK_TRANSACTION (obj);
+	
+	if (!self->completed)
+		gck_transaction_complete (self);
+    
+	G_OBJECT_CLASS (gck_transaction_parent_class)->dispose (obj);
+}
+
+static void
+gck_transaction_finalize (GObject *obj)
+{
+	GckTransaction *self = GCK_TRANSACTION (obj);
+
+	g_assert (!self->completes);
+	g_assert (self->completed);
+	
+	G_OBJECT_CLASS (gck_transaction_parent_class)->finalize (obj);
+}
+
+static void
+gck_transaction_set_property (GObject *obj, guint prop_id, const GValue *value, 
+                              GParamSpec *pspec)
+{
+	switch (prop_id) {
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gck_transaction_get_property (GObject *obj, guint prop_id, GValue *value, 
+                              GParamSpec *pspec)
+{
+	GckTransaction *self = GCK_TRANSACTION (obj);
+
+	switch (prop_id) {
+	case PROP_COMPLETED:
+		g_value_set_boolean (value, gck_transaction_get_completed (self));
+		break;
+	case PROP_FAILED:
+		g_value_set_boolean (value, gck_transaction_get_failed (self));
+		break;
+	case PROP_RESULT:
+		g_value_set_ulong (value, gck_transaction_get_result (self));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gck_transaction_class_init (GckTransactionClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+    
+	gobject_class->dispose = gck_transaction_dispose;
+	gobject_class->finalize = gck_transaction_finalize;
+	gobject_class->set_property = gck_transaction_set_property;
+	gobject_class->get_property = gck_transaction_get_property;
+	
+	klass->complete = gck_transaction_real_complete;
+    
+	g_object_class_install_property (gobject_class, PROP_COMPLETED,
+	           g_param_spec_boolean ("completed", "Completed", "Whether transaction is complete", 
+	                                 FALSE, G_PARAM_READABLE));
+	
+	g_object_class_install_property (gobject_class, PROP_FAILED,
+	           g_param_spec_boolean ("failed", "Failed", "Whether transaction failed", 
+	                                 FALSE, G_PARAM_READABLE));
+    
+	g_object_class_install_property (gobject_class, PROP_RESULT,
+	           g_param_spec_ulong ("result", "Result", "Result code for transaction",
+	                               0, G_MAXULONG, CKR_OK, G_PARAM_READABLE));
+	                               
+	signals[COMPLETE] = g_signal_new ("complete", GCK_TYPE_TRANSACTION, 
+	                                  G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GckTransactionClass, complete),
+	                                  complete_accumulator, NULL, gck_marshal_BOOLEAN__VOID, 
+	                                  G_TYPE_BOOLEAN, 0, G_TYPE_NONE);
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC 
+ */
+
+GckTransaction*
+gck_transaction_new (void)
+{
+	return g_object_new (GCK_TYPE_TRANSACTION, NULL);
+}
+
+void
+gck_transaction_add (GckTransaction *self, gpointer object,
+                     GckTransactionFunc func, gpointer user_data)
+{
+	Complete *complete;
+	
+	g_return_if_fail (GCK_IS_TRANSACTION (self));
+	g_return_if_fail (G_IS_OBJECT (object));
+	g_return_if_fail (func);
+	
+	complete = g_slice_new0 (Complete);
+	complete->func = func;
+	complete->object = g_object_ref (object);
+	complete->user_data = user_data;
+	
+	self->completes = g_list_prepend (self->completes, complete);
+}
+
+void
+gck_transaction_fail (GckTransaction *self, CK_RV result)
+{
+	g_return_if_fail (GCK_IS_TRANSACTION (self));
+	g_return_if_fail (!self->completed);
+	g_return_if_fail (result != CKR_OK);
+	g_return_if_fail (!self->failed);
+
+	self->failed = TRUE;
+	self->result = result;
+	
+	g_object_notify (G_OBJECT (self), "failed");
+	g_object_notify (G_OBJECT (self), "result");
+}
+
+void
+gck_transaction_complete(GckTransaction *self)
+{
+	gboolean critical = FALSE;
+	
+	g_return_if_fail (GCK_IS_TRANSACTION (self));
+	g_return_if_fail (!self->completed);
+	g_signal_emit (self, signals[COMPLETE], 0, &critical);
+	g_assert (self->completed);
+	
+	if (!self->failed && critical) {
+		g_warning ("transaction failed to commit, data may be lost");
+		self->failed = TRUE;
+		self->result = CKR_GENERAL_ERROR;
+		g_object_notify (G_OBJECT (self), "failed");
+		g_object_notify (G_OBJECT (self), "result");
+	}
+}
+
+gboolean
+gck_transaction_get_completed (GckTransaction *self)
+{
+	g_return_val_if_fail (GCK_IS_TRANSACTION (self), FALSE);
+	return self->completed;
+}
+
+gboolean
+gck_transaction_get_failed (GckTransaction *self)
+{
+	g_return_val_if_fail (GCK_IS_TRANSACTION (self), FALSE);
+	return self->failed;
+}
+
+CK_RV
+gck_transaction_get_result (GckTransaction *self)
+{
+	g_return_val_if_fail (GCK_IS_TRANSACTION (self), FALSE);
+	return self->result;
+}

Added: trunk/pkcs11/gck/gck-transaction.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-transaction.h	Sat Jan  3 19:30:08 2009
@@ -0,0 +1,72 @@
+/* 
+ * gnome-keyring
+ * 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program 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
+ * Lesser General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef __GCK_TRANSACTION_H__
+#define __GCK_TRANSACTION_H__
+
+#include <glib-object.h>
+
+#include "gck-types.h"
+
+#include "pkcs11/pkcs11.h"
+
+#define GCK_TYPE_TRANSACTION               (gck_transaction_get_type ())
+#define GCK_TRANSACTION(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_TRANSACTION, GckTransaction))
+#define GCK_TRANSACTION_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCK_TYPE_TRANSACTION, GckTransactionClass))
+#define GCK_IS_TRANSACTION(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCK_TYPE_TRANSACTION))
+#define GCK_IS_TRANSACTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_TRANSACTION))
+#define GCK_TRANSACTION_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_TRANSACTION, GckTransactionClass))
+
+typedef struct _GckTransactionClass GckTransactionClass;
+    
+struct _GckTransactionClass {
+	GObjectClass parent_class;
+    
+	/* signals --------------------------------------------------------- */
+    
+	gboolean (*complete) (GckTransaction *transaction);
+};
+
+GType                       gck_transaction_get_type               (void);
+
+GckTransaction*             gck_transaction_new                    (void);
+
+typedef gboolean            (*GckTransactionFunc)                  (GckTransaction *self,
+                                                                    GObject *object,
+                                                                    gpointer user_data);
+
+void                        gck_transaction_add                    (GckTransaction *self,
+                                                                    gpointer object,
+                                                                    GckTransactionFunc callback,
+                                                                    gpointer user_data);
+
+void                        gck_transaction_fail                   (GckTransaction *self,
+                                                                    CK_RV result);
+
+void                        gck_transaction_complete               (GckTransaction *self);
+
+gboolean                    gck_transaction_get_failed             (GckTransaction *self);
+
+CK_RV                       gck_transaction_get_result             (GckTransaction *self);
+
+gboolean                    gck_transaction_get_completed          (GckTransaction *self);
+
+#endif /* __GCK_TRANSACTION_H__ */

Added: trunk/pkcs11/gck/gck-types.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-types.h	Sat Jan  3 19:30:08 2009
@@ -0,0 +1,41 @@
+/* 
+ * gnome-keyring
+ * 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program 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
+ * Lesser General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef __GCK_TYPES_H__
+#define __GCK_TYPES_H__
+
+typedef struct _GckCertificate GckCertificate;
+typedef struct _GckCertificateKey GckCertificateKey;
+typedef struct _GckKey GckKey;
+typedef struct _GckFactoryInfo GckFactoryInfo;
+typedef struct _GckManager GckManager;
+typedef struct _GckModule GckModule;
+typedef struct _GckObject GckObject;
+typedef struct _GckPrivateKey GckPrivateKey;
+typedef struct _GckPublicKey GckPublicKey;
+typedef struct _GckSession GckSession;
+typedef struct _GckSessionPrivateKey GckSessionPrivateKey;
+typedef struct _GckSessionPublicKey GckSessionPublicKey;
+typedef struct _GckSexp GckSexp;
+typedef struct _GckStore GckStore;
+typedef struct _GckTransaction GckTransaction;
+
+#endif /* __GCK_TYPES_H__ */

Modified: trunk/pkcs11/gck/gck-util.c
==============================================================================
--- trunk/pkcs11/gck/gck-util.c	(original)
+++ trunk/pkcs11/gck/gck-util.c	Sat Jan  3 19:30:08 2009
@@ -58,69 +58,11 @@
 }
 
 CK_RV
-gck_util_set_bool (CK_ATTRIBUTE_PTR attr, CK_BBOOL value)
-{
-	return gck_util_set_data (attr, &value, sizeof (CK_BBOOL));
-}
-
-CK_RV
-gck_util_set_ulong (CK_ATTRIBUTE_PTR attr, CK_ULONG value)
-{
-	return gck_util_set_data (attr, &value, sizeof (CK_ULONG));
-}
-
-CK_RV
-gck_util_set_string (CK_ATTRIBUTE_PTR attr, const gchar* string)
-{
-	g_return_val_if_fail (string, CKR_GENERAL_ERROR);
-	return gck_util_set_data (attr, (CK_VOID_PTR)string, strlen (string));
-}
-
-CK_RV
-gck_util_set_date (CK_ATTRIBUTE_PTR attr, time_t time)
-{
-	CK_DATE date;
-	struct tm tm;
-	gchar buf[16];
-	
-	/* 'Empty' date as defined in PKCS#11 */
-	if (time == (time_t)-1)
-		return gck_util_set_data (attr, NULL, 0);
-	
-	if (!attr->pValue) {
-		attr->ulValueLen = sizeof (CK_DATE);
-		return CKR_OK;
-	}
-
-	if (!gmtime_r (&time, &tm))
-		g_return_val_if_reached (CKR_GENERAL_ERROR);
-		
-	g_assert (sizeof (date.year) == 4);
-	snprintf ((char*)buf, 5, "%04d", 1900 + tm.tm_year);
-	memcpy (date.year, buf, 4);
-	 
-	g_assert (sizeof (date.month) == 2);
-	snprintf ((char*)buf, 3, "%02d", tm.tm_mon + 1);
-	memcpy (date.month, buf, 2);
-	
-	g_assert (sizeof (date.day) == 2);
-	snprintf ((char*)buf, 3, "%02d", tm.tm_mday);
-	memcpy (date.day, buf, 2);
-		
-	return gck_util_set_data (attr, &date, sizeof (date));
-}
-CK_RV
-gck_util_set_data (CK_ATTRIBUTE_PTR attr, gconstpointer value, gsize n_value)
-{
-	return gck_util_return_data (attr->pValue, &(attr->ulValueLen), value, n_value);
-}
-
-CK_RV
 gck_util_return_data (CK_VOID_PTR output, CK_ULONG_PTR n_output,
                       gconstpointer input, gsize n_input)
 {
 	g_return_val_if_fail (n_output, CKR_GENERAL_ERROR);
-	g_return_val_if_fail (input, CKR_GENERAL_ERROR);
+	g_return_val_if_fail (input || !n_input, CKR_GENERAL_ERROR);
 	
 	/* Just asking for the length */
 	if (!output) {
@@ -135,38 +77,8 @@
 	}
 
 	*n_output = n_input;
-	memcpy (output, input, n_input);
-	return CKR_OK;
-}
-
-CK_RV
-gck_util_set_mpi (CK_ATTRIBUTE_PTR attr, gcry_mpi_t mpi)
-{
-	gsize len;
-  	gcry_error_t gcry;
-
-	g_assert (attr);
-	g_assert (mpi);
-	
-	/* Get the size */
-	gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &len, mpi);
-	g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
-
-	if (!attr->pValue) {
-		attr->ulValueLen = len;
-		return CKR_OK;
-	}
-	
-	if (len > attr->ulValueLen) {
-		attr->ulValueLen = len;
-		return CKR_BUFFER_TOO_SMALL;
-	}
-
-	/* Write in directly to attribute */
-	gcry = gcry_mpi_print (GCRYMPI_FMT_USG, attr->pValue, len, &len, mpi);	
-	g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
-	
-	attr->ulValueLen = len;
+	if (n_input)
+		memcpy (output, input, n_input);
 	return CKR_OK;
 }
 

Modified: trunk/pkcs11/gck/gck-util.h
==============================================================================
--- trunk/pkcs11/gck/gck-util.h	(original)
+++ trunk/pkcs11/gck/gck-util.h	Sat Jan  3 19:30:08 2009
@@ -37,28 +37,12 @@
 
 void                  gck_util_ulong_free                         (gpointer ptr_to_ulong);
 
-CK_RV                 gck_util_set_bool                           (CK_ATTRIBUTE_PTR attr,
-                                                                   CK_BBOOL value);
-
-CK_RV                 gck_util_set_ulong                          (CK_ATTRIBUTE_PTR attr, 
-                                                                   CK_ULONG value);
-
-CK_RV                 gck_util_set_string                         (CK_ATTRIBUTE_PTR attr, 
-                                                                   const gchar* string);
-
-CK_RV                 gck_util_set_date                           (CK_ATTRIBUTE_PTR attr,
-                                                                   time_t when);
-
-CK_RV                 gck_util_set_data                           (CK_ATTRIBUTE_PTR attr,
-                                                                   gconstpointer value,
-                                                                   gsize n_value);
-
 CK_RV                 gck_util_return_data                        (CK_VOID_PTR output,
                                                                    CK_ULONG_PTR n_output,
                                                                    gconstpointer input,
                                                                    gsize n_input);
 
-CK_RV                 gck_util_set_mpi                            (CK_ATTRIBUTE_PTR attr, 
+CK_RV                 gck_attribute_set_mpi                            (CK_ATTRIBUTE_PTR attr, 
                                                                    gcry_mpi_t mpi);
 
 CK_ULONG              gck_util_next_handle                        (void);

Modified: trunk/pkcs11/gck/tests/Makefile.am
==============================================================================
--- trunk/pkcs11/gck/tests/Makefile.am	(original)
+++ trunk/pkcs11/gck/tests/Makefile.am	Sat Jan  3 19:30:08 2009
@@ -5,13 +5,17 @@
 asn1-def-test.h: test.asn
 	asn1Parser -o asn1-def-test.h test.asn 
 	
+# Test files should be listed in order they need to run
 UNIT_AUTO = \
 	unit-test-crypto.c \
 	unit-test-data-asn1.c \
 	unit-test-data-der.c \
 	unit-test-data-openssl.c \
-	unit-test-file-tracker.c \
-	$(BUILT_SOURCES)
+	unit-test-transaction.c \ 
+	unit-test-store.c \
+	unit-test-memory-store.c \
+	unit-test-file-store.c \
+	unit-test-file-tracker.c
 
 UNIT_PROMPT = 
 

Added: trunk/pkcs11/gck/tests/test-data/test-file-store.store
==============================================================================
Binary file. No diff available.

Added: trunk/pkcs11/gck/tests/unit-test-file-store.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/tests/unit-test-file-store.c	Sat Jan  3 19:30:08 2009
@@ -0,0 +1,388 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-file-store.c: Test file store functionality
+
+   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 "run-auto-test.h"
+
+#include "gck/gck-file-store.h"
+#include "gck/gck-object.h"
+#include "gck/gck-transaction.h"
+
+/* Both point to the same thing */
+static GckStore *store = NULL;
+static GckFileStore *file_store = NULL;
+static GckTransaction *transaction = NULL;
+static GckObject *object = NULL;
+static GckObject *prv_object = NULL;
+static gchar *test_filename = NULL;
+
+static void
+copy_file (const gchar *from, const gchar *to)
+{
+	gchar *contents;
+	gsize length;
+	gboolean ret;
+	
+	ret = g_file_get_contents (from, &contents, &length, NULL);
+	g_assert (ret == TRUE);
+	ret = g_file_set_contents (to, contents, length, NULL);
+	g_assert (ret == TRUE);
+	g_free (contents);
+}
+
+DEFINE_SETUP(file_store)
+{
+	CK_ATTRIBUTE attr;
+	CK_ULONG twentyfour = 24;
+	
+	test_filename = test_build_filename ("unit-test-file-store");
+
+	copy_file ("./test-data/test-file-store.store", test_filename);
+	file_store = gck_file_store_new (test_filename);
+	store = GCK_STORE (file_store);
+
+	attr.type = CKA_LABEL;
+	attr.pValue = "label";
+	attr.ulValueLen = 5;
+	
+	gck_store_register_schema (store, &attr, NULL, 0);
+	g_assert (gck_store_lookup_schema (store, CKA_LABEL, NULL));
+
+	attr.type = CKA_VALUE;
+	attr.pValue = NULL;
+	attr.ulValueLen = 0;
+	
+	gck_store_register_schema (store, &attr, NULL, GCK_STORE_IS_SENSITIVE);
+	
+	attr.type = CKA_BITS_PER_PIXEL;
+	attr.pValue = &twentyfour;
+	attr.ulValueLen = sizeof (twentyfour);
+	
+	gck_store_register_schema (store, &attr, NULL, GCK_STORE_IS_INTERNAL);
+	
+	transaction = gck_transaction_new ();
+	object = g_object_new (GCK_TYPE_OBJECT, NULL);
+	prv_object = g_object_new (GCK_TYPE_OBJECT, NULL);
+	
+	gck_file_store_connect_entry (file_store, "unique-one", object);
+	gck_file_store_connect_entry (file_store, "unique-private", prv_object);
+}
+
+DEFINE_TEARDOWN(file_store)
+{
+	g_free (test_filename);
+	
+	gck_file_store_disconnect_entry (file_store, "unique-private", prv_object);
+	
+	if (prv_object != NULL)
+		g_object_unref (prv_object);
+	prv_object = NULL;
+
+	g_object_unref (file_store);
+	file_store = NULL;
+	store = NULL;
+	
+	g_object_unref (transaction);
+	transaction = NULL;
+	
+	if (object != NULL)
+		g_object_unref (object);
+	object = NULL;
+}
+
+DEFINE_TEST(test_properties)
+{
+	const gchar *filename;
+	gboolean locked;
+	gchar *name;
+		
+	filename = gck_file_store_get_filename (file_store);
+	g_assert_cmpstr (filename, ==, test_filename);
+	
+	locked = gck_file_store_get_locked (file_store);
+	g_assert (locked == TRUE);
+	
+	/* Try properties */
+	locked = FALSE;
+	g_object_get (file_store, "filename", &name, "locked", &locked, NULL);
+	g_assert_cmpstr (name, ==, test_filename);
+	g_assert (locked == TRUE);
+}
+
+DEFINE_TEST(test_store_read)
+{
+	gboolean ret;
+	
+	ret = gck_file_store_refresh (file_store);
+	g_assert (ret);
+}
+
+DEFINE_TEST(test_unlock)
+{
+	gchar *str;
+	CK_RV rv;
+	
+	/* We shouldn't be able to read from private object */
+	g_assert (!gck_file_store_have_entry (file_store, "unique-private"));
+
+	/* Try with wrong password */
+	rv = gck_file_store_unlock (file_store, (guchar*)"password", 8);
+	g_assert (rv == CKR_PIN_INCORRECT);
+	g_assert (gck_file_store_get_locked (file_store) == TRUE);
+
+	/* A valid unlock */
+	rv = gck_file_store_unlock (file_store, (guchar*)"booo", 4);
+	g_assert (rv == CKR_OK);
+	g_assert (gck_file_store_get_locked (file_store) == FALSE);
+
+	/* Unlocking twice should result in this code */
+	rv = gck_file_store_unlock (file_store, (guchar*)"booo", 4);
+	g_assert (rv == CKR_USER_ALREADY_LOGGED_IN);
+	g_assert (gck_file_store_get_locked (file_store) == FALSE);
+
+	/* Now we should be able to read from private object */
+	g_assert (gck_file_store_have_entry (file_store, "unique-private"));
+	str = gck_store_read_string (store, prv_object, CKA_LABEL);
+	g_assert_cmpstr (str, ==, "private-label");
+	g_free (str);
+	
+	/* Now lock again */
+	rv = gck_file_store_lock (file_store);
+	g_assert (rv == CKR_OK);
+
+	/* Locking twice should result in this code */
+	rv = gck_file_store_lock (file_store);
+	g_assert (rv == CKR_USER_NOT_LOGGED_IN);
+
+	/* We should get default attributes */
+	str = gck_store_read_string (store, prv_object, CKA_LABEL);
+	g_assert_cmpstr (str, ==, "label");
+	g_free (str);
+}
+
+DEFINE_TEST(write_encrypted)
+{
+	CK_ATTRIBUTE attr;
+	gboolean ret;
+	gchar *str;
+	CK_RV rv;
+	
+	rv = gck_file_store_unlock (file_store, (guchar*)"booo", 4);
+	g_assert (rv == CKR_OK);
+
+	attr.type = CKA_LABEL;
+	attr.pValue = "private-label-two";
+	attr.ulValueLen = 17;
+	
+	gck_store_set_attribute (store, transaction, prv_object, &attr);
+	
+	gck_transaction_complete (transaction);
+	g_assert (gck_transaction_get_result (transaction) == CKR_OK);
+	
+	ret = gck_file_store_refresh (file_store);
+	g_assert (ret);
+	
+	str = gck_store_read_string (store, prv_object, CKA_LABEL);
+	g_assert_cmpstr (str, ==, "private-label-two");
+	g_free (str);
+}
+
+DEFINE_TEST(file_set_get_attribute)
+{
+	gchar buffer[16];
+	CK_ATTRIBUTE attr;
+	CK_RV rv;
+	
+	attr.type = CKA_LABEL;
+	attr.pValue = "booyah";
+	attr.ulValueLen = 6;
+	
+	gck_store_set_attribute (store, transaction, object, &attr);
+	
+	gck_transaction_complete (transaction);
+	g_assert (gck_transaction_get_result (transaction) == CKR_OK);
+	
+	attr.pValue = buffer;
+	attr.ulValueLen = 7;
+	rv = gck_store_get_attribute (store, object, &attr);
+	g_assert (rv == CKR_OK);
+	g_assert (attr.ulValueLen == 6);
+	g_assert (memcmp (attr.pValue, "booyah", 6) == 0);
+}
+
+DEFINE_TEST(file_write_read_value)
+{
+	CK_ATTRIBUTE attr;
+	CK_ULONG five = 5;
+	gconstpointer value;
+	gsize n_value;
+	
+	attr.type = CKA_BITS_PER_PIXEL;
+	attr.pValue = &five;
+	attr.ulValueLen = sizeof (five);
+	
+	gck_store_write_value (store, transaction, object, &attr);
+
+	gck_transaction_complete (transaction);
+	g_assert (gck_transaction_get_result (transaction) == CKR_OK);
+
+	value = gck_store_read_value (store, object, CKA_BITS_PER_PIXEL, &n_value);
+	g_assert (value);
+	g_assert (n_value == sizeof (five));
+	g_assert (memcmp (value, &five, sizeof (five)) == 0);
+}
+
+DEFINE_TEST(destroy_entry)
+{
+	gboolean ret;
+	gchar *str;
+	
+	str = gck_store_read_string (store, object, CKA_LABEL);
+	g_assert_cmpstr (str, ==, "public-label");
+	g_free (str);
+
+	gck_file_store_destroy_entry (file_store, transaction, "unique-one");
+	gck_transaction_complete (transaction);
+	
+	g_assert (gck_transaction_get_result (transaction) == CKR_OK);
+	g_assert (!gck_transaction_get_failed (transaction));
+	
+	ret = gck_file_store_refresh (file_store);
+	g_assert (ret);
+	
+	str = gck_store_read_string (store, object, CKA_LABEL);
+	g_assert_cmpstr (str, ==, "label");
+	g_free (str);
+}
+
+DEFINE_TEST(refresh_modifications)
+{
+	GckFileStore *fs;
+	gboolean ret;
+	gchar *str;
+
+	/* Check that our label is correct */
+	str = gck_store_read_string (store, object, CKA_LABEL);
+	g_assert_cmpstr (str, ==, "public-label");
+	g_free (str);
+
+	/* Open a second file store on the same file */
+	fs = gck_file_store_new (test_filename);
+	ret = gck_file_store_refresh (fs);
+	g_assert (ret);
+	
+	/* Delete something from other store */
+	gck_file_store_destroy_entry (fs, transaction, "unique-one");
+	gck_transaction_complete (transaction);
+	g_assert (gck_transaction_get_result (transaction) == CKR_OK);
+	g_assert (!gck_transaction_get_failed (transaction));
+
+	/* Refresh first file store */
+	ret = gck_file_store_refresh (file_store);
+	g_assert (ret);
+	
+	/* Should be gone, we should see default label */
+	str = gck_store_read_string (store, object, CKA_LABEL);
+	g_assert_cmpstr (str, ==, "label");
+	g_free (str);
+	
+	g_object_unref (fs);
+}
+
+DEFINE_TEST(file_store_revert_first)
+{
+	CK_ATTRIBUTE attr, prev;
+	gconstpointer value;
+	gsize n_value;
+	
+	prev.type = CKA_LABEL;
+	prev.pValue = "numberone";
+	prev.ulValueLen = 9;
+
+	/* Change the attribute */
+	gck_store_set_attribute (store, transaction, object, &prev);
+	gck_transaction_complete (transaction);
+	g_assert (gck_transaction_get_failed (transaction) == FALSE);
+
+	/* Value should be new value */
+	value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+	g_assert (value && n_value == prev.ulValueLen);
+	g_assert (memcmp (prev.pValue, value, n_value) == 0);
+
+	/* A new transaction */
+	g_object_unref (transaction);
+	transaction = gck_transaction_new ();
+
+	attr.type = CKA_LABEL;
+	attr.pValue = "second";
+	attr.ulValueLen = 6;
+
+	gck_store_set_attribute (store, transaction, object, &attr);
+	g_assert (gck_transaction_get_failed (transaction) == FALSE);
+
+	/* Should get new value */
+	value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+	g_assert (value && n_value == attr.ulValueLen);
+	g_assert (memcmp (attr.pValue, value, n_value) == 0);
+
+	attr.type = CKA_LABEL;
+	attr.pValue = "third";
+	attr.ulValueLen = 5;
+
+	gck_store_set_attribute (store, transaction, object, &attr);
+	g_assert (gck_transaction_get_failed (transaction) == FALSE);
+
+	/* Should get new value */
+	value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+	g_assert (value && n_value == attr.ulValueLen);
+	g_assert (memcmp (attr.pValue, value, n_value) == 0);
+	
+	/* Fail for some arbitrary reason */
+	gck_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
+	
+	/* Value should not have changed yet */
+	value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+	g_assert (value && n_value == attr.ulValueLen);
+	g_assert (memcmp (attr.pValue, value, n_value) == 0);
+	
+	/* Now complete the transaction */
+	gck_transaction_complete (transaction);
+	g_assert (gck_transaction_get_failed (transaction) == TRUE);
+
+	/* Value should now have changed, back to default */
+	value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+	g_assert (value && n_value == prev.ulValueLen);
+	g_assert (memcmp (prev.pValue, value, n_value) == 0);
+}
+
+DEFINE_TEST(file_store_nonexistant)
+{
+	GckFileStore *fs;
+	gboolean ret;
+
+	/* Should be able to read from a nonexistant file store */
+	fs = gck_file_store_new ("./nonexistant");
+	ret = gck_file_store_refresh (fs);
+	g_assert (ret);
+		
+	g_object_unref (fs);
+}

Added: trunk/pkcs11/gck/tests/unit-test-memory-store.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/tests/unit-test-memory-store.c	Sat Jan  3 19:30:08 2009
@@ -0,0 +1,431 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-memory-store.c: Test memory store functionality
+
+   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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "run-auto-test.h"
+
+#include "gck/gck-object.h"
+#include "gck/gck-memory-store.h"
+#include "gck/gck-transaction.h"
+
+static GckStore *store = NULL;
+static GckObject *object = NULL;
+static GckTransaction *transaction = NULL;
+static guchar buffer[1024];
+
+static CK_RV
+test_validator (GckObject *obj, CK_ATTRIBUTE_PTR attr)
+{
+	const gchar *data;
+	guint i;
+	
+	g_assert (obj == object);
+	g_assert (attr);
+	g_assert (attr->type == CKA_LABEL);
+	
+	/* Test that the whole string is ascii and lower case */
+	data = attr->pValue; 
+	for (i = 0; i < attr->ulValueLen; ++i) {
+		if (!g_ascii_isprint(data[i]) || !g_ascii_islower (data[i]))
+			return CKR_ATTRIBUTE_VALUE_INVALID;
+	}
+	
+	return CKR_OK;
+}
+
+DEFINE_SETUP(memory_store)
+{
+	CK_ATTRIBUTE attr;
+	CK_ULONG twentyfour = 24;
+	
+	attr.type = CKA_LABEL;
+	attr.pValue = "label";
+	attr.ulValueLen = 5;
+
+	store = GCK_STORE (gck_memory_store_new ());
+	
+	gck_store_register_schema (store, &attr, test_validator, 0);
+	g_assert (gck_store_lookup_schema (store, CKA_LABEL, NULL));
+
+	attr.type = CKA_VALUE;
+	attr.pValue = NULL;
+	attr.ulValueLen = 0;
+	
+	gck_store_register_schema (store, &attr, NULL, GCK_STORE_IS_SENSITIVE);
+	
+	attr.type = CKA_BITS_PER_PIXEL;
+	attr.pValue = &twentyfour;
+	attr.ulValueLen = sizeof (twentyfour);
+	
+	gck_store_register_schema (store, &attr, NULL, GCK_STORE_IS_INTERNAL);
+	
+	object = g_object_new (GCK_TYPE_OBJECT, NULL);
+	
+	transaction = gck_transaction_new ();
+}
+
+DEFINE_TEARDOWN(memory_store)
+{
+	g_object_unref (store);
+	store = NULL;
+
+	g_object_unref (transaction);
+	transaction = NULL;
+
+	if (object != NULL)
+		g_object_unref (object);
+	object = NULL;
+}
+
+DEFINE_TEST(get_attribute_default)
+{
+	CK_ATTRIBUTE attr;
+	CK_RV rv;
+	
+	attr.type = CKA_LABEL;
+	attr.pValue = NULL;
+	rv = gck_store_get_attribute (store, object, &attr);
+	g_assert (rv == CKR_OK);
+	g_assert (attr.ulValueLen == 5);
+	attr.pValue = buffer;
+	rv = gck_store_get_attribute (store, object, &attr);
+	g_assert (rv == CKR_OK);
+	g_assert (attr.ulValueLen == 5);
+	g_assert (memcmp (attr.pValue, "label", 5) == 0);
+}
+
+DEFINE_TEST(read_value_default)
+{
+	gconstpointer value;
+	gsize n_value;
+	
+	value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+	g_assert (value);
+	g_assert (n_value == 5);
+	g_assert (memcmp (value, "label", 5) == 0);
+
+	value = gck_store_read_value (store, object, CKA_BITS_PER_PIXEL, &n_value);
+	g_assert (value);
+	g_assert (n_value == sizeof (CK_ULONG));
+	g_assert (*((CK_ULONG_PTR)value) == 24);
+}
+
+DEFINE_TEST(read_string)
+{
+	gchar *str;
+	
+	str = gck_store_read_string (store, object, CKA_LABEL);
+	g_assert_cmpstr (str, ==, "label");
+	g_free (str);
+}
+
+DEFINE_TEST(get_invalid)
+{
+	CK_ATTRIBUTE attr;
+	CK_RV rv;
+
+	attr.type = CKA_APPLICATION;
+	attr.pValue = NULL;
+	attr.ulValueLen = 0;
+	
+	rv = gck_store_get_attribute (store, object, &attr);
+	g_assert (rv == CKR_ATTRIBUTE_TYPE_INVALID);
+}
+
+DEFINE_TEST(get_sensitive)
+{
+	CK_ATTRIBUTE attr;
+	CK_RV rv;
+
+	attr.type = CKA_VALUE;
+	attr.pValue = NULL;
+	attr.ulValueLen = 0;
+	
+	rv = gck_store_get_attribute (store, object, &attr);
+	g_assert (rv == CKR_ATTRIBUTE_SENSITIVE);
+}
+
+DEFINE_TEST(get_internal)
+{
+	CK_ATTRIBUTE attr;
+	CK_RV rv;
+
+	attr.type = CKA_BITS_PER_PIXEL;
+	attr.pValue = NULL;
+	attr.ulValueLen = 0;
+	
+	rv = gck_store_get_attribute (store, object, &attr);
+	g_assert (rv == CKR_ATTRIBUTE_TYPE_INVALID);
+}
+
+DEFINE_TEST(set_invalid)
+{
+	CK_ATTRIBUTE attr;
+	
+	attr.type = CKA_APPLICATION;
+	attr.pValue = "me";
+	attr.ulValueLen = 2;
+	
+	gck_store_set_attribute (store, transaction, object, &attr);
+	g_assert (gck_transaction_get_result (transaction) == CKR_ATTRIBUTE_TYPE_INVALID);
+}
+
+DEFINE_TEST(set_internal)
+{
+	CK_ATTRIBUTE attr;
+	CK_ULONG five = 5;
+	
+	attr.type = CKA_BITS_PER_PIXEL;
+	attr.pValue = &five;
+	attr.ulValueLen = sizeof (five);
+	
+	gck_store_set_attribute (store, transaction, object, &attr);
+	g_assert (gck_transaction_get_result (transaction) == CKR_ATTRIBUTE_TYPE_INVALID);
+}
+
+DEFINE_TEST(set_get_attribute)
+{
+	CK_ATTRIBUTE attr;
+	CK_RV rv;
+	
+	attr.type = CKA_LABEL;
+	attr.pValue = "booyah";
+	attr.ulValueLen = 6;
+	
+	gck_store_set_attribute (store, transaction, object, &attr);
+	
+	gck_transaction_complete (transaction);
+	g_assert (gck_transaction_get_result (transaction) == CKR_OK);
+	
+	attr.pValue = buffer;
+	attr.ulValueLen = 1024;
+	rv = gck_store_get_attribute (store, object, &attr);
+	g_assert (rv == CKR_OK);
+	g_assert (attr.ulValueLen == 6);
+	g_assert (memcmp (attr.pValue, "booyah", 6) == 0);
+}
+
+DEFINE_TEST(write_read_value)
+{
+	CK_ATTRIBUTE attr;
+	CK_ULONG five = 5;
+	gconstpointer value;
+	gsize n_value;
+	
+	attr.type = CKA_BITS_PER_PIXEL;
+	attr.pValue = &five;
+	attr.ulValueLen = sizeof (five);
+	
+	gck_store_write_value (store, transaction, object, &attr);
+
+	gck_transaction_complete (transaction);
+	g_assert (gck_transaction_get_result (transaction) == CKR_OK);
+
+	value = gck_store_read_value (store, object, CKA_BITS_PER_PIXEL, &n_value);
+	g_assert (value);
+	g_assert (n_value == sizeof (five));
+	g_assert (memcmp (value, &five, sizeof (five)) == 0);
+}
+
+DEFINE_TEST(set_no_validate)
+{
+	CK_ATTRIBUTE attr;
+	
+	attr.type = CKA_LABEL;
+	attr.pValue = "CAPITALS";
+	attr.ulValueLen = 8;
+	
+	gck_store_set_attribute (store, transaction, object, &attr);
+	g_assert (gck_transaction_get_failed (transaction));
+	
+	gck_transaction_complete (transaction);
+	g_assert (gck_transaction_get_result (transaction) == CKR_ATTRIBUTE_VALUE_INVALID);
+}
+
+DEFINE_TEST(set_transaction_default)
+{
+	CK_ATTRIBUTE attr;
+	gconstpointer value;
+	gsize n_value;
+
+	
+	attr.type = CKA_LABEL;
+	attr.pValue = "another";
+	attr.ulValueLen = 7;
+
+	/* Change the attribute */
+	gck_store_set_attribute (store, transaction, object, &attr);
+	g_assert (gck_transaction_get_failed (transaction) == FALSE);
+
+	/* Should get new value */
+	value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+	g_assert (value && n_value == attr.ulValueLen);
+	g_assert (memcmp (attr.pValue, value, n_value) == 0);
+	
+	/* Fail for some arbitrary reason */
+	gck_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
+	
+	/* Value should not have changed yet */
+	value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+	g_assert (value && n_value == attr.ulValueLen);
+	g_assert (memcmp (attr.pValue, value, n_value) == 0);
+	
+	/* Now complete the transaction */
+	gck_transaction_complete (transaction);
+	g_assert (gck_transaction_get_failed (transaction) == TRUE);
+
+	/* Value should now have changed, back to default */
+	value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+	g_assert (value && n_value == 5);
+	g_assert (memcmp (value, "label", 5) == 0);
+}
+
+DEFINE_TEST(set_transaction_revert_first)
+{
+	CK_ATTRIBUTE attr, prev;
+	gconstpointer value;
+	gsize n_value;
+	
+	prev.type = CKA_LABEL;
+	prev.pValue = "numberone";
+	prev.ulValueLen = 9;
+
+	/* Change the attribute */
+	gck_store_set_attribute (store, transaction, object, &prev);
+	gck_transaction_complete (transaction);
+	g_assert (gck_transaction_get_failed (transaction) == FALSE);
+
+	/* Value should be new value */
+	value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+	g_assert (value && n_value == prev.ulValueLen);
+	g_assert (memcmp (prev.pValue, value, n_value) == 0);
+
+	/* A new transaction */
+	g_object_unref (transaction);
+	transaction = gck_transaction_new ();
+
+	attr.type = CKA_LABEL;
+	attr.pValue = "second";
+	attr.ulValueLen = 6;
+
+	gck_store_set_attribute (store, transaction, object, &attr);
+	g_assert (gck_transaction_get_failed (transaction) == FALSE);
+
+	/* Should get new value */
+	value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+	g_assert (value && n_value == attr.ulValueLen);
+	g_assert (memcmp (attr.pValue, value, n_value) == 0);
+
+	attr.type = CKA_LABEL;
+	attr.pValue = "third";
+	attr.ulValueLen = 5;
+
+	gck_store_set_attribute (store, transaction, object, &attr);
+	g_assert (gck_transaction_get_failed (transaction) == FALSE);
+
+	/* Should get new value */
+	value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+	g_assert (value && n_value == attr.ulValueLen);
+	g_assert (memcmp (attr.pValue, value, n_value) == 0);
+	
+	/* Fail for some arbitrary reason */
+	gck_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
+	
+	/* Value should not have changed yet */
+	value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+	g_assert (value && n_value == attr.ulValueLen);
+	g_assert (memcmp (attr.pValue, value, n_value) == 0);
+	
+	/* Now complete the transaction */
+	gck_transaction_complete (transaction);
+	g_assert (gck_transaction_get_failed (transaction) == TRUE);
+
+	/* Value should now have changed, back to default */
+	value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+	g_assert (value && n_value == prev.ulValueLen);
+	g_assert (memcmp (prev.pValue, value, n_value) == 0);
+}
+
+static void
+notify_attribute (GckObject *obj, CK_ATTRIBUTE_TYPE type, gpointer data)
+{
+	g_assert (obj == object);
+	g_assert (type == CKA_LABEL);
+	g_assert (data);
+	
+	*((CK_ATTRIBUTE_TYPE*)data) = type;
+}
+
+DEFINE_TEST(set_notifies)
+{
+	CK_ATTRIBUTE attr;
+	CK_ATTRIBUTE_TYPE type = 0;
+
+	attr.type = CKA_LABEL;
+	attr.pValue = "valid";
+	attr.ulValueLen = 5;
+
+	g_signal_connect (object, "notify-attribute", G_CALLBACK (notify_attribute), &type);
+
+	gck_store_set_attribute (store, transaction, object, &attr);
+
+	/* We should have been notified that the attribute changed at this point */
+	g_assert (type == CKA_LABEL);
+	
+	/* Reset for next notify */
+	type = 0;
+	
+	/* Fail for some arbitrary reason */
+	gck_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
+	
+	/* We should not have been notified yet */
+	g_assert (type == 0);
+	
+	/* Now complete the transaction */
+	gck_transaction_complete (transaction);
+	g_assert (gck_transaction_get_failed (transaction) == TRUE);
+
+	/* Now we should have been notified that this changed back */
+	g_assert (type == CKA_LABEL);
+}
+
+DEFINE_TEST(set_object_gone_first)
+{
+	CK_ATTRIBUTE attr;
+	
+	attr.type = CKA_LABEL;
+	attr.pValue = "valid";
+	attr.ulValueLen = 5;
+	
+	gck_store_set_attribute (store, transaction, object, &attr);
+	gck_transaction_complete (transaction);
+	g_assert (gck_transaction_get_result (transaction) == CKR_OK);
+	
+	/* This tests memory store internal tracking */
+	g_object_unref (object);
+	object = NULL;
+}

Added: trunk/pkcs11/gck/tests/unit-test-store.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/tests/unit-test-store.c	Sat Jan  3 19:30:08 2009
@@ -0,0 +1,79 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-store.c: Test general store functionality
+
+   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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "run-auto-test.h"
+
+#include "gck/gck-store.h"
+
+static GckStore *store = NULL;
+
+DEFINE_SETUP(store)
+{
+	store = g_object_new (GCK_TYPE_STORE, NULL);
+}
+
+DEFINE_TEARDOWN(store)
+{
+	g_object_unref (store);
+	store = NULL;
+}
+
+DEFINE_TEST(store_schema)
+{
+	CK_ATTRIBUTE attr;
+	
+	attr.type = CKA_LABEL;
+	attr.pValue = "Label";
+	attr.ulValueLen = 5;
+	
+	gck_store_register_schema (store, &attr, NULL, 0);
+	g_assert (gck_store_lookup_schema (store, CKA_LABEL, NULL));
+	
+	/* Not in the schema */
+	g_assert (!gck_store_lookup_schema (store, CKA_VALUE, NULL));
+}
+
+DEFINE_TEST(store_schema_flags)
+{
+	CK_ATTRIBUTE attr;
+	guint flags;
+	
+	attr.type = CKA_VALUE;
+	attr.pValue = NULL;
+	attr.ulValueLen = 0;
+	
+	gck_store_register_schema (store, &attr, NULL, GCK_STORE_IS_SENSITIVE);
+	g_assert (gck_store_lookup_schema (store, CKA_VALUE, &flags));
+	g_assert (flags == GCK_STORE_IS_SENSITIVE);
+}
+
+/* 
+ * That's all we can test in the base class of GckStore without a proper
+ * derived class. For more tests see unit-test-memory-store.c and 
+ * unit-test-file-store.c
+ */

Added: trunk/pkcs11/gck/tests/unit-test-transaction.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/tests/unit-test-transaction.c	Sat Jan  3 19:30:08 2009
@@ -0,0 +1,188 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-store.c: Test general store functionality
+
+   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 "run-auto-test.h"
+
+#include "gck/gck-transaction.h"
+
+DEFINE_TEST(transaction_empty)
+{
+	GckTransaction *transaction;
+	gboolean completed, failed;
+	CK_RV result;
+	
+	transaction = gck_transaction_new ();
+	g_assert (GCK_IS_TRANSACTION (transaction));
+	
+	g_assert (gck_transaction_get_failed (transaction) == FALSE);
+	g_assert (gck_transaction_get_completed (transaction) == FALSE);
+	g_assert (gck_transaction_get_result (transaction) == CKR_OK);
+	
+	gck_transaction_complete (transaction);
+	
+	/* Make sure values are actually set */
+	result = (CK_RV)-1;
+	completed = failed = FALSE;
+	
+	g_object_get (transaction, "completed", &completed, "failed", &failed, "result", &result, NULL);
+	g_assert (result == CKR_OK);
+	g_assert (completed == TRUE);
+	g_assert (failed == FALSE);
+	
+	g_object_unref (transaction);
+}
+
+DEFINE_TEST(transaction_fail)
+{
+	GckTransaction *transaction;
+	
+	transaction = gck_transaction_new ();
+
+	gck_transaction_fail (transaction, CKR_ARGUMENTS_BAD);
+	
+	g_assert (gck_transaction_get_failed (transaction) == TRUE);
+	g_assert (gck_transaction_get_completed (transaction) == FALSE);
+	g_assert (gck_transaction_get_result (transaction) == CKR_ARGUMENTS_BAD);
+	
+	gck_transaction_complete (transaction);
+
+	g_assert (gck_transaction_get_failed (transaction) == TRUE);
+	g_assert (gck_transaction_get_completed (transaction) == TRUE);
+	g_assert (gck_transaction_get_result (transaction) == CKR_ARGUMENTS_BAD);
+	
+	g_object_unref (transaction);
+}
+
+
+static gboolean
+completed_signal (GckTransaction *transaction, gpointer data)
+{
+	g_assert (GCK_IS_TRANSACTION (transaction));
+	g_assert (data);
+	
+	*((guint*)data) = TRUE;
+	return TRUE;
+}
+
+static gboolean
+completed_callback (GckTransaction *transaction, GObject *object, gpointer data)
+{
+	g_assert (GCK_IS_TRANSACTION (transaction));
+	g_assert (data);
+	
+	/* In this case we set the object to the transaction for fun */
+	g_assert (GCK_IS_TRANSACTION (transaction));
+	g_assert (transaction == GCK_TRANSACTION (object));
+	
+	*((guint*)data) = gck_transaction_get_failed (transaction);
+	return TRUE;
+}
+
+DEFINE_TEST(transaction_signals_success)
+{
+	GckTransaction *transaction = gck_transaction_new ();
+	
+	/* Initialize with some invalid values */
+	guint completed = 3;
+	guint failed = 3;
+
+	g_signal_connect (transaction, "complete", G_CALLBACK (completed_signal), &completed);
+	gck_transaction_add (transaction, transaction, completed_callback, &failed);
+	
+	/* No callbacks called yet */
+	g_assert (completed == 3);
+	g_assert (failed == 3);
+
+	gck_transaction_complete (transaction);
+
+	g_assert (completed == TRUE);
+	g_assert (failed == FALSE);
+	
+	g_object_unref (transaction);
+}
+
+DEFINE_TEST(transaction_signals_failure)
+{
+	GckTransaction *transaction = gck_transaction_new ();
+	
+	/* Initialize with some invalid values */
+	guint completed = 3;
+	guint failed = 3;
+
+	g_signal_connect (transaction, "complete", G_CALLBACK (completed_signal), &completed);
+	gck_transaction_add (transaction, transaction, completed_callback, &failed);
+
+	gck_transaction_fail (transaction, CKR_ARGUMENTS_BAD);
+	
+	/* No callbacks called yet */
+	g_assert (completed == 3);
+	g_assert (failed == 3);
+
+	gck_transaction_complete (transaction);
+
+	g_assert (completed == TRUE);
+	g_assert (failed == TRUE);
+	
+	g_object_unref (transaction);
+}
+
+static guint order_value = 3;
+
+static gboolean
+order_callback (GckTransaction *transaction, GObject *object, gpointer data)
+{
+	g_assert (GCK_IS_TRANSACTION (transaction));
+	g_assert (data);
+	g_assert (GPOINTER_TO_UINT (data) == order_value);
+	--order_value;
+	return TRUE;
+}
+
+DEFINE_TEST(transaction_order_is_reverse)
+{
+	GckTransaction *transaction = gck_transaction_new ();
+	
+	order_value = 3;
+	gck_transaction_add (transaction, transaction, order_callback, GUINT_TO_POINTER (1));
+	gck_transaction_add (transaction, transaction, order_callback, GUINT_TO_POINTER (2));
+	gck_transaction_add (transaction, transaction, order_callback, GUINT_TO_POINTER (3));
+
+	gck_transaction_complete (transaction);
+	g_object_unref (transaction);	
+}
+
+DEFINE_TEST(transaction_dispose_completes)
+{
+	GckTransaction *transaction = gck_transaction_new ();
+	
+	/* Initialize with some invalid values */
+	guint completed = 3;
+
+	g_signal_connect (transaction, "complete", G_CALLBACK (completed_signal), &completed);
+
+	g_object_run_dispose (G_OBJECT (transaction));
+	
+	g_assert (completed == TRUE);
+
+	g_object_unref (transaction);
+}

Modified: trunk/pkcs11/roots/gck-roots-certificate.c
==============================================================================
--- trunk/pkcs11/roots/gck-roots-certificate.c	(original)
+++ trunk/pkcs11/roots/gck-roots-certificate.c	Sat Jan  3 19:30:08 2009
@@ -61,7 +61,7 @@
 	
 	switch (attr->type) {
 	case CKA_TRUSTED:
-		return gck_util_set_bool (attr, TRUE);
+		return gck_attribute_set_bool (attr, TRUE);
 		
 	case CKA_CERTIFICATE_CATEGORY:
 		if (!gck_certificate_calc_category (GCK_CERTIFICATE (self), &category))
@@ -69,7 +69,7 @@
 		/* Unknown category, is CA by default in this slot */
 		if (category == 0) 
 			category = 2;
-		return gck_util_set_ulong (attr, category);
+		return gck_attribute_set_ulong (attr, category);
 	}
 	
 	return GCK_OBJECT_CLASS (gck_roots_certificate_parent_class)->get_attribute (base, attr);

Modified: trunk/pkcs11/ssh-keys/gck-ssh-private-key.c
==============================================================================
--- trunk/pkcs11/ssh-keys/gck-ssh-private-key.c	(original)
+++ trunk/pkcs11/ssh-keys/gck-ssh-private-key.c	Sat Jan  3 19:30:08 2009
@@ -24,6 +24,7 @@
 #include "gck-ssh-openssh.h"
 #include "gck-ssh-private-key.h"
 
+#include "gck/gck-attributes.h"
 #include "gck/gck-manager.h"
 #include "gck/gck-object.h"
 #include "gck/gck-sexp.h"
@@ -138,7 +139,7 @@
 	
 	switch (attr->type) {
 	case CKA_LABEL:
-		return gck_util_set_string (attr, self->label ? self->label : "");
+		return gck_attribute_set_string (attr, self->label ? self->label : "");
 	}
 	
 	return GCK_OBJECT_CLASS (gck_ssh_private_key_parent_class)->get_attribute (base, attr);

Modified: trunk/pkcs11/ssh-keys/gck-ssh-public-key.c
==============================================================================
--- trunk/pkcs11/ssh-keys/gck-ssh-public-key.c	(original)
+++ trunk/pkcs11/ssh-keys/gck-ssh-public-key.c	Sat Jan  3 19:30:08 2009
@@ -51,7 +51,7 @@
 	
 	switch (attr->type) {
 	case CKA_LABEL:
-		return gck_util_set_string (attr, self->label ? self->label : "");
+		return gck_attribute_set_string (attr, self->label ? self->label : "");
 	}
 	
 	return GCK_OBJECT_CLASS (gck_ssh_public_key_parent_class)->get_attribute (base, attr);

Modified: trunk/tests/gtest-helpers.c
==============================================================================
--- trunk/tests/gtest-helpers.c	(original)
+++ trunk/tests/gtest-helpers.c	Sat Jan  3 19:30:08 2009
@@ -36,6 +36,7 @@
 #include "common/gkr-secure-memory.h"
 
 static GStaticMutex memory_mutex = G_STATIC_MUTEX_INIT;
+static const gchar *test_path = NULL;
 
 void gkr_memory_lock (void) 
 { 
@@ -87,6 +88,12 @@
 	return mainloop;
 }
 
+gchar*
+test_build_filename (const gchar *basename)
+{
+	return g_build_filename (test_path, basename, NULL);
+}
+
 static void 
 chdir_base_dir (char* argv0)
 {
@@ -112,16 +119,16 @@
 main (int argc, char* argv[])
 {
 	GLogLevelFlags fatal_mask;
-	const gchar* envi;
 
 	g_thread_init (NULL);
 
-	envi = getenv ("GNOME_KEYRING_TEST_PATH");
-	if (envi) {
+	test_path = getenv ("GNOME_KEYRING_TEST_PATH");
+	if (test_path) {
 		setenv ("GNOME_KEYRING_OUTSIDE_TEST", "TRUE", 1);
 	} else {
-		setenv ("GNOME_KEYRING_TEST_PATH", "/tmp/test-gnome-keyring", 1);
-		g_mkdir_with_parents ("/tmp/test-gnome-keyring", 0777);
+		test_path = "/tmp/test-gnome-keyring";
+		setenv ("GNOME_KEYRING_TEST_PATH", test_path, 1);
+		g_mkdir_with_parents (test_path, 0777);
 	}
 
 	chdir_base_dir (argv[0]);

Modified: trunk/tests/gtest-helpers.h
==============================================================================
--- trunk/tests/gtest-helpers.h	(original)
+++ trunk/tests/gtest-helpers.h	Sat Jan  3 19:30:08 2009
@@ -24,12 +24,23 @@
 #ifndef GTEST_HELPERS_H_
 #define GTEST_HELPERS_H_
 
+#include "config.h"
+
 #include <glib.h>
+#include <glib-object.h>
+#include <glib/gstdio.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
 
 void test_mainloop_quit (void);
 void test_mainloop_run (int timeout);
 GMainLoop* test_mainloop_get (void);
 
+gchar* test_build_filename (const gchar *basename);
+
 #define DECLARE_SETUP(x) \
 	void setup_##x(int *v, gconstpointer d)
 #define DEFINE_SETUP(x) \



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]