diff options
author | Stefan Walter <stefw@src.gnome.org> | 2009-01-05 03:59:24 +0000 |
---|---|---|
committer | Stefan Walter <stefw@src.gnome.org> | 2009-01-05 03:59:24 +0000 |
commit | 29392679144def0183662777d8ebbd86ee8e7d79 (patch) | |
tree | 59847549b0e278fff904b826302906ccd97e1c42 /gp11 | |
parent | c83085b836d70bef522001322a7c4cd12a6e9a80 (diff) | |
download | gnome-keyring-29392679144def0183662777d8ebbd86ee8e7d79.tar.gz |
Add gp11_module_enumerate_objects set of functions which enumerates all
* gp11/gp11.h:
* gp11/gp11-call.c:
* gp11/gp11-module.c:
* gp11/gp11-private.h:
* gp11/gp11-session.c:
* gp11/gp11-slot.c:
* gp11/tests/unit-test-gp11-crypto.c:
* gp11/tests/unit-test-gp11-module.c:
* gp11/tests/unit-test-gp11-session.c: Add gp11_module_enumerate_objects
set of functions which enumerates all objects of a given type on a token.
Move 'auto-authenticate' and session pool to the module level.
svn path=/trunk/; revision=1431
Diffstat (limited to 'gp11')
-rw-r--r-- | gp11/gp11-call.c | 4 | ||||
-rw-r--r-- | gp11/gp11-module.c | 695 | ||||
-rw-r--r-- | gp11/gp11-private.h | 31 | ||||
-rw-r--r-- | gp11/gp11-session.c | 34 | ||||
-rw-r--r-- | gp11/gp11-slot.c | 544 | ||||
-rw-r--r-- | gp11/gp11.h | 66 | ||||
-rw-r--r-- | gp11/tests/unit-test-gp11-crypto.c | 12 | ||||
-rw-r--r-- | gp11/tests/unit-test-gp11-module.c | 69 | ||||
-rw-r--r-- | gp11/tests/unit-test-gp11-session.c | 29 |
9 files changed, 881 insertions, 603 deletions
diff --git a/gp11/gp11-call.c b/gp11/gp11-call.c index 04a73b50..c850b6b2 100644 --- a/gp11/gp11-call.c +++ b/gp11/gp11-call.c @@ -393,7 +393,7 @@ _gp11_call_sync (gpointer object, gpointer perform, gpointer complete, g_assert (GP11_IS_MODULE (module)); /* We now hold a reference to module until below */ - args->pkcs11 = gp11_module_get_function_list (module); + args->pkcs11 = gp11_module_get_functions (module); g_assert (args->pkcs11); do { @@ -460,7 +460,7 @@ _gp11_call_async_object (GP11Call *call, gpointer object) g_object_get (object, "module", &call->module, "handle", &call->args->handle, NULL); g_assert (GP11_IS_MODULE (call->module)); - call->args->pkcs11 = gp11_module_get_function_list (call->module); + call->args->pkcs11 = gp11_module_get_functions (call->module); /* We now hold a reference on module until finalize */ } diff --git a/gp11/gp11-module.c b/gp11/gp11-module.c index ad27461f..eda82932 100644 --- a/gp11/gp11-module.c +++ b/gp11/gp11-module.c @@ -24,6 +24,8 @@ #include "config.h" #include "gp11.h" +#include "gp11-private.h" +#include "gp11-marshal.h" #include <string.h> @@ -38,20 +40,32 @@ enum { PROP_0, PROP_PATH, - PROP_FUNCTION_LIST + PROP_FUNCTIONS, + PROP_POOL_SESSIONS, + PROP_AUTO_AUTHENTICATE +}; + +enum { + AUTHENTICATE_SLOT, + AUTHENTICATE_OBJECT, + LAST_SIGNAL }; typedef struct _GP11ModuleData { GModule *module; gchar *path; - gint finalized; + gboolean initialized; CK_FUNCTION_LIST_PTR funcs; CK_C_INITIALIZE_ARGS init_args; } GP11ModuleData; typedef struct _GP11ModulePrivate { GP11ModuleData data; - /* Add future mutex and non-MT-safe data here */ + GStaticMutex mutex; + gboolean finalized; + GHashTable *open_sessions; + gboolean auto_authenticate; + GP11TokenInfo *token_info; } GP11ModulePrivate; #define GP11_MODULE_GET_DATA(o) \ @@ -59,10 +73,37 @@ typedef struct _GP11ModulePrivate { G_DEFINE_TYPE (GP11Module, gp11_module, G_TYPE_OBJECT); +static guint signals[LAST_SIGNAL] = { 0 }; + +typedef struct _SessionPool { + CK_SLOT_ID slot; + CK_FUNCTION_LIST_PTR funcs; + GArray *ro_sessions; /* array of CK_SESSION_HANDLE */ + GArray *rw_sessions; /* array of CK_SESSION_HANDLE */ +} SessionPool; + /* ---------------------------------------------------------------------------- * HELPERS */ +static guint +ulong_hash (gconstpointer v) +{ + const signed char *p = v; + guint32 i, h = *p; + + for(i = 0; i < sizeof (gulong); ++i) + h = (h << 5) - h + *(p++); + + return h; +} + +static gboolean +ulong_equal (gconstpointer v1, gconstpointer v2) +{ + return *((const gulong*)v1) == *((const gulong*)v2); +} + static CK_RV create_mutex (void **mutex) { @@ -106,14 +147,296 @@ unlock_mutex (void *mutex) return CKR_OK; } +static void +close_session (CK_FUNCTION_LIST_PTR funcs, CK_SESSION_HANDLE handle) +{ + CK_RV rv; + + g_return_if_fail (funcs); + + rv = (funcs->C_CloseSession) (handle); + if (rv != CKR_OK) { + g_warning ("couldn't close session properly: %s", + gp11_message_from_rv (rv)); + } +} + +/* ---------------------------------------------------------------------------- + * INTERNAL + */ + +static GP11ModulePrivate* +lock_private (gpointer obj) +{ + GP11ModulePrivate *pv; + GP11Module *self; + + g_assert (GP11_IS_MODULE (obj)); + self = GP11_MODULE (obj); + + g_object_ref (self); + + pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GP11_TYPE_MODULE, GP11ModulePrivate); + g_static_mutex_lock (&pv->mutex); + + return pv; +} + +static void +unlock_private (gpointer obj, GP11ModulePrivate *pv) +{ + GP11Module *self; + + g_assert (pv); + g_assert (GP11_IS_MODULE (obj)); + + self = GP11_MODULE (obj); + + g_assert (G_TYPE_INSTANCE_GET_PRIVATE (self, GP11_TYPE_MODULE, GP11ModulePrivate) == pv); + + g_static_mutex_unlock (&pv->mutex); + g_object_unref (self); +} + +static void +free_session_pool (gpointer p) +{ + SessionPool *pool = p; + guint i; + + if (pool->ro_sessions) { + for(i = 0; i < pool->ro_sessions->len; ++i) + close_session (pool->funcs, g_array_index (pool->ro_sessions, CK_SESSION_HANDLE, i)); + g_array_free (pool->ro_sessions, TRUE); + } + + if (pool->rw_sessions) { + for(i = 0; i < pool->rw_sessions->len; ++i) + close_session (pool->funcs, g_array_index (pool->rw_sessions, CK_SESSION_HANDLE, i)); + g_array_free (pool->rw_sessions, TRUE); + } + + g_free (pool); +} + +static gboolean +push_session_table (GP11ModulePrivate *pv, CK_SLOT_ID slot, gulong flags, CK_SESSION_HANDLE handle) +{ + SessionPool *pool; + GArray *array; + + g_assert (handle); + + if (pv->open_sessions == NULL) + return FALSE; + + pool = g_hash_table_lookup (pv->open_sessions, &slot); + if (!pool) { + pool = g_new0 (SessionPool, 1); + pool->funcs = pv->data.funcs; + g_hash_table_insert (pv->open_sessions, g_memdup (&slot, sizeof (slot)), pool); + } + + if (flags & CKF_RW_SESSION) { + if (!pool->rw_sessions) + pool->rw_sessions = g_array_new (FALSE, TRUE, sizeof (CK_SESSION_HANDLE)); + array = pool->rw_sessions; + } else { + if (!pool->ro_sessions) + pool->ro_sessions = g_array_new (FALSE, TRUE, sizeof (CK_SESSION_HANDLE)); + array = pool->ro_sessions; + } + + g_array_append_val (array, handle); + return TRUE; +} + +static CK_SESSION_HANDLE +pop_session_table (GP11ModulePrivate *pv, CK_SLOT_ID slot, gulong flags) +{ + CK_SESSION_HANDLE result = 0; + SessionPool *pool; + GArray **array; + + g_return_val_if_fail (pv, 0); + + if (!pv->open_sessions) + return 0; + + pool = g_hash_table_lookup (pv->open_sessions, &slot); + if (pool == NULL) + return 0; + + if (flags & CKF_RW_SESSION) + array = &pool->rw_sessions; + else + array = &pool->ro_sessions; + + if (*array == NULL) + return 0; + + g_assert ((*array)->len > 0); + result = g_array_index (*array, CK_SESSION_HANDLE, (*array)->len - 1); + g_assert (result != 0); + g_array_remove_index_fast (*array, (*array)->len - 1); + + if (!(*array)->len) { + g_array_free (*array, TRUE); + *array = NULL; + if (!pool->rw_sessions && !pool->ro_sessions) + g_hash_table_remove (pv->open_sessions, &slot); + } + + return result; +} + +static void +destroy_session_table (GP11ModulePrivate *pv) +{ + if (pv->open_sessions) + g_hash_table_unref (pv->open_sessions); + pv->open_sessions = NULL; +} + +static void +create_session_table (GP11ModulePrivate *pv) +{ + if (!pv->open_sessions) + pv->open_sessions = g_hash_table_new_full (ulong_hash, ulong_equal, g_free, free_session_pool); +} + +CK_SESSION_HANDLE +_gp11_module_pooled_session_handle (GP11Module *self, CK_SLOT_ID slot, gulong flags) +{ + GP11ModulePrivate *pv = lock_private (self); + CK_SESSION_HANDLE handle; + + g_return_val_if_fail (GP11_IS_MODULE (self), 0); + + { + handle = pop_session_table (pv, slot, flags); + } + + unlock_private (self, pv); + + return handle; +} + +gboolean +_gp11_module_pool_session_handle (GP11Session *session, CK_SESSION_HANDLE handle, GP11Module *self) +{ + GP11ModuleData *data = GP11_MODULE_GET_DATA (self); + GP11ModulePrivate *pv; + CK_SESSION_INFO info; + gboolean handled = FALSE; + CK_RV rv; + + g_return_val_if_fail (GP11_IS_SESSION (session), FALSE); + g_return_val_if_fail (GP11_IS_MODULE (self), FALSE); + + /* Get the session info so we know where to categorize this */ + rv = (data->funcs->C_GetSessionInfo) (handle, &info); + + if (rv == CKR_OK) { + + pv = lock_private (self); + + { + /* Keep this one around for later use */ + handled = push_session_table (pv, info.slotID, info.flags, handle); + } + + unlock_private (self, pv); + + } else { + + /* An already closed session, we don't want to bother with */ + if (rv == CKR_SESSION_CLOSED || rv == CKR_SESSION_HANDLE_INVALID) + handled = TRUE; + } + + return handled; +} + +gboolean +_gp11_module_fire_authenticate_slot (GP11Module *self, GP11Slot *slot, gchar *label, gchar **password) +{ + GP11TokenInfo *info; + gchar *allocated = NULL; + gboolean ret; + + g_assert (GP11_IS_MODULE (self)); + + info = gp11_slot_get_token_info (slot); + if (info != NULL) { + if (info->flags & CKF_PROTECTED_AUTHENTICATION_PATH) { + gp11_token_info_free (info); + *password = NULL; + return TRUE; + } + + if (label == NULL) + label = allocated = g_strdup (info->label); + + gp11_token_info_free (info); + } + + g_signal_emit (self, signals[AUTHENTICATE_SLOT], 0, slot, label, password, &ret); + g_free (allocated); + return ret; +} + +gboolean +_gp11_module_fire_authenticate_object (GP11Module *self, GP11Object *object, + gchar *label, gchar **password) +{ + GP11TokenInfo *info; + GP11Slot *slot; + gboolean ret; + + g_assert (GP11_IS_MODULE (self)); + g_assert (GP11_IS_OBJECT (object)); + g_assert (password); + + slot = gp11_object_get_slot (object); + info = gp11_slot_get_token_info (slot); + g_object_unref (slot); + + if (info != NULL) { + if (info->flags & CKF_PROTECTED_AUTHENTICATION_PATH) { + gp11_token_info_free (info); + *password = NULL; + return TRUE; + } + + gp11_token_info_free (info); + } + + g_signal_emit (self, signals[AUTHENTICATE_OBJECT], 0, object, label, password, &ret); + return ret; +} + /* ---------------------------------------------------------------------------- * OBJECT */ +static gboolean +gp11_module_real_authenticate_slot (GP11Module *module, GP11Slot *self, gchar *label, gchar **password) +{ + return FALSE; +} + +static gboolean +gp11_module_real_authenticate_object (GP11Module *module, GP11Object *object, gchar *label, gchar **password) +{ + return FALSE; +} + static void gp11_module_init (GP11Module *self) { - + GP11ModulePrivate *pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GP11_TYPE_MODULE, GP11ModulePrivate); + g_static_mutex_init (&pv->mutex); } static void @@ -126,8 +449,14 @@ gp11_module_get_property (GObject *obj, guint prop_id, GValue *value, case PROP_PATH: g_value_set_string (value, gp11_module_get_path (self)); break; - case PROP_FUNCTION_LIST: - g_value_set_pointer (value, gp11_module_get_function_list (self)); + case PROP_FUNCTIONS: + g_value_set_pointer (value, gp11_module_get_functions (self)); + break; + case PROP_AUTO_AUTHENTICATE: + g_value_set_boolean (value, gp11_module_get_auto_authenticate (self)); + break; + case PROP_POOL_SESSIONS: + g_value_set_boolean (value, gp11_module_get_pool_sessions (self)); break; } } @@ -136,6 +465,7 @@ static void gp11_module_set_property (GObject *obj, guint prop_id, const GValue *value, GParamSpec *pspec) { + GP11Module *self = GP11_MODULE (obj); GP11ModuleData *data = GP11_MODULE_GET_DATA (obj); /* Only allowed during initialization */ @@ -144,6 +474,16 @@ gp11_module_set_property (GObject *obj, guint prop_id, const GValue *value, g_return_if_fail (!data->path); data->path = g_value_dup_string (value); break; + case PROP_FUNCTIONS: + g_return_if_fail (!data->funcs); + data->funcs = g_value_get_pointer (value); + break; + case PROP_AUTO_AUTHENTICATE: + gp11_module_set_auto_authenticate (self, g_value_get_boolean (value)); + break; + case PROP_POOL_SESSIONS: + gp11_module_set_pool_sessions (self, g_value_get_boolean (value)); + break; } } @@ -151,12 +491,23 @@ static void gp11_module_dispose (GObject *obj) { GP11ModuleData *data = GP11_MODULE_GET_DATA (obj); - gint finalized = g_atomic_int_get (&data->finalized); + GP11ModulePrivate *pv = lock_private (obj); + gboolean finalize = FALSE; CK_RV rv; + + { + destroy_session_table (pv); + + if (!pv->finalized && data->initialized && data->funcs) { + finalize = TRUE; + pv->finalized = TRUE; + } + } + + unlock_private (obj, pv); /* Must be careful when accessing funcs */ - if (data->funcs && !finalized && - g_atomic_int_compare_and_exchange (&data->finalized, finalized, 1)) { + if (finalize) { rv = (data->funcs->C_Finalize) (NULL); if (rv != CKR_OK) { g_warning ("C_Finalize on module '%s' failed: %s", @@ -170,8 +521,11 @@ gp11_module_dispose (GObject *obj) static void gp11_module_finalize (GObject *obj) { + GP11ModulePrivate *pv = G_TYPE_INSTANCE_GET_PRIVATE (obj, GP11_TYPE_MODULE, GP11ModulePrivate); GP11ModuleData *data = GP11_MODULE_GET_DATA (obj); + g_assert (!pv->open_sessions); + data->funcs = NULL; if (data->module) { @@ -180,10 +534,12 @@ gp11_module_finalize (GObject *obj) g_module_error ()); data->module = NULL; } - + g_free (data->path); data->path = NULL; + g_static_mutex_free (&pv->mutex); + G_OBJECT_CLASS (gp11_module_parent_class)->finalize (obj); } @@ -199,13 +555,34 @@ gp11_module_class_init (GP11ModuleClass *klass) gobject_class->dispose = gp11_module_dispose; gobject_class->finalize = gp11_module_finalize; + klass->authenticate_object = gp11_module_real_authenticate_object; + klass->authenticate_slot = gp11_module_real_authenticate_slot; + g_object_class_install_property (gobject_class, PROP_PATH, g_param_spec_string ("path", "Module Path", "Path to the PKCS11 Module", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - g_object_class_install_property (gobject_class, PROP_FUNCTION_LIST, - g_param_spec_pointer ("function-list", "Function List", "PKCS11 Function List", - G_PARAM_READABLE)); + g_object_class_install_property (gobject_class, PROP_FUNCTIONS, + g_param_spec_pointer ("functions", "Function List", "PKCS11 Function List", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property (gobject_class, PROP_AUTO_AUTHENTICATE, + g_param_spec_boolean ("auto-authenticate", "Auto Authenticate", "Auto Login to Token when necessary", + FALSE, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_POOL_SESSIONS, + g_param_spec_boolean ("pool-sessions", "Pool Sessions", "Pool sessions?", + FALSE, G_PARAM_READWRITE)); + + signals[AUTHENTICATE_SLOT] = g_signal_new ("authenticate-slot", GP11_TYPE_MODULE, + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GP11ModuleClass, authenticate_slot), + g_signal_accumulator_true_handled, NULL, _gp11_marshal_BOOLEAN__OBJECT_STRING_POINTER, + G_TYPE_BOOLEAN, 3, GP11_TYPE_SLOT, G_TYPE_STRING, G_TYPE_POINTER); + + signals[AUTHENTICATE_OBJECT] = g_signal_new ("authenticate-object", GP11_TYPE_MODULE, + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GP11ModuleClass, authenticate_object), + g_signal_accumulator_true_handled, NULL, _gp11_marshal_BOOLEAN__OBJECT_STRING_POINTER, + G_TYPE_BOOLEAN, 3, GP11_TYPE_OBJECT, G_TYPE_STRING, G_TYPE_POINTER); g_type_class_add_private (gobject_class, sizeof (GP11ModulePrivate)); } @@ -278,44 +655,9 @@ gp11_module_initialize (const gchar *path, gpointer reserved, GError **err) return NULL; } - mod = gp11_module_initialize_with_functions (funcs, reserved, err); - if (mod == NULL) { - g_module_close (module); - return NULL; - } - + mod = g_object_new (GP11_TYPE_MODULE, "functions", funcs, "path", path, NULL); data = GP11_MODULE_GET_DATA (mod); - data->path = g_strdup (path); data->module = module; - - return mod; -} - -/** - * gp11_module_initialize_with_functions: - * @funcs: Initialized PKCS#11 function list pointer - * @reserved: Extra arguments for the PKCS#11 module, should usually be NULL. - * @err: A location to store an error resulting from a failed load. - * - * Initialize a PKCS#11 module represented by a GP11Module object. - * - * Return value: The loaded PKCS#11 module or NULL if failed. - **/ -GP11Module* -gp11_module_initialize_with_functions (CK_FUNCTION_LIST_PTR funcs, gpointer reserved, - GError **err) -{ - GP11ModuleData *data; - GP11Module *mod; - CK_RV rv; - - g_return_val_if_fail (funcs, NULL); - g_return_val_if_fail (!err || !*err, NULL); - - mod = g_object_new (GP11_TYPE_MODULE, NULL); - data = GP11_MODULE_GET_DATA (mod); - - data->funcs = funcs; memset (&data->init_args, 0, sizeof (data->init_args)); data->init_args.flags = CKF_OS_LOCKING_OK; @@ -333,11 +675,30 @@ gp11_module_initialize_with_functions (CK_FUNCTION_LIST_PTR funcs, gpointer rese g_object_unref (mod); return NULL; } - + + data->initialized = TRUE; return mod; } /** + * gp11_module_new: + * @funcs: Initialized PKCS#11 function list pointer + * @reserved: Extra arguments for the PKCS#11 module, should usually be NULL. + * @err: A location to store an error resulting from a failed load. + * + * Create a GP11Module representing a PKCS#11 module. It is assumed that + * this the module is already initialized. In addition it will not be + * finalized when complete. + * + * Return value: The new PKCS#11 module. + **/ +GP11Module* +gp11_module_new (CK_FUNCTION_LIST_PTR funcs) +{ + return g_object_new (GP11_TYPE_MODULE, "functions", funcs, NULL); +} + +/** * gp11_module_get_info: * @self: The module to get info for. * @@ -444,7 +805,7 @@ gp11_module_get_path (GP11Module *self) } /** - * gp11_module_get_function_list: + * gp11_module_get_functions: * @self: The module for which to get the function list. * * Get the PKCS#11 function list for the module. @@ -452,9 +813,239 @@ gp11_module_get_path (GP11Module *self) * Return value: The function list, do not modify this structure. **/ CK_FUNCTION_LIST_PTR -gp11_module_get_function_list (GP11Module *self) +gp11_module_get_functions (GP11Module *self) { GP11ModuleData *data = GP11_MODULE_GET_DATA (self); g_return_val_if_fail (GP11_IS_MODULE (self), NULL); return data->funcs; } + + +/** + * gp11_module_get_pool_sessions: + * @self: The module to get setting from. + * + * Get the reuse sessions setting. When this is set, sessions + * will be pooled and reused if their flags match when + * gp11_slot_open_session() is called. + * + * Return value: Whether reusing sessions or not. + **/ +gboolean +gp11_module_get_pool_sessions (GP11Module *self) +{ + GP11ModulePrivate *pv = lock_private (self); + gboolean ret; + + g_return_val_if_fail (pv, FALSE); + + { + ret = pv->open_sessions != NULL; + } + + unlock_private (self, pv); + + return ret; +} + +/** + * gp11_module_set_pool_sessions: + * @self: The module to set the setting on. + * @reuse: Whether to reuse sessions or not. + * + * When this is set, sessions will be pooled and reused + * if their flags match when gp11_slot_open_session() is called. + **/ +void +gp11_module_set_pool_sessions (GP11Module *self, gboolean pool) +{ + GP11ModulePrivate *pv = lock_private (self); + + g_return_if_fail (pv); + + { + if (pool) + create_session_table (pv); + else + destroy_session_table (pv); + } + + unlock_private (self, pv); + g_object_notify (G_OBJECT (self), "pool-sessions"); +} + +/** + * gp11_module_get_auto_authenticate: + * @self: The module to get setting from. + * + * Get the auto login setting. When this is set, this slot + * will emit the 'authenticate-slot' signal when a session + * requires authentication, and the 'authenticate-object' + * signal when an object requires authintication. + * + * Return value: Whether auto login or not. + **/ +gboolean +gp11_module_get_auto_authenticate (GP11Module *self) +{ + GP11ModulePrivate *pv = lock_private (self); + gboolean ret; + + g_return_val_if_fail (pv, FALSE); + + { + ret = pv->auto_authenticate; + } + + unlock_private (self, pv); + + return ret; +} + +/** + * gp11_module_set_auto_authenticate: + * @self: The module to set the setting on. + * @auto_login: Whether auto login or not. + * + * When this is set, this slot + * will emit the 'authenticate-slot' signal when a session + * requires authentication, and the 'authenticate-object' + * signal when an object requires authintication. + **/ +void +gp11_module_set_auto_authenticate (GP11Module *self, gboolean auto_login) +{ + GP11ModulePrivate *pv = lock_private (self); + + g_return_if_fail (pv); + + { + pv->auto_authenticate = auto_login; + } + + unlock_private (self, pv); + g_object_notify (G_OBJECT (self), "auto-authenticate"); +} + +/** + * gp11_module_enumerate_objects: + * @self: The module to enumerate objects. + * @attrs: Attributes that the objects must have, or empty for all objects. + * @func: Function to call for each object. + * @user_data: Data to pass to the function. + * + * Call a function for every matching object on the module. This call may + * block for an indefinite period. + * + * The arguments must be triples of: attribute type, data type, value + * + * <para>The variable argument list should contain: + * <variablelist> + * <varlistentry> + * <term>a)</term> + * <listitem><para>The gulong attribute type (ie: CKA_LABEL). </para></listitem> + * </varlistentry> + * <varlistentry> + * <term>b)</term> + * <listitem><para>The attribute data type (one of GP11_BOOLEAN, GP11_ULONG, + * GP11_STRING, GP11_DATE) orthe raw attribute value length.</para></listitem> + * </varlistentry> + * <varlistentry> + * <term>c)</term> + * <listitem><para>The attribute value, either a gboolean, gulong, gchar*, GDate* or + * a pointer to a raw attribute value.</para></listitem> + * </varlistentry> + * </variablelist> + * The variable argument list should be terminated with GP11_INVALID.</para> + * + * This function will open a session per slot. It's recommended that you + * set the 'reuse-sessions' property on each slot if you'll be calling + * it a lot. + * + * You can access the session in which the object was found, by using the + * gp11_object_get_session() function on the resulting objects. + * + * The function can return FALSE to stop the enumeration. + **/ +void +gp11_module_enumerate_objects (GP11Module *self, GP11ObjectForeachFunc func, + gpointer user_data, ...) +{ + GP11Attributes *attrs; + va_list va; + + va_start (va, user_data); + attrs = gp11_attributes_new_valist (g_realloc, va); + va_end (va); + + gp11_module_enumerate_objects_full (self, attrs, NULL, func, user_data); + gp11_attributes_unref (attrs); +} + +/** + * gp11_module_enumerate_objects_full: + * @self: The module to enumerate objects. + * @attrs: Attributes that the objects must have, or empty for all objects. + * @cancellable: Optional cancellation object, or NULL. + * @func: Function to call for each object. + * @user_data: Data to pass to the function. + * + * Call a function for every matching object on the module. This call may + * block for an indefinite period. + * + * This function will open a session per slot. It's recommended that you + * set the 'reuse-sessions' property on each slot if you'll be calling + * it a lot. + * + * You can access the session in which the object was found, by using the + * gp11_object_get_session() function on the resulting objects. + * + * The function can return FALSE to stop the enumeration. + **/ +void +gp11_module_enumerate_objects_full (GP11Module *self, GP11Attributes *attrs, + GCancellable *cancellable, GP11ObjectForeachFunc func, + gpointer user_data) +{ + gboolean stop = FALSE; + GList *objects, *o; + GList *slots, *l; + GError *error = NULL; + GP11Session *session; + + g_return_if_fail (GP11_IS_MODULE (self)); + g_return_if_fail (attrs); + g_return_if_fail (func); + + gp11_attributes_ref (attrs); + slots = gp11_module_get_slots (self, TRUE); + + for (l = slots; !stop && l; l = g_list_next (l)) { + session = gp11_slot_open_session (l->data, CKF_SERIAL_SESSION, &error); + if (error) { + g_warning ("couldn't open session on slot: %s", error->message); + g_clear_error (&error); + } + + objects = gp11_session_find_objects_full (session, attrs, cancellable, &error); + if (error) { + g_warning ("couldn't find objects on slot: %s", error->message); + g_clear_error (&error); + } + + for (o = objects; !stop && o; o = g_list_next (o)) { + gp11_object_set_session (o->data, session); + if (!(func)(o->data, user_data)) { + stop = TRUE; + break; + } + } + + g_object_unref (session); + gp11_list_unref_free (objects); + } + + gp11_list_unref_free (slots); + gp11_attributes_unref (attrs); +} + diff --git a/gp11/gp11-private.h b/gp11/gp11-private.h index b251c9ea..bd33df02 100644 --- a/gp11/gp11-private.h +++ b/gp11/gp11-private.h @@ -50,19 +50,32 @@ CK_ATTRIBUTE_PTR _gp11_attributes_commit_out (GP11Attributes *att CK_ULONG_PTR n_attrs); /* ---------------------------------------------------------------------------- - * SLOT + * MODULE */ -gboolean _gp11_slot_fire_authenticate_token (GP11Slot *slot, - gchar *label, - gchar **password); +gboolean _gp11_module_fire_authenticate_slot (GP11Module *module, + GP11Slot *slot, + gchar *label, + gchar **password); + +gboolean _gp11_module_fire_authenticate_object (GP11Module *module, + GP11Object *object, + gchar *label, + gchar **password); + +gboolean _gp11_module_pool_session_handle (GP11Session *session, + CK_SESSION_HANDLE handle, + GP11Module *self); + +CK_SESSION_HANDLE _gp11_module_pooled_session_handle (GP11Module *module, + CK_SLOT_ID slot, + gulong flags); -gboolean _gp11_slot_fire_authenticate_object (GP11Slot *slot, - GP11Object *object, - gchar *label, - gchar **password); +/* ---------------------------------------------------------------------------- + * SLOT + */ -gboolean _gp11_slot_is_protected_auth_path (GP11Slot *slot); +gboolean _gp11_slot_is_protected_auth_path (GP11Slot *slot); /* ---------------------------------------------------------------------------- * CALL diff --git a/gp11/gp11-session.c b/gp11/gp11-session.c index feab0dab..d8ee9ff0 100644 --- a/gp11/gp11-session.c +++ b/gp11/gp11-session.c @@ -120,7 +120,7 @@ gp11_session_real_discard_handle (GP11Session *self, CK_OBJECT_HANDLE handle) g_return_val_if_fail (data->module, FALSE); g_object_ref (data->module); - funcs = gp11_module_get_function_list (data->module); + funcs = gp11_module_get_functions (data->module); g_return_val_if_fail (funcs, FALSE); rv = (funcs->C_CloseSession) (handle); @@ -386,7 +386,7 @@ gp11_session_get_info (GP11Session *self) g_object_ref (data->module); - funcs = gp11_module_get_function_list (data->module); + funcs = gp11_module_get_functions (data->module); g_return_val_if_fail (funcs, NULL); memset (&info, 0, sizeof (info)); @@ -989,7 +989,7 @@ typedef enum _AuthenticateState { typedef struct _Authenticate { AuthenticateState state; gboolean protected_auth; - GP11Slot *slot; + GP11Module *module; GP11Object *object; gchar *label; gchar *password; @@ -1106,21 +1106,21 @@ authenticate_complete (Authenticate *auth, GP11Arguments *base, CK_RV result) /* We're done here if not in this state */ if (auth->state == AUTHENTICATE_WANT) { - g_assert (GP11_IS_SLOT (auth->slot)); + g_assert (GP11_IS_MODULE (auth->module)); g_assert (GP11_IS_OBJECT (auth->object)); g_free (auth->password); auth->password = NULL; - if (_gp11_slot_fire_authenticate_object (auth->slot, auth->object, auth->label, &auth->password)) { + if (_gp11_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->slot) - g_object_unref (auth->slot); + if (auth->module) + g_object_unref (auth->module); if (auth->object) g_object_unref (auth->object); g_free (auth->label); @@ -1133,16 +1133,20 @@ authenticate_complete (Authenticate *auth, GP11Arguments *base, CK_RV result) static void authenticate_init (Authenticate *auth, GP11Slot *slot, GP11Object *object) { + GP11Module *module; + g_assert (GP11_IS_SLOT (slot)); g_assert (GP11_IS_OBJECT (object)); - if (gp11_slot_get_auto_login (slot)) { + module = gp11_slot_get_module (slot); + if (gp11_module_get_auto_authenticate (module)) { auth->state = AUTHENTICATE_CAN; auth->protected_auth = _gp11_slot_is_protected_auth_path (slot); - auth->slot = g_object_ref (slot); + auth->module = module; auth->object = g_object_ref (object); } else { auth->state = AUTHENTICATE_NONE; + g_object_unref (module); } } @@ -1339,7 +1343,7 @@ gp11_session_encrypt_full (GP11Session *self, GP11Object *key, GP11Mechanism *me g_object_get (self, "module", &module, NULL); g_return_val_if_fail (module != NULL, NULL); - funcs = gp11_module_get_function_list (module); + funcs = gp11_module_get_functions (module); g_return_val_if_fail (module != NULL, NULL); ret = crypt_sync (self, key, mech_args, input, n_input, n_result, cancellable, err, @@ -1360,7 +1364,7 @@ gp11_session_encrypt_async (GP11Session *self, GP11Object *key, GP11Mechanism *m g_object_get (self, "module", &module, NULL); g_return_if_fail (module != NULL); - funcs = gp11_module_get_function_list (module); + funcs = gp11_module_get_functions (module); g_return_if_fail (module != NULL); crypt_async (self, key, mech_args, input, n_input, cancellable, callback, user_data, @@ -1400,7 +1404,7 @@ gp11_session_decrypt_full (GP11Session *self, GP11Object *key, GP11Mechanism *me g_object_get (self, "module", &module, NULL); g_return_val_if_fail (module != NULL, NULL); - funcs = gp11_module_get_function_list (module); + funcs = gp11_module_get_functions (module); g_return_val_if_fail (module != NULL, NULL); ret = crypt_sync (self, key, mech_args, input, n_input, n_result, cancellable, err, @@ -1420,7 +1424,7 @@ gp11_session_decrypt_async (GP11Session *self, GP11Object *key, GP11Mechanism *m g_object_get (self, "module", &module, NULL); g_return_if_fail (module != NULL); - funcs = gp11_module_get_function_list (module); + funcs = gp11_module_get_functions (module); g_return_if_fail (module != NULL); crypt_async (self, key, mech_args, input, n_input, cancellable, callback, user_data, @@ -1459,7 +1463,7 @@ gp11_session_sign_full (GP11Session *self, GP11Object *key, GP11Mechanism *mech_ g_object_get (self, "module", &module, NULL); g_return_val_if_fail (module != NULL, NULL); - funcs = gp11_module_get_function_list (module); + funcs = gp11_module_get_functions (module); g_return_val_if_fail (module != NULL, NULL); ret = crypt_sync (self, key, mech_args, input, n_input, n_result, cancellable, err, @@ -1479,7 +1483,7 @@ gp11_session_sign_async (GP11Session *self, GP11Object *key, GP11Mechanism *mech g_object_get (self, "module", &module, NULL); g_return_if_fail (module != NULL); - funcs = gp11_module_get_function_list (module); + funcs = gp11_module_get_functions (module); g_return_if_fail (module != NULL); crypt_async (self, key, mech_args, input, n_input, cancellable, callback, user_data, diff --git a/gp11/gp11-slot.c b/gp11/gp11-slot.c index a285500c..fb96f140 100644 --- a/gp11/gp11-slot.c +++ b/gp11/gp11-slot.c @@ -25,22 +25,13 @@ #include "gp11.h" #include "gp11-private.h" -#include "gp11-marshal.h" #include <string.h> enum { PROP_0, PROP_MODULE, - PROP_HANDLE, - PROP_REUSE_SESSIONS, - PROP_AUTO_LOGIN -}; - -enum { - AUTHENTICATE_TOKEN, - AUTHENTICATE_OBJECT, - LAST_SIGNAL + PROP_HANDLE }; typedef struct _GP11SlotData { @@ -50,10 +41,6 @@ typedef struct _GP11SlotData { typedef struct _GP11SlotPrivate { GP11SlotData data; - GStaticMutex mutex; - gboolean auto_login; - GHashTable *open_sessions; - GP11TokenInfo *token_info; } GP11SlotPrivate; G_DEFINE_TYPE (GP11Slot, gp11_slot, G_TYPE_OBJECT); @@ -61,14 +48,6 @@ G_DEFINE_TYPE (GP11Slot, gp11_slot, G_TYPE_OBJECT); #define GP11_SLOT_GET_DATA(o) \ (G_TYPE_INSTANCE_GET_PRIVATE((o), GP11_TYPE_SLOT, GP11SlotData)) -typedef struct _SessionPool { - gulong flags; - GP11Module *module; /* weak */ - GArray *sessions; /* array of CK_SESSION_HANDLE */ -} SessionPool; - -static guint signals[LAST_SIGNAL] = { 0 }; - #ifndef HAVE_TIMEGM time_t @@ -106,213 +85,24 @@ timegm(struct tm *t) * HELPERS */ -static guint -ulong_hash (gconstpointer v) -{ - const signed char *p = v; - guint32 i, h = *p; - - for(i = 0; i < sizeof (gulong); ++i) - h = (h << 5) - h + *(p++); - - return h; -} - -static gboolean -ulong_equal (gconstpointer v1, gconstpointer v2) -{ - return *((const gulong*)v1) == *((const gulong*)v2); -} - -static void -close_session (GP11Module *module, CK_SESSION_HANDLE handle) -{ - CK_FUNCTION_LIST_PTR funcs; - CK_RV rv; - - g_return_if_fail (GP11_IS_MODULE (module)); - - g_object_ref (module); - - funcs = gp11_module_get_function_list (module); - g_return_if_fail (funcs); - - rv = (funcs->C_CloseSession) (handle); - if (rv != CKR_OK) { - g_warning ("couldn't close session properly: %s", - gp11_message_from_rv (rv)); - } - - g_object_unref (module); -} - -static GP11SlotPrivate* -lock_private (gpointer obj) -{ - GP11SlotPrivate *pv; - GP11Slot *self; - - g_assert (GP11_IS_SLOT (obj)); - self = GP11_SLOT (obj); - - g_object_ref (self); - - pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GP11_TYPE_SLOT, GP11SlotPrivate); - g_static_mutex_lock (&pv->mutex); - - return pv; -} - -static void -unlock_private (gpointer obj, GP11SlotPrivate *pv) -{ - GP11Slot *self; - - g_assert (pv); - g_assert (GP11_IS_SLOT (obj)); - - self = GP11_SLOT (obj); - - g_assert (G_TYPE_INSTANCE_GET_PRIVATE (self, GP11_TYPE_SLOT, GP11SlotPrivate) == pv); - - g_static_mutex_unlock (&pv->mutex); - g_object_unref (self); -} - -static void -free_session_pool (gpointer p) -{ - SessionPool *pool = p; - guint i; - - for(i = 0; i < pool->sessions->len; ++i) - close_session (pool->module, g_array_index(pool->sessions, CK_SESSION_HANDLE, i)); - g_array_free(pool->sessions, TRUE); - g_free (pool); -} - -static gboolean -push_session_table (GP11SlotPrivate *pv, gulong flags, CK_SESSION_HANDLE handle) -{ - SessionPool *pool; - - g_assert (handle); - g_assert (GP11_IS_MODULE (pv->data.module)); - - if (pv->open_sessions == NULL) - return FALSE; - - pool = g_hash_table_lookup (pv->open_sessions, &flags); - if (!pool) { - pool = g_new0 (SessionPool, 1); - pool->flags = flags; - pool->module = pv->data.module; /* weak ref */ - pool->sessions = g_array_new (FALSE, TRUE, sizeof (CK_SESSION_HANDLE)); - g_hash_table_insert (pv->open_sessions, g_memdup (&flags, sizeof (flags)), pool); - } - - g_assert (pool->flags == flags); - g_array_append_val (pool->sessions, handle); - return TRUE; -} - -static CK_SESSION_HANDLE -pop_session_table (GP11SlotPrivate *pv, gulong flags) -{ - CK_SESSION_HANDLE result = 0; - SessionPool *pool; - - g_return_val_if_fail (pv, 0); - - - g_assert (GP11_IS_MODULE (pv->data.module)); - - if (pv->open_sessions) { - pool = g_hash_table_lookup (pv->open_sessions, &flags); - if (pool) { - g_assert (pool->sessions->len > 0); - result = g_array_index (pool->sessions, CK_SESSION_HANDLE, pool->sessions->len - 1); - g_assert (result != 0); - g_array_remove_index_fast (pool->sessions, pool->sessions->len - 1); - if (!pool->sessions->len) - g_hash_table_remove(pv->open_sessions, &flags); - } - } - - return result; -} - -static void -destroy_session_table (GP11SlotPrivate *pv) -{ - if (pv->open_sessions) - g_hash_table_unref (pv->open_sessions); - pv->open_sessions = NULL; -} - -static void -create_session_table (GP11SlotPrivate *pv) -{ - if (!pv->open_sessions) - pv->open_sessions = g_hash_table_new_full (ulong_hash, ulong_equal, g_free, free_session_pool); -} - -static gboolean -reuse_session_handle (GP11Session *session, CK_SESSION_HANDLE handle, GP11Slot *self) -{ - GP11SlotData *data = GP11_SLOT_GET_DATA (self); - GP11SlotPrivate *pv; - CK_FUNCTION_LIST_PTR funcs; - CK_SESSION_INFO info; - gboolean handled = FALSE; - CK_RV rv; - - g_return_val_if_fail (GP11_IS_SESSION (session), FALSE); - g_return_val_if_fail (GP11_IS_SLOT (self), FALSE); - - funcs = gp11_module_get_function_list (data->module); - g_return_val_if_fail (funcs, FALSE); - - /* Get the session info so we know where to categorize this */ - rv = (funcs->C_GetSessionInfo) (handle, &info); - - if (rv == CKR_OK) { - - /* Keep this one around for later use */ - pv = lock_private (self); - - { - handled = push_session_table (pv, info.flags, handle); - } - - unlock_private (self, pv); - - } else { - - /* An already closed session, we don't want to bother with */ - if (rv == CKR_SESSION_CLOSED || rv == CKR_SESSION_HANDLE_INVALID) - handled = TRUE; - } - - return handled; -} - static GP11Session* make_session_object (GP11Slot *self, gulong flags, CK_SESSION_HANDLE handle) { GP11Session *session; + GP11Module *module; g_return_val_if_fail (handle != 0, NULL); - g_object_ref (self); - - session = gp11_session_from_handle (self, handle); - g_return_val_if_fail (session != NULL, NULL); - - /* Session keeps a reference to us, so this is safe */ - g_signal_connect (session, "discard-handle", G_CALLBACK (reuse_session_handle), self); + module = gp11_slot_get_module (self); + + session = gp11_session_from_handle (self, handle); + g_return_val_if_fail (session != NULL, NULL); - g_object_unref (self); + /* Session keeps a reference to module so this is safe */ + g_signal_connect (session, "discard-handle", + G_CALLBACK (_gp11_module_pool_session_handle), module); + + g_object_unref (module); return session; } @@ -321,23 +111,10 @@ make_session_object (GP11Slot *self, gulong flags, CK_SESSION_HANDLE handle) * OBJECT */ -static gboolean -gp11_slot_real_authenticate_token (GP11Slot *self, gchar *label, gchar **password) -{ - return FALSE; -} - -static gboolean -gp11_slot_real_authenticate_object (GP11Slot *self, GP11Object *object, gchar *label, gchar **password) -{ - return FALSE; -} - static void gp11_slot_init (GP11Slot *self) { - GP11SlotPrivate *pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GP11_TYPE_SLOT, GP11SlotPrivate); - g_static_mutex_init (&pv->mutex); + } static void @@ -353,12 +130,6 @@ gp11_slot_get_property (GObject *obj, guint prop_id, GValue *value, case PROP_HANDLE: g_value_set_ulong (value, gp11_slot_get_handle (self)); break; - case PROP_AUTO_LOGIN: - g_value_set_boolean (value, gp11_slot_get_auto_login (self)); - break; - case PROP_REUSE_SESSIONS: - g_value_set_boolean (value, gp11_slot_get_reuse_sessions (self)); - break; } } @@ -367,7 +138,6 @@ gp11_slot_set_property (GObject *obj, guint prop_id, const GValue *value, GParamSpec *pspec) { GP11SlotData *data = GP11_SLOT_GET_DATA (obj); - GP11Slot *self = GP11_SLOT (obj); /* All writes to data members below, happen only during construct phase */ @@ -382,50 +152,26 @@ gp11_slot_set_property (GObject *obj, guint prop_id, const GValue *value, g_assert (!data->handle); data->handle = g_value_get_ulong (value); break; - case PROP_AUTO_LOGIN: - gp11_slot_set_auto_login (self, g_value_get_boolean (value)); - break; - case PROP_REUSE_SESSIONS: - gp11_slot_set_reuse_sessions (self, g_value_get_boolean (value)); - break; } } static void gp11_slot_dispose (GObject *obj) { - GP11SlotPrivate *pv = lock_private (obj); - - { - /* Need to do this before the module goes away */ - destroy_session_table (pv); - } - - unlock_private (obj, pv); - G_OBJECT_CLASS (gp11_slot_parent_class)->dispose (obj); } static void gp11_slot_finalize (GObject *obj) { - GP11SlotPrivate *pv = G_TYPE_INSTANCE_GET_PRIVATE (obj, GP11_TYPE_SLOT, GP11SlotPrivate); GP11SlotData *data = GP11_SLOT_GET_DATA (obj); data->handle = 0; - g_assert (!pv->open_sessions); - if (data->module) g_object_unref (data->module); data->module = NULL; - - if (pv->token_info) - gp11_token_info_free (pv->token_info); - pv->token_info = NULL; - g_static_mutex_free (&pv->mutex); - G_OBJECT_CLASS (gp11_slot_parent_class)->finalize (obj); } @@ -441,9 +187,6 @@ gp11_slot_class_init (GP11SlotClass *klass) gobject_class->dispose = gp11_slot_dispose; gobject_class->finalize = gp11_slot_finalize; - klass->authenticate_object = gp11_slot_real_authenticate_object; - klass->authenticate_token = gp11_slot_real_authenticate_token; - g_object_class_install_property (gobject_class, PROP_MODULE, g_param_spec_object ("module", "Module", "PKCS11 Module", GP11_TYPE_MODULE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); @@ -452,25 +195,6 @@ gp11_slot_class_init (GP11SlotClass *klass) g_param_spec_ulong ("handle", "Handle", "PKCS11 Slot ID", 0, G_MAXULONG, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - g_object_class_install_property (gobject_class, PROP_AUTO_LOGIN, - g_param_spec_boolean ("auto-login", "Auto Login", "Auto Login to Token when necessary", - FALSE, G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_REUSE_SESSIONS, - g_param_spec_boolean ("reuse-sessions", "Reuse Sessions", "Reuse sessions?", - FALSE, G_PARAM_READWRITE)); - - signals[AUTHENTICATE_TOKEN] = g_signal_new ("authenticate-token", GP11_TYPE_SLOT, - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GP11SlotClass, authenticate_token), - g_signal_accumulator_true_handled, NULL, _gp11_marshal_BOOLEAN__STRING_POINTER, - G_TYPE_BOOLEAN, 2, G_TYPE_STRING, G_TYPE_POINTER); - - signals[AUTHENTICATE_OBJECT] = g_signal_new ("authenticate-object", GP11_TYPE_SLOT, - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GP11SlotClass, authenticate_object), - g_signal_accumulator_true_handled, NULL, _gp11_marshal_BOOLEAN__OBJECT_STRING_POINTER, - G_TYPE_BOOLEAN, 3, G_TYPE_OBJECT, G_TYPE_STRING, G_TYPE_POINTER); - - g_type_class_add_private (gobject_class, sizeof (GP11SlotPrivate)); } @@ -478,74 +202,17 @@ gp11_slot_class_init (GP11SlotClass *klass) * INTERNAL AUTHENTICATION */ - -gboolean -_gp11_slot_fire_authenticate_token (GP11Slot *self, gchar *label, gchar **password) -{ - GP11SlotPrivate *pv = lock_private (self); - gboolean protected_auth = FALSE; - gchar *allocated = NULL; - gboolean ret; - - g_assert (GP11_IS_SLOT (self)); - g_assert (pv); - - { - if (!pv->token_info) - pv->token_info = gp11_slot_get_token_info (self); - if (pv->token_info) { - protected_auth = (pv->token_info->flags & CKF_PROTECTED_AUTHENTICATION_PATH) ? TRUE : FALSE; - if (!label) - label = allocated = g_strdup (pv->token_info->label); - } - } - - unlock_private (self, pv); - - if (protected_auth) { - *password = NULL; - return TRUE; - } - - g_signal_emit (self, signals[AUTHENTICATE_TOKEN], 0, label, password, &ret); - g_free (allocated); - return ret; -} - -gboolean -_gp11_slot_fire_authenticate_object (GP11Slot *self, GP11Object *object, - gchar *label, gchar **password) -{ - gboolean ret; - - g_assert (GP11_IS_SLOT (self)); - g_assert (password); - - if (_gp11_slot_is_protected_auth_path (self)) { - *password = NULL; - return TRUE; - } - - g_signal_emit (self, signals[AUTHENTICATE_OBJECT], 0, object, label, password, &ret); - return ret; -} - gboolean _gp11_slot_is_protected_auth_path (GP11Slot *self) { - GP11SlotPrivate *pv = lock_private (self); + GP11TokenInfo *info; gboolean ret; g_assert (GP11_IS_SLOT (self)); - g_assert (pv); - { - if (!pv->token_info) - pv->token_info = gp11_slot_get_token_info (self); - ret = (pv->token_info && pv->token_info->flags & CKF_PROTECTED_AUTHENTICATION_PATH); - } - - unlock_private (self, pv); + info = gp11_slot_get_token_info (self); + ret = (info && info->flags & CKF_PROTECTED_AUTHENTICATION_PATH); + gp11_token_info_free (info); return ret; } @@ -636,110 +303,6 @@ gp11_slot_get_module (GP11Slot *self) } /** - * gp11_slot_get_reuse_sessions: - * @self: The slot to get setting from. - * - * Get the reuse sessions setting. When this is set, sessions - * will be pooled and reused if their flags match when - * gp11_slot_open_session() is called. - * - * Return value: Whether reusing sessions or not. - **/ -gboolean -gp11_slot_get_reuse_sessions (GP11Slot *self) -{ - GP11SlotPrivate *pv = lock_private (self); - gboolean ret; - - g_return_val_if_fail (pv, FALSE); - - { - ret = pv->open_sessions != NULL; - } - - unlock_private (self, pv); - - return ret; -} - -/** - * gp11_slot_set_reuse_sessions: - * @self: The slot to set the setting on. - * @reuse: Whether to reuse sessions or not. - * - * When this is set, sessions will be pooled and reused - * if their flags match when gp11_slot_open_session() is called. - **/ -void -gp11_slot_set_reuse_sessions (GP11Slot *self, gboolean reuse) -{ - GP11SlotPrivate *pv = lock_private (self); - - g_return_if_fail (pv); - - { - if (reuse) - create_session_table (pv); - else - destroy_session_table (pv); - } - - unlock_private (self, pv); - g_object_notify (G_OBJECT (self), "reuse-sessions"); -} - -/** - * gp11_slot_get_auto_login: - * @self: The slot to get setting from. - * - * Get the auto login setting. When this is set, this slot - * will emit the 'authenticate-token' signal when a session - * requires authentication. - * - * Return value: Whether auto login or not. - **/ -gboolean -gp11_slot_get_auto_login (GP11Slot *self) -{ - GP11SlotPrivate *pv = lock_private (self); - gboolean ret; - - g_return_val_if_fail (pv, FALSE); - - { - ret = pv->auto_login; - } - - unlock_private (self, pv); - - return ret; -} - -/** - * gp11_slot_set_auto_login: - * @self: The slot to set the setting on. - * @auto_login: Whether auto login or not. - * - * When this is set, this slot - * will emit the 'authenticate-token' signal when a session - * requires authentication. - **/ -void -gp11_slot_set_auto_login (GP11Slot *self, gboolean auto_login) -{ - GP11SlotPrivate *pv = lock_private (self); - - g_return_if_fail (pv); - - { - pv->auto_login = auto_login; - } - - unlock_private (self, pv); - g_object_notify (G_OBJECT (self), "auto-login"); -} - -/** * gp11_slot_get_info: * @self: The slot to get info for. * @@ -763,7 +326,7 @@ gp11_slot_get_info (GP11Slot *self) g_object_get (self, "module", &module, "handle", &handle, NULL); g_return_val_if_fail (GP11_IS_MODULE (module), NULL); - funcs = gp11_module_get_function_list (module); + funcs = gp11_module_get_functions (module); g_return_val_if_fail (funcs, NULL); memset (&info, 0, sizeof (info)); @@ -816,7 +379,7 @@ gp11_slot_get_token_info (GP11Slot *self) g_object_get (self, "module", &module, "handle", &handle, NULL); g_return_val_if_fail (GP11_IS_MODULE (module), NULL); - funcs = gp11_module_get_function_list (module); + funcs = gp11_module_get_functions (module); g_return_val_if_fail (funcs, NULL); memset (&info, 0, sizeof (info)); @@ -891,7 +454,7 @@ gp11_slot_get_mechanisms (GP11Slot *self) g_object_get (self, "module", &module, "handle", &handle, NULL); g_return_val_if_fail (GP11_IS_MODULE (module), NULL); - funcs = gp11_module_get_function_list (module); + funcs = gp11_module_get_functions (module); g_return_val_if_fail (funcs, NULL); rv = (funcs->C_GetMechanismList) (handle, NULL, &count); @@ -948,7 +511,7 @@ gp11_slot_get_mechanism_info (GP11Slot *self, gulong mech_type) g_object_get (self, "module", &module, "handle", &handle, NULL); g_return_val_if_fail (GP11_IS_MODULE (module), NULL); - funcs = gp11_module_get_function_list (module); + funcs = gp11_module_get_functions (module); g_return_val_if_fail (funcs, NULL); memset (&info, 0, sizeof (info)); @@ -1023,6 +586,7 @@ typedef struct OpenSession { GP11Slot *slot; gulong flags; gchar *password; + gboolean auto_login; CK_SESSION_HANDLE session; } OpenSession; @@ -1041,7 +605,7 @@ perform_open_session (OpenSession *args) NULL, NULL, &args->session); } - if (rv != CKR_OK || !gp11_slot_get_auto_login (args->slot)) + if (rv != CKR_OK || !args->auto_login) return rv; /* Step two, check if session is logged in */ @@ -1062,17 +626,26 @@ perform_open_session (OpenSession *args) static gboolean complete_open_session (OpenSession *args, CK_RV result) { + GP11Module *module; + gboolean ret = TRUE; + g_free (args->password); args->password = NULL; /* Ask the token for a password */ - if (gp11_slot_get_auto_login (args->slot) && result == CKR_PIN_INCORRECT) { - if (_gp11_slot_fire_authenticate_token (args->slot, NULL, &args->password)) - return FALSE; /* Call is not complete */ + module = gp11_slot_get_module (args->slot); + + if (args->auto_login && result == CKR_PIN_INCORRECT) { + + ret = _gp11_module_fire_authenticate_slot (module, args->slot, NULL, &args->password); + + /* Call is not complete */ + ret = !ret; } - - /* Call is complete */ - return TRUE; + + g_object_unref (module); + + return ret; } static void @@ -1120,24 +693,21 @@ gp11_slot_open_session (GP11Slot *self, gulong flags, GError **err) GP11Session* gp11_slot_open_session_full (GP11Slot *self, gulong flags, GCancellable *cancellable, GError **err) { - GP11SlotPrivate *pv; GP11Session *session = NULL; + GP11Module *module = NULL; CK_SESSION_HANDLE handle; + CK_SLOT_ID slot_id; flags |= CKF_SERIAL_SESSION; g_object_ref (self); - pv = lock_private (self); - - { - /* Try to use a cached session */ - handle = pop_session_table (pv, flags); - if (handle != 0) - session = make_session_object (self, flags, handle); - } - - unlock_private (self, pv); + /* Try to use a cached session */ + module = gp11_slot_get_module (self); + slot_id = gp11_slot_get_handle (self); + handle = _gp11_module_pooled_session_handle (module, slot_id, flags); + if (handle != 0) + session = make_session_object (self, flags, handle); /* Open a new session */ if (session == NULL) { @@ -1146,12 +716,14 @@ gp11_slot_open_session_full (GP11Slot *self, gulong flags, GCancellable *cancell args.slot = self; args.flags = flags; args.password = NULL; + args.auto_login = gp11_module_get_auto_authenticate (module); args.session = 0; if (_gp11_call_sync (self, perform_open_session, complete_open_session, &args, cancellable, err)) session = make_session_object (self, flags, args.session); } + g_object_unref (module); g_object_unref (self); return session; @@ -1174,9 +746,10 @@ void gp11_slot_open_session_async (GP11Slot *self, gulong flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { - GP11SlotPrivate *pv; + GP11Module *module = NULL; GP11Call *call; OpenSession *args; + CK_SLOT_ID slot_id; flags |= CKF_SERIAL_SESSION; @@ -1184,17 +757,16 @@ gp11_slot_open_session_async (GP11Slot *self, gulong flags, GCancellable *cancel args = _gp11_call_async_prep (self, self, perform_open_session, complete_open_session, sizeof (*args), free_open_session); - - pv = lock_private (self); - { - /* Try to use a cached session */ - args->session = pop_session_table (pv, flags); - args->flags = flags; - args->slot = g_object_ref (self); - } - - unlock_private (self, pv); + args->flags = flags; + args->slot = g_object_ref (self); + + /* Try to use a cached session */ + module = gp11_slot_get_module (self); + slot_id = gp11_slot_get_handle (self); + args->session = _gp11_module_pooled_session_handle (module, slot_id, flags); + args->auto_login = gp11_module_get_auto_authenticate (module); + g_object_unref (module); call = _gp11_call_async_ready (args, cancellable, callback, user_data); if (args->session) diff --git a/gp11/gp11.h b/gp11/gp11.h index 023b15bc..452ea746 100644 --- a/gp11/gp11.h +++ b/gp11/gp11.h @@ -224,6 +224,8 @@ typedef struct _GP11Module GP11Module; typedef struct _GP11Session GP11Session; typedef struct _GP11Object GP11Object; +typedef gboolean (*GP11ObjectForeachFunc) (GP11Object *object, gpointer user_data); + /* ------------------------------------------------------------------------- * MODULE */ @@ -258,28 +260,68 @@ struct _GP11Module { struct _GP11ModuleClass { GObjectClass parent; + + gboolean (*authenticate_slot) (GP11Module *self, GP11Slot *slot, gchar *label, gchar **password); + + gboolean (*authenticate_object) (GP11Module *self, GP11Object *object, gchar *label, gchar **password); + gpointer reserved[8]; }; GType gp11_module_get_type (void) G_GNUC_CONST; -GP11Module* gp11_module_initialize (const gchar *path, - gpointer reserved, - GError **err); +GP11Module* gp11_module_new (CK_FUNCTION_LIST_PTR funcs); -GP11Module* gp11_module_initialize_with_functions (CK_FUNCTION_LIST_PTR funcs, +GP11Module* gp11_module_initialize (const gchar *path, gpointer reserved, GError **err); const gchar* gp11_module_get_path (GP11Module *self); -CK_FUNCTION_LIST_PTR gp11_module_get_function_list (GP11Module *self); +CK_FUNCTION_LIST_PTR gp11_module_get_functions (GP11Module *self); GP11ModuleInfo* gp11_module_get_info (GP11Module *self); GList* gp11_module_get_slots (GP11Module *self, gboolean token_present); +gboolean gp11_module_get_pool_sessions (GP11Module *self); + +void gp11_module_set_pool_sessions (GP11Module *self, + gboolean pool_sessions); + +gboolean gp11_module_get_auto_authenticate (GP11Module *self); + +void gp11_module_set_auto_authenticate (GP11Module *self, + gboolean auto_authenticate); + +void gp11_module_enumerate_objects (GP11Module *self, + GP11ObjectForeachFunc func, + gpointer user_data, + ...); + +void gp11_module_enumerate_objects_full (GP11Module *self, + GP11Attributes *attrs, + GCancellable *cancellable, + GP11ObjectForeachFunc func, + gpointer user_data); + +#ifdef UNIMPLEMENTED +void gp11_module_enumerate_objects_async (GP11Module *self, + GP11Attributes *attrs, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +GP11Object* gp11_module_enumerate_objects_next (GP11Module *self, + GAsyncResult *res, + GError **error); + +void gp11_module_enumerate_objects_finish (GP11Module *self, + GAsyncResult *res, + GError **error); +#endif + enum { GP11_IS_STRING = -1, GP11_IS_BOOLEAN = -2, @@ -361,10 +403,6 @@ struct _GP11Slot { struct _GP11SlotClass { GObjectClass parent; - gboolean (*authenticate_token) (GP11Slot *self, gchar *label, gchar **password); - - gboolean (*authenticate_object) (GP11Slot *self, GP11Object *object, gchar *label, gchar **password); - #ifdef UNIMPLEMENTED void (*slot_event) (GP11Slot *self); #endif @@ -378,16 +416,6 @@ GP11Module* gp11_slot_get_module (GP11Slot *self); CK_SLOT_ID gp11_slot_get_handle (GP11Slot *self); -gboolean gp11_slot_get_reuse_sessions (GP11Slot *self); - -void gp11_slot_set_reuse_sessions (GP11Slot *self, - gboolean reuse); - -gboolean gp11_slot_get_auto_login (GP11Slot *self); - -void gp11_slot_set_auto_login (GP11Slot *self, - gboolean auto_login); - gint gp11_slot_get_max_pin_length (GP11Slot *self); GP11SlotInfo* gp11_slot_get_info (GP11Slot *self); diff --git a/gp11/tests/unit-test-gp11-crypto.c b/gp11/tests/unit-test-gp11-crypto.c index ff95ce17..a6bf68e0 100644 --- a/gp11/tests/unit-test-gp11-crypto.c +++ b/gp11/tests/unit-test-gp11-crypto.c @@ -76,9 +76,9 @@ find_key (GP11Session *session, CK_ATTRIBUTE_TYPE method, CK_MECHANISM_TYPE mech } static gboolean -authenticate_object (GP11Slot *slot, GP11Object *object, gchar *label, gchar **password) +authenticate_object (GP11Slot *module, GP11Object *object, gchar *label, gchar **password) { - g_assert (GP11_IS_SLOT (slot)); + g_assert (GP11_IS_MODULE (module)); g_assert (GP11_IS_OBJECT (object)); g_assert (password); g_assert (!*password); @@ -219,8 +219,8 @@ DEFINE_TEST(sign) mech.parameter = "my-prefix:"; /* Enable auto-login on this session, see previous test */ - gp11_slot_set_auto_login (slot, TRUE); - g_signal_connect (slot, "authenticate-object", G_CALLBACK (authenticate_object), NULL); + gp11_module_set_auto_authenticate (module, TRUE); + g_signal_connect (module, "authenticate-object", G_CALLBACK (authenticate_object), NULL); /* Find the right key */ key = find_key (session, CKA_SIGN, CKM_PREFIX); @@ -270,8 +270,8 @@ DEFINE_TEST(verify) mech.parameter = "my-prefix:"; /* Enable auto-login on this session, shouldn't be needed */ - gp11_slot_set_auto_login (slot, TRUE); - g_signal_connect (slot, "authenticate-object", G_CALLBACK (authenticate_object), NULL); + gp11_module_set_auto_authenticate (module, TRUE); + g_signal_connect (module, "authenticate-object", G_CALLBACK (authenticate_object), NULL); /* Find the right key */ key = find_key (session, CKA_VERIFY, CKM_PREFIX); diff --git a/gp11/tests/unit-test-gp11-module.c b/gp11/tests/unit-test-gp11-module.c index fe56108e..f2564acf 100644 --- a/gp11/tests/unit-test-gp11-module.c +++ b/gp11/tests/unit-test-gp11-module.c @@ -63,3 +63,72 @@ DEFINE_TEST(module_info) gp11_module_info_free (info); } + +static int n_objects = 0; +static GP11Object *last_object = NULL; + +static gboolean +for_each_object (GP11Object *object, gpointer user_data) +{ + g_assert (GP11_IS_OBJECT (object)); + g_assert_cmpstr ("blah", ==, user_data); + g_assert (user_data); + + if (last_object) + g_object_unref (last_object); + last_object = g_object_ref (object); + + ++n_objects; + + return TRUE; +} + +static gboolean +for_first_object (GP11Object *object, gpointer user_data) +{ + g_assert (GP11_IS_OBJECT (object)); + g_assert_cmpstr ("first", ==, user_data); + g_assert (user_data); + + if (last_object) + g_object_unref (last_object); + last_object = g_object_ref (object); + + ++n_objects; + + return FALSE; +} + +DEFINE_TEST(module_enumerate) +{ + GP11Session *session; + GP11Attributes *attrs; + + attrs = gp11_attributes_new (); + gp11_module_enumerate_objects_full (module, attrs, NULL, for_first_object, "first"); + g_assert_cmpint (n_objects, ==, 1); + g_assert (GP11_IS_OBJECT (last_object)); + gp11_attributes_unref (attrs); + + session = gp11_object_get_session (last_object); + g_assert (GP11_IS_SESSION (session)); + g_object_unref (session); + + g_object_unref (last_object); + last_object = NULL; + n_objects = 0; + + gp11_module_enumerate_objects (module, for_each_object, "blah", + CKA_CLASS, GP11_ULONG, CKO_PRIVATE_KEY, + GP11_INVALID); + g_assert_cmpint (n_objects, ==, 2); + g_assert (GP11_IS_OBJECT (last_object)); + + session = gp11_object_get_session (last_object); + g_assert (GP11_IS_SESSION (session)); + g_object_unref (session); + + g_object_unref (last_object); + last_object = NULL; + n_objects = 0; +} diff --git a/gp11/tests/unit-test-gp11-session.c b/gp11/tests/unit-test-gp11-session.c index 8028b1f5..5042f45d 100644 --- a/gp11/tests/unit-test-gp11-session.c +++ b/gp11/tests/unit-test-gp11-session.c @@ -108,10 +108,10 @@ DEFINE_TEST(open_reused) GError *err = NULL; gboolean value; - g_assert (gp11_slot_get_reuse_sessions (slot) == FALSE); - gp11_slot_set_reuse_sessions (slot, TRUE); - g_assert (gp11_slot_get_reuse_sessions (slot) == TRUE); - g_object_get (slot, "reuse-sessions", &value, NULL); + g_assert (gp11_module_get_pool_sessions (module) == FALSE); + gp11_module_set_pool_sessions (module, TRUE); + g_assert (gp11_module_get_pool_sessions (module) == TRUE); + g_object_get (module, "pool-sessions", &value, NULL); g_assert (value == TRUE); sess = gp11_slot_open_session (slot, 0, &err); @@ -152,8 +152,8 @@ DEFINE_TEST(open_reused) if (!sess2) return; g_assert (gp11_session_get_handle (sess) != gp11_session_get_handle (sess2)); - g_object_set (slot, "reuse-sessions", FALSE, NULL); - g_assert (gp11_slot_get_reuse_sessions (slot) == FALSE); + g_object_set (module, "pool-sessions", FALSE, NULL); + g_assert (gp11_module_get_pool_sessions (module) == FALSE); g_object_unref (sess); g_object_unref (sess2); @@ -205,11 +205,12 @@ DEFINE_TEST(login_logout) } static gboolean -authenticate_token (GP11Slot *slot, gchar *label, gchar **password, gpointer unused) +authenticate_token (GP11Module *module, GP11Slot *slot, gchar *label, gchar **password, gpointer unused) { g_assert (unused == GUINT_TO_POINTER (35)); g_assert (password != NULL); g_assert (*password == NULL); + g_assert (GP11_IS_MODULE (module)); g_assert (GP11_IS_SLOT (slot)); *password = g_strdup ("booo"); @@ -238,13 +239,13 @@ DEFINE_TEST(auto_login) g_clear_error (&err); /* Setup for auto login */ - g_assert (gp11_slot_get_auto_login (slot) == FALSE); - gp11_slot_set_auto_login (slot, TRUE); - g_assert (gp11_slot_get_auto_login (slot) == TRUE); - g_object_get (slot, "auto-login", &value, NULL); + g_assert (gp11_module_get_auto_authenticate (module) == FALSE); + gp11_module_set_auto_authenticate (module, TRUE); + g_assert (gp11_module_get_auto_authenticate (module) == TRUE); + g_object_get (module, "auto-authenticate", &value, NULL); g_assert (value == TRUE); - g_signal_connect (slot, "authenticate-token", G_CALLBACK (authenticate_token), GUINT_TO_POINTER (35)); + g_signal_connect (module, "authenticate-slot", G_CALLBACK (authenticate_token), GUINT_TO_POINTER (35)); /* Create a new session */ new_session = gp11_slot_open_session (slot, CKF_RW_SESSION, &err); @@ -282,6 +283,6 @@ DEFINE_TEST(auto_login) ret = gp11_session_logout (session, &err); SUCCESS_RES (ret, err); - g_object_set (slot, "auto-login", FALSE, NULL); - g_assert (gp11_slot_get_auto_login (slot) == FALSE); + g_object_set (module, "auto-authenticate", FALSE, NULL); + g_assert (gp11_module_get_auto_authenticate (module) == FALSE); } |