summaryrefslogtreecommitdiff
path: root/module/p11-unity.c
diff options
context:
space:
mode:
authorStef Walter <stefw@collabora.co.uk>2011-01-22 16:34:29 -0600
committerStef Walter <stefw@collabora.co.uk>2011-01-22 16:34:29 -0600
commit492c2ff7c191e5df75140a47e4e43fa25fd16023 (patch)
tree42666bd02b932d90188725b3a8d856ccc61112e2 /module/p11-unity.c
parentc2a5aaf7baf4bcc006674a1938205f93028b8ab0 (diff)
Rework public library API so that we can initialize arbitrary
modules.
Diffstat (limited to 'module/p11-unity.c')
-rw-r--r--module/p11-unity.c752
1 files changed, 491 insertions, 261 deletions
diff --git a/module/p11-unity.c b/module/p11-unity.c
index 35e8f53..6b24c6a 100644
--- a/module/p11-unity.c
+++ b/module/p11-unity.c
@@ -72,7 +72,8 @@ typedef struct _Module {
char *path;
void *dl_module;
CK_FUNCTION_LIST_PTR funcs;
- int initialized;
+ int ref_count;
+ int initialize_count;
struct _Module *next;
} Module;
@@ -92,13 +93,13 @@ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
* we can audit thread safety easier.
*/
static struct _Shared {
- int initialize_count;
Mapping *mappings;
unsigned int n_mappings;
hsh_t *sessions;
Module *modules;
CK_ULONG last_handle;
-} gl = { 0, NULL, 0, NULL, NULL, FIRST_HANDLE };
+ int registered_loaded;
+} gl = { NULL, 0, NULL, NULL, FIRST_HANDLE, 0 };
#define MANUFACTURER_ID "PKCS#11 Unity "
#define LIBRARY_DESCRIPTION "PKCS#11 Unity Proxy Module "
@@ -184,85 +185,26 @@ xrealloc (void * memory, size_t length)
}
/* -----------------------------------------------------------------------------
- * HELPER FUNCTIONS
+ * P11-UNITY FUNCTIONALITY
*/
static CK_RV
-map_slot_unlocked (CK_SLOT_ID slot, Mapping *mapping)
-{
- assert (mapping);
-
- if (slot < MAPPING_OFFSET)
- return CKR_SLOT_ID_INVALID;
- slot -= MAPPING_OFFSET;
-
- if (slot > gl.n_mappings) {
- return CKR_SLOT_ID_INVALID;
- } else {
- assert (gl.mappings);
- memcpy (mapping, &gl.mappings[slot], sizeof (Mapping));
- return CKR_OK;
- }
-}
-
-static CK_RV
-map_slot_to_real (CK_SLOT_ID_PTR slot, Mapping *mapping)
-{
- CK_RV rv;
-
- assert (mapping);
-
- pthread_mutex_lock (&mutex);
-
- if (gl.initialize_count == 0)
- rv = CKR_CRYPTOKI_NOT_INITIALIZED;
- else
- rv = map_slot_unlocked (*slot, mapping);
- if (rv == CKR_OK)
- *slot = mapping->real_slot;
-
- pthread_mutex_unlock (&mutex);
-
- return rv;
-}
-
-static CK_RV
-map_session_to_real (CK_SESSION_HANDLE_PTR handle, Mapping *mapping, Session *session)
-{
- CK_RV rv = CKR_OK;
- Session *sess;
-
- assert (handle);
- assert (mapping);
-
- pthread_mutex_lock (&mutex);
-
- if (gl.initialize_count == 0) {
- rv = CKR_CRYPTOKI_NOT_INITIALIZED;
- } else {
- assert (gl.sessions);
- sess = hsh_get (gl.sessions, handle, sizeof (handle));
- if (sess != NULL) {
- *handle = sess->real_session;
- rv = map_slot_unlocked (sess->wrap_slot, mapping);
- if (session != NULL)
- memcpy (session, sess, sizeof (Session));
- } else {
- rv = CKR_SESSION_HANDLE_INVALID;
- }
- }
-
- pthread_mutex_unlock (&mutex);
-
- return rv;
-}
-
-static CK_RV
load_module_unlocked (const char *name, Module *module)
{
CK_C_GetFunctionList gfl;
CK_RV rv;
+ /*
+ * TODO: This function will change significantly once we're loading
+ * from a config, see below.
+ */
+ assert (name);
+ assert (module);
+
+ module->name = strdup (name);
+ if (!module->name)
+ return CKR_HOST_MEMORY;
+
module->path = strconcat (PKCS11_MODULE_PATH, "/", name, NULL);
if (!module->path)
return CKR_HOST_MEMORY;
@@ -294,89 +236,33 @@ load_module_unlocked (const char *name, Module *module)
static void
unload_module_unlocked (Module *module)
{
+ assert (module);
+
/* Should have been finalized before this */
- assert (!module->initialized);
+ assert (!module->initialize_count);
if (module->dl_module) {
dlclose (module->dl_module);
module->dl_module = NULL;
}
- if (module->path) {
- free (module->path);
- module->path = NULL;
- }
-
- module->funcs = NULL;
-}
-
-static CK_RV
-finalize_unlocked (CK_VOID_PTR args)
-{
- Module *module, *next;
- hsh_index_t *iter;
-
- if (gl.initialize_count == 0)
- return CKR_CRYPTOKI_NOT_INITIALIZED;
-
- /* Finalize all the modules */
- for (module = gl.modules; module; module = next) {
- next = module->next;
- if (module->initialized) {
- (module->funcs->C_Finalize) (args);
- module->initialized = 0;
- }
-
- unload_module_unlocked (module);
- free (module);
- }
- gl.modules = NULL;
-
- /* No more mappings */
- free (gl.mappings);
- gl.mappings = NULL;
- gl.n_mappings = 0;
+ free (module->path);
+ module->path = NULL;
- /* no more sessions */
- if (gl.sessions) {
- for (iter = hsh_first (gl.sessions); iter; iter = hsh_next (iter))
- free (hsh_this (iter, NULL, NULL));
- hsh_free (gl.sessions);
- gl.sessions = NULL;
- }
+ free (module->name);
+ module->name = NULL;
- --gl.initialize_count;
- return CKR_OK;
+ module->funcs = NULL;
}
static CK_RV
-initialize_unlocked (CK_VOID_PTR init_args)
+load_registered_modules_unlocked (void)
{
- CK_SLOT_ID_PTR slots;
- CK_ULONG i, count;
- DIR *dir;
struct dirent *dp;
Module *module;
+ DIR *dir;
CK_RV rv;
- /*
- * We bend the rules of PKCS#11 here. We never return the
- * CKR_ALREADY_INITIALIZED error code, but just increase
- * an initialization ref count.
- *
- * C_Finalize must be called the same amount of times as
- * C_Initialize.
- */
-
- if (gl.initialize_count > 0) {
- ++gl.initialize_count;
- return CKR_OK;
- }
-
- assert (!gl.mappings);
- assert (gl.n_mappings == 0);
- assert (!gl.modules);
-
/* First we load all the modules */
dir = opendir (PKCS11_MODULE_PATH);
@@ -390,80 +276,17 @@ initialize_unlocked (CK_VOID_PTR init_args)
rv = CKR_HOST_MEMORY;
else
rv = load_module_unlocked (dp->d_name, module);
- if (rv != CKR_OK) {
- if (module)
- unload_module_unlocked (module);
- free (module);
- break;
- }
+ /* Cleanup for failures happens at caller */
module->next = gl.modules;
gl.modules = module;
- }
- }
-
- closedir (dir);
-
- for (module = gl.modules; rv == CKR_OK && module; module = module->next) {
-
- /* Initialize each module */
- rv = (module->funcs->C_Initialize) (init_args);
- if (rv == CKR_CRYPTOKI_ALREADY_INITIALIZED)
- rv = CKR_OK;
- else if (rv == CKR_OK)
- module->initialized = 1;
- else
- break;
-
- /* And then ask it for its slots */
- rv = (module->funcs->C_GetSlotList) (FALSE, NULL, &count);
- if (rv != CKR_OK)
- break;
- if (!count)
- continue;
- slots = calloc (sizeof (CK_SLOT_ID), count);
- if (!slots) {
- rv = CKR_HOST_MEMORY;
- break;
- }
- rv = (module->funcs->C_GetSlotList) (FALSE, slots, &count);
- if (rv != CKR_OK) {
- free (slots);
- break;
- }
-
- gl.mappings = xrealloc (gl.mappings, sizeof (Mapping) * (gl.n_mappings + count));
- if (!gl.mappings) {
- rv = CKR_HOST_MEMORY;
- free (slots);
- break;
- }
- /* And now add a mapping for each of those slots */
- for (i = 0; i < count; ++i) {
- gl.mappings[gl.n_mappings].funcs = module->funcs;
- gl.mappings[gl.n_mappings].wrap_slot = gl.n_mappings + MAPPING_OFFSET;
- gl.mappings[gl.n_mappings].real_slot = slots[i];
- ++gl.n_mappings;
+ if (rv != CKR_OK)
+ break;
}
-
- free (slots);
}
- gl.sessions = hsh_create ();
-
- /*
- * In the case of failure, we just finalize the partially
- * initialized stuff, which cleans everything up. That's
- * why we increment initialize_count, as finalize will bring
- * it back to zero.
- */
-
- gl.initialize_count = 1;
- if (rv != CKR_OK) {
- finalize_unlocked (NULL);
- assert (gl.initialize_count == 0);
- }
+ closedir (dir);
return rv;
}
@@ -531,16 +354,167 @@ unlock_mutex (CK_VOID_PTR mut)
return CKR_OK;
}
-/* -----------------------------------------------------------------------------
- * PUBLIC FUNCTIONALITY
- */
+static CK_RV
+initialize_module_unlocked_reentrant (Module *module, CK_C_INITIALIZE_ARGS_PTR args)
+{
+ CK_RV rv = CKR_OK;
+
+ assert (module);
+
+ /*
+ * Initialize first, so module doesn't get freed out from
+ * underneath us when the mutex is unlocked below.
+ */
+ ++module->ref_count;
+
+ if (!module->initialize_count) {
+
+ pthread_mutex_unlock (&mutex);
+
+ assert (module->funcs);
+ rv = module->funcs->C_Initialize (args);
+
+ pthread_mutex_lock (&mutex);
+
+ /*
+ * Because we have the mutex unlocked above, two initializes could
+ * race. Therefore we need to take CKR_CRYPTOKI_ALREADY_INITIALIZED
+ * into account.
+ *
+ * We also need to take into account where in a race both calls return
+ * CKR_OK (which is not according to the spec but may happen, I mean we
+ * do it in this module, so it's not unimaginable).
+ */
+
+ if (rv == CKR_OK)
+ ++module->initialize_count;
+ else if (rv == CKR_CRYPTOKI_ALREADY_INITIALIZED)
+ rv = CKR_OK;
+ else
+ --module->ref_count;
+ }
+
+ return rv;
+}
+
+static CK_RV
+finalize_module_unlocked_reentrant (Module *module, CK_VOID_PTR args)
+{
+ Module *mod, *next;
+
+ assert (module);
+
+ /*
+ * We leave module info around until all are finalized
+ * so we can encounter these zombie Module structures.
+ */
+ if (module->ref_count == 0)
+ return CKR_ARGUMENTS_BAD;
+
+ if (--module->ref_count > 0)
+ return CKR_OK;
+
+ /*
+ * Becuase of the mutex unlock below, we temporarily increase
+ * the ref count. This prevents module from being freed out
+ * from ounder us.
+ */
+ ++module->ref_count;
+
+ while (module->initialize_count > 0) {
+
+ pthread_mutex_unlock (&mutex);
+
+ assert (module->funcs);
+ module->funcs->C_Finalize (args);
+
+ pthread_mutex_lock (&mutex);
+
+ if (module->initialize_count > 0)
+ --module->initialize_count;
+ }
+
+ /* Match the increment above */
+ --module->ref_count;
+
+ /* Check if any modules have a ref count */
+ for (mod = gl.modules; mod; mod = mod->next) {
+ if (mod->ref_count)
+ break;
+ }
+
+ /* No modules had a refcount? unload and free all info */
+ if (mod == NULL) {
+ for (mod = gl.modules; mod; mod = next) {
+ next = mod->next;
+ unload_module_unlocked (mod);
+ free (mod);
+ }
+ gl.modules = NULL;
+ gl.registered_loaded = 0;
+ }
+
+ return CKR_OK;
+}
+
+static Module*
+find_module_for_funcs_unlocked (CK_FUNCTION_LIST_PTR funcs)
+{
+ Module *module;
+
+ assert (funcs);
+
+ for (module = gl.modules; module; module = module->next)
+ if (module->ref_count && module->funcs == funcs)
+ return module;
+ return NULL;
+}
+
+static Module*
+find_module_for_name_unlocked (const char *name)
+{
+ Module *module;
+
+ assert (name);
+
+ for (module = gl.modules; module; module = module->next)
+ if (module->ref_count && module->name && strcmp (name, module->name))
+ return module;
+ return NULL;
+}
+
+static CK_RV
+initialize_registered_unlocked_reentrant (CK_C_INITIALIZE_ARGS_PTR args)
+{
+ Module *module;
+ CK_RV rv;
+
+ rv = load_registered_modules_unlocked ();
+ if (rv == CKR_OK) {
+ for (module = gl.modules; module; module = module->next) {
+
+ /* Skip all modules that aren't registered */
+ if (!module->name)
+ continue;
+
+ rv = initialize_module_unlocked_reentrant (module, args);
+
+ if (rv != CKR_OK)
+ break;
+ }
+ }
+
+ return rv;
+}
CK_RV
-p11_unity_initialize (void)
+p11_unity_initialize_registered (void)
{
CK_C_INITIALIZE_ARGS args;
CK_RV rv;
+ /* WARNING: This function must be reentrant */
+
memset (&args, 0, sizeof (args));
args.CreateMutex = create_mutex;
args.DestroyMutex = destroy_mutex;
@@ -550,21 +524,48 @@ p11_unity_initialize (void)
pthread_mutex_lock (&mutex);
- rv = initialize_unlocked (&args);
+ /* WARNING: Reentrancy can occur here */
+ rv = initialize_registered_unlocked_reentrant (&args);
pthread_mutex_unlock (&mutex);
+ /* Cleanup any partial initialization */
+ if (rv != CKR_OK)
+ p11_unity_finalize_registered ();
+
return rv;
}
+static CK_RV
+finalize_registered_unlocked_reentrant (CK_VOID_PTR args)
+{
+ Module *module;
+
+ /* WARNING: This function must be reentrant */
+
+ for (module = gl.modules; module; module = module->next) {
+
+ /* Skip all modules that aren't registered */
+ if (!module->name)
+ continue;
+
+ /* WARNING: Reentrant calls can occur here */
+ finalize_module_unlocked_reentrant (module, args);
+ }
+
+ return CKR_OK;
+}
CK_RV
-p11_unity_finalize (void)
+p11_unity_finalize_registered (void)
{
CK_RV rv;
+ /* WARNING: This function must be reentrant */
+
pthread_mutex_lock (&mutex);
- rv = finalize_unlocked (NULL);
+ /* WARNING: Reentrant calls can occur here */
+ rv = finalize_registered_unlocked_reentrant (NULL);
pthread_mutex_unlock (&mutex);
@@ -572,7 +573,7 @@ p11_unity_finalize (void)
}
char**
-p11_unity_module_names (void)
+p11_unity_registered_names (void)
{
Module *module;
char **result;
@@ -580,18 +581,14 @@ p11_unity_module_names (void)
pthread_mutex_lock (&mutex);
- if (!gl.initialize_count) {
- result = NULL;
- } else {
- for (module = gl.modules, count = 0;
- module; module = module->next)
- ++count;
- result = calloc (count + 1, sizeof (char*));
- if (result) {
- for (module = gl.modules, i = 0;
- module; module = module->next, ++i)
- result[i] = strdup (module->name);
- }
+ for (module = gl.modules, count = 0;
+ module; module = module->next)
+ ++count;
+ result = calloc (count + 1, sizeof (char*));
+ if (result) {
+ for (module = gl.modules, i = 0;
+ module; module = module->next, ++i)
+ result[i] = strdup (module->name);
}
pthread_mutex_unlock (&mutex);
@@ -599,16 +596,8 @@ p11_unity_module_names (void)
return result;
}
-void
-p11_unity_free_names (char **module_names)
-{
- char **name;
- for (name = module_names; *name; ++name)
- free (name);
-}
-
CK_FUNCTION_LIST_PTR
-p11_unity_module_functions (const char *module_name)
+p11_unity_registered_module (const char *module_name)
{
CK_FUNCTION_LIST_PTR result;
Module *module;
@@ -618,13 +607,10 @@ p11_unity_module_functions (const char *module_name)
pthread_mutex_lock (&mutex);
- if (gl.initialize_count) {
- for (module = gl.modules; module; module = module->next) {
- if (strcmp (module_name, module->name) == 0) {
- result = module->funcs;
- break;
- }
- }
+ module = find_module_for_name_unlocked (module_name);
+ if (module) {
+ assert (module);
+ result = module->funcs;
}
pthread_mutex_unlock (&mutex);
@@ -632,25 +618,80 @@ p11_unity_module_functions (const char *module_name)
return result;
}
-int
-p11_unity_module_add (const char *module_name, CK_FUNCTION_LIST_PTR module)
+void
+p11_unity_free_names (char **module_names)
{
- assert (0);
- return -1;
+ char **name;
+ for (name = module_names; *name; ++name)
+ free (name);
}
-int
-p11_unity_module_remove (const char *module_name)
+char*
+p11_unity_registered_option (const char *module_name, const char *field)
{
+ /* TODO: Need to implement */
assert (0);
- return -1;
+ return NULL;
}
-char*
-p11_unity_config_get_option (const char *module_name, const char *field)
+CK_RV
+p11_unity_initialize_module (CK_FUNCTION_LIST_PTR funcs, CK_C_INITIALIZE_ARGS_PTR init_args)
{
- assert (0);
- return NULL;
+ Module *module;
+ Module *allocated = NULL;
+ CK_RV rv = CKR_OK;
+
+ /* WARNING: This function must be reentrant for the same arguments */
+
+ pthread_mutex_lock (&mutex);
+
+ module = find_module_for_funcs_unlocked (funcs);
+ if (module == NULL) {
+ allocated = module = calloc (1, sizeof (Module));
+ module->name = NULL;
+ module->dl_module = NULL;
+ module->path = NULL;
+ module->funcs = funcs;
+ }
+
+ /* WARNING: Reentrancy can occur here */
+ rv = initialize_module_unlocked_reentrant (module, init_args);
+
+ /* If this was newly allocated, add it to the list */
+ if (rv == CKR_OK && allocated) {
+ allocated->next = gl.modules;
+ gl.modules = allocated;
+ allocated = NULL;
+ }
+
+ free (allocated);
+
+ pthread_mutex_unlock (&mutex);
+
+ return rv;
+}
+
+CK_RV
+p11_unity_finalize_module (CK_FUNCTION_LIST_PTR funcs, CK_VOID_PTR reserved)
+{
+ Module *module;
+ CK_RV rv = CKR_OK;
+
+ /* WARNING: This function must be reentrant for the same arguments */
+
+ pthread_mutex_lock (&mutex);
+
+ module = find_module_for_funcs_unlocked (funcs);
+ if (module == NULL) {
+ rv = CKR_ARGUMENTS_BAD;
+ } else {
+ /* WARNING: Rentrancy can occur here */
+ rv = finalize_module_unlocked_reentrant (module, reserved);
+ }
+
+ pthread_mutex_unlock (&mutex);
+
+ return rv;
}
/* -----------------------------------------------------------------------------
@@ -658,16 +699,115 @@ p11_unity_config_get_option (const char *module_name, const char *field)
*/
static CK_RV
+map_slot_unlocked (CK_SLOT_ID slot, Mapping *mapping)
+{
+ assert (mapping);
+
+ if (slot < MAPPING_OFFSET)
+ return CKR_SLOT_ID_INVALID;
+ slot -= MAPPING_OFFSET;
+
+ if (slot > gl.n_mappings) {
+ return CKR_SLOT_ID_INVALID;
+ } else {
+ assert (gl.mappings);
+ memcpy (mapping, &gl.mappings[slot], sizeof (Mapping));
+ return CKR_OK;
+ }
+}
+
+static CK_RV
+map_slot_to_real (CK_SLOT_ID_PTR slot, Mapping *mapping)
+{
+ CK_RV rv;
+
+ assert (mapping);
+
+ pthread_mutex_lock (&mutex);
+
+ if (!gl.mappings)
+ rv = CKR_CRYPTOKI_NOT_INITIALIZED;
+ else
+ rv = map_slot_unlocked (*slot, mapping);
+ if (rv == CKR_OK)
+ *slot = mapping->real_slot;
+
+ pthread_mutex_unlock (&mutex);
+
+ return rv;
+}
+
+static CK_RV
+map_session_to_real (CK_SESSION_HANDLE_PTR handle, Mapping *mapping, Session *session)
+{
+ CK_RV rv = CKR_OK;
+ Session *sess;
+
+ assert (handle);
+ assert (mapping);
+
+ pthread_mutex_lock (&mutex);
+
+ if (!gl.sessions) {
+ rv = CKR_CRYPTOKI_NOT_INITIALIZED;
+ } else {
+ assert (gl.sessions);
+ sess = hsh_get (gl.sessions, handle, sizeof (handle));
+ if (sess != NULL) {
+ *handle = sess->real_session;
+ rv = map_slot_unlocked (sess->wrap_slot, mapping);
+ if (session != NULL)
+ memcpy (session, sess, sizeof (Session));
+ } else {
+ rv = CKR_SESSION_HANDLE_INVALID;
+ }
+ }
+
+ pthread_mutex_unlock (&mutex);
+
+ return rv;
+}
+
+static void
+finalize_mappings_unlocked (void)
+{
+ hsh_index_t *iter;
+
+ /* No more mappings */
+ free (gl.mappings);
+ gl.mappings = NULL;
+ gl.n_mappings = 0;
+
+ /* no more sessions */
+ if (gl.sessions) {
+ for (iter = hsh_first (gl.sessions); iter; iter = hsh_next (iter))
+ free (hsh_this (iter, NULL, NULL));
+ hsh_free (gl.sessions);
+ gl.sessions = NULL;
+ }
+}
+
+static CK_RV
unity_C_Finalize (CK_VOID_PTR reserved)
{
CK_RV rv;
+ /* WARNING: This function must be reentrant */
+
if (reserved)
return CKR_ARGUMENTS_BAD;
pthread_mutex_lock (&mutex);
- rv = finalize_unlocked (reserved);
+ /* WARNING: Reentrancy can occur here */
+ rv = finalize_registered_unlocked_reentrant (reserved);
+
+ /*
+ * If modules are all gone, then this was the last
+ * finalize, so cleanup our mappings
+ */
+ if (gl.modules == NULL)
+ finalize_mappings_unlocked ();
pthread_mutex_unlock (&mutex);
@@ -675,16 +815,99 @@ unity_C_Finalize (CK_VOID_PTR reserved)
}
static CK_RV
+initialize_mappings_unlocked_reentrant (void)
+{
+ CK_FUNCTION_LIST_PTR funcs;
+ Mapping *mappings = NULL;
+ int n_mappings = 0;
+ CK_SLOT_ID_PTR slots;
+ CK_ULONG i, count;
+ Module *module;
+ CK_RV rv;
+
+ assert (!gl.mappings);
+
+ for (module = gl.modules; module; module = module->next) {
+
+ /* Only do registered modules */
+ if (module->ref_count && !module->name)
+ continue;
+
+ funcs = module->funcs;
+ assert (funcs);
+ slots = NULL;
+
+ pthread_mutex_unlock (&mutex);
+
+ /* Ask module for its slots */
+ rv = (funcs->C_GetSlotList) (FALSE, NULL, &count);
+ if (rv == CKR_OK && count) {
+ slots = calloc (sizeof (CK_SLOT_ID), count);
+ if (!slots)
+ rv = CKR_HOST_MEMORY;
+ else
+ rv = (funcs->C_GetSlotList) (FALSE, slots, &count);
+ }
+
+ pthread_mutex_lock (&mutex);
+
+ if (rv != CKR_OK) {
+ free (slots);
+ break;
+ }
+
+ mappings = xrealloc (mappings, sizeof (Mapping) * (n_mappings + count));
+ if (!mappings) {
+ free (slots);
+ rv = CKR_HOST_MEMORY;
+ break;
+ }
+
+ /* And now add a mapping for each of those slots */
+ for (i = 0; i < count; ++i) {
+ mappings[n_mappings].funcs = funcs;
+ mappings[n_mappings].wrap_slot = n_mappings + MAPPING_OFFSET;
+ mappings[n_mappings].real_slot = slots[i];
+ ++n_mappings;
+ }
+
+ free (slots);
+ }
+
+ /* Another thread raced us here due to above reentrancy */
+ if (gl.mappings) {
+ free (mappings);
+ return CKR_OK;
+ }
+
+ assert (!gl.sessions);
+ gl.sessions = hsh_create ();
+
+ /* Any cleanup necessary for failure will happen at caller */
+ return rv;
+}
+
+static CK_RV
unity_C_Initialize (CK_VOID_PTR init_args)
{
CK_RV rv;
+ /* WARNING: This function must be reentrant */
+
pthread_mutex_lock (&mutex);
- rv = initialize_unlocked (init_args);
+ /* WARNING: Reentrancy can occur here */
+ rv = initialize_registered_unlocked_reentrant (init_args);
+
+ /* WARNING: Reentrancy can occur here */
+ if (rv == CKR_OK && !gl.mappings)
+ rv = initialize_mappings_unlocked_reentrant ();
pthread_mutex_unlock (&mutex);
+ if (rv != CKR_OK)
+ unity_C_Finalize (NULL);
+
return rv;
}
@@ -698,7 +921,7 @@ unity_C_GetInfo (CK_INFO_PTR info)
pthread_mutex_lock (&mutex);
- if (gl.initialize_count == 0)
+ if (!gl.mappings)
rv = CKR_CRYPTOKI_NOT_INITIALIZED;
pthread_mutex_unlock (&mutex);
@@ -742,7 +965,7 @@ unity_C_GetSlotList (CK_BBOOL token_present, CK_SLOT_ID_PTR slot_list,
pthread_mutex_lock (&mutex);
- if (gl.initialize_count == 0) {
+ if (!gl.mappings) {
rv = CKR_CRYPTOKI_NOT_INITIALIZED;
} else {
index = 0;
@@ -866,8 +1089,15 @@ unity_C_OpenSession (CK_SLOT_ID id, CK_FLAGS flags, CK_VOID_PTR user_data,
if (rv == CKR_OK) {
pthread_mutex_lock (&mutex);
- if (gl.initialize_count == 0) {
+ if (!gl.sessions) {
+ /*
+ * The underlying module should have returned an error, so this
+ * code should never be reached with properly behaving modules.
+ * That's why we don't cleanup and close the newly opened session here
+ * or anything like that.
+ */
rv = CKR_CRYPTOKI_NOT_INITIALIZED;
+
} else {
sess = calloc (1, sizeof (Session));
sess->wrap_slot = map.wrap_slot;
@@ -899,7 +1129,7 @@ unity_C_CloseSession (CK_SESSION_HANDLE handle)
if (rv == CKR_OK) {
pthread_mutex_lock (&mutex);
- if (gl.initialize_count != 0)
+ if (gl.sessions)
hsh_rem (gl.sessions, &key, sizeof (key));
pthread_mutex_unlock (&mutex);
@@ -919,7 +1149,7 @@ unity_C_CloseAllSessions (CK_SLOT_ID id)
pthread_mutex_lock (&mutex);
- if (gl.initialize_count == 0) {
+ if (!gl.sessions) {
rv = CKR_CRYPTOKI_NOT_INITIALIZED;
} else {
to_close = calloc (sizeof (CK_SESSION_HANDLE), hsh_count (gl.sessions));