[gnome-keyring] Implement collection storing lock on idle, and unlock timeout



commit dbfc7003c830761722eea7831db6ddcf6680eb50
Author: Stef Walter <stef memberwebs com>
Date:   Mon Feb 1 02:27:10 2010 +0000

    Implement collection storing lock on idle, and unlock timeout

 pkcs11/gck/gck-attributes.c                 |  114 ++++++++++++++++++++++++---
 pkcs11/gck/gck-attributes.h                 |   22 +++++-
 pkcs11/gck/tests/unit-test-attributes.c     |   49 ++++++++++++
 pkcs11/secret-store/gck-secret-binary.c     |   23 ++++--
 pkcs11/secret-store/gck-secret-collection.c |   69 ++++++++++++-----
 pkcs11/secret-store/gck-secret-collection.h |    5 +
 pkcs11/secret-store/gck-secret-textual.c    |   17 +++--
 7 files changed, 254 insertions(+), 45 deletions(-)
---
diff --git a/pkcs11/gck/gck-attributes.c b/pkcs11/gck/gck-attributes.c
index 62465cd..b2c7c53 100644
--- a/pkcs11/gck/gck-attributes.c
+++ b/pkcs11/gck/gck-attributes.c
@@ -162,6 +162,25 @@ gck_attribute_get_mpi (CK_ATTRIBUTE_PTR attr, gcry_mpi_t *value)
 	return CKR_OK;
 }
 
+CK_RV
+gck_attribute_get_template (CK_ATTRIBUTE_PTR attr, GArray **template)
+{
+	CK_ULONG n_attrs;
+
+	g_return_val_if_fail (attr, CKR_GENERAL_ERROR);
+	g_return_val_if_fail (attr, CKR_GENERAL_ERROR);
+
+	/* Validate everything first */
+	if (attr->ulValueLen % sizeof (CK_ATTRIBUTE) != 0)
+		return CKR_ATTRIBUTE_VALUE_INVALID;
+
+	n_attrs = attr->ulValueLen / sizeof (CK_ATTRIBUTE);
+	if (n_attrs != 0 && !attr->pValue)
+		return CKR_ATTRIBUTE_VALUE_INVALID;
+
+	*template = gck_template_new (attr->pValue, n_attrs);
+	return CKR_OK;
+}
 
 CK_RV
 gck_attribute_set_empty (CK_ATTRIBUTE_PTR attr)
@@ -288,10 +307,10 @@ gck_attribute_set_mpi (CK_ATTRIBUTE_PTR attr, gcry_mpi_t mpi)
 }
 
 CK_RV
