summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/reference/gck/gck-sections.txt23
-rw-r--r--gck/Makefile.am2
-rw-r--r--gck/gck-enumerator.c311
-rw-r--r--gck/gck-interaction.c176
-rw-r--r--gck/gck-misc.c15
-rw-r--r--gck/gck-module.c82
-rw-r--r--gck/gck-modules.c12
-rw-r--r--gck/gck-password.c255
-rw-r--r--gck/gck-private.h48
-rw-r--r--gck/gck-session.c643
-rw-r--r--gck/gck-slot.c184
-rw-r--r--gck/gck.h56
-rw-r--r--gck/gck.symbols9
-rw-r--r--gck/tests/Makefile.am4
-rw-r--r--gck/tests/mock-interaction.c97
-rw-r--r--gck/tests/mock-interaction.h43
-rw-r--r--gck/tests/test-gck-crypto.c2
-rw-r--r--gck/tests/test-gck-enumerator.c76
-rw-r--r--gck/tests/test-gck-session.c2
19 files changed, 1543 insertions, 497 deletions
diff --git a/docs/reference/gck/gck-sections.txt b/docs/reference/gck/gck-sections.txt
index 14a7d30..0c9ea15 100644
--- a/docs/reference/gck/gck-sections.txt
+++ b/docs/reference/gck/gck-sections.txt
@@ -124,6 +124,8 @@ gck_slot_hash
gck_slot_get_module
gck_slot_get_handle
gck_slot_get_info
+gck_slot_get_interaction
+gck_slot_set_interaction
gck_slot_match
gck_slot_get_token_info
gck_slot_get_mechanisms
@@ -172,6 +174,7 @@ gck_session_get_module
gck_session_get_slot
gck_session_get_handle
gck_session_get_info
+gck_session_get_interaction
gck_session_login
gck_session_login_async
gck_session_login_finish
@@ -319,6 +322,8 @@ 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
@@ -336,6 +341,24 @@ GCK_TYPE_ENUMERATOR
</SECTION>
<SECTION>
+<FILE>gck-password</FILE>
+GckPassword
+GckPasswordClass
+gck_password_get_key
+gck_password_get_module
+gck_password_get_token
+<SUBSECTION Private>
+gck_password_get_type
+GckPasswordPrivate
+GCK_IS_PASSWORD
+GCK_IS_PASSWORD_CLASS
+GCK_PASSWORD
+GCK_PASSWORD_CLASS
+GCK_PASSWORD_GET_CLASS
+GCK_TYPE_PASSWORD
+</SECTION>
+
+<SECTION>
<FILE>gck-misc</FILE>
GckError
gck_list_ref_copy
diff --git a/gck/Makefile.am b/gck/Makefile.am
index a6d9a97..6a2a6c3 100644
--- a/gck/Makefile.am
+++ b/gck/Makefile.am
@@ -39,6 +39,7 @@ PUBLIC_FILES = \
gck-module.c \
gck-modules.c \
gck-object.c \
+ gck-password.c \
gck-session.c \
gck-slot.c \
gck-uri.c
@@ -47,6 +48,7 @@ INTERNAL_FILES = \
gck-call.c \
gck-debug.c gck-debug.h \
gck-deprecated.h \
+ gck-interaction.c \
gck-private.h \
pkcs11.h
diff --git a/gck/gck-enumerator.c b/gck/gck-enumerator.c
index dfb5bf4..c57297e 100644
--- a/gck/gck-enumerator.c
+++ b/gck/gck-enumerator.c
@@ -43,6 +43,11 @@
* gck_enumerator_next_async() functions.
*/
+enum {
+ PROP_0,
+ PROP_INTERACTION
+};
+
/**
* GckEnumerator:
* @parent: derived from this.
@@ -57,7 +62,6 @@ typedef gpointer (*GckEnumeratorFunc) (GckEnumeratorState *args, gboolean forwar
struct _GckEnumeratorState {
/* For the current call */
gint want_objects;
- gboolean want_password;
/* The state we're currently in */
GckEnumeratorFunc handler;
@@ -65,9 +69,8 @@ struct _GckEnumeratorState {
/* Input to enumerator */
GList *modules;
GckUriData *match;
- guint session_options;
- gboolean authenticate;
- gchar *password;
+ GckSessionOptions session_options;
+ GTlsInteraction *interaction;
/* state_slots */
GList *slots;
@@ -88,9 +91,9 @@ struct _GckEnumeratorState {
};
struct _GckEnumeratorPrivate {
- /* Data here is set atomically */
- gpointer state;
- gint mode;
+ GMutex *mutex;
+ GckEnumeratorState *the_state;
+ GTlsInteraction *interaction;
};
G_DEFINE_TYPE (GckEnumerator, gck_enumerator, G_TYPE_OBJECT);
@@ -152,11 +155,7 @@ cleanup_state (GckEnumeratorState *args)
gck_list_unref_free (args->modules);
args->modules = NULL;
- /* TODO: Can we use secure memory here? */
- if (args->password) {
- g_free (args->password);
- args->password = NULL;
- }
+ g_clear_object (&args->interaction);
if (args->match) {
if (args->match->attributes)
@@ -321,65 +320,38 @@ state_slot (GckEnumeratorState *args, gboolean forward)
static gpointer
state_session (GckEnumeratorState *args, gboolean forward)
{
- GckSessionInfo *sinfo;
- CK_ULONG n_pin;
+ GTlsInteraction *interaction;
CK_RV rv;
g_assert (args->funcs);
g_assert (args->session);
- g_assert (!args->want_password);
g_assert (args->token_info);
/* session to authenticated state */
if (forward) {
/* Don't want to authenticate? */
- if (!args->authenticate) {
+ if ((args->session_options & GCK_SESSION_LOGIN_USER) == 0) {
_gck_debug ("no authentication necessary, skipping");
return state_authenticated;
}
- /* No login necessary */
- if ((args->token_info->flags & CKF_LOGIN_REQUIRED) == 0) {
- _gck_debug ("no login required, skipping");
- return state_authenticated;
- }
+ /* Compatibility, hook into GckModule signals if no interaction set */
+ if (args->interaction)
+ interaction = g_object_ref (args->interaction);
+ else
+ interaction = _gck_interaction_new (args->slot);
- /* Next check if session is logged in */
- sinfo = gck_session_get_info (args->session);
- if (sinfo == NULL) {
- g_message ("couldn't get session info when enumerating");
- return rewind_state (args, state_slots);
- }
+ rv = _gck_session_authenticate_token (args->funcs,
+ gck_session_get_handle (args->session),
+ args->slot, interaction, NULL);
- /* Already logged in? */
- if (sinfo->state == CKS_RW_USER_FUNCTIONS ||
- sinfo->state == CKS_RO_USER_FUNCTIONS ||
- sinfo->state == CKS_RW_SO_FUNCTIONS) {
- gck_session_info_free (sinfo);
- _gck_debug ("already logged in, skipping");
- return state_authenticated;
- }
-
- gck_session_info_free (sinfo);
- _gck_debug ("trying to log into session");
-
- /* Try to log in */
- n_pin = args->password ? strlen (args->password) : 0;
- rv = (args->funcs->C_Login) (gck_session_get_handle (args->session), CKU_USER,
- (CK_BYTE_PTR)args->password, n_pin);
-
- /* Authentication failed, ask for a password */
- if (rv == CKR_PIN_INCORRECT) {
- _gck_debug ("login was incorrect, want password");
- args->want_password = TRUE;
- return NULL;
+ g_object_unref (interaction);
- /* Any other failure continue without authentication */
- } else if (rv != CKR_OK) {
+ if (rv != CKR_OK)
g_message ("couldn't authenticate when enumerating: %s", gck_message_from_rv (rv));
- }
+ /* We try to proceed anyway with the enumeration */
return state_authenticated;
/* Session to slot state */
@@ -406,7 +378,6 @@ state_authenticated (GckEnumeratorState *args, gboolean forward)
/* This is where we do the actual searching */
g_assert (args->session);
- g_assert (!args->want_password);
g_assert (args->want_objects);
g_assert (args->funcs);
@@ -506,38 +477,95 @@ state_results (GckEnumeratorState *args, gboolean forward)
static void
gck_enumerator_init (GckEnumerator *self)
{
- GckEnumeratorState *args;
-
self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCK_TYPE_ENUMERATOR, GckEnumeratorPrivate);
- args = g_new0 (GckEnumeratorState, 1);
- g_atomic_pointer_set (&self->pv->state, args);
+ self->pv->mutex = g_mutex_new ();
+ self->pv->the_state = g_new0 (GckEnumeratorState, 1);
+}
+
+static void
+gck_enumerator_get_property (GObject *obj,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GckEnumerator *self = GCK_ENUMERATOR (obj);
+
+ switch (prop_id) {
+ case PROP_INTERACTION:
+ g_value_take_object (value, gck_enumerator_get_interaction (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gck_enumerator_set_property (GObject *obj,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GckEnumerator *self = GCK_ENUMERATOR (obj);
+
+ switch (prop_id) {
+ case PROP_INTERACTION:
+ gck_enumerator_set_interaction (self, g_value_get_object (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gck_enumerator_dispose (GObject *obj)
+{
+ GckEnumerator *self = GCK_ENUMERATOR (obj);
+
+ gck_enumerator_set_interaction (self, NULL);
+
+ G_OBJECT_CLASS (gck_enumerator_parent_class)->dispose (obj);
}
static void
gck_enumerator_finalize (GObject *obj)
{
GckEnumerator *self = GCK_ENUMERATOR (obj);
- GckEnumeratorState *state = g_atomic_pointer_get (&self->pv->state);
- if (!g_atomic_pointer_compare_and_exchange (&self->pv->state, state, NULL))
- g_assert_not_reached ();
+ g_assert (self->pv->interaction == NULL);
+
+ g_assert (self->pv->the_state != NULL);
+ cleanup_state (self->pv->the_state);
+ g_free (self->pv->the_state);
- g_assert (state);
- cleanup_state (state);
- g_free (state);
+ g_mutex_free (self->pv->mutex);
G_OBJECT_CLASS (gck_enumerator_parent_class)->finalize (obj);
}
-
static void
gck_enumerator_class_init (GckEnumeratorClass *klass)
{
GObjectClass *gobject_class = (GObjectClass*)klass;
- gck_enumerator_parent_class = g_type_class_peek_parent (klass);
+ gobject_class->get_property = gck_enumerator_get_property;
+ gobject_class->set_property = gck_enumerator_set_property;
+ gobject_class->dispose = gck_enumerator_dispose;
gobject_class->finalize = gck_enumerator_finalize;
+
g_type_class_add_private (klass, sizeof (GckEnumeratorPrivate));
+
+ /**
+ * GckEnumerator:interaction:
+ *
+ * Interaction object used to ask the user for pins when opening
+ * sessions. Used if the session_options of the enumerator have
+ * %GCK_SESSION_LOGIN_USER
+ */
+ 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));
}
/* ----------------------------------------------------------------------------
@@ -545,14 +573,15 @@ gck_enumerator_class_init (GckEnumeratorClass *klass)
*/
GckEnumerator*
-_gck_enumerator_new (GList *modules_or_slots, guint session_options,
+_gck_enumerator_new (GList *modules_or_slots,
+ GckSessionOptions session_options,
GckUriData *uri_data)
{
GckEnumerator *self;
GckEnumeratorState *state;
self = g_object_new (GCK_TYPE_ENUMERATOR, NULL);
- state = g_atomic_pointer_get (&self->pv->state);
+ state = self->pv->the_state;
state->session_options = session_options;
@@ -596,7 +625,6 @@ perform_enumerate_next (EnumerateNext *args)
g_assert (args->state);
state = args->state;
- g_assert (!state->want_password);
g_assert (state->handler);
for (;;) {
@@ -610,43 +638,105 @@ perform_enumerate_next (EnumerateNext *args)
return CKR_OK;
}
-static gboolean
-complete_enumerate_next (EnumerateNext *args, CK_RV result)
+static void
+free_enumerate_next (EnumerateNext *args)
{
- GckEnumeratorState *state;
- GckModule *module;
- gboolean ret = TRUE;
+ /* Should have been assigned back to enumerator */
+ g_assert (!args->state);
- g_assert (args->state);
- state = args->state;
+ g_free (args);
+}
- if (state->want_password) {
- g_assert (state->slot);
+/**
+ * gck_enumerator_get_interaction:
+ * @self: the enumerator
+ *
+ * Get the interaction used when a pin is needed
+ *
+ * Returns: (transfer full) (allow-none): the interaction or %NULL
+ */
+GTlsInteraction *
+gck_enumerator_get_interaction (GckEnumerator *self)
+{
+ GTlsInteraction *result = NULL;
- _gck_debug ("wants password, emitting authenticate-slot");
+ g_return_val_if_fail (GCK_IS_ENUMERATOR (self), NULL);
- /* TODO: Should we be using secure memory here? */
- g_free (state->password);
- state->password = NULL;
+ g_mutex_lock (self->pv->mutex);
- module = gck_slot_get_module (state->slot);
- ret = _gck_module_fire_authenticate_slot (module, state->slot, NULL, &state->password);
- g_object_unref (module);
+ if (self->pv->interaction)
+ result = g_object_ref (self->pv->interaction);
- /* If authenticate returns TRUE then call is not complete */
- ret = !ret;
- }
+ g_mutex_unlock (self->pv->mutex);
- return ret;
+ return result;
+}
+
+/**
+ * gck_enumerator_set_interaction:
+ * @self: the enumerator
+ * @interaction: (allow-none): the interaction or %NULL
+ *
+ * Set the interaction used when a pin is needed
+ */
+void
+gck_enumerator_set_interaction (GckEnumerator *self,
+ GTlsInteraction *interaction)
+{
+ GTlsInteraction *previous = NULL;
+
+ g_return_if_fail (GCK_IS_ENUMERATOR (self));
+ g_return_if_fail (interaction == NULL || G_IS_TLS_INTERACTION (interaction));
+
+ g_mutex_lock (self->pv->mutex);
+
+ if (interaction != self->pv->interaction) {
+ previous = self->pv->interaction;
+ self->pv->interaction = interaction;
+ if (interaction)
+ g_object_ref (interaction);
+ }
+
+ g_mutex_unlock (self->pv->mutex);
+
+ g_clear_object (&previous);
+ g_object_notify (G_OBJECT (self), "interaction");
+}
+
+static GckEnumeratorState *
+check_out_enumerator_state (GckEnumerator *self)
+{
+ GckEnumeratorState *state = NULL;
+
+ g_mutex_lock (self->pv->mutex);
+
+ if (self->pv->the_state) {
+ state = self->pv->the_state;
+ self->pv->the_state = NULL;
+
+ g_clear_object (&state->interaction);
+ if (self->pv->interaction)
+ state->interaction = g_object_ref (self->pv->interaction);
+ }
+
+ g_mutex_unlock (self->pv->mutex);
+
+ if (state == NULL)
+ g_warning ("this enumerator is already running a next operation");
+
+ return state;
}
static void
-free_enumerate_next (EnumerateNext *args)
+check_in_enumerator_state (GckEnumerator *self,
+ GckEnumeratorState *state)
{
- /* Should have been assigned back to enumerator */
- g_assert (!args->state);
+ g_mutex_lock (self->pv->mutex);
- g_free (args);
+ g_assert (self->pv->the_state == NULL);
+ self->pv->the_state = state;
+
+ g_mutex_unlock (self->pv->mutex);
}
/**
@@ -672,12 +762,8 @@ gck_enumerator_next (GckEnumerator *self, GCancellable *cancellable, GError **er
g_return_val_if_fail (GCK_IS_ENUMERATOR (self), NULL);
g_return_val_if_fail (!error || !*error, NULL);
- /* Remove the state and own it ourselves */
- args.state = g_atomic_pointer_get (&self->pv->state);
- if (!args.state || !g_atomic_pointer_compare_and_exchange (&self->pv->state, args.state, NULL)) {
- g_warning ("this enumerator is already running a next operation");
- return NULL;
- }
+ args.state = check_out_enumerator_state (self);
+ g_return_val_if_fail (args.state != NULL, NULL);
/* A result from a previous run? */
result = extract_result (args.state);
@@ -685,7 +771,7 @@ gck_enumerator_next (GckEnumerator *self, GCancellable *cancellable, GError **er
args.state->want_objects = 1;
/* Run the operation and steal away the results */
- if (_gck_call_sync (NULL, perform_enumerate_next, complete_enumerate_next, &args, cancellable, error)) {
+ 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);
@@ -698,8 +784,7 @@ gck_enumerator_next (GckEnumerator *self, GCancellable *cancellable, GError **er
}
/* Put the state back */
- if (!g_atomic_pointer_compare_and_exchange (&self->pv->state, NULL, args.state))
- g_assert_not_reached ();
+ check_in_enumerator_state (self, args.state);
return result;
}
@@ -733,16 +818,13 @@ gck_enumerator_next_n (GckEnumerator *self, gint max_objects, GCancellable *canc
g_return_val_if_fail (!error || !*error, NULL);
/* Remove the state and own it ourselves */
- args.state = g_atomic_pointer_get (&self->pv->state);
- if (!args.state || !g_atomic_pointer_compare_and_exchange (&self->pv->state, args.state, NULL)) {
- g_warning ("this enumerator is already running a next operation");
- return NULL;
- }
+ 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;
/* Run the operation and steal away the results */
- if (_gck_call_sync (NULL, perform_enumerate_next, complete_enumerate_next, &args, cancellable, error)) {
+ if (_gck_call_sync (NULL, perform_enumerate_next, NULL, &args, cancellable, error)) {
results = args.state->results;
args.state->results = NULL;
}
@@ -750,8 +832,7 @@ gck_enumerator_next_n (GckEnumerator *self, gint max_objects, GCancellable *canc
args.state->want_objects = 0;
/* Put the state back */
- if (!g_atomic_pointer_compare_and_exchange (&self->pv->state, NULL, args.state))
- g_assert_not_reached ();
+ check_in_enumerator_state (self, args.state);
return results;
}
@@ -782,14 +863,11 @@ gck_enumerator_next_async (GckEnumerator *self, gint max_objects, GCancellable *
g_object_ref (self);
/* Remove the state and own it ourselves */
- state = g_atomic_pointer_get (&self->pv->state);
- if (!state || !g_atomic_pointer_compare_and_exchange (&self->pv->state, state, NULL)) {
- g_warning ("this enumerator is already running a next operation");
- return;
- }
+ state = check_out_enumerator_state (self);
+ g_return_if_fail (state != NULL);
state->want_objects = max_objects <= 0 ? G_MAXINT : max_objects;
- args = _gck_call_async_prep (NULL, self, perform_enumerate_next, complete_enumerate_next,
+ args = _gck_call_async_prep (NULL, self, perform_enumerate_next, NULL,
sizeof (*args), free_enumerate_next);
args->state = state;
@@ -831,8 +909,7 @@ gck_enumerator_next_finish (GckEnumerator *self, GAsyncResult *result, GError **
}
/* Put the state back */
- if (!g_atomic_pointer_compare_and_exchange (&self->pv->state, NULL, state))
- g_assert_not_reached ();
+ check_in_enumerator_state (self, state);
g_object_unref (self);
diff --git a/gck/gck-interaction.c b/gck/gck-interaction.c
new file mode 100644
index 0000000..33d5ad3
--- /dev/null
+++ b/gck/gck-interaction.c
@@ -0,0 +1,176 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gck-interaction.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-private.h"
+
+#include <string.h>
+
+#define GCK_INTERACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCK_TYPE_INTERACTION, GckInteraction))
+#define GCK_IS_INTERACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_INTERACTION))
+#define GCK_INTERACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_INTERACTION, GckInteractionClass))
+
+typedef struct _GckInteractionClass GckInteractionClass;
+
+struct _GckInteraction {
+ GTlsInteraction interaction;
+ GckModule *module;
+};
+
+struct _GckInteractionClass {
+ GTlsInteractionClass parent;
+};
+
+enum {
+ PROP_0,
+ PROP_MODULE
+};
+
+G_DEFINE_TYPE (GckInteraction, _gck_interaction, G_TYPE_TLS_INTERACTION);
+
+static void
+_gck_interaction_init (GckInteraction *self)
+{
+
+}
+
+static void
+_gck_interaction_get_property (GObject *obj,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GckInteraction *self = GCK_INTERACTION (obj);
+
+ switch (prop_id) {
+ case PROP_MODULE:
+ g_value_set_object (value, self->module);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_gck_interaction_set_property (GObject *obj,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GckInteraction *self = GCK_INTERACTION (obj);
+
+ switch (prop_id) {
+ case PROP_MODULE:
+ g_return_if_fail (self->module == NULL);
+ self->module = g_value_dup_object (value);
+ g_return_if_fail (self->module != NULL);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_gck_interaction_dispose (GObject *obj)
+{
+ GckInteraction *self = GCK_INTERACTION (obj);
+
+ g_clear_object (&self->module);
+
+ G_OBJECT_CLASS (_gck_interaction_parent_class)->dispose (obj);
+}
+
+static GTlsInteractionResult
+_gck_interaction_ask_password (GTlsInteraction *interaction,
+ GTlsPassword *password,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GckInteraction *self = GCK_INTERACTION (interaction);
+ gchar *value = NULL;
+ gboolean ret = FALSE;
+ GckSlot *token;
+ GckObject *key;
+
+ if (!self->module)
+ return G_TLS_INTERACTION_UNHANDLED;
+
+ token = gck_password_get_token (GCK_PASSWORD (password));
+ if (token != NULL) {
+ g_signal_emit_by_name (self->module, "authenticate-slot", token,
+ g_tls_password_get_description (password),
+ &value, &ret);
+ g_object_unref (token);
+
+ } else {
+ key = gck_password_get_key (GCK_PASSWORD (password));
+ g_return_val_if_fail (GCK_IS_OBJECT (key), G_TLS_INTERACTION_UNHANDLED);
+
+ g_signal_emit_by_name (self->module, "authenticate-object", key,
+ g_tls_password_get_description (password),
+ &value, &ret);
+ }
+
+ if (ret) {
+ g_tls_password_set_value_full (password, (guchar *)value, -1, g_free);
+ return G_TLS_INTERACTION_HANDLED;
+ } else {
+ return G_TLS_INTERACTION_UNHANDLED;
+ }
+}
+
+static void
+_gck_interaction_class_init (GckInteractionClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GTlsInteractionClass *interaction_class = G_TLS_INTERACTION_CLASS (klass);
+
+ object_class->get_property = _gck_interaction_get_property;
+ object_class->set_property = _gck_interaction_set_property;
+ object_class->dispose = _gck_interaction_dispose;
+
+ interaction_class->ask_password = _gck_interaction_ask_password;
+
+ g_object_class_install_property (object_class, PROP_MODULE,
+ g_param_spec_object ("module", "Module", "PKCS11 Module",
+ GCK_TYPE_MODULE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+GTlsInteraction *
+_gck_interaction_new (gpointer token_or_key)
+{
+ GTlsInteraction *result;
+ GModule *module = NULL;
+
+ g_return_val_if_fail (GCK_IS_SLOT (token_or_key) ||
+ GCK_IS_OBJECT (token_or_key), NULL);
+
+ g_object_get (token_or_key, "module", &module, NULL);
+ result = g_object_new (GCK_TYPE_INTERACTION, "module", module, NULL);
+ g_object_unref (module);
+
+ return result;
+}
diff --git a/gck/gck-misc.c b/gck/gck-misc.c
index 595f619..47d444e 100644
--- a/gck/gck-misc.c
+++ b/gck/gck-misc.c
@@ -218,6 +218,21 @@ _gck_stringize_rv (CK_RV rv)
}
}
+CK_RV
+_gck_rv_from_error (GError *error,
+ CK_RV catch_all_code)
+{
+ g_return_val_if_fail (error != NULL, CKR_GENERAL_ERROR);
+
+ if (error->domain == GCK_ERROR)
+ return error->code;
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ return CKR_FUNCTION_CANCELED;
+
+ return catch_all_code;
+}
+
/**
* SECTION:gck-misc
* @title: Miscellaneous Functions
diff --git a/gck/gck-module.c b/gck/gck-module.c
index 8806dd7..cdd9d45 100644
--- a/gck/gck-module.c
+++ b/gck/gck-module.c
@@ -106,76 +106,6 @@ G_DEFINE_TYPE (GckModule, gck_module, G_TYPE_OBJECT);
static guint signals[LAST_SIGNAL] = { 0 };
/* ----------------------------------------------------------------------------
- * INTERNAL
- */
-
-gboolean
-_gck_module_fire_authenticate_slot (GckModule *self, GckSlot *slot, gchar *label, gchar **password)
-{
- GckTokenInfo *info;
- gchar *allocated = NULL;
- gboolean ret;
-
- g_assert (GCK_IS_MODULE (self));
-
- info = gck_slot_get_token_info (slot);
- if (info != NULL) {
-
- /*
- * We'll have tried to login at least once at this point,
- * with NULL password. This means that CKF_PROTECTED_AUTHENTICATION_PATH
- * tokens have had their chance and we don't need to prompt for it.
- */
-
- if (info->flags & CKF_PROTECTED_AUTHENTICATION_PATH)
- return FALSE;
-
- if (label == NULL)
- label = allocated = g_strdup (info->label);
-
- gck_token_info_free (info);
- }
-
- g_signal_emit (self, signals[AUTHENTICATE_SLOT], 0, slot, label, password, &ret);
- g_free (allocated);
- return ret;
-}
-
-gboolean
-_gck_module_fire_authenticate_object (GckModule *self, GckObject *object,
- gchar *label, gchar **password)
-{
- GckTokenInfo *info;
- GckSession *session;
- GckSlot *slot;
- gboolean ret;
-
- g_assert (GCK_IS_MODULE (self));
- g_assert (GCK_IS_OBJECT (object));
- g_assert (password);
-
- session = gck_object_get_session (object);
- slot = gck_session_get_slot (session);
- g_object_unref (session);
-
- info = gck_slot_get_token_info (slot);
- g_object_unref (slot);
-
- if (info != NULL) {
- if (info->flags & CKF_PROTECTED_AUTHENTICATION_PATH) {
- gck_token_info_free (info);
- *password = NULL;
- return TRUE;
- }
-
- gck_token_info_free (info);
- }
-
- g_signal_emit (self, signals[AUTHENTICATE_OBJECT], 0, object, label, password, &ret);
- return ret;
-}
-
-/* ----------------------------------------------------------------------------
* OBJECT
*/
@@ -321,11 +251,9 @@ gck_module_class_init (GckModuleClass *klass)
* @string: A displayable label which describes the object.
* @password: A gchar** where a password should be returned.
*
- * This signal is emitted when a password is needed to authenticate a PKCS&num;11
- * slot. If the module prompts for passwords itself, then this signal will
- * not be emitted.
+ * Use gck_slot_set_interaction() instead of connecting to this signal.
*
- * Returns: FALSE if the user cancelled, TRUE if we should proceed.
+ * Deprecated: Since 3.4
*/
signals[AUTHENTICATE_SLOT] = g_signal_new ("authenticate-slot", GCK_TYPE_MODULE,
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GckModuleClass, authenticate_slot),
@@ -339,11 +267,9 @@ gck_module_class_init (GckModuleClass *klass)
* @label: A displayable label which describes the object.
* @password: A gchar** where a password should be returned.
*
- * This signal is emitted when a password is needed to authenticate a PKCS&num;11
- * object like a key. If the module prompts for passwords itself, then this signal will
- * not be emitted.
+ * Use gck_slot_set_interaction() instead of connecting to this signal.
*
- * Returns: FALSE if the user cancelled, TRUE if we should proceed.
+ * Deprecated: Since 3.4
*/
signals[AUTHENTICATE_OBJECT] = g_signal_new ("authenticate-object", GCK_TYPE_MODULE,
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GckModuleClass, authenticate_object),
diff --git a/gck/gck-modules.c b/gck/gck-modules.c
index 497d2ff..9a93103 100644
--- a/gck/gck-modules.c
+++ b/gck/gck-modules.c
@@ -341,7 +341,9 @@ gck_modules_tokens_for_uri (GList *modules,
* g_object_unref(), or %NULL if no matching object was found.
*/
GckObject*
-gck_modules_object_for_uri (GList *modules, const gchar *uri, guint session_options,
+gck_modules_object_for_uri (GList *modules,
+ const gchar *uri,
+ GckSessionOptions session_options,
GError **error)
{
GckEnumerator *en;
@@ -377,7 +379,9 @@ gck_modules_object_for_uri (GList *modules, const gchar *uri, guint session_opti
* was found.
*/
GList*
-gck_modules_objects_for_uri (GList *modules, const gchar *uri, guint session_options,
+gck_modules_objects_for_uri (GList *modules,
+ const gchar *uri,
+ GckSessionOptions session_options,
GError **error)
{
GckEnumerator *en;
@@ -411,7 +415,9 @@ gck_modules_objects_for_uri (GList *modules, const gchar *uri, guint session_opt
* Returns: (transfer full): A new #GckEnumerator, or %NULL if an error occurs.
*/
GckEnumerator*
-gck_modules_enumerate_uri (GList *modules, const gchar *uri, guint session_options,
+gck_modules_enumerate_uri (GList *modules,
+ const gchar *uri,
+ GckSessionOptions session_options,
GError **error)
{
GckUriData *uri_data;
diff --git a/gck/gck-password.c b/gck/gck-password.c
new file mode 100644
index 0000000..56200ea
--- /dev/null
+++ b/gck/gck-password.c
@@ -0,0 +1,255 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gck-password.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 "egg/egg-timegm.h"
+
+#include <string.h>
+
+/**
+ * SECTION:gck-password
+ * @title: GckPassword
+ * @short_description: Represents a password hich is requested of the user
+ *
+ * This is used in conjuction with GTlsInteraction. #GckPassword is a
+ * GTlsPassword which contains additional information about which PKCS\#11
+ * token or key the password is being requested for.
+ */
+
+/**
+ * GckPassword:
+ * @parent: parent object
+ *
+ * A #GTlsPasswordClass that contains information about the PKCS\#11 token
+ * or key the password is being requested for.
+ */
+
+/**
+ * GckPasswordClass:
+ * @parent: parent class
+ *
+ * The class for #GTlsPassword.
+ */
+enum {
+ PROP_0,
+ PROP_MODULE,
+ PROP_TOKEN,
+ PROP_KEY
+};
+
+struct _GckPasswordPrivate {
+ gboolean for_token;
+ gpointer token_or_key;
+};
+
+G_DEFINE_TYPE (GckPassword, gck_password, G_TYPE_TLS_PASSWORD);
+
+static void
+gck_password_init (GckPassword *self)
+{
+ self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCK_TYPE_PASSWORD, GckPasswordPrivate);
+}
+
+static void
+gck_password_constructed (GObject *obj)
+{
+ GckPassword *self = GCK_PASSWORD (obj);
+
+ G_OBJECT_CLASS (gck_password_parent_class)->constructed (obj);
+
+ g_return_if_fail (GCK_IS_SLOT (self->pv->token_or_key) ||
+ GCK_IS_OBJECT (self->pv->token_or_key));
+}
+
+static void
+gck_password_get_property (GObject *obj,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GckPassword *self = GCK_PASSWORD (obj);
+
+ switch (prop_id) {
+ case PROP_MODULE:
+ g_value_take_object (value, gck_password_get_module (self));
+ break;
+ case PROP_TOKEN:
+ g_value_take_object (value, gck_password_get_token (self));
+ break;
+ case PROP_KEY:
+ g_value_take_object (value, gck_password_get_key (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gck_password_set_property (GObject *obj,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GckPassword *self = GCK_PASSWORD (obj);
+ gpointer object;
+
+ /* All writes to data members below, happen only during construct phase */
+
+ switch (prop_id) {
+ case PROP_TOKEN:
+ object = g_value_dup_object (value);
+ if (object != NULL) {
+ g_assert (self->pv->token_or_key == NULL);
+ self->pv->token_or_key = object;
+ self->pv->for_token = TRUE;
+ }
+ break;
+ case PROP_KEY:
+ object = g_value_dup_object (value);
+ if (object != NULL) {
+ g_assert (self->pv->token_or_key == NULL);
+ self->pv->token_or_key = object;
+ self->pv->for_token = FALSE;
+ }
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gck_password_finalize (GObject *obj)
+{
+ GckPassword *self = GCK_PASSWORD (obj);
+
+ g_clear_object (&self->pv->token_or_key);
+
+ G_OBJECT_CLASS (gck_password_parent_class)->finalize (obj);
+}
+
+static void
+gck_password_class_init (GckPasswordClass *klass)
+{
+ GObjectClass *gobject_class = (GObjectClass*)klass;
+
+ gobject_class->constructed = gck_password_constructed;
+ gobject_class->get_property = gck_password_get_property;
+ gobject_class->set_property = gck_password_set_property;
+ gobject_class->finalize = gck_password_finalize;
+
+ /**
+ * GckPassword:module:
+ *
+ * The PKCS\#11 module that is requesting the password
+ */
+ g_object_class_install_property (gobject_class, PROP_MODULE,
+ g_param_spec_object ("module", "Module", "PKCS11 Module",
+ GCK_TYPE_MODULE, G_PARAM_READABLE));
+
+ /**
+ * GckPassword:token:
+ *
+ * The PKCS\#11 token the password is for, if this is set then
+ * the GckPassword:object property will be %NULL
+ */
+ g_object_class_install_property (gobject_class, PROP_TOKEN,
+ g_param_spec_object ("token", "Token", "PKCS11 Token",
+ GCK_TYPE_SLOT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ /**
+ * GckPassword:key:
+ *
+ * The PKCS\#11 key that the password is being requested for. If this
+ * is set then the GckPassword:token property will be %NULL
+ */
+ g_object_class_install_property (gobject_class, PROP_KEY,
+ g_param_spec_object ("key", "Object", "PKCS11 Key Object",
+ GCK_TYPE_OBJECT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_type_class_add_private (gobject_class, sizeof (GckPasswordPrivate));
+}
+
+/**
+ * gck_password_get_module:
+ * @self: the password object
+ *
+ * Get the PKCS\#11 module that is requesting the password.
+ *
+ * Returns: (transfer full): the module that is requesting the password, which
+ * must be unreferenced after use
+ */
+GckModule *
+gck_password_get_module (GckPassword *self)
+{
+ g_return_val_if_fail (GCK_IS_PASSWORD (self), NULL);
+ if (self->pv->for_token)
+ return gck_slot_get_module (self->pv->token_or_key);
+ else
+ return gck_object_get_module (self->pv->token_or_key);
+}
+
+/**
+ * gck_password_get_token:
+ * @self: the password object
+ *
+ * If the password request is to unlock a PKCS\#11 token, then this is the
+ * slot containing that token.
+ *
+ * Returns: (transfer full): the slot that contains the token, or %NULL if not
+ * being requested for a token; must be unreferenced after use
+ */
+GckSlot *
+gck_password_get_token (GckPassword *self)
+{
+ g_return_val_if_fail (GCK_IS_PASSWORD (self), NULL);
+ if (!self->pv->for_token)
+ return NULL;
+ g_return_val_if_fail (GCK_IS_SLOT (self->pv->token_or_key), NULL);
+ return g_object_ref (self->pv->token_or_key);
+}
+
+/**
+ * gck_password_get_key:
+ * @self: the password object
+ *
+ * If the password request is to unlock a PKCS\#11 key, then this is the
+ * the object representing that key.
+ *
+ * Returns: (transfer full): the password is for this key, or %NULL if not
+ * being requested for a key; must be unreferenced after use
+ */
+GckObject *
+gck_password_get_key (GckPassword *self)
+{
+ g_return_val_if_fail (GCK_IS_PASSWORD (self), NULL);
+ if (self->pv->for_token)
+ return NULL;
+ g_return_val_if_fail (GCK_IS_OBJECT (self->pv->token_or_key), NULL);
+ return g_object_ref (self->pv->token_or_key);
+}
diff --git a/gck/gck-private.h b/gck/gck-private.h
index 64739a2..c2919cf 100644
--- a/gck/gck-private.h
+++ b/gck/gck-private.h
@@ -62,22 +62,15 @@ gboolean _gck_ulong_equal (gconstpointer v1,
const gchar * _gck_stringize_rv (CK_RV rv);
+CK_RV _gck_rv_from_error (GError *error,
+ CK_RV catch_all_code);
+
/* ----------------------------------------------------------------------------
* MODULE
*/
GckModule* _gck_module_new_initialized (CK_FUNCTION_LIST_PTR funcs);
-gboolean _gck_module_fire_authenticate_slot (GckModule *module,
- GckSlot *slot,
- gchar *label,
- gchar **password);
-
-gboolean _gck_module_fire_authenticate_object (GckModule *module,
- GckObject *object,
- gchar *label,
- gchar **password);
-
GckModuleInfo* _gck_module_info_from_pkcs11 (CK_INFO_PTR info);
void _gck_module_info_to_pkcs11 (GckModuleInfo* module_info,
@@ -91,7 +84,7 @@ gboolean _gck_module_info_match (GckModuleInfo *matc
*/
GckEnumerator* _gck_enumerator_new (GList *modules,
- guint session_options,
+ GckSessionOptions session_options,
GckUriData *uri_data);
/* ----------------------------------------------------------------------------
@@ -106,6 +99,39 @@ void _gck_token_info_to_pkcs11 (GckTokenInfo *token
gboolean _gck_token_info_match (GckTokenInfo *match,
GckTokenInfo *info);
+CK_RV _gck_session_authenticate_token (CK_FUNCTION_LIST_PTR funcs,
+ CK_SESSION_HANDLE session,
+ GckSlot *token,
+ GTlsInteraction *interaction,
+ GCancellable *cancellable);
+
+CK_RV _gck_session_authenticate_key (CK_FUNCTION_LIST_PTR funcs,
+ CK_SESSION_HANDLE session,
+ GckObject *key,
+ GTlsInteraction *interaction,
+ GCancellable *cancellable);
+
+/* ----------------------------------------------------------------------------
+ * PASSWORD
+ */
+
+void _gck_password_update (GckPassword *self,
+ gboolean request_retry);
+
+/* ----------------------------------------------------------------------------
+ * INTERACTION
+ */
+
+#define GCK_TYPE_INTERACTION (_gck_interaction_get_type ())
+#define GCK_INTERACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_INTERACTION, GckInteraction))
+#define GCK_IS_INTERACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCK_TYPE_INTERACTION))
+
+typedef struct _GckInteraction GckInteraction;
+
+GType _gck_interaction_get_type (void) G_GNUC_CONST;
+
+GTlsInteraction * _gck_interaction_new (gpointer token_or_key);
+
/* ----------------------------------------------------------------------------
* CALL
*/
diff --git a/gck/gck-session.c b/gck/gck-session.c
index eba1de6..c984eb6 100644
--- a/gck/gck-session.c
+++ b/gck/gck-session.c
@@ -77,6 +77,7 @@ enum {
PROP_0,
PROP_MODULE,
PROP_HANDLE,
+ PROP_INTERACTION,
PROP_SLOT,
PROP_OPTIONS,
};
@@ -85,7 +86,8 @@ struct _GckSessionPrivate {
GckSlot *slot;
GckModule *module;
CK_SESSION_HANDLE handle;
- guint options;
+ GTlsInteraction *interaction;
+ GckSessionOptions options;
/* Modified atomically */
gint discarded;
@@ -148,6 +150,12 @@ gck_session_get_property (GObject *obj, guint prop_id, GValue *value,
case PROP_OPTIONS:
g_value_set_uint (value, gck_session_get_options (self));
break;
+ case PROP_INTERACTION:
+ g_value_take_object (value, self->pv->interaction);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
}
}
@@ -169,6 +177,10 @@ gck_session_set_property (GObject *obj, guint prop_id, const GValue *value,
g_return_if_fail (!self->pv->handle);
self->pv->handle = g_value_get_ulong (value);
break;
+ case PROP_INTERACTION:
+ g_return_if_fail (self->pv->interaction == NULL);
+ self->pv->interaction = g_value_dup_object (value);
+ break;
case PROP_SLOT:
g_return_if_fail (!self->pv->slot);
self->pv->slot = g_value_dup_object (value);
@@ -176,7 +188,10 @@ gck_session_set_property (GObject *obj, guint prop_id, const GValue *value,
break;
case PROP_OPTIONS:
g_return_if_fail (!self->pv->options);
- self->pv->options = g_value_get_uint (value);
+ self->pv->options = g_value_get_flags (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
break;
}
}
@@ -210,13 +225,9 @@ gck_session_finalize (GObject *obj)
g_assert (g_atomic_int_get (&self->pv->discarded) != 0);
- if (self->pv->slot)
- g_object_unref (self->pv->slot);
- self->pv->slot = NULL;
-
- if (self->pv->module)
- g_object_unref (self->pv->module);
- self->pv->module = NULL;
+ g_clear_object (&self->pv->interaction);
+ g_clear_object (&self->pv->slot);
+ g_clear_object (&self->pv->module);
G_OBJECT_CLASS (gck_session_parent_class)->finalize (obj);
}
@@ -267,8 +278,20 @@ gck_session_class_init (GckSessionClass *klass)
* The options this session was opened with.
*/
g_object_class_install_property (gobject_class, PROP_OPTIONS,
- g_param_spec_uint ("options", "Session Options", "Session Options",
- 0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_param_spec_flags ("options", "Session Options", "Session Options",
+ GCK_TYPE_SESSION_OPTIONS, GCK_SESSION_READ_ONLY,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ /**
+ * GckSession:interaction:
+ *
+ * Interaction object used to ask the user for pins when opening
+ * sessions. Used if the session_options of the enumerator have
+ * %GCK_SESSION_LOGIN_USER
+ */
+ 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));
/**
* GckSession::discard-handle:
@@ -364,21 +387,27 @@ gck_session_info_free (GckSessionInfo *session_info)
GckSession *
gck_session_from_handle (GckSlot *slot,
gulong session_handle,
- guint options)
+ GckSessionOptions options)
{
+ GTlsInteraction *interaction;
GckModule *module;
GckSession *session;
g_return_val_if_fail (GCK_IS_SLOT (slot), NULL);
module = gck_slot_get_module (slot);
+ interaction = gck_slot_get_interaction (slot);
+
session = g_object_new (GCK_TYPE_SESSION,
"module", module,
+ "interaction", interaction,
"handle", session_handle,
"slot", slot,
"options", options,
NULL);
+
g_object_unref (module);
+ g_clear_object (&interaction);
return session;
}
@@ -518,13 +547,33 @@ gck_session_get_state (GckSession *self)
*
* Return value: The session options.
**/
-guint
+GckSessionOptions
gck_session_get_options (GckSession *self)
{
g_return_val_if_fail (GCK_IS_SESSION (self), 0);
return self->pv->options;
}
+/**
+ * gck_session_get_interaction:
+ * @self: the session
+ *
+ * Get the interaction object set on this session, which is used to prompt
+ * for pins and the like.
+ *
+ * Returns: (transfer full) (allow-none): the interaction object, or %NULL
+ */
+GTlsInteraction *
+gck_session_get_interaction (GckSession *self)
+{
+ g_return_val_if_fail (GCK_IS_SESSION (self), NULL);
+
+ if (self->pv->interaction)
+ return g_object_ref (self->pv->interaction);
+
+ return NULL;
+}
+
/* ---------------------------------------------------------------------------------------------
* INIT PIN
*/
@@ -1913,191 +1962,20 @@ gck_session_derive_key_finish (GckSession *self, GAsyncResult *result, GError **
}
/* --------------------------------------------------------------------------------------------------
- * AUTHENTICATE
- */
-
-typedef enum _AuthenticateState {
- AUTHENTICATE_NONE,
- AUTHENTICATE_CAN,
- AUTHENTICATE_WANT,
- AUTHENTICATE_PERFORM
-} AuthenticateState;
-
-typedef struct _Authenticate {
- AuthenticateState state;
- gboolean protected_auth;
- GckModule *module;
- GckObject *object;
- gchar *label;
- gchar *password;
-} Authenticate;
-
-static CK_RV
-authenticate_perform (Authenticate *args, GckArguments *base)
-{
- CK_ATTRIBUTE attributes[2];
- CK_OBJECT_HANDLE handle;
- CK_ULONG pin_len;
- CK_BBOOL bvalue;
- CK_RV rv;
-
- g_assert (args);
- g_assert (base);
-
- switch (args->state) {
-
- /*
- * Cannot authenticate for whatever reason, perhaps not
- * enabled, or failed incomprehensibly etc.
- *
- */
- case AUTHENTICATE_NONE:
- return CKR_OK;
-
- /*
- * Can authenticate but haven't seen if we should, yet
- * check out the object in question.
- */
- case AUTHENTICATE_CAN:
-
- handle = gck_object_get_handle (args->object);
-
- attributes[0].type = CKA_LABEL;
- attributes[0].pValue = NULL;
- attributes[0].ulValueLen = 0;
- attributes[1].type = CKA_ALWAYS_AUTHENTICATE;
- attributes[1].pValue = &bvalue;
- attributes[1].ulValueLen = sizeof (bvalue);
-
- rv = (base->pkcs11->C_GetAttributeValue) (base->handle, handle, attributes, 2);
- if (rv == CKR_ATTRIBUTE_TYPE_INVALID)
- bvalue = CK_FALSE;
- else if (rv != CKR_OK)
- return rv;
-
- /* No authentication needed, on this object */
- if (bvalue != CK_TRUE) {
- args->state = AUTHENTICATE_NONE;
- return CKR_OK;
- }
-
- /* Protected authentication path, just go to perform */
- if (args->protected_auth) {
- args->state = AUTHENTICATE_PERFORM;
- return authenticate_perform (args, base);
- }
-
- /* Get the label for a prompt */
- g_assert (!args->label);
- if (attributes[0].ulValueLen) {
- attributes[0].pValue = g_malloc0 (attributes[0].ulValueLen + 1);
- rv = (base->pkcs11->C_GetAttributeValue) (base->handle, handle, attributes, 2);
- if (rv == CKR_OK) {
- g_assert (!args->label);
- args->label = attributes[0].pValue;
- args->label[attributes[0].ulValueLen] = 0;
- } else {
- g_free (attributes[0].pValue);
- }
- }
-
- /* Need a password */
- args->state = AUTHENTICATE_WANT;
- return CKR_USER_NOT_LOGGED_IN;
-
- /*
- * This state should be handled in verify_authenticate.
- */
- case AUTHENTICATE_WANT:
- g_assert (FALSE);
- return CKR_GENERAL_ERROR;
-
- /*
- * Do the actual login authentication.
- */
- case AUTHENTICATE_PERFORM:
- pin_len = args->password ? strlen (args->password) : 0;
- rv = (base->pkcs11->C_Login) (base->handle, CKU_CONTEXT_SPECIFIC,
- (CK_UTF8CHAR_PTR)args->password, pin_len);
- if (rv == CKR_PIN_INCORRECT && !args->protected_auth)
- args->state = AUTHENTICATE_WANT;
- else
- args->state = AUTHENTICATE_NONE;
- return rv;
-
- default:
- g_assert_not_reached ();
- return CKR_GENERAL_ERROR;
- }
-}
-
-static gboolean
-authenticate_complete (Authenticate *auth, GckArguments *base, CK_RV result)
-{
- g_assert (auth);
- g_assert (base);
-
- /* We're done here if not in this state */
- if (auth->state == AUTHENTICATE_WANT) {
-
- g_assert (GCK_IS_MODULE (auth->module));
- g_assert (GCK_IS_OBJECT (auth->object));
-
- g_free (auth->password);
- auth->password = NULL;
-
- if (_gck_module_fire_authenticate_object (auth->module, auth->object, auth->label, &auth->password)) {
- auth->state = AUTHENTICATE_PERFORM;
- return FALSE; /* Want to continue processing this call */
- }
- }
-
- /* Free up various memory */
- if (auth->module)
- g_object_unref (auth->module);
- if (auth->object)
- g_object_unref (auth->object);
- g_free (auth->label);
- g_free (auth->password);
-
- /* The call is complete */
- return TRUE;
-}
-
-static void
-authenticate_init (Authenticate *auth, GckSlot *slot, GckObject *object, guint options)
-{
- GckModule *module;
-
- g_assert (GCK_IS_SLOT (slot));
- g_assert (GCK_IS_OBJECT (object));
-
- module = gck_slot_get_module (slot);
- if ((options & GCK_SESSION_AUTHENTICATE) == GCK_SESSION_AUTHENTICATE) {
- auth->state = AUTHENTICATE_CAN;
- auth->protected_auth = gck_slot_has_flags (slot, CKF_PROTECTED_AUTHENTICATION_PATH);
- auth->module = module;
- auth->object = g_object_ref (object);
- } else {
- auth->state = AUTHENTICATE_NONE;
- g_object_unref (module);
- }
-}
-
-/* --------------------------------------------------------------------------------------------------
* COMMON CRYPTO ROUTINES
*/
typedef struct _Crypt {
GckArguments base;
- /* Authenticator */
- Authenticate auth;
-
/* Functions to call */
CK_C_EncryptInit init_func;
CK_C_Encrypt complete_func;
+ /* Interaction */
+ GckObject *key_object;
+ GTlsInteraction *interaction;
+
/* Input */
CK_OBJECT_HANDLE key;
GckMechanism mechanism;
@@ -2113,6 +1991,7 @@ typedef struct _Crypt {
static CK_RV
perform_crypt (Crypt *args)
{
+ GTlsInteraction *interaction;
CK_RV rv;
g_assert (args);
@@ -2126,7 +2005,17 @@ perform_crypt (Crypt *args)
if (rv != CKR_OK)
return rv;
- rv = authenticate_perform (&args->auth, &args->base);
+ /* Compatibility, hook into GckModule signals if no interaction set */
+ if (args->interaction)
+ interaction = g_object_ref (args->interaction);
+ else
+ interaction = _gck_interaction_new (args->key_object);
+
+ rv = _gck_session_authenticate_key (args->base.pkcs11, args->base.handle,
+ args->key_object, interaction, NULL);
+
+ g_object_unref (interaction);
+
if (rv != CKR_OK)
return rv;
@@ -2140,19 +2029,12 @@ perform_crypt (Crypt *args)
return (args->complete_func) (args->base.handle, args->input, args->n_input, args->result, &args->n_result);
}
-static gboolean
-complete_crypt (Crypt *args, CK_RV result)
-{
- if (!authenticate_complete (&args->auth, &args->base, result))
- return FALSE;
-
- /* Call is complete */
- return TRUE;
-}
-
static void
free_crypt (Crypt *args)
{
+ g_clear_object (&args->interaction);
+ g_clear_object (&args->key_object);
+
g_free (args->input);
g_free (args->result);
g_free (args);
@@ -2164,7 +2046,6 @@ crypt_sync (GckSession *self, GckObject *key, GckMechanism *mechanism, const guc
CK_C_EncryptInit init_func, CK_C_Encrypt complete_func)
{
Crypt args;
- GckSlot *slot;
g_return_val_if_fail (GCK_IS_OBJECT (key), NULL);
g_return_val_if_fail (mechanism, NULL);
@@ -2185,11 +2066,10 @@ crypt_sync (GckSession *self, GckObject *key, GckMechanism *mechanism, const guc
args.init_func = init_func;
args.complete_func = complete_func;
- slot = gck_session_get_slot (self);
- authenticate_init (&args.auth, slot, key, self->pv->options);
- g_object_unref (slot);
+ args.key_object = key;
+ args.interaction = self->pv->interaction;
- if (!_gck_call_sync (self, perform_crypt, complete_crypt, &args, cancellable, error)) {
+ if (!_gck_call_sync (self, perform_crypt, NULL, &args, cancellable, error)) {
g_free (args.result);
return NULL;
}
@@ -2203,8 +2083,7 @@ crypt_async (GckSession *self, GckObject *key, GckMechanism *mechanism, const gu
gsize n_input, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data,
CK_C_EncryptInit init_func, CK_C_Encrypt complete_func)
{
- Crypt *args = _gck_call_async_prep (self, self, perform_crypt, complete_crypt, sizeof (*args), free_crypt);
- GckSlot *slot;
+ Crypt *args = _gck_call_async_prep (self, self, perform_crypt, NULL, sizeof (*args), free_crypt);
g_return_if_fail (GCK_IS_OBJECT (key));
g_return_if_fail (mechanism);
@@ -2223,9 +2102,8 @@ crypt_async (GckSession *self, GckObject *key, GckMechanism *mechanism, const gu
args->init_func = init_func;
args->complete_func = complete_func;
- slot = gck_session_get_slot (self);
- authenticate_init (&args->auth, slot, key, self->pv->options);
- g_object_unref (slot);
+ args->key_object = g_object_ref (key);
+ args->interaction = gck_session_get_interaction (self);
_gck_call_async_ready_go (args, cancellable, callback, user_data);
}
@@ -2614,8 +2492,9 @@ gck_session_sign_finish (GckSession *self, GAsyncResult *result,
typedef struct _Verify {
GckArguments base;
- /* Authenticator */
- Authenticate auth;
+ /* Interaction */
+ GckObject *key_object;
+ GTlsInteraction *interaction;
/* Input */
CK_OBJECT_HANDLE key;
@@ -2630,6 +2509,7 @@ typedef struct _Verify {
static CK_RV
perform_verify (Verify *args)
{
+ GTlsInteraction *interaction;
CK_RV rv;
/* Initialize the crypt operation */
@@ -2637,7 +2517,18 @@ perform_verify (Verify *args)
if (rv != CKR_OK)
return rv;
- rv = authenticate_perform (&args->auth, &args->base);
+ /* Compatibility, hook into GckModule signals if no interaction set */
+ if (args->interaction)
+ interaction = g_object_ref (args->interaction);
+ else
+ interaction = _gck_interaction_new (args->key_object);
+
+
+ rv = _gck_session_authenticate_key (args->base.pkcs11, args->base.handle,
+ args->key_object, interaction, NULL);
+
+ g_object_unref (interaction);
+
if (rv != CKR_OK)
return rv;
@@ -2646,19 +2537,12 @@ perform_verify (Verify *args)
args->signature, args->n_signature);
}
-static gboolean
-complete_verify (Verify *args, CK_RV result)
-{
- if (!authenticate_complete (&args->auth, &args->base, result))
- return FALSE;
-
- /* Call is complete */
- return TRUE;
-}
-
static void
free_verify (Verify *args)
{
+ g_clear_object (&args->interaction);
+ g_clear_object (&args->key_object);
+
g_free (args->input);
g_free (args->signature);
g_free (args);
@@ -2713,7 +2597,6 @@ gck_session_verify_full (GckSession *self, GckObject *key, GckMechanism *mechani
gsize n_signature, GCancellable *cancellable, GError **error)
{
Verify args;
- GckSlot *slot;
g_return_val_if_fail (GCK_IS_OBJECT (key), FALSE);
g_return_val_if_fail (mechanism, FALSE);
@@ -2731,11 +2614,10 @@ gck_session_verify_full (GckSession *self, GckObject *key, GckMechanism *mechani
args.signature = (guchar*)signature;
args.n_signature = n_signature;
- slot = gck_session_get_slot (self);
- authenticate_init (&args.auth, slot, key, self->pv->options);
- g_object_unref (slot);
+ args.key_object = key;
+ args.interaction = self->pv->interaction;
- return _gck_call_sync (self, perform_verify, complete_verify, &args, cancellable, error);
+ return _gck_call_sync (self, perform_verify, NULL, &args, cancellable, error);
}
/**
@@ -2760,8 +2642,7 @@ gck_session_verify_async (GckSession *self, GckObject *key, GckMechanism *mechan
gsize n_signature, GCancellable *cancellable,
GAsyncReadyCallback callback, gpointer user_data)
{
- Verify *args = _gck_call_async_prep (self, self, perform_verify, complete_verify, sizeof (*args), free_verify);
- GckSlot *slot;
+ Verify *args = _gck_call_async_prep (self, self, perform_verify, NULL, sizeof (*args), free_verify);
g_return_if_fail (GCK_IS_OBJECT (key));
g_return_if_fail (mechanism);
@@ -2777,9 +2658,8 @@ gck_session_verify_async (GckSession *self, GckObject *key, GckMechanism *mechan
args->signature = signature && n_signature ? g_memdup (signature, n_signature) : NULL;
args->n_signature = n_signature;
- slot = gck_session_get_slot (self);
- authenticate_init (&args->auth, slot, key, self->pv->options);
- g_object_unref (slot);
+ args->key_object = g_object_ref (key);
+ args->interaction = gck_session_get_interaction (self);
_gck_call_async_ready_go (args, cancellable, callback, user_data);
}
@@ -2799,3 +2679,302 @@ gck_session_verify_finish (GckSession *self, GAsyncResult *result, GError **erro
{
return _gck_call_basic_finish (result, error);
}
+
+static void
+update_password_for_token (GTlsPassword *password,
+ CK_TOKEN_INFO *token_info,
+ gboolean request_retry)
+{
+ GTlsPasswordFlags flags;
+ gchar *label;
+
+ label = gck_string_from_chars (token_info->label, sizeof (token_info->label));
+ g_tls_password_set_description (password, label);
+ g_free (label);
+
+ flags = 0;
+ if (request_retry)
+ flags |= G_TLS_PASSWORD_RETRY;
+ if (token_info && token_info->flags & CKF_USER_PIN_COUNT_LOW)
+ flags |= G_TLS_PASSWORD_MANY_TRIES;
+ if (token_info && token_info->flags & CKF_USER_PIN_FINAL_TRY)
+ flags |= G_TLS_PASSWORD_FINAL_TRY;
+ g_tls_password_set_flags (password, flags);
+}
+
+CK_RV
+_gck_session_authenticate_token (CK_FUNCTION_LIST_PTR funcs,
+ CK_SESSION_HANDLE session,
+ GckSlot *token,
+ GTlsInteraction *interaction,
+ GCancellable *cancellable)
+{
+ CK_SESSION_INFO session_info;
+ GTlsPassword *password = NULL;
+ CK_TOKEN_INFO token_info;
+ GTlsInteractionResult res;
+ gboolean request_retry;
+ CK_SLOT_ID slot_id;
+ CK_BYTE_PTR pin;
+ CK_ULONG n_pin;
+ CK_RV rv = CKR_OK;
+ GError *error = NULL;
+
+ g_assert (funcs != NULL);
+ g_assert (GCK_IS_SLOT (token));
+
+ slot_id = gck_slot_get_handle (token);
+ request_retry = FALSE;
+
+ do {
+ if (g_cancellable_is_cancelled (cancellable)) {
+ rv = CKR_FUNCTION_CANCELED;
+ break;
+ }
+
+ rv = (funcs->C_GetTokenInfo) (slot_id, &token_info);
+ if (rv != CKR_OK) {
+ g_warning ("couldn't get token info when logging in: %s",
+ gck_message_from_rv (rv));
+ break;
+ }
+
+ /* No login necessary? */
+ if ((token_info.flags & CKF_LOGIN_REQUIRED) == 0) {
+ _gck_debug ("no login required for token, skipping login");
+ rv = CKR_OK;
+ break;
+ }
+
+ /* Next check if session is logged in? */
+ rv = (funcs->C_GetSessionInfo) (session, &session_info);
+ if (rv != CKR_OK) {
+ g_warning ("couldn't get session info when logging in: %s",
+ gck_message_from_rv (rv));
+ break;
+ }
+
+ /* Already logged in? */
+ if (session_info.state == CKS_RW_USER_FUNCTIONS ||
+ session_info.state == CKS_RO_USER_FUNCTIONS ||
+ session_info.state == CKS_RW_SO_FUNCTIONS) {
+ _gck_debug ("already logged in, skipping login");
+ rv = CKR_OK;
+ break;
+ }
+
+ if (token_info.flags & CKF_PROTECTED_AUTHENTICATION_PATH) {
+ _gck_debug ("trying to log into session: protected authentication path, no password");
+
+ /* No password passed for PAP */
+ pin = NULL;
+ n_pin = 0;
+
+
+ /* Not protected auth path */
+ } else {
+ _gck_debug ("trying to log into session: want password %s",
+ request_retry ? "login was incorrect" : "");
+
+ if (password == NULL)
+ password = g_object_new (GCK_TYPE_PASSWORD, "token", token, NULL);
+
+ update_password_for_token (password, &token_info, request_retry);
+
+ if (interaction == NULL)
+ res = G_TLS_INTERACTION_UNHANDLED;
+
+ else
+ res = g_tls_interaction_invoke_ask_password (interaction,
+ G_TLS_PASSWORD (password),
+ NULL, &error);
+
+ if (res == G_TLS_INTERACTION_FAILED) {
+ g_message ("interaction couldn't ask password: %s", error->message);
+ rv = _gck_rv_from_error (error, CKR_USER_NOT_LOGGED_IN);
+ g_clear_error (&error);
+ break;
+
+ } else if (res == G_TLS_INTERACTION_UNHANDLED) {
+ g_message ("couldn't authenticate: no interaction handler");
+ rv = CKR_USER_NOT_LOGGED_IN;
+ break;
+ }
+
+ pin = (CK_BYTE_PTR)g_tls_password_get_value (password, &n_pin);
+ }
+
+ /* Try to log in */
+ rv = (funcs->C_Login) (session, CKU_USER, (CK_BYTE_PTR)pin, n_pin);
+
+ /* Only one C_Login call if protected auth path */
+ if (token_info.flags & CKF_PROTECTED_AUTHENTICATION_PATH)
+ break;
+
+ request_retry = TRUE;
+ } while (rv == CKR_PIN_INCORRECT);
+
+ g_clear_object (&password);
+
+ return rv;
+}
+
+static void
+update_password_for_key (GTlsPassword *password,
+ CK_TOKEN_INFO *token_info,
+ gboolean request_retry)
+{
+ GTlsPasswordFlags flags;
+
+ flags = 0;
+ if (request_retry)
+ flags |= G_TLS_PASSWORD_RETRY;
+ if (token_info && token_info->flags & CKF_USER_PIN_COUNT_LOW)
+ flags |= G_TLS_PASSWORD_MANY_TRIES;
+ if (token_info && token_info->flags & CKF_USER_PIN_FINAL_TRY)
+ flags |= G_TLS_PASSWORD_FINAL_TRY;
+ g_tls_password_set_flags (password, flags);
+}
+
+CK_RV
+_gck_session_authenticate_key (CK_FUNCTION_LIST_PTR funcs,
+ CK_SESSION_HANDLE session,
+ GckObject *key,
+ GTlsInteraction *interaction,
+ GCancellable *cancellable)
+{
+ CK_ATTRIBUTE attrs[2];
+ CK_SESSION_INFO session_info;
+ CK_TOKEN_INFO token_info;
+ GTlsPassword *password = NULL;
+ CK_OBJECT_HANDLE handle;
+ GTlsInteractionResult res;
+ gboolean request_retry;
+ GError *error = NULL;
+ CK_BYTE_PTR pin;
+ gsize pin_len;
+ CK_BBOOL bvalue;
+ gboolean got_label;
+ CK_RV rv;
+
+ g_assert (funcs != NULL);
+
+ handle = gck_object_get_handle (key);
+
+ attrs[0].type = CKA_LABEL;
+ attrs[0].pValue = NULL;
+ attrs[0].ulValueLen = 0;
+ attrs[1].type = CKA_ALWAYS_AUTHENTICATE;
+ attrs[1].pValue = &bvalue;
+ attrs[1].ulValueLen = sizeof (bvalue);
+
+ rv = (funcs->C_GetAttributeValue) (session, handle, attrs, 2);
+ if (rv == CKR_ATTRIBUTE_TYPE_INVALID) {
+ bvalue = CK_FALSE;
+
+ } else if (rv != CKR_OK) {
+ g_message ("couldn't check whether key requires authentication, assuming it doesn't: %s",
+ gck_message_from_rv (rv));
+ return CKR_OK;
+ }
+
+ /* No authentication needed, on this object */
+ if (bvalue != CK_TRUE) {
+ _gck_debug ("key does not require authentication");
+ return CKR_OK;
+ }
+
+ got_label = FALSE;
+ request_retry = FALSE;
+
+ do {
+ if (g_cancellable_is_cancelled (cancellable)) {
+ rv = CKR_FUNCTION_CANCELED;
+ break;
+ }
+
+ rv = (funcs->C_GetSessionInfo) (session, &session_info);
+ if (rv != CKR_OK) {
+ g_warning ("couldn't get session info when authenticating key: %s",
+ gck_message_from_rv (rv));
+ return rv;
+ }
+
+ rv = (funcs->C_GetTokenInfo) (session_info.slotID, &token_info);
+ if (rv != CKR_OK) {
+ g_warning ("couldn't get token info when authenticating key: %s",
+ gck_message_from_rv (rv));
+ return rv;
+ }
+
+ /* Protected authentication path, just use NULL passwords */
+ if (token_info.flags & CKF_PROTECTED_AUTHENTICATION_PATH) {
+
+ password = NULL;
+ pin = NULL;
+ pin_len = 0;
+
+ /* Need to prompt for a password */
+ } else {
+ _gck_debug ("trying to log into session: want password %s",
+ request_retry ? "login was incorrect" : "");
+
+ if (password == NULL)
+ password = g_object_new (GCK_TYPE_PASSWORD, "key", key, NULL);
+
+ /* Set the password */
+ update_password_for_key (password, &token_info, request_retry);
+
+ /* Set the label properly */
+ if (!got_label) {
+ if (attrs[0].ulValueLen && attrs[0].ulValueLen != GCK_INVALID) {
+ attrs[0].pValue = g_malloc0 (attrs[0].ulValueLen + 1);
+ rv = (funcs->C_GetAttributeValue) (session, handle, attrs, 1);
+ if (rv == CKR_OK) {
+ ((gchar *)attrs[0].pValue)[attrs[0].ulValueLen] = 0;
+ g_tls_password_set_description (password, attrs[0].pValue);
+ }
+ g_free (attrs[0].pValue);
+ attrs[0].pValue = NULL;
+ }
+
+ got_label = TRUE;
+ }
+
+ if (interaction == NULL)
+ res = G_TLS_INTERACTION_UNHANDLED;
+
+ else
+ res = g_tls_interaction_invoke_ask_password (interaction,
+ G_TLS_PASSWORD (password),
+ NULL, &error);
+
+ if (res == G_TLS_INTERACTION_FAILED) {
+ g_message ("interaction couldn't ask password: %s", error->message);
+ rv = _gck_rv_from_error (error, CKR_USER_NOT_LOGGED_IN);
+ g_clear_error (&error);
+ break;
+
+ } else if (res == G_TLS_INTERACTION_UNHANDLED) {
+ g_message ("couldn't authenticate: no interaction handler");
+ rv = CKR_USER_NOT_LOGGED_IN;
+ break;
+ }
+
+ pin = (CK_BYTE_PTR)g_tls_password_get_value (G_TLS_PASSWORD (password), &pin_len);
+ }
+
+ /* Try to log in */
+ rv = (funcs->C_Login) (session, CKU_CONTEXT_SPECIFIC, pin, pin_len);
+
+ /* Only one C_Login call if protected auth path */
+ if (token_info.flags & CKF_PROTECTED_AUTHENTICATION_PATH)
+ break;
+
+ request_retry = TRUE;
+ } while (rv == CKR_PIN_INCORRECT);
+
+ g_clear_object (&password);
+
+ return rv;
+}
diff --git a/gck/gck-slot.c b/gck/gck-slot.c
index 05c7d8e..2be6a83 100644
--- a/gck/gck-slot.c
+++ b/gck/gck-slot.c
@@ -49,12 +49,17 @@
enum {
PROP_0,
PROP_MODULE,
- PROP_HANDLE
+ PROP_HANDLE,
+ PROP_INTERACTION
};
struct _GckSlotPrivate {
GckModule *module;
CK_SLOT_ID handle;
+
+ /* Changable data locked by mutex */
+ GMutex *mutex;
+ GTlsInteraction *interaction;
};
G_DEFINE_TYPE (GckSlot, gck_slot, G_TYPE_OBJECT);
@@ -64,7 +69,9 @@ G_DEFINE_TYPE (GckSlot, gck_slot, G_TYPE_OBJECT);
*/
static GckSession*
-make_session_object (GckSlot *self, guint options, CK_SESSION_HANDLE handle)
+make_session_object (GckSlot *self,
+ GckSessionOptions options,
+ CK_SESSION_HANDLE handle)
{
GckSession *session;
GckModule *module;
@@ -89,6 +96,7 @@ static void
gck_slot_init (GckSlot *self)
{
self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCK_TYPE_SLOT, GckSlotPrivate);
+ self->pv->mutex = g_mutex_new ();
}
static void
@@ -104,6 +112,12 @@ gck_slot_get_property (GObject *obj, guint prop_id, GValue *value,
case PROP_HANDLE:
g_value_set_ulong (value, gck_slot_get_handle (self));
break;
+ case PROP_INTERACTION:
+ g_value_take_object (value, gck_slot_get_interaction (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
}
}
@@ -126,12 +140,22 @@ gck_slot_set_property (GObject *obj, guint prop_id, const GValue *value,
g_assert (!self->pv->handle);
self->pv->handle = g_value_get_ulong (value);
break;
+ case PROP_INTERACTION:
+ gck_slot_set_interaction (self, g_value_get_object (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
}
}
static void
gck_slot_dispose (GObject *obj)
{
+ GckSlot *self = GCK_SLOT (obj);
+
+ gck_slot_set_interaction (self, NULL);
+
G_OBJECT_CLASS (gck_slot_parent_class)->dispose (obj);
}
@@ -139,16 +163,16 @@ static void
gck_slot_finalize (GObject *obj)
{
GckSlot *self = GCK_SLOT (obj);
- self->pv->handle = 0;
- if (self->pv->module)
- g_object_unref (self->pv->module);
- self->pv->module = NULL;
+ g_assert (self->pv->interaction == NULL);
+
+ self->pv->handle = 0;
+ g_clear_object (&self->pv->module);
+ g_mutex_free (self->pv->mutex);
G_OBJECT_CLASS (gck_slot_parent_class)->finalize (obj);
}
-
static void
gck_slot_class_init (GckSlotClass *klass)
{
@@ -178,6 +202,17 @@ gck_slot_class_init (GckSlotClass *klass)
g_param_spec_ulong ("handle", "Handle", "PKCS11 Slot ID",
0, G_MAXULONG, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ /**
+ * GckSlot:interaction:
+ *
+ * Interaction object used to ask the user for pins when opening
+ * sessions. Used if the session_options of the enumerator have
+ * %GCK_SESSION_LOGIN_USER or %GCK_SESSION_AUTHENTICATE
+ */
+ 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));
+
g_type_class_add_private (gobject_class, sizeof (GckSlotPrivate));
}
@@ -909,6 +944,62 @@ gck_slot_has_flags (GckSlot *self, gulong flags)
}
/**
+ * gck_slot_get_interaction:
+ * @self: the slot
+ *
+ * Get the interaction used when a pin is needed
+ *
+ * Returns: (transfer full) (allow-none): the interaction or %NULL
+ */
+GTlsInteraction *
+gck_slot_get_interaction (GckSlot *self)
+{
+ GTlsInteraction *result = NULL;
+
+ g_return_val_if_fail (GCK_IS_SLOT (self), NULL);
+
+ g_mutex_lock (self->pv->mutex);
+
+ if (self->pv->interaction)
+ result = g_object_ref (self->pv->interaction);
+
+ g_mutex_unlock (self->pv->mutex);
+
+ return result;
+}
+
+/**
+ * gck_slot_set_interaction:
+ * @self: the slot
+ * @interaction: (allow-none): the interaction or %NULL
+ *
+ * Set the interaction used when a pin is needed
+ */
+void
+gck_slot_set_interaction (GckSlot *self,
+ GTlsInteraction *interaction)
+{
+ GTlsInteraction *previous = NULL;
+
+ g_return_if_fail (GCK_IS_SLOT (self));
+ g_return_if_fail (interaction == NULL || G_IS_TLS_INTERACTION (interaction));
+
+ g_mutex_lock (self->pv->mutex);
+
+ if (interaction != self->pv->interaction) {
+ previous = self->pv->interaction;
+ self->pv->interaction = interaction;
+ if (interaction)
+ g_object_ref (interaction);
+ }
+
+ g_mutex_unlock (self->pv->mutex);
+
+ g_clear_object (&previous);
+ g_object_notify (G_OBJECT (self), "interaction");
+}
+
+/**
* gck_slots_enumerate_objects:
* @slots: (element-type Gck.Slot): a list of #GckSlot to enumerate objects on.
* @attrs: Attributes that the objects must have, or empty for all objects.
@@ -938,6 +1029,7 @@ gck_slots_enumerate_objects (GList *slots,
typedef struct OpenSession {
GckArguments base;
+ GTlsInteraction *interaction;
GckSlot *slot;
gulong flags;
gpointer app_data;
@@ -950,9 +1042,8 @@ typedef struct OpenSession {
static CK_RV
perform_open_session (OpenSession *args)
{
- CK_SESSION_INFO info;
+ GTlsInteraction *interaction;
CK_RV rv = CKR_OK;
- CK_ULONG pin_len;
/* Can be called multiple times */
@@ -965,52 +1056,26 @@ perform_open_session (OpenSession *args)
if (rv != CKR_OK || !args->auto_login)
return rv;
- /* Step two, check if session is logged in */
- rv = (args->base.pkcs11->C_GetSessionInfo) (args->session, &info);
- if (rv != CKR_OK)
- return rv;
-
- /* Already logged in? */
- if (info.state != CKS_RO_PUBLIC_SESSION && info.state != CKS_RW_PUBLIC_SESSION)
- return CKR_OK;
-
- /* Try to login */
- pin_len = args->password ? strlen (args->password) : 0;
- return (args->base.pkcs11->C_Login) (args->session, CKU_USER,
- (CK_UTF8CHAR_PTR)args->password, pin_len);
-}
-
-static gboolean
-complete_open_session (OpenSession *args, CK_RV result)
-{
- GckModule *module;
- gboolean ret = TRUE;
-
- g_free (args->password);
- args->password = NULL;
-
- /* Ask the token for a password */
- module = gck_slot_get_module (args->slot);
-
- if (args->auto_login && result == CKR_PIN_INCORRECT) {
+ /* Compatibility, hook into GckModule signals if no interaction set */
+ if (args->interaction)
+ interaction = g_object_ref (args->interaction);
+ else
+ interaction = _gck_interaction_new (args->slot);
- ret = _gck_module_fire_authenticate_slot (module, args->slot, NULL, &args->password);
+ rv = _gck_session_authenticate_token (args->base.pkcs11, args->session,
+ args->slot, interaction, NULL);
- /* If authenticate returns TRUE then call is not complete */
- ret = !ret;
- }
-
- g_object_unref (module);
+ g_object_unref (interaction);
- return ret;
+ return rv;
}
static void
free_open_session (OpenSession *args)
{
+ g_clear_object (&args->interaction);
+ g_clear_object (&args->slot);
g_assert (!args->password);
- if (args->slot)
- g_object_unref (args->slot);
g_free (args);
}
@@ -1055,8 +1120,13 @@ gck_slot_open_session (GckSlot *self,
* Returns: (transfer full): a new session or %NULL if an error occurs
**/
GckSession *
-gck_slot_open_session_full (GckSlot *self, guint options, gulong pkcs11_flags, gpointer app_data,
- CK_NOTIFY notify, GCancellable *cancellable, GError **error)
+gck_slot_open_session_full (GckSlot *self,
+ GckSessionOptions options,
+ gulong pkcs11_flags,
+ gpointer app_data,
+ CK_NOTIFY notify,
+ GCancellable *cancellable,
+ GError **error)
{
OpenSession args = { GCK_ARGUMENTS_INIT, 0, };
GckSession *session = NULL;
@@ -1072,6 +1142,7 @@ gck_slot_open_session_full (GckSlot *self, guint options, gulong pkcs11_flags, g
args.notify = notify;
args.password = NULL;
args.session = 0;
+ args.interaction = gck_slot_get_interaction (self);
args.auto_login = ((options & GCK_SESSION_LOGIN_USER) == GCK_SESSION_LOGIN_USER);
@@ -1079,9 +1150,10 @@ gck_slot_open_session_full (GckSlot *self, guint options, gulong pkcs11_flags, g
if ((options & GCK_SESSION_READ_WRITE) == GCK_SESSION_READ_WRITE)
args.flags |= CKF_RW_SESSION;
- if (_gck_call_sync (self, perform_open_session, complete_open_session, &args, cancellable, error))
+ if (_gck_call_sync (self, perform_open_session, NULL, &args, cancellable, error))
session = make_session_object (self, options, args.session);
+ g_clear_object (&args.interaction);
g_object_unref (module);
g_object_unref (self);
@@ -1128,20 +1200,26 @@ gck_slot_open_session_async (GckSlot *self,
* This call will return immediately and complete asynchronously.
**/
void
-gck_slot_open_session_full_async (GckSlot *self, guint options, gulong pkcs11_flags, gpointer app_data,
- CK_NOTIFY notify, GCancellable *cancellable,
- GAsyncReadyCallback callback, gpointer user_data)
+gck_slot_open_session_full_async (GckSlot *self,
+ GckSessionOptions options,
+ gulong pkcs11_flags,
+ gpointer app_data,
+ CK_NOTIFY notify,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
OpenSession *args;
g_object_ref (self);
- args = _gck_call_async_prep (self, self, perform_open_session, complete_open_session,
+ args = _gck_call_async_prep (self, self, perform_open_session, NULL,
sizeof (*args), free_open_session);
args->app_data = app_data;
args->notify = notify;
args->slot = g_object_ref (self);
+ args->interaction = gck_slot_get_interaction (self);
args->auto_login = ((options & GCK_SESSION_LOGIN_USER) == GCK_SESSION_LOGIN_USER);
diff --git a/gck/gck.h b/gck/gck.h
index 890854b..cb2992c 100644
--- a/gck/gck.h
+++ b/gck/gck.h
@@ -434,6 +434,11 @@ struct _GckEnumeratorClass {
GType gck_enumerator_get_type (void) G_GNUC_CONST;
+GTlsInteraction * gck_enumerator_get_interaction (GckEnumerator *self);
+
+void gck_enumerator_set_interaction (GckEnumerator *self,
+ GTlsInteraction *interaction);
+
GckObject* gck_enumerator_next (GckEnumerator *self,
GCancellable *cancellable,
GError **error);
@@ -587,9 +592,10 @@ GckMechanismInfo* gck_slot_get_mechanism_info (GckSlot *self,
gboolean gck_slot_has_flags (GckSlot *self,
gulong flags);
-GckEnumerator* gck_slots_enumerate_objects (GList *slots,
- GckAttributes *attrs,
- GckSessionOptions options);
+GTlsInteraction * gck_slot_get_interaction (GckSlot *self);
+
+void gck_slot_set_interaction (GckSlot *self,
+ GTlsInteraction *interaction);
GckSession* gck_slot_open_session (GckSlot *self,
GckSessionOptions options,
@@ -623,6 +629,10 @@ GckSession* gck_slot_open_session_finish (GckSlot *self,
GAsyncResult *result,
GError **error);
+GckEnumerator* gck_slots_enumerate_objects (GList *slots,
+ GckAttributes *attrs,
+ GckSessionOptions options);
+
/* ------------------------------------------------------------------------
* SESSION
*/
@@ -689,6 +699,8 @@ gulong gck_session_get_state (GckSession *self);
GckSessionOptions gck_session_get_options (GckSession *self);
+GTlsInteraction * gck_session_get_interaction (GckSession *self);
+
gboolean gck_session_init_pin (GckSession *self,
const guchar *pin,
gsize n_pin,
@@ -1193,6 +1205,44 @@ GckAttributes* gck_object_get_template_finish (GckObject *self,
GAsyncResult *result,
GError **error);
+/* ------------------------------------------------------------------------
+ * PASSWORD
+ */
+
+#define GCK_TYPE_PASSWORD (gck_password_get_type ())
+#define GCK_PASSWORD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_PASSWORD, GckPassword))
+#define GCK_PASSWORD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCK_TYPE_PASSWORD, GckPassword))
+#define GCK_IS_PASSWORD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCK_TYPE_PASSWORD))
+#define GCK_IS_PASSWORD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_PASSWORD))
+#define GCK_PASSWORD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_PASSWORD, GckPasswordClass))
+
+typedef struct _GckPassword GckPassword;
+typedef struct _GckPasswordClass GckPasswordClass;
+typedef struct _GckPasswordPrivate GckPasswordPrivate;
+
+struct _GckPassword {
+ GTlsPassword parent;
+
+ /*< private >*/
+ GckPasswordPrivate *pv;
+ gpointer reserved[4];
+};
+
+struct _GckPasswordClass {
+ GTlsPasswordClass parent;
+
+ /*< private >*/
+ gpointer reserved[4];
+};
+
+GType gck_password_get_type (void) G_GNUC_CONST;
+
+GckModule * gck_password_get_module (GckPassword *self);
+
+GckSlot * gck_password_get_token (GckPassword *self);
+
+GckObject * gck_password_get_key (GckPassword *self);
+
/* ----------------------------------------------------------------------------
* URI
*/
diff --git a/gck/gck.symbols b/gck/gck.symbols
index 37f7f67..d5afd66 100644
--- a/gck/gck.symbols
+++ b/gck/gck.symbols
@@ -53,11 +53,13 @@ gck_attributes_new_empty
gck_attributes_new_full
gck_attributes_ref
gck_attributes_unref
+gck_enumerator_get_interaction
gck_enumerator_get_type
gck_enumerator_next
gck_enumerator_next_async
gck_enumerator_next_finish
gck_enumerator_next_n
+gck_enumerator_set_interaction
gck_error_get_quark
gck_error_get_type
gck_get_error_quark
@@ -122,6 +124,10 @@ gck_object_set_template
gck_object_set_template_async
gck_object_set_template_finish
gck_objects_from_handle_array
+gck_password_get_key
+gck_password_get_module
+gck_password_get_token
+gck_password_get_type
gck_session_create_object
gck_session_create_object_async
gck_session_create_object_finish
@@ -147,6 +153,7 @@ gck_session_generate_key_pair_finish
gck_session_generate_key_pair_full
gck_session_get_handle
gck_session_get_info
+gck_session_get_interaction
gck_session_get_module
gck_session_get_options
gck_session_get_slot
@@ -188,6 +195,7 @@ gck_slot_equal
gck_slot_from_handle
gck_slot_get_handle
gck_slot_get_info
+gck_slot_get_interaction
gck_slot_get_mechanism_info
gck_slot_get_mechanisms
gck_slot_get_module
@@ -204,6 +212,7 @@ gck_slot_open_session_async
gck_slot_open_session_finish
gck_slot_open_session_full
gck_slot_open_session_full_async
+gck_slot_set_interaction
gck_slots_enumerate_objects
gck_string_from_chars
gck_string_to_chars
diff --git a/gck/tests/Makefile.am b/gck/tests/Makefile.am
index 99aaf10..734e9d8 100644
--- a/gck/tests/Makefile.am
+++ b/gck/tests/Makefile.am
@@ -27,6 +27,10 @@ TEST_PROGS = \
test-gck-enumerator \
test-gck-modules
+test_gck_enumerator_SOURCES = \
+ test-gck-enumerator.c \
+ mock-interaction.c mock-interaction.h
+
check_PROGRAMS = $(TEST_PROGS)
test: $(TEST_PROGS)
diff --git a/gck/tests/mock-interaction.c b/gck/tests/mock-interaction.c
new file mode 100644
index 0000000..ed25a47
--- /dev/null
+++ b/gck/tests/mock-interaction.c
@@ -0,0 +1,97 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* mock-interaction.c
+
+ 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 "mock-interaction.h"
+
+#define MOCK_INTERACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOCK_TYPE_INTERACTION, MockInteraction))
+#define MOCK_IS_INTERACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOCK_TYPE_INTERACTION))
+#define MOCK_INTERACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOCK_TYPE_INTERACTION, MockInteractionClass))
+
+typedef struct _MockInteractionClass MockInteractionClass;
+
+struct _MockInteraction {
+ GTlsInteraction interaction;
+ gchar *password;
+};
+
+struct _MockInteractionClass {
+ GTlsInteractionClass parent;
+};
+
+G_DEFINE_TYPE (MockInteraction, mock_interaction, G_TYPE_TLS_INTERACTION);
+
+static void
+mock_interaction_init (MockInteraction *self)
+{
+
+}
+
+static void
+mock_interaction_finalize (GObject *obj)
+{
+ MockInteraction *self = MOCK_INTERACTION (obj);
+
+ g_free (self->password);
+
+ G_OBJECT_CLASS (mock_interaction_parent_class)->dispose (obj);
+}
+
+static GTlsInteractionResult
+mock_interaction_ask_password (GTlsInteraction *interaction,
+ GTlsPassword *password,
+ GCancellable *cancellable,
+ GError **error)
+{
+ MockInteraction *self = MOCK_INTERACTION (interaction);
+
+ if (self->password) {
+ g_tls_password_set_value (password, (const guchar *)self->password, -1);
+ return G_TLS_INTERACTION_HANDLED;
+ } else {
+ return G_TLS_INTERACTION_UNHANDLED;
+ }
+}
+
+static void
+mock_interaction_class_init (MockInteractionClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GTlsInteractionClass *interaction_class = G_TLS_INTERACTION_CLASS (klass);
+
+ object_class->finalize = mock_interaction_finalize;
+
+ interaction_class->ask_password = mock_interaction_ask_password;
+}
+
+GTlsInteraction *
+mock_interaction_new (const gchar *password)
+{
+ MockInteraction *result;
+
+ result = g_object_new (MOCK_TYPE_INTERACTION, NULL);
+ result->password = g_strdup (password);
+
+ return G_TLS_INTERACTION (result);
+}
diff --git a/gck/tests/mock-interaction.h b/gck/tests/mock-interaction.h
new file mode 100644
index 0000000..0747f4b
--- /dev/null
+++ b/gck/tests/mock-interaction.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* mock-interaction.h
+
+ 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>
+*/
+
+#ifndef MOCK_INTERACTION_H
+#define MOCK_INTERACTION_H
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define MOCK_TYPE_INTERACTION (mock_interaction_get_type ())
+#define MOCK_INTERACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MOCK_TYPE_INTERACTION, MockInteraction))
+#define MOCK_IS_INTERACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MOCK_TYPE_INTERACTION))
+
+typedef struct _MockInteraction MockInteraction;
+
+GType mock_interaction_get_type (void) G_GNUC_CONST;
+
+GTlsInteraction * mock_interaction_new (const gchar *password);
+
+G_END_DECLS
+
+#endif /* MOCK_INTERACTION_H */
diff --git a/gck/tests/test-gck-crypto.c b/gck/tests/test-gck-crypto.c
index 3aac0fc..9630123 100644
--- a/gck/tests/test-gck-crypto.c
+++ b/gck/tests/test-gck-crypto.c
@@ -631,6 +631,8 @@ main (int argc, char **argv)
g_type_init ();
g_test_init (&argc, &argv, NULL);
+ g_set_prgname ("test-gck-crypto");
+
g_test_add ("/gck/crypto/encrypt", Test, NULL, setup, test_encrypt, teardown);
g_test_add ("/gck/crypto/decrypt", Test, NULL, setup, test_decrypt, teardown);
g_test_add ("/gck/crypto/login_context_specific", Test, NULL, setup, test_login_context_specific, teardown);
diff --git a/gck/tests/test-gck-enumerator.c b/gck/tests/test-gck-enumerator.c
index 9287b1b..d5d669e 100644
--- a/gck/tests/test-gck-enumerator.c
+++ b/gck/tests/test-gck-enumerator.c
@@ -28,6 +28,8 @@
#include "gck/gck-private.h"
#include "gck/gck-test.h"
+#include "mock-interaction.h"
+
#include "egg/egg-testing.h"
#include <glib.h>
@@ -242,6 +244,76 @@ test_attributes (Test *test, gconstpointer unused)
}
static void
+test_authenticate_interaction (Test *test,
+ gconstpointer unused)
+{
+ GTlsInteraction *interaction;
+ GTlsInteraction *check;
+ GckUriData *uri_data;
+ GError *error = NULL;
+ GckEnumerator *en;
+ GckObject *obj;
+
+ uri_data = gck_uri_data_new ();
+ en = _gck_enumerator_new (test->modules, GCK_SESSION_LOGIN_USER, uri_data);
+ g_assert (GCK_IS_ENUMERATOR (en));
+
+ interaction = mock_interaction_new ("booo");
+ g_object_set (en, "interaction", interaction, NULL);
+
+ check = NULL;
+ g_object_get (en, "interaction", &check, NULL);
+ g_assert (interaction == check);
+ g_object_unref (interaction);
+
+ obj = gck_enumerator_next (en, NULL, &error);
+ g_assert (GCK_IS_OBJECT (obj));
+
+ g_object_unref (obj);
+ g_object_unref (en);
+}
+
+static gboolean
+on_authenticate_token (GckModule *module,
+ GckSlot *slot,
+ gchar *label,
+ gchar **password,
+ gpointer unused)
+{
+ g_assert (unused == GUINT_TO_POINTER (35));
+ g_assert (password != NULL);
+ g_assert (*password == NULL);
+ g_assert (GCK_IS_MODULE (module));
+ g_assert (GCK_IS_SLOT (slot));
+
+ *password = g_strdup ("booo");
+ return TRUE;
+}
+
+static void
+test_authenticate_compat (Test *test,
+ gconstpointer unused)
+{
+ GckUriData *uri_data;
+ GError *error = NULL;
+ GckEnumerator *en;
+ GckObject *obj;
+
+ g_signal_connect (test->modules->data, "authenticate-slot",
+ G_CALLBACK (on_authenticate_token), GUINT_TO_POINTER (35));
+
+ uri_data = gck_uri_data_new ();
+ en = _gck_enumerator_new (test->modules, GCK_SESSION_LOGIN_USER, uri_data);
+ g_assert (GCK_IS_ENUMERATOR (en));
+
+ obj = gck_enumerator_next (en, NULL, &error);
+ g_assert (GCK_IS_OBJECT (obj));
+
+ g_object_unref (obj);
+ g_object_unref (en);
+}
+
+static void
test_token_match (Test *test, gconstpointer unused)
{
GckUriData *uri_data;
@@ -269,6 +341,8 @@ main (int argc, char **argv)
g_type_init ();
g_test_init (&argc, &argv, NULL);
+ g_set_prgname ("test-gck-enumerator");
+
g_test_add ("/gck/enumerator/create", Test, NULL, setup, test_create, teardown);
g_test_add ("/gck/enumerator/create_slots", Test, NULL, setup, test_create_slots, teardown);
g_test_add ("/gck/enumerator/next", Test, NULL, setup, test_next, teardown);
@@ -276,6 +350,8 @@ main (int argc, char **argv)
g_test_add ("/gck/enumerator/next_and_resume", Test, NULL, setup, test_next_and_resume, teardown);
g_test_add ("/gck/enumerator/next_n", Test, NULL, setup, test_next_n, teardown);
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/token_match", Test, NULL, setup, test_token_match, teardown);
diff --git a/gck/tests/test-gck-session.c b/gck/tests/test-gck-session.c
index e89ce54..632a760 100644
--- a/gck/tests/test-gck-session.c
+++ b/gck/tests/test-gck-session.c
@@ -306,6 +306,8 @@ main (int argc, char **argv)
g_type_init ();
g_test_init (&argc, &argv, NULL);
+ g_set_prgname ("test-gck-session");
+
g_test_add ("/gck/session/session_props", Test, NULL, setup, test_session_props, teardown);
g_test_add ("/gck/session/session_info", Test, NULL, setup, test_session_info, teardown);
g_test_add ("/gck/session/open_close_session", Test, NULL, setup, test_open_close_session, teardown);