[gcr] gck: Enumerator can now retrieve object attributes
- From: Stefan Walter <stefw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gcr] gck: Enumerator can now retrieve object attributes
- Date: Wed, 12 Oct 2011 10:29:56 +0000 (UTC)
commit 074c6666bb3bb5264d9a0833c136c44ee9492b5e
Author: Stef Walter <stefw collabora co uk>
Date: Wed Oct 12 11:18:05 2011 +0200
gck: Enumerator can now retrieve object attributes
* New interface called GckObjectAttributes. Callers derive from
GckObject, implement GckObjectAttributes and set fields in the
iface to denote which attributes are interested in.
* Caller passes type of derived object to gck_enumerator_set_object_type()
and then enumerator will retrieve attributes set in iface, and return
objects of that type
* GckObjectAttributes has attributes property.
.gitignore | 1 -
docs/reference/gck/Makefile.am | 2 +-
docs/reference/gck/gck-docs.sgml | 1 +
docs/reference/gck/gck-sections.txt | 24 ++-
docs/reference/gck/gck.interfaces | 1 +
docs/reference/gcr/gcr.interfaces | 39 ++++
gck/Makefile.am | 1 +
gck/gck-enumerator.c | 413 +++++++++++++++++++++++++++--------
gck/gck-object-attributes.c | 106 +++++++++
gck/gck-object.c | 35 ++--
gck/gck-private.h | 3 +
gck/gck.h | 41 ++++-
gck/gck.symbols | 5 +
gck/tests/Makefile.am | 2 +-
gck/tests/test-gck-enumerator.c | 137 ++++++++++++-
15 files changed, 694 insertions(+), 117 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index db54d73..c45aa9e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -54,7 +54,6 @@ stamp-*
/docs/reference/*/*-unused.txt
/docs/reference/*/*.args
/docs/reference/*/*.hierarchy
-/docs/reference/*/*.interfaces
/docs/reference/*/*.prerequisites
/docs/reference/*/*.signals
/docs/reference/*/html
diff --git a/docs/reference/gck/Makefile.am b/docs/reference/gck/Makefile.am
index 72ea16f..98cbc34 100644
--- a/docs/reference/gck/Makefile.am
+++ b/docs/reference/gck/Makefile.am
@@ -64,7 +64,7 @@ IGNORE_HFILES= \
pkcs11n.h \
pkcs11x.h \
pkcs11i.h \
- tests/mock-interaction.h
+ mock-interaction.h
# Images to copy into HTML directory.
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
diff --git a/docs/reference/gck/gck-docs.sgml b/docs/reference/gck/gck-docs.sgml
index f5668f3..e70290a 100644
--- a/docs/reference/gck/gck-docs.sgml
+++ b/docs/reference/gck/gck-docs.sgml
@@ -21,6 +21,7 @@
<xi:include href="xml/gck-object.xml"/>
<xi:include href="xml/gck-attribute.xml"/>
<xi:include href="xml/gck-attributes.xml"/>
+ <xi:include href="xml/gck-object-attributes.xml"/>
<xi:include href="xml/gck-enumerator.xml"/>
<xi:include href="xml/gck-modules.xml"/>
<xi:include href="xml/gck-error.xml"/>
diff --git a/docs/reference/gck/gck-sections.txt b/docs/reference/gck/gck-sections.txt
index a26f2c1..6482a6d 100644
--- a/docs/reference/gck/gck-sections.txt
+++ b/docs/reference/gck/gck-sections.txt
@@ -61,10 +61,10 @@ gck_attributes_unref
gck_attributes_contains
gck_attributes_dump
gck_attributes_new_full
+GCK_TYPE_ATTRIBUTES
GckAllocator
<SUBSECTION Standard>
gck_attributes_get_type
-GCK_TYPE_ATTRIBUTES
gck_attributes_get_boxed_type
</SECTION>
@@ -255,6 +255,7 @@ gck_session_info_get_type
<SECTION>
<FILE>gck-object</FILE>
GckObject
+GckObjectClass
gck_object_from_handle
gck_objects_from_handle_array
gck_object_equal
@@ -283,7 +284,6 @@ gck_object_set_template
gck_object_set_template_async
gck_object_set_template_finish
<SUBSECTION Standard>
-GckObjectClass
gck_object_get_type
GCK_IS_OBJECT
GCK_IS_OBJECT_CLASS
@@ -295,6 +295,20 @@ GckObjectPrivate
</SECTION>
<SECTION>
+<FILE>gck-object-attributes</FILE>
+GckObjectAttributes
+GckObjectAttributesIface
+gck_object_attributes_get_attributes
+gck_object_attributes_set_attributes
+<SUBSECTION Standard>
+gck_object_attributes_get_type
+GCK_IS_OBJECT_ATTRIBUTES
+GCK_OBJECT_ATTRIBUTES
+GCK_OBJECT_ATTRIBUTES_GET_INTERFACE
+GCK_TYPE_OBJECT_ATTRIBUTES
+</SECTION>
+
+<SECTION>
<FILE>gck-error</FILE>
GCK_VENDOR_CODE
GCK_ERROR
@@ -329,12 +343,14 @@ gck_uri_flags_get_type
<SECTION>
<FILE>gck-enumerator</FILE>
GckEnumerator
-gck_enumerator_get_interaction
-gck_enumerator_set_interaction
gck_enumerator_next
gck_enumerator_next_async
gck_enumerator_next_finish
gck_enumerator_next_n
+gck_enumerator_get_interaction
+gck_enumerator_set_interaction
+gck_enumerator_get_object_type
+gck_enumerator_set_object_type
<SUBSECTION Standard>
GckEnumeratorClass
gck_enumerator_get_type
diff --git a/docs/reference/gck/gck.interfaces b/docs/reference/gck/gck.interfaces
new file mode 100644
index 0000000..5fdaecc
--- /dev/null
+++ b/docs/reference/gck/gck.interfaces
@@ -0,0 +1 @@
+gck_object_attributes_get_type
diff --git a/docs/reference/gcr/gcr.interfaces b/docs/reference/gcr/gcr.interfaces
new file mode 100644
index 0000000..5af264f
--- /dev/null
+++ b/docs/reference/gcr/gcr.interfaces
@@ -0,0 +1,39 @@
+GcrCertificateRenderer GcrRenderer GcrComparableIface GcrCertificate
+GtkWidget AtkImplementorIface GtkBuildable
+GtkContainer AtkImplementorIface GtkBuildable
+GtkBin AtkImplementorIface GtkBuildable
+GtkAlignment AtkImplementorIface GtkBuildable
+GcrCertificateWidget AtkImplementorIface GtkBuildable
+GcrKeyWidget AtkImplementorIface GtkBuildable
+GcrUnlockOptionsWidget AtkImplementorIface GtkBuildable
+GtkComboBox AtkImplementorIface GtkBuildable GtkCellLayout GtkCellEditable
+GcrComboSelector AtkImplementorIface GtkBuildable GtkCellLayout GtkCellEditable
+GtkButton AtkImplementorIface GtkBuildable GtkActivatable
+GcrImportButton AtkImplementorIface GtkBuildable GtkActivatable
+GtkScrolledWindow AtkImplementorIface GtkBuildable
+GcrDisplayScrolled AtkImplementorIface GtkBuildable GcrViewer
+GcrViewerWidget AtkImplementorIface GtkBuildable GcrViewer
+GtkWindow AtkImplementorIface GtkBuildable
+GcrViewerWindow AtkImplementorIface GtkBuildable
+GtkTreeView AtkImplementorIface GtkBuildable GtkScrollable
+GcrListSelector AtkImplementorIface GtkBuildable GtkScrollable
+GcrTreeSelector AtkImplementorIface GtkBuildable GtkScrollable
+GtkCellArea GtkCellLayout GtkBuildable
+GtkTreeViewColumn GtkCellLayout GtkBuildable
+GcrCollectionModel GtkTreeModel GtkTreeSortable
+GcrKeyRenderer GcrRenderer
+GcrPkcs11Certificate GcrComparableIface GcrCertificate
+GcrSimpleCertificate GcrComparableIface GcrCertificate
+GcrSimpleCollection GcrCollection
+GcrUnionCollection GcrCollection
+GtkWidgetAccessible AtkComponent
+GtkContainerAccessible AtkComponent
+GtkComboBoxAccessible AtkComponent AtkAction AtkSelection
+GtkButtonAccessible AtkComponent AtkAction AtkImage
+GtkTreeViewAccessible AtkComponent AtkTable AtkSelection GtkCellAccessibleParent
+GtkScrolledWindowAccessible AtkComponent
+GtkWindowAccessible AtkComponent AtkWindow
+GtkAction GtkBuildable
+GdkPixbuf GIcon
+GApplication GActionGroup
+GtkApplication GActionGroup
diff --git a/gck/Makefile.am b/gck/Makefile.am
index c43f306..5856f0f 100644
--- a/gck/Makefile.am
+++ b/gck/Makefile.am
@@ -41,6 +41,7 @@ PUBLIC_FILES = \
gck-module.c \
gck-modules.c \
gck-object.c \
+ gck-object-attributes.c \
gck-password.c \
gck-session.c \
gck-slot.c \
diff --git a/gck/gck-enumerator.c b/gck/gck-enumerator.c
index c57297e..add0bee 100644
--- a/gck/gck-enumerator.c
+++ b/gck/gck-enumerator.c
@@ -45,7 +45,8 @@
enum {
PROP_0,
- PROP_INTERACTION
+ PROP_INTERACTION,
+ PROP_OBJECT_TYPE
};
/**
@@ -55,9 +56,16 @@ enum {
* An object that allows enumerating of objects across modules, tokens.
*/
+typedef struct _GckEnumeratorResult {
+ gulong handle;
+ GckSession *session;
+ GckAttributes *attrs;
+} GckEnumeratorResult;
+
typedef struct _GckEnumeratorState GckEnumeratorState;
-typedef gpointer (*GckEnumeratorFunc) (GckEnumeratorState *args, gboolean forward);
+typedef gpointer (*GckEnumeratorFunc) (GckEnumeratorState *args,
+ gboolean forward);
struct _GckEnumeratorState {
/* For the current call */
@@ -72,6 +80,11 @@ struct _GckEnumeratorState {
GckSessionOptions session_options;
GTlsInteraction *interaction;
+ /* The type of objects to create */
+ GType object_type;
+ gpointer object_class;
+ GckObjectAttributesIface *object_iface;
+
/* state_slots */
GList *slots;
@@ -84,30 +97,50 @@ struct _GckEnumeratorState {
GckSession *session;
/* state_results */
- GArray *objects;
-
- /* Output from enumerator */
- GList *results;
+ GQueue *results;
};
struct _GckEnumeratorPrivate {
GMutex *mutex;
GckEnumeratorState *the_state;
GTlsInteraction *interaction;
+ GType object_type;
+ GckObjectClass *object_class;
};
G_DEFINE_TYPE (GckEnumerator, gck_enumerator, G_TYPE_OBJECT);
-static gpointer state_modules (GckEnumeratorState *args, gboolean forward);
-static gpointer state_slots (GckEnumeratorState *args, gboolean forward);
-static gpointer state_slot (GckEnumeratorState *args, gboolean forward);
-static gpointer state_session (GckEnumeratorState *args, gboolean forward);
-static gpointer state_authenticated (GckEnumeratorState *args, gboolean forward);
-static gpointer state_results (GckEnumeratorState *args, gboolean forward);
+static gpointer state_modules (GckEnumeratorState *args,
+ gboolean forward);
-/* ----------------------------------------------------------------------------
- * INTERNAL
- */
+static gpointer state_slots (GckEnumeratorState *args,
+ gboolean forward);
+
+static gpointer state_slot (GckEnumeratorState *args,
+ gboolean forward);
+
+static gpointer state_session (GckEnumeratorState *args,
+ gboolean forward);
+
+static gpointer state_authenticated (GckEnumeratorState *args,
+ gboolean forward);
+
+static gpointer state_results (GckEnumeratorState *args,
+ gboolean forward);
+
+static gpointer state_attributes (GckEnumeratorState *args,
+ gboolean forward);
+
+
+static void
+_gck_enumerator_result_free (gpointer data)
+{
+ GckEnumeratorResult *result = data;
+ g_object_unref (result->session);
+ if (result->attrs)
+ gck_attributes_unref (result->attrs);
+ g_slice_free (GckEnumeratorResult, result);
+}
static gpointer
rewind_state (GckEnumeratorState *args, GckEnumeratorFunc handler)
@@ -144,19 +177,22 @@ cleanup_state (GckEnumeratorState *args)
g_assert (!args->session);
/* state_results */
- if (args->objects)
- g_array_free (args->objects, TRUE);
- args->objects = NULL;
-
- /* Other cleanup */
- gck_list_unref_free (args->results);
- args->results = NULL;
+ if (args->results) {
+ g_queue_foreach (args->results, (GFunc) _gck_enumerator_result_free, NULL);
+ g_queue_free (args->results);
+ args->results = NULL;
+ }
gck_list_unref_free (args->modules);
args->modules = NULL;
g_clear_object (&args->interaction);
+ if (args->object_class)
+ g_type_class_unref (args->object_class);
+ args->object_class = NULL;
+ args->object_type = 0;
+
if (args->match) {
if (args->match->attributes)
_gck_attributes_unlock (args->match->attributes);
@@ -368,7 +404,8 @@ state_authenticated (GckEnumeratorState *args, gboolean forward)
CK_OBJECT_HANDLE objects[128];
CK_SESSION_HANDLE session;
CK_ATTRIBUTE_PTR attrs;
- CK_ULONG n_attrs, count;
+ CK_ULONG n_attrs, i,count;
+ GckEnumeratorResult *result;
CK_RV rv;
/* Just go back, no logout */
@@ -377,9 +414,12 @@ state_authenticated (GckEnumeratorState *args, gboolean forward)
/* This is where we do the actual searching */
- g_assert (args->session);
- g_assert (args->want_objects);
- g_assert (args->funcs);
+ g_assert (args->session != NULL);
+ g_assert (args->want_objects > 0);
+ g_assert (args->funcs != NULL);
+
+ if (!args->results)
+ args->results = g_queue_new ();
if (args->match->attributes) {
attrs = _gck_attributes_commit_out (args->match->attributes, &n_attrs);
@@ -406,80 +446,133 @@ state_authenticated (GckEnumeratorState *args, gboolean forward)
if (rv != CKR_OK || count == 0)
break;
- if (!args->objects)
- args->objects = g_array_new (FALSE, TRUE, sizeof (CK_OBJECT_HANDLE));
_gck_debug ("matched %lu objects", count);
- g_array_append_vals (args->objects, objects, count);
+
+ for (i = 0; i < count; i++) {
+ result = g_slice_new0 (GckEnumeratorResult);
+ result->handle = objects[i];
+ result->session = g_object_ref (args->session);
+ g_queue_push_tail (args->results, result);
+ }
}
(args->funcs->C_FindObjectsFinal) (session);
}
_gck_debug ("finding objects completed with: %s", _gck_stringize_rv (rv));
- return state_results;
+ return state_attributes;
}
-static GckObject*
-extract_result (GckEnumeratorState *args)
+static gpointer
+state_attributes (GckEnumeratorState *args,
+ gboolean forward)
{
- CK_OBJECT_HANDLE handle;
+ GckEnumeratorResult *result;
+ GckAttributes *attrs;
+ CK_ATTRIBUTE_PTR template;
+ CK_ULONG n_template;
+ CK_SESSION_HANDLE session;
+ gint count;
+ GList *l;
+ gint i;
+ CK_RV rv;
- if (!args->objects || !args->objects->len)
- return NULL;
+ g_assert (args->funcs != NULL);
+ g_assert (args->object_class != NULL);
+ g_assert (args->results != NULL);
- g_assert (args->session);
+ /* No cleanup, just unwind */
+ if (!forward)
+ return state_authenticated;
+
+ /* If no request for attributes, just go forward */
+ if (args->object_iface == NULL ||
+ args->object_iface->n_attribute_types == 0)
+ return state_results;
- handle = g_array_index (args->objects, CK_OBJECT_HANDLE, 0);
- g_array_remove_index_fast (args->objects, 0);
+ session = gck_session_get_handle (args->session);
+ g_return_val_if_fail (session, NULL);
+
+ count = 0;
+
+ /* Get the attributes for want_objects */
+ for (count = 0, l = args->results->head;
+ l != NULL && count < args->want_objects;
+ l = g_list_next (l), count++) {
+ result = l->data;
+
+ attrs = gck_attributes_new ();
+ for (i = 0; i < args->object_iface->n_attribute_types; ++i)
+ gck_attributes_add_empty (attrs, args->object_iface->attribute_types[i]);
+ _gck_attributes_lock (attrs);
+
+ /* Ask for attribute sizes */
+ template = _gck_attributes_prepare_in (attrs, &n_template);
+
+ rv = (args->funcs->C_GetAttributeValue) (session, result->handle, template, n_template);
+ if (GCK_IS_GET_ATTRIBUTE_RV_OK (rv)) {
+
+ /* Allocate memory for each value */
+ template = _gck_attributes_commit_in (attrs, &n_template);
+
+ /* Now get the actual values */
+ rv = (args->funcs->C_GetAttributeValue) (session, result->handle, template, n_template);
+ }
+
+ _gck_attributes_unlock (attrs);
+
+ if (GCK_IS_GET_ATTRIBUTE_RV_OK (rv)) {
+ if (_gck_debugging) {
+ gchar *string = _gck_attributes_format (attrs);
+ _gck_debug ("retrieved attributes for object %lu: %s",
+ result->handle, string);
+ g_free (string);
+ }
+ result->attrs = attrs;
+ rv = CKR_OK;
+
+ } else {
+ g_message ("couldn't retrieve attributes when enumerating: %s",
+ gck_message_from_rv (rv));
+ gck_attributes_unref (attrs);
+ }
+ }
- return gck_object_from_handle (args->session, handle);
+ return state_results;
}
static gpointer
-state_results (GckEnumeratorState *args, gboolean forward)
+state_results (GckEnumeratorState *args,
+ gboolean forward)
{
- GckObject *object;
- guint have;
-
- g_assert (args->session);
+ g_assert (args->results != NULL);
/* No cleanup, just unwind */
if (!forward)
return state_authenticated;
- /* Create result objects from what we have */
- have = g_list_length (args->results);
-
- while (have < args->want_objects) {
-
- object = extract_result (args);
- if (!object) {
- _gck_debug ("wanted %d objects, have %d, looking for more",
- args->want_objects, have);
- return rewind_state (args, state_slots);
- }
-
- args->results = g_list_append (args->results, object);
- ++have;
+ while (args->want_objects > g_queue_get_length (args->results)) {
+ _gck_debug ("wanted %d objects, have %d, looking for more",
+ args->want_objects, g_queue_get_length (args->results));
+ return rewind_state (args, state_slots);
}
_gck_debug ("wanted %d objects, returned %d objects",
- args->want_objects, have);
+ args->want_objects, g_queue_get_length (args->results));
/* We got all the results we wanted */
return NULL;
}
-/* ----------------------------------------------------------------------------
- * OBJECT
- */
-
static void
gck_enumerator_init (GckEnumerator *self)
{
self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCK_TYPE_ENUMERATOR, GckEnumeratorPrivate);
self->pv->mutex = g_mutex_new ();
self->pv->the_state = g_new0 (GckEnumeratorState, 1);
+ self->pv->object_type = GCK_TYPE_OBJECT;
+ self->pv->object_class = g_type_class_ref (self->pv->object_type);
+ g_assert (self->pv->object_class);
}
static void
@@ -494,6 +587,9 @@ gck_enumerator_get_property (GObject *obj,
case PROP_INTERACTION:
g_value_take_object (value, gck_enumerator_get_interaction (self));
break;
+ case PROP_OBJECT_TYPE:
+ g_value_set_gtype (value, gck_enumerator_get_object_type (self));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
break;
@@ -512,6 +608,9 @@ gck_enumerator_set_property (GObject *obj,
case PROP_INTERACTION:
gck_enumerator_set_interaction (self, g_value_get_object (value));
break;
+ case PROP_OBJECT_TYPE:
+ gck_enumerator_set_object_type (self, g_value_get_gtype (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
break;
@@ -540,6 +639,7 @@ gck_enumerator_finalize (GObject *obj)
g_free (self->pv->the_state);
g_mutex_free (self->pv->mutex);
+ g_type_class_unref (self->pv->object_class);
G_OBJECT_CLASS (gck_enumerator_parent_class)->finalize (obj);
}
@@ -566,6 +666,16 @@ gck_enumerator_class_init (GckEnumeratorClass *klass)
g_object_class_install_property (gobject_class, PROP_INTERACTION,
g_param_spec_object ("interaction", "Interaction", "Interaction asking for pins",
G_TYPE_TLS_INTERACTION, G_PARAM_READWRITE));
+
+ /**
+ * GckEnumerator:object-type:
+ *
+ * The type of objects that are created by the enumerator. Must be
+ * GckObject or derived from it.
+ */
+ g_object_class_install_property (gobject_class, PROP_OBJECT_TYPE,
+ g_param_spec_gtype ("object-type", "Object Type", "Type of objects created",
+ GCK_TYPE_OBJECT, G_PARAM_READWRITE));
}
/* ----------------------------------------------------------------------------
@@ -648,6 +758,69 @@ free_enumerate_next (EnumerateNext *args)
}
/**
+ * gck_enumerator_get_object_type:
+ * @self: an enumerator
+ *
+ * Get the type of objects created by this enumerator. The type will always
+ * either be #GckObject or derived from it.
+ *
+ * Returns: (transfer none): the type of objects created
+ */
+GType
+gck_enumerator_get_object_type (GckEnumerator *self)
+{
+ GType result;
+
+ g_return_val_if_fail (GCK_IS_ENUMERATOR (self), 0);
+
+ g_mutex_lock (self->pv->mutex);
+
+ result = self->pv->object_type;
+
+ g_mutex_unlock (self->pv->mutex);
+
+ return result;
+}
+
+/**
+ * gck_enumerator_set_object_type:
+ * @self: an enumerator
+ * @object_type: the type of objects to create
+ *
+ * Set the type of objects to be created by this enumerator. The type must
+ * always be either #GckObject or derived from it.
+ *
+ * If the #GckObjectClass:attribute_types and #GckObjectClass:n_attribute_types
+ * are set in a derived class, then the derived class must have a property
+ * called 'attributes' of boxed type GCK_TYPE_ATTRIBUTE.
+ */
+void
+gck_enumerator_set_object_type (GckEnumerator *self,
+ GType object_type)
+{
+ gpointer klass;
+
+ g_return_if_fail (GCK_IS_ENUMERATOR (self));
+
+ if (!g_type_is_a (object_type, GCK_TYPE_OBJECT)) {
+ g_warning ("the object_type '%s' is not a derived type of GckObject",
+ g_type_name (object_type));
+ return;
+ }
+
+ klass = g_type_class_ref (object_type);
+
+ g_mutex_lock (self->pv->mutex);
+
+ if (self->pv->object_type)
+ g_type_class_unref (self->pv->object_class);
+ self->pv->object_type = object_type;
+ self->pv->object_class = klass;
+
+ g_mutex_unlock (self->pv->mutex);
+}
+
+/**
* gck_enumerator_get_interaction:
* @self: the enumerator
*
@@ -717,6 +890,17 @@ check_out_enumerator_state (GckEnumerator *self)
g_clear_object (&state->interaction);
if (self->pv->interaction)
state->interaction = g_object_ref (self->pv->interaction);
+
+ if (state->object_class)
+ g_type_class_unref (state->object_class);
+
+ /* Must already be holding a reference, state also holds a ref */
+ state->object_type = self->pv->object_type;
+ state->object_class = g_type_class_peek (state->object_type);
+ g_assert (state->object_class == self->pv->object_class);
+ state->object_iface = g_type_interface_peek (state->object_class,
+ GCK_TYPE_OBJECT_ATTRIBUTES);
+ g_type_class_ref (state->object_type);
}
g_mutex_unlock (self->pv->mutex);
@@ -739,6 +923,57 @@ check_in_enumerator_state (GckEnumerator *self,
g_mutex_unlock (self->pv->mutex);
}
+static GckObject *
+extract_result (GckEnumeratorState *state)
+{
+ GckEnumeratorResult *result;
+ GckModule *module;
+ GckObject *object;
+
+ g_assert (state != NULL);
+
+ if (state->results == NULL)
+ return NULL;
+
+ result = g_queue_pop_head (state->results);
+ if (result == NULL)
+ return NULL;
+
+ module = gck_session_get_module (result->session);
+ object = g_object_new (state->object_type,
+ "module", module,
+ "handle", result->handle,
+ "session", result->session,
+ result->attrs ? "attributes" : NULL, result->attrs,
+ NULL);
+ g_object_unref (module);
+
+ _gck_enumerator_result_free (result);
+ return object;
+}
+
+static GList *
+extract_results (GckEnumeratorState *state,
+ gint *want_objects)
+{
+ GList *objects = NULL;
+ GckObject *object;
+ gint i;
+
+ g_assert (state != NULL);
+ g_assert (want_objects != NULL);
+
+ for (i = 0; i < *want_objects; i++) {
+ object = extract_result (state);
+ if (object == NULL)
+ break;
+ objects = g_list_prepend (objects, object);
+ }
+
+ *want_objects -= i;
+ return g_list_reverse (objects);
+}
+
/**
* gck_enumerator_next:
* @self: The enumerator
@@ -753,8 +988,10 @@ check_in_enumerator_state (GckEnumerator *self,
* Returns: (transfer full) (allow-none): The next object, which must be released
* using g_object_unref, or %NULL.
*/
-GckObject*
-gck_enumerator_next (GckEnumerator *self, GCancellable *cancellable, GError **error)
+GckObject *
+gck_enumerator_next (GckEnumerator *self,
+ GCancellable *cancellable,
+ GError **error)
{
EnumerateNext args = { GCK_ARGUMENTS_INIT, NULL, };
GckObject *result = NULL;
@@ -767,18 +1004,12 @@ gck_enumerator_next (GckEnumerator *self, GCancellable *cancellable, GError **er
/* A result from a previous run? */
result = extract_result (args.state);
- if (!result) {
+ if (result == NULL) {
args.state->want_objects = 1;
/* Run the operation and steal away the results */
- if (_gck_call_sync (NULL, perform_enumerate_next, NULL, &args, cancellable, error)) {
- if (args.state->results) {
- g_assert (g_list_length (args.state->results) == 1);
- result = g_object_ref (args.state->results->data);
- gck_list_unref_free (args.state->results);
- args.state->results = NULL;
- }
- }
+ if (_gck_call_sync (NULL, perform_enumerate_next, NULL, &args, cancellable, error))
+ result = extract_result (args.state);
args.state->want_objects = 0;
}
@@ -806,12 +1037,15 @@ gck_enumerator_next (GckEnumerator *self, GCancellable *cancellable, GError **er
* Returns: (transfer full) (element-type Gck.Object): A list of objects, which
* should be freed using gck_list_unref_free().
*/
-GList*
-gck_enumerator_next_n (GckEnumerator *self, gint max_objects, GCancellable *cancellable,
+GList *
+gck_enumerator_next_n (GckEnumerator *self,
+ gint max_objects,
+ GCancellable *cancellable,
GError **error)
{
EnumerateNext args = { GCK_ARGUMENTS_INIT, NULL, };
GList *results = NULL;
+ gint want_objects;
g_return_val_if_fail (GCK_IS_ENUMERATOR (self), NULL);
g_return_val_if_fail (max_objects == -1 || max_objects > 0, NULL);
@@ -821,15 +1055,22 @@ gck_enumerator_next_n (GckEnumerator *self, gint max_objects, GCancellable *canc
args.state = check_out_enumerator_state (self);
g_return_val_if_fail (args.state != NULL, NULL);
- args.state->want_objects = max_objects <= 0 ? G_MAXINT : max_objects;
+ want_objects = max_objects <= 0 ? G_MAXINT : max_objects;
+
+ /* A result from a previous run? */
+ results = extract_results (args.state, &want_objects);
+ if (want_objects > 0) {
+ args.state->want_objects = want_objects;
+
+ /* Run the operation and steal away the results */
+ if (_gck_call_sync (NULL, perform_enumerate_next, NULL, &args, cancellable, error))
+ results = g_list_concat (results, extract_results (args.state, &want_objects));
- /* Run the operation and steal away the results */
- if (_gck_call_sync (NULL, perform_enumerate_next, NULL, &args, cancellable, error)) {
- results = args.state->results;
- args.state->results = NULL;
+ args.state->want_objects = 0;
}
- args.state->want_objects = 0;
+ if (results)
+ g_clear_error (error);
/* Put the state back */
check_in_enumerator_state (self, args.state);
@@ -895,18 +1136,18 @@ gck_enumerator_next_finish (GckEnumerator *self, GAsyncResult *result, GError **
EnumerateNext *args;
GckEnumeratorState *state;
GList *results = NULL;
+ gint want_objects;
g_object_ref (self);
args = _gck_call_arguments (result, EnumerateNext);
state = args->state;
args->state = NULL;
+ want_objects = state->want_objects;
state->want_objects = 0;
- if (_gck_call_basic_finish (result, error)) {
- results = state->results;
- state->results = NULL;
- }
+ if (_gck_call_basic_finish (result, error))
+ results = extract_results (state, &want_objects);
/* Put the state back */
check_in_enumerator_state (self, state);
diff --git a/gck/gck-object-attributes.c b/gck/gck-object-attributes.c
new file mode 100644
index 0000000..fad6055
--- /dev/null
+++ b/gck/gck-object-attributes.c
@@ -0,0 +1,106 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gck-object-attributes.c - the GObject PKCS#11 wrapper library
+
+ Copyright (C) 2011 Collabora Ltd.
+
+ 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 <stefw collabora co uk>
+*/
+
+#include "config.h"
+
+#include "gck.h"
+#include "gck-private.h"
+
+#include <string.h>
+
+/**
+ * SECTION:gck-object-attributes
+ * @title: GckObjectAttributes
+ * @short_description: An interface which holds attributes for a PKCS\#11 object
+ *
+ * #GckObjectAttributes is an interface implemented by derived classes of
+ * #GckObject to indicate which attributes they'd like an enumerator to retrieve.
+ * These attributes are then cached on the object and can be retrieved through
+ * the #GckObjectAttributes:attributes property.
+ */
+
+/**
+ * GckObjectAttributesIface:
+ * @interface: parent interface
+ * @attribute_types: (array length=n_attribute_types): attribute types that an
+ * enumerator should retrieve
+ * @n_attribute_types: number of attribute types to be retrieved
+ *
+ * Interface for #GckObjectAttributes. If the @attribute_types field is set by
+ * a implementing class, then the a #GckEnumerator which has been setup using
+ * gck_enumerator_set_object_type()
+ */
+
+typedef GckObjectAttributesIface GckObjectAttributesInterface;
+G_DEFINE_INTERFACE (GckObjectAttributes, gck_object_attributes, GCK_TYPE_OBJECT);
+
+static void
+gck_object_attributes_default_init (GckObjectAttributesIface *iface)
+{
+ static volatile gsize initialized = 0;
+ if (g_once_init_enter (&initialized)) {
+
+ /**
+ * GckObjectAttributes:attributes:
+ *
+ * The attributes cached on this object.
+ */
+ g_object_interface_install_property (iface,
+ g_param_spec_boxed ("attributes", "Attributes", "PKCS#11 Attributes",
+ GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_once_init_leave (&initialized, 1);
+ }
+}
+
+/**
+ * gck_object_attributes_get_attributes:
+ * @object: an object with attributes
+ *
+ * Gets the attributes cached on this object.
+ *
+ * Returns: (transfer full) (allow-none): the attributes
+ */
+GckAttributes *
+gck_object_attributes_get_attributes (GckObjectAttributes *object)
+{
+ GckAttributes *attributes = NULL;
+ g_return_val_if_fail (GCK_IS_OBJECT_ATTRIBUTES (object), NULL);
+ g_object_get (object, "attributes", &attributes, NULL);
+ return attributes;
+}
+
+/**
+ * gck_object_attributes_set_attributes:
+ * @object: an object with attributes
+ * @attributes: (allow-none): the attributes to cache
+ *
+ * Sets the attributes cached on this object.
+ */
+void
+gck_object_attributes_set_attributes (GckObjectAttributes *object,
+ GckAttributes *attributes)
+{
+ g_return_if_fail (GCK_IS_OBJECT_ATTRIBUTES (object));
+ g_object_set (object, "attributes", attributes, NULL);
+}
diff --git a/gck/gck-object.c b/gck/gck-object.c
index 7798db2..c7b1eb0 100644
--- a/gck/gck-object.c
+++ b/gck/gck-object.c
@@ -44,6 +44,19 @@
* Represents a PKCS11 object handle such as a key or certifiacte.
*/
+/**
+ * GckObjectClass:
+ * @parent: derived from this
+ *
+ * The class for a #GckObject.
+ *
+ * If the @attribute_types field is set by a derived class, then the a
+ * #GckEnumerator which has been setup using gck_enumerator_set_object_type()
+ * with this derived type will retrieve these attributes when enumerating. In
+ * this case the class must implement an 'attributes' property of boxed type
+ * GCK_TYPE_ATTRIBUTES.
+ */
+
/*
* MT safe -- Nothing in GckObjectData changes between
* init and finalize. All GckObjectPrivate access between init
@@ -588,24 +601,6 @@ typedef struct _GetAttributes {
GckAttributes *attrs;
} GetAttributes;
-/*
- * Certain failure return values only apply to individual attributes
- * being retrieved. These are ignored, since the attribute should
- * already have -1 set as the length.
- */
-static gboolean
-is_ok_get_attributes_rv (CK_RV rv)
-{
- switch (rv) {
- case CKR_OK:
- case CKR_ATTRIBUTE_SENSITIVE:
- case CKR_ATTRIBUTE_TYPE_INVALID:
- return TRUE;
- default:
- return FALSE;
- }
-}
-
static CK_RV
perform_get_attributes (GetAttributes *args)
{
@@ -622,7 +617,7 @@ perform_get_attributes (GetAttributes *args)
/* Get the size of each value */
rv = (args->base.pkcs11->C_GetAttributeValue) (args->base.handle, args->object,
attrs, n_attrs);
- if (!is_ok_get_attributes_rv (rv))
+ if (!GCK_IS_GET_ATTRIBUTE_RV_OK (rv))
return rv;
/* Allocate memory for each value */
@@ -632,7 +627,7 @@ perform_get_attributes (GetAttributes *args)
rv = (args->base.pkcs11->C_GetAttributeValue) (args->base.handle, args->object,
attrs, n_attrs);
- if (is_ok_get_attributes_rv (rv))
+ if (GCK_IS_GET_ATTRIBUTE_RV_OK (rv))
rv = CKR_OK;
return rv;
diff --git a/gck/gck-private.h b/gck/gck-private.h
index c2919cf..4caf079 100644
--- a/gck/gck-private.h
+++ b/gck/gck-private.h
@@ -32,6 +32,9 @@
G_BEGIN_DECLS
+#define GCK_IS_GET_ATTRIBUTE_RV_OK(rv) \
+ ((rv) == CKR_OK || (rv) == CKR_ATTRIBUTE_SENSITIVE || (rv) == CKR_ATTRIBUTE_TYPE_INVALID)
+
/* ---------------------------------------------------------------------------
* ATTRIBUTE INTERNALS
*/
diff --git a/gck/gck.h b/gck/gck.h
index c62e1de..4b02220 100644
--- a/gck/gck.h
+++ b/gck/gck.h
@@ -287,6 +287,7 @@ typedef struct _GckSlot GckSlot;
typedef struct _GckModule GckModule;
typedef struct _GckSession GckSession;
typedef struct _GckObject GckObject;
+typedef struct _GckObjectAttributes GckObjectAttributes;
typedef struct _GckEnumerator GckEnumerator;
typedef struct _GckUriData GckUriData;
@@ -455,7 +456,12 @@ GTlsInteraction * gck_enumerator_get_interaction (GckEnumerator *se
void gck_enumerator_set_interaction (GckEnumerator *self,
GTlsInteraction *interaction);
-GckObject* gck_enumerator_next (GckEnumerator *self,
+GType gck_enumerator_get_object_type (GckEnumerator *self);
+
+void gck_enumerator_set_object_type (GckEnumerator *self,
+ GType object_type);
+
+GckObject * gck_enumerator_next (GckEnumerator *self,
GCancellable *cancellable,
GError **error);
@@ -1090,7 +1096,7 @@ GckObject* gck_session_derive_key_finish (GckSession *self,
#define GCK_TYPE_OBJECT (gck_object_get_type())
#define GCK_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GCK_TYPE_OBJECT, GckObject))
-#define GCK_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GCK_TYPE_OBJECT, GckObject))
+#define GCK_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GCK_TYPE_OBJECT, GckObjectClass))
#define GCK_IS_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GCK_TYPE_OBJECT))
#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))
@@ -1108,6 +1114,8 @@ struct _GckObject {
struct _GckObjectClass {
GObjectClass parent;
+
+ /*< private >*/
gpointer reserved[8];
};
@@ -1239,6 +1247,35 @@ GckAttributes* gck_object_get_template_finish (GckObject *self,
GError **error);
/* ------------------------------------------------------------------------
+ * OBJECT ATTRIBUTES
+ */
+
+#define GCK_TYPE_OBJECT_ATTRIBUTES (gck_object_attributes_get_type ())
+#define GCK_OBJECT_ATTRIBUTES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_OBJECT_ATTRIBUTES, GckObjectAttributes))
+#define GCK_IS_OBJECT_ATTRIBUTES(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCK_TYPE_OBJECT_ATTRIBUTES))
+#define GCK_OBJECT_ATTRIBUTES_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GCK_TYPE_OBJECT_ATTRIBUTES, GckObjectAttributesIface))
+
+typedef struct _GckObjectAttributes GckObjectAttributes;
+typedef struct _GckObjectAttributesIface GckObjectAttributesIface;
+
+struct _GckObjectAttributesIface {
+ GTypeInterface interface;
+
+ const gulong *attribute_types;
+ gint n_attribute_types;
+
+ /*< private >*/
+ gpointer reserved[6];
+};
+
+GType gck_object_attributes_get_type (void) G_GNUC_CONST;
+
+GckAttributes * gck_object_attributes_get_attributes (GckObjectAttributes *object);
+
+void gck_object_attributes_set_attributes (GckObjectAttributes *object,
+ GckAttributes *attributes);
+
+/* ------------------------------------------------------------------------
* PASSWORD
*/
diff --git a/gck/gck.symbols b/gck/gck.symbols
index 818ce22..3b573c4 100644
--- a/gck/gck.symbols
+++ b/gck/gck.symbols
@@ -58,12 +58,14 @@ gck_attributes_set_string
gck_attributes_set_ulong
gck_attributes_unref
gck_enumerator_get_interaction
+gck_enumerator_get_object_type
gck_enumerator_get_type
gck_enumerator_next
gck_enumerator_next_async
gck_enumerator_next_finish
gck_enumerator_next_n
gck_enumerator_set_interaction
+gck_enumerator_set_object_type
gck_error_get_quark
gck_error_get_type
gck_get_error_quark
@@ -100,6 +102,9 @@ gck_modules_object_for_uri
gck_modules_objects_for_uri
gck_modules_token_for_uri
gck_modules_tokens_for_uri
+gck_object_attributes_get_attributes
+gck_object_attributes_get_type
+gck_object_attributes_set_attributes
gck_object_destroy
gck_object_destroy_async
gck_object_destroy_finish
diff --git a/gck/tests/Makefile.am b/gck/tests/Makefile.am
index 734e9d8..abddc6a 100644
--- a/gck/tests/Makefile.am
+++ b/gck/tests/Makefile.am
@@ -3,7 +3,7 @@ INCLUDES = \
-I$(top_builddir) \
-I$(top_srcdir) \
-DSRCDIR="\"@abs_srcdir \"" \
- -DBUILDDIR="\"$(builddir)\"" \
+ -DBUILDDIR="\"@abs_builddir \"" \
-DGCK_API_SUBJECT_TO_CHANGE \
$(GLIB_CFLAGS)
diff --git a/gck/tests/test-gck-enumerator.c b/gck/tests/test-gck-enumerator.c
index d5d669e..a70bfa4 100644
--- a/gck/tests/test-gck-enumerator.c
+++ b/gck/tests/test-gck-enumerator.c
@@ -71,11 +71,16 @@ static void
test_create (Test *test, gconstpointer unused)
{
GckUriData *uri_data;
+ GType object_type;
GckEnumerator *en;
uri_data = gck_uri_data_new ();
en = _gck_enumerator_new (test->modules, 0, uri_data);
g_assert (GCK_IS_ENUMERATOR (en));
+
+ g_object_get (en, "object-type", &object_type, NULL);
+ g_assert (object_type == GCK_TYPE_OBJECT);
+
g_object_unref (en);
}
@@ -221,7 +226,7 @@ test_next_async (Test *test, gconstpointer unused)
}
static void
-test_attributes (Test *test, gconstpointer unused)
+test_attribute_match (Test *test, gconstpointer unused)
{
GckUriData *uri_data;
GError *error = NULL;
@@ -335,6 +340,133 @@ test_token_match (Test *test, gconstpointer unused)
g_object_unref (en);
}
+enum {
+ PROP_0,
+ PROP_ATTRIBUTES,
+};
+
+static const gulong mock_attribute_types[] = {
+ CKA_CLASS,
+ CKA_ID,
+ CKA_LABEL,
+};
+
+typedef struct {
+ GckObject parent;
+ GckAttributes *attrs;
+} MockObject;
+
+typedef struct {
+ GckObjectClass parent;
+} MockObjectClass;
+
+GType mock_object_get_type (void) G_GNUC_CONST;
+static void mock_object_attributes_init (GckObjectAttributesIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (MockObject, mock_object, GCK_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GCK_TYPE_OBJECT_ATTRIBUTES,
+ mock_object_attributes_init)
+);
+
+static void
+mock_object_init (MockObject *self)
+{
+
+}
+
+static void
+mock_object_get_property (GObject *obj,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ MockObject *self = (MockObject *)obj;
+
+ switch (prop_id) {
+ case PROP_ATTRIBUTES:
+ g_value_set_boxed (value, self->attrs);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+mock_object_set_property (GObject *obj,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MockObject *self = (MockObject *)obj;
+
+ switch (prop_id) {
+ case PROP_ATTRIBUTES:
+ g_assert (self->attrs == NULL);
+ self->attrs = g_value_dup_boxed (value);
+ g_assert (self->attrs != NULL);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+mock_object_finalize (GObject *obj)
+{
+ MockObject *self = (MockObject *)obj;
+ gck_attributes_unref (self->attrs);
+ G_OBJECT_CLASS (mock_object_parent_class)->finalize (obj);
+}
+
+static void
+mock_object_class_init (MockObjectClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->get_property = mock_object_get_property;
+ gobject_class->set_property = mock_object_set_property;
+ gobject_class->finalize = mock_object_finalize;
+
+ g_object_class_override_property (gobject_class, PROP_ATTRIBUTES, "attributes");
+}
+
+static void
+mock_object_attributes_init (GckObjectAttributesIface *iface)
+{
+ iface->attribute_types = mock_attribute_types;
+ iface->n_attribute_types = G_N_ELEMENTS (mock_attribute_types);
+}
+
+static void
+test_attribute_get (Test *test,
+ gconstpointer unused)
+{
+ GckUriData *uri_data;
+ GError *error = NULL;
+ GckEnumerator *en;
+ GList *objects, *l;
+ MockObject *mock;
+
+ uri_data = gck_uri_data_new ();
+ en = _gck_enumerator_new (test->modules, 0, uri_data);
+ g_object_set (en, "object-type", mock_object_get_type (), NULL);
+
+ objects = gck_enumerator_next_n (en, -1, NULL, &error);
+ g_assert_no_error (error);
+ g_assert_cmpint (g_list_length (objects), ==, 5);
+
+ for (l = objects; l != NULL; l = g_list_next (l)) {
+ mock = l->data;
+ g_assert (G_TYPE_CHECK_INSTANCE_TYPE (mock, mock_object_get_type ()));
+ g_assert (mock->attrs != NULL);
+ }
+
+ gck_list_unref_free (objects);
+ g_object_unref (en);
+}
+
int
main (int argc, char **argv)
{
@@ -352,8 +484,9 @@ main (int argc, char **argv)
g_test_add ("/gck/enumerator/next_async", Test, NULL, setup, test_next_async, teardown);
g_test_add ("/gck/enumerator/authenticate-interaction", Test, NULL, setup, test_authenticate_interaction, teardown);
g_test_add ("/gck/enumerator/authenticate-compat", Test, NULL, setup, test_authenticate_compat, teardown);
- g_test_add ("/gck/enumerator/attributes", Test, NULL, setup, test_attributes, teardown);
+ g_test_add ("/gck/enumerator/attribute_match", Test, NULL, setup, test_attribute_match, teardown);
g_test_add ("/gck/enumerator/token_match", Test, NULL, setup, test_token_match, teardown);
+ g_test_add ("/gck/enumerator/attribute_get", Test, NULL, setup, test_attribute_get, teardown);
return egg_tests_run_in_thread_with_loop ();
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]