-gck_attribute_set_template (CK_ATTRIBUTE_PTR attr, CK_ATTRIBUTE_PTR template,
-                            CK_ULONG n_template)
+gck_attribute_set_template (CK_ATTRIBUTE_PTR attr, GArray *template)
 {
 	CK_ATTRIBUTE_PTR array;
+	CK_ATTRIBUTE_PTR at;
 	CK_RV rv;
 	gulong len;
 	gulong i;
@@ -299,7 +318,7 @@ gck_attribute_set_template (CK_ATTRIBUTE_PTR attr, CK_ATTRIBUTE_PTR template,
 	g_assert (attr);
 	g_warn_if_fail ((attr->type & CKF_ARRAY_ATTRIBUTE) != 0);
 
-	len = sizeof (CK_ATTRIBUTE) * n_template;
+	len = sizeof (CK_ATTRIBUTE) * template->len;
 	if (!attr->pValue) {
 		attr->ulValueLen = len;
 		return CKR_OK;
@@ -313,20 +332,21 @@ gck_attribute_set_template (CK_ATTRIBUTE_PTR attr, CK_ATTRIBUTE_PTR template,
 	rv = CKR_OK;
 
 	/* Start working with individual elements */
-	for (i = 0; i < n_template; ++i) {
-		array[i].type = template[i].type;
+	for (i = 0; i < template->len; ++i) {
+		at = &g_array_index (template, CK_ATTRIBUTE, i);
+		array[i].type = at->type;
 		if (!array[i].pValue) {
-			array[i].ulValueLen = template[i].ulValueLen;
-		} else if (array[i].ulValueLen < template[i].ulValueLen) {
+			array[i].ulValueLen = at->ulValueLen;
+		} else if (array[i].ulValueLen < at->ulValueLen) {
 			array[i].ulValueLen = (CK_ULONG)-1;
 			rv = CKR_BUFFER_TOO_SMALL;
 		} else {
-			memcpy(array[i].pValue, template[i].pValue, template[i].ulValueLen);
-			array[i].ulValueLen = template[i].ulValueLen;
+			memcpy(array[i].pValue, at->pValue, at->ulValueLen);
+			array[i].ulValueLen = at->ulValueLen;
 		}
 	}
 
-	return CKR_OK;
+	return rv;
 }
 
 gboolean
@@ -519,3 +539,77 @@ gck_attributes_find_string (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs,
 
 	return gck_attribute_get_string (attr, value) == CKR_OK;
 }
+
+GArray*
+gck_template_new (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
+{
+	GArray *template = g_array_new (FALSE, FALSE, sizeof (CK_ATTRIBUTE));
+	CK_ATTRIBUTE_PTR pat;
+	gulong i;
+
+	g_return_val_if_fail (attrs || !n_attrs, NULL);
+
+	g_array_append_vals (template, attrs, n_attrs);
+	for (i = 0; i < n_attrs; ++i) {
+		pat = &g_array_index (template, CK_ATTRIBUTE, i);
+		if (pat->pValue)
+			pat->pValue = g_memdup (pat->pValue, pat->ulValueLen);
+	}
+
+	return template;
+}
+
+void
+gck_template_set (GArray *template, CK_ATTRIBUTE_PTR attr)
+{
+	CK_ATTRIBUTE_PTR pat;
+	CK_ATTRIBUTE at;
+	guint i;
+
+	g_return_if_fail (template);
+	g_return_if_fail (attr);
+
+	pat = gck_attributes_find ((CK_ATTRIBUTE_PTR)template->data, template->len, attr->type);
+
+	/* Remove any previous value */
+	for (i = 0; i < template->len; ++i) {
+		if (g_array_index (template, CK_ATTRIBUTE, i).type == attr->type) {
+			g_free (g_array_index (template, CK_ATTRIBUTE, i).pValue);
+			g_array_remove_index_fast (template, i);
+			break;
+		}
+	}
+
+	/* Add a new attribute */
+	memcpy (&at, attr, sizeof (at));
+	if (at.pValue)
+		at.pValue = g_memdup (at.pValue, at.ulValueLen);
+	g_array_append_vals (template, &at, 1);
+}
+
+void
+gck_template_free (GArray *template)
+{
+	guint i;
+
+	if (!template)
+		return;
+
+	for (i = 0; i < template->len; ++i)
+		g_free (g_array_index (template, CK_ATTRIBUTE, i).pValue);
+	g_array_free (template, TRUE);
+}
+
+gboolean
+gck_template_find_boolean (GArray *template, CK_ATTRIBUTE_TYPE type, gboolean *value)
+{
+	g_return_val_if_fail (template, FALSE);
+	return gck_attributes_find_boolean ((CK_ATTRIBUTE_PTR)template->data, template->len, type, value);
+}
+
+gboolean
+gck_template_find_ulong (GArray *template, CK_ATTRIBUTE_TYPE type, gulong *value)
+{
+	g_return_val_if_fail (template, FALSE);
+	return gck_attributes_find_ulong ((CK_ATTRIBUTE_PTR)template->data, template->len, type, value);
+}
diff --git a/pkcs11/gck/gck-attributes.h b/pkcs11/gck/gck-attributes.h
index 5e8bcb6..e392eab 100644
--- a/pkcs11/gck/gck-attributes.h
+++ b/pkcs11/gck/gck-attributes.h
@@ -43,6 +43,9 @@ CK_RV                 gck_attribute_get_string                         (CK_ATTRI
 CK_RV                 gck_attribute_get_mpi                            (CK_ATTRIBUTE_PTR attr,
                                                                         gcry_mpi_t *value);
 
+CK_RV                 gck_attribute_get_template                       (CK_ATTRIBUTE_PTR attr,
+                                                                        GArray **template);
+
 CK_RV                 gck_attribute_set_empty                          (CK_ATTRIBUTE_PTR attr);
 
 CK_RV                 gck_attribute_set_bool                           (CK_ATTRIBUTE_PTR attr,
@@ -68,8 +71,7 @@ CK_RV                 gck_attribute_set_mpi                            (CK_ATTRI
                                                                         gcry_mpi_t mpi);
 
 CK_RV                 gck_attribute_set_template                       (CK_ATTRIBUTE_PTR attr,
-                                                                        CK_ATTRIBUTE_PTR template,
-                                                                        CK_ULONG n_template);
+                                                                        GArray *template);
 
 guint                 gck_attribute_hash                               (gconstpointer v);
 
@@ -113,4 +115,20 @@ gboolean              gck_attributes_find_string                       (CK_ATTRI
                                                                         CK_ATTRIBUTE_TYPE type,
                                                                         gchar **value);
 
+GArray*               gck_template_new                                 (CK_ATTRIBUTE_PTR attrs,
+                                                                        CK_ULONG n_attrs);
+
+void                  gck_template_set                                 (GArray *template,
+                                                                        CK_ATTRIBUTE_PTR attr);
+
+void                  gck_template_free                                (GArray *template);
+
+gboolean              gck_template_find_boolean                        (GArray *template,
+                                                                        CK_ATTRIBUTE_TYPE type,
+                                                                        gboolean *value);
+
+gboolean              gck_template_find_ulong                          (GArray *template,
+                                                                        CK_ATTRIBUTE_TYPE type,
+                                                                        gulong *value);
+
 #endif /* GCK_ATTRIBUTE_H_ */
diff --git a/pkcs11/gck/tests/unit-test-attributes.c b/pkcs11/gck/tests/unit-test-attributes.c
index b1d4903..ed9cbb0 100644
--- a/pkcs11/gck/tests/unit-test-attributes.c
+++ b/pkcs11/gck/tests/unit-test-attributes.c
@@ -728,3 +728,52 @@ DEFINE_TEST(attributes_consume)
 
 	g_free (attrs);
 }
+
+DEFINE_TEST(template_new_free)
+{
+	GArray *template = gck_template_new (attr_template, G_N_ELEMENTS (attr_template));
+	g_assert (template);
+	gck_template_free (template);
+}
+
+DEFINE_TEST(template_find)
+{
+	GArray *template = gck_template_new (attr_template, G_N_ELEMENTS (attr_template));
+	gulong uvalue;
+	gboolean ret, bvalue;
+
+	ret = gck_template_find_ulong (template, CKA_CLASS, &uvalue);
+	g_assert (ret);
+	g_assert (uvalue == attr_template_klass);
+
+	ret = gck_template_find_boolean (template, CKA_TOKEN, &bvalue);
+	g_assert (ret);
+	g_assert (bvalue == attr_template_token);
+
+	/* An invalid attribute */
+	ret = gck_template_find_boolean (template, CKA_AC_ISSUER, &bvalue);
+	g_assert (!ret);
+
+	gck_template_free (template);
+}
+
+DEFINE_TEST(template_set_replace)
+{
+	GArray *template = gck_template_new (attr_template, G_N_ELEMENTS (attr_template));
+	CK_OBJECT_CLASS klass = CKO_HW_FEATURE;
+	CK_ATTRIBUTE attr = { CKA_CLASS, &klass, sizeof (klass) };
+	gulong uvalue;
+
+	if (!gck_template_find_ulong (template, CKA_CLASS, &uvalue))
+		g_assert_not_reached ();
+	g_assert (uvalue == attr_template_klass);
+
+	/* Replace a previous attribute */
+	gck_template_set (template, &attr);
+
+	if (!gck_template_find_ulong (template, CKA_CLASS, &uvalue))
+		g_assert_not_reached ();
+	g_assert (uvalue == CKO_HW_FEATURE);
+
+	gck_template_free (template);
+}
diff --git a/pkcs11/secret-store/gck-secret-binary.c b/pkcs11/secret-store/gck-secret-binary.c
index d8fa13f..99a0085 100644
--- a/pkcs11/secret-store/gck-secret-binary.c
+++ b/pkcs11/secret-store/gck-secret-binary.c
@@ -56,7 +56,10 @@
  * DECLARATIONS
  */
 
-#define LOCK_ON_IDLE_FLAG (1<<0)
+enum {
+	LOCK_ON_IDLE_FLAG = 1 << 0,
+	LOCK_AFTER_FLAG = 1 << 1
+};
 
 typedef struct {
 	/* unencrypted: */
@@ -568,7 +571,7 @@ gck_secret_binary_write (GckSecretCollection *collection, GckSecretData *sdata,
         gint hash_iterations;
         gint lock_timeout;
         guchar salt[8];
-	guint flags;
+	guint flags = 0;
 	int i;
 
 	g_return_val_if_fail (GCK_IS_SECRET_COLLECTION (collection), GCK_DATA_FAILURE);
@@ -594,10 +597,15 @@ gck_secret_binary_write (GckSecretCollection *collection, GckSecretData *sdata,
 	buffer_add_time (&buffer, gck_secret_object_get_modified (obj));
 	buffer_add_time (&buffer, gck_secret_object_get_created (obj));
 
-	flags = 0;
 	lock_timeout = gck_secret_collection_get_lock_idle (collection);
-	if (lock_timeout)
+	if (lock_timeout) {
 		flags |= LOCK_ON_IDLE_FLAG;
+	} else {
+		lock_timeout = gck_secret_collection_get_lock_after (collection);
+		if (lock_timeout)
+			flags |= LOCK_AFTER_FLAG;
+	}
+
 	egg_buffer_add_uint32 (&buffer, flags);
 
 	egg_buffer_add_uint32 (&buffer, lock_timeout);
@@ -939,9 +947,10 @@ gck_secret_binary_read (GckSecretCollection *collection, GckSecretData *sdata,
 	gck_secret_object_set_label (obj, display_name);
 	gck_secret_object_set_modified (obj, mtime);
 	gck_secret_object_set_created (obj, ctime);
-	if (!(flags & LOCK_ON_IDLE_FLAG))
-		lock_timeout = 0;
-	gck_secret_collection_set_lock_idle (collection, lock_timeout);
+	if (flags & LOCK_ON_IDLE_FLAG)
+		gck_secret_collection_set_lock_idle (collection, lock_timeout);
+	else if (flags & LOCK_AFTER_FLAG)
+		gck_secret_collection_set_lock_after (collection, lock_timeout);
 
 	/* Build a Hash table where we can track ids we haven't yet seen */
 	checks = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
diff --git a/pkcs11/secret-store/gck-secret-collection.c b/pkcs11/secret-store/gck-secret-collection.c
index 07a3089..1769ea9 100644
--- a/pkcs11/secret-store/gck-secret-collection.c
+++ b/pkcs11/secret-store/gck-secret-collection.c
@@ -48,11 +48,7 @@ struct _GckSecretCollection {
 	GHashTable *items;
 	gchar *filename;
 	guint32 watermark;
-
-	/* Template for credential */
-	CK_ATTRIBUTE tp_attrs[2];
-	CK_ULONG tp_idle;
-	CK_BBOOL tp_token;
+	GArray *template;
 };
 
 G_DEFINE_TYPE (GckSecretCollection, gck_secret_collection, GCK_TYPE_SECRET_OBJECT);
@@ -358,7 +354,7 @@ gck_secret_collection_get_attribute (GckObject *base, GckSession *session, CK_AT
 	case CKA_CLASS:
 		return gck_attribute_set_ulong (attr, CKO_G_COLLECTION);
 	case CKA_G_CREDENTIAL_TEMPLATE:
-		return gck_attribute_set_template (attr, self->tp_attrs, G_N_ELEMENTS (self->tp_attrs));
+		return gck_attribute_set_template (attr, self->template);
 	}
 	return GCK_OBJECT_CLASS (gck_secret_collection_parent_class)->get_attribute (base, session, attr);
 }
@@ -370,6 +366,7 @@ gck_secret_collection_set_attribute (GckObject *object, GckSession *session,
 	GckSecretCollection *self = GCK_SECRET_COLLECTION (object);
 	CK_OBJECT_HANDLE handle = 0;
 	GckCredential *cred;
+	GArray *template;
 	CK_RV rv;
 
 	switch (attr->type) {
@@ -386,6 +383,13 @@ gck_secret_collection_set_attribute (GckObject *object, GckSession *session,
 			return gck_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
 		change_master_password (self, transaction, cred);
 		return;
+	case CKA_G_CREDENTIAL_TEMPLATE:
+		rv = gck_attribute_get_template (attr, &template);
+		if (rv != CKR_OK)
+			return gck_transaction_fail (transaction, rv);
+		gck_template_free (self->template);
+		self->template = template;
+		return;
 	};
 
 	return GCK_OBJECT_CLASS (gck_secret_collection_parent_class)->set_attribute (object, session, transaction, attr);
@@ -470,17 +474,17 @@ gck_secret_collection_real_is_locked (GckSecretObject *obj, GckSession *session)
 static void
 gck_secret_collection_init (GckSecretCollection *self)
 {
-	self->items = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
-
-	self->tp_token = CK_FALSE;
-	self->tp_attrs[0].type = CKA_TOKEN;
-	self->tp_attrs[0].pValue = &self->tp_token;
-	self->tp_attrs[0].ulValueLen = sizeof (self->tp_token);
+	CK_ULONG idle = 0;
+	CK_ULONG after = 0;
+	CK_BBOOL token = CK_TRUE;
+	CK_ATTRIBUTE attrs[] = {
+		{ CKA_TOKEN, &token, sizeof (token) },
+		{ CKA_G_DESTRUCT_IDLE, &idle, sizeof (idle) },
+		{ CKA_G_DESTRUCT_AFTER, &after, sizeof (after) },
+	};
 
-	self->tp_idle = 0;
-	self->tp_attrs[1].type = CKA_G_DESTRUCT_IDLE;
-	self->tp_attrs[1].pValue = &self->tp_idle;
-	self->tp_attrs[1].ulValueLen = sizeof (self->tp_idle);
+	self->items = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+	self->template = gck_template_new (attrs, G_N_ELEMENTS (attrs));
 }
 
 static void
@@ -539,6 +543,9 @@ gck_secret_collection_finalize (GObject *obj)
 	g_free (self->filename);
 	self->filename = NULL;
 
+	gck_template_free (self->template);
+	self->template = NULL;
+
 	G_OBJECT_CLASS (gck_secret_collection_parent_class)->finalize (obj);
 }
 
@@ -864,15 +871,37 @@ gck_secret_collection_destroy (GckSecretCollection *self, GckTransaction *transa
 gint
 gck_secret_collection_get_lock_idle (GckSecretCollection *self)
 {
+	gulong value;
 	g_return_val_if_fail (GCK_IS_SECRET_COLLECTION (self), 0);
-	return (gint)self->tp_idle;
+	if (!gck_template_find_ulong (self->template, CKA_G_DESTRUCT_IDLE, &value))
+		value = 0;
+	return (gint)value;
 }
 
 void
 gck_secret_collection_set_lock_idle (GckSecretCollection *self, gint lock_timeout)
 {
+	CK_ULONG value = (lock_timeout < 0) ? 0 : lock_timeout;
+	CK_ATTRIBUTE attr = { CKA_G_DESTRUCT_IDLE, &value, sizeof (value) };
+	g_return_if_fail (GCK_IS_SECRET_COLLECTION (self));
+	gck_template_set (self->template, &attr);
+}
+
+gint
+gck_secret_collection_get_lock_after (GckSecretCollection *self)
+{
+	gulong value;
+	g_return_val_if_fail (GCK_IS_SECRET_COLLECTION (self), 0);
+	if (!gck_template_find_ulong (self->template, CKA_G_DESTRUCT_AFTER, &value))
+		value = 0;
+	return (gint)value;
+}
+
+void
+gck_secret_collection_set_lock_after (GckSecretCollection *self, gint lock_timeout)
+{
+	CK_ULONG value = (lock_timeout < 0) ? 0 : lock_timeout;
+	CK_ATTRIBUTE attr = { CKA_G_DESTRUCT_AFTER, &value, sizeof (value) };
 	g_return_if_fail (GCK_IS_SECRET_COLLECTION (self));
-	if (lock_timeout < 0)
-		lock_timeout = 0;
-	self->tp_idle = (CK_ULONG)lock_timeout;
+	gck_template_set (self->template, &attr);
 }
diff --git a/pkcs11/secret-store/gck-secret-collection.h b/pkcs11/secret-store/gck-secret-collection.h
index e0a8e57..690a2f2 100644
--- a/pkcs11/secret-store/gck-secret-collection.h
+++ b/pkcs11/secret-store/gck-secret-collection.h
@@ -96,4 +96,9 @@ gint                 gck_secret_collection_get_lock_idle   (GckSecretCollection
 void                 gck_secret_collection_set_lock_idle   (GckSecretCollection *self,
                                                             gint lock_timeout);
 
+gint                 gck_secret_collection_get_lock_after  (GckSecretCollection *self);
+
+void                 gck_secret_collection_set_lock_after  (GckSecretCollection *self,
+                                                            gint lock_timeout);
+
 #endif /* __GCK_SECRET_COLLECTION_H__ */
diff --git a/pkcs11/secret-store/gck-secret-textual.c b/pkcs11/secret-store/gck-secret-textual.c
index 6c4e7d1..2eaddd9 100644
--- a/pkcs11/secret-store/gck-secret-textual.c
+++ b/pkcs11/secret-store/gck-secret-textual.c
@@ -406,11 +406,14 @@ gck_secret_textual_write (GckSecretCollection *collection, GckSecretData *sdata,
 	key_file_set_uint64 (file, "keyring", "ctime", gck_secret_object_get_created (obj));
 	key_file_set_uint64 (file, "keyring", "mtime", gck_secret_object_get_modified (obj));
 
-	/* Not currently used :( */
 	idle_timeout = gck_secret_collection_get_lock_idle (collection);
 	g_key_file_set_boolean (file, "keyring", "lock-on-idle", idle_timeout > 0);
-	idle_timeout = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (collection), "lock-timeout"));
-	g_key_file_set_integer (file, "keyring", "lock-timeout", idle_timeout);
+	if (idle_timeout)
+		g_key_file_set_integer (file, "keyring", "lock-timeout", idle_timeout);
+	idle_timeout = gck_secret_collection_get_lock_after (collection);
+	g_key_file_set_boolean (file, "keyring", "lock-after", idle_timeout > 0);
+	if (idle_timeout)
+		g_key_file_set_integer (file, "keyring", "lock-timeout", idle_timeout);
 
 	items = gck_secret_collection_get_items (collection);
 	for (l = items; l; l = g_list_next (l)) 
@@ -457,7 +460,6 @@ gck_secret_textual_read (GckSecretCollection *collection, GckSecretData *sdata,
 	gchar *start = NULL;
 	const gchar *identifier;
 	GHashTable *checks = NULL;
-	gboolean lock_idle;
 	gint lock_timeout;
 	gchar *value;
 	guint64 num;
@@ -499,9 +501,12 @@ gck_secret_textual_read (GckSecretCollection *collection, GckSecretData *sdata,
 	gck_secret_object_set_modified (obj, num);
 	
 	/* Not currently used :( */
-	lock_idle = g_key_file_get_boolean (file, "keyring", "lock-on-idle", NULL);
-	g_object_set_data (G_OBJECT (collection), "lock-on-idle", GINT_TO_POINTER (lock_idle));
 	lock_timeout = g_key_file_get_integer (file, "keyring", "lock-timeout", NULL);
+	if (g_key_file_get_boolean (file, "keyring", "lock-after", NULL))
+		gck_secret_collection_set_lock_idle (collection, lock_timeout);
+	else if (g_key_file_get_boolean (file, "keyring", "lock-on-idle", NULL))
+		gck_secret_collection_set_lock_idle (collection, lock_timeout);
+
 	g_object_set_data (G_OBJECT (collection), "lock-timeout", GINT_TO_POINTER (lock_timeout));
 	
 	/* Build a Hash table where we can track ids we haven't yet seen */



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