From c2a5aaf7baf4bcc006674a1938205f93028b8ab0 Mon Sep 17 00:00:00 2001
From: Stef Walter <stefw@collabora.co.uk>
Date: Sat, 22 Jan 2011 14:45:57 -0600
Subject: Rough idea of possible library functions.

---
 module/p11-unity.c | 307 ++++++++++++++++++++++++++++++++++++++++++++---------
 module/p11-unity.h |  56 ++++++++++
 2 files changed, 310 insertions(+), 53 deletions(-)
 create mode 100644 module/p11-unity.h

(limited to 'module')

diff --git a/module/p11-unity.c b/module/p11-unity.c
index e6ea668..35e8f53 100644
--- a/module/p11-unity.c
+++ b/module/p11-unity.c
@@ -37,11 +37,13 @@
 
 #include "hash.h"
 #include "pkcs11.h"
+#include "p11-unity.h"
 
 #include <sys/types.h>
 #include <assert.h>
 #include <dirent.h>
 #include <dlfcn.h>
+#include <errno.h>
 #include <pthread.h>
 #include <stdarg.h>
 #include <stddef.h>
@@ -66,6 +68,7 @@ typedef struct _Session {
 } Session;
 
 typedef struct _Module {
+	char *name;
 	char *path;
 	void *dl_module;
 	CK_FUNCTION_LIST_PTR funcs;
@@ -76,6 +79,12 @@ typedef struct _Module {
 /* Forward declaration */
 static CK_FUNCTION_LIST unity_function_list;
 
+/*
+ * This is the mutex that protects the global data of this library
+ * and the pkcs11 proxy module. Note that we *never* call into our
+ * underlying pkcs11 modules while holding this mutex. Therefore it
+ * doesn't have to be recursive and we can keep things simple.
+ */
 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 
 /*
@@ -302,6 +311,45 @@ unload_module_unlocked (Module *module)
 }
 
 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;
+
+	/* 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;
+	}
+
+	--gl.initialize_count;
+	return CKR_OK;
+}
+
+static CK_RV
 initialize_unlocked (CK_VOID_PTR init_args)
 {
 	CK_SLOT_ID_PTR slots;
@@ -311,6 +359,20 @@ initialize_unlocked (CK_VOID_PTR init_args)
 	Module *module;
 	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);
@@ -389,46 +451,210 @@ initialize_unlocked (CK_VOID_PTR init_args)
 	}
 
 	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);
+	}
+
 	return rv;
 }
 
 static CK_RV
-finalize_unlocked (CK_VOID_PTR args)
+create_mutex (CK_VOID_PTR_PTR mut)
 {
-	Module *module, *next;
-	hsh_index_t *iter;
+	pthread_mutex_t *pmutex;
+	int err;
 
-	/* 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;
-		}
+	pmutex = malloc (sizeof (pthread_mutex_t));
+	if (!pmutex)
+		return CKR_HOST_MEMORY;
+	err = pthread_mutex_init (pmutex, NULL);
+	if (err == ENOMEM)
+		return CKR_HOST_MEMORY;
+	else if (err != 0)
+		return CKR_GENERAL_ERROR;
+	*mut = pmutex;
+	return CKR_OK;
+}
 
-		unload_module_unlocked (module);
-		free (module);
-	}
-	gl.modules = NULL;
+static CK_RV
+destroy_mutex (CK_VOID_PTR mut)
+{
+	pthread_mutex_t *pmutex = mut;
+	int err;
 
-	/* No more mappings */
-	free (gl.mappings);
-	gl.mappings = NULL;
-	gl.n_mappings = 0;
+	err = pthread_mutex_destroy (pmutex);
+	if (err == EINVAL)
+		return CKR_MUTEX_BAD;
+	else if (err != 0)
+		return CKR_GENERAL_ERROR;
+	free (pmutex);
+	return CKR_OK;
+}
 
-	/* 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
+lock_mutex (CK_VOID_PTR mut)
+{
+	pthread_mutex_t *pmutex = mut;
+	int err;
 
+	err = pthread_mutex_lock (pmutex);
+	if (err == EINVAL)
+		return CKR_MUTEX_BAD;
+	else if (err != 0)
+		return CKR_GENERAL_ERROR;
+	return CKR_OK;
+}
+
+static CK_RV
+unlock_mutex (CK_VOID_PTR mut)
+{
+	pthread_mutex_t *pmutex = mut;
+	int err;
+
+	err = pthread_mutex_unlock (pmutex);
+	if (err == EINVAL)
+		return CKR_MUTEX_BAD;
+	else if (err == EPERM)
+		return CKR_MUTEX_NOT_LOCKED;
+	else if (err != 0)
+		return CKR_GENERAL_ERROR;
 	return CKR_OK;
 }
 
 /* -----------------------------------------------------------------------------
- * PKCS#11 FUNCTIONS
+ * PUBLIC FUNCTIONALITY
+ */
+
+CK_RV
+p11_unity_initialize (void)
+{
+	CK_C_INITIALIZE_ARGS args;
+	CK_RV rv;
+
+	memset (&args, 0, sizeof (args));
+	args.CreateMutex = create_mutex;
+	args.DestroyMutex = destroy_mutex;
+	args.LockMutex = lock_mutex;
+	args.UnlockMutex = unlock_mutex;
+	args.flags = CKF_OS_LOCKING_OK;
+
+	pthread_mutex_lock (&mutex);
+
+		rv = initialize_unlocked (&args);
+
+	pthread_mutex_unlock (&mutex);
+
+	return rv;
+}
+
+CK_RV
+p11_unity_finalize (void)
+{
+	CK_RV rv;
+
+	pthread_mutex_lock (&mutex);
+
+		rv = finalize_unlocked (NULL);
+
+	pthread_mutex_unlock (&mutex);
+
+	return rv;
+}
+
+char**
+p11_unity_module_names (void)
+{
+	Module *module;
+	char **result;
+	int count, i;
+
+	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);
+			}
+		}
+
+	pthread_mutex_unlock (&mutex);
+
+	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)
+{
+	CK_FUNCTION_LIST_PTR result;
+	Module *module;
+
+	if (!module_name)
+		return NULL;
+
+	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;
+				}
+			}
+		}
+
+	pthread_mutex_unlock (&mutex);
+
+	return result;
+}
+
+int
+p11_unity_module_add (const char *module_name, CK_FUNCTION_LIST_PTR module)
+{
+	assert (0);
+	return -1;
+}
+
+int
+p11_unity_module_remove (const char *module_name)
+{
+	assert (0);
+	return -1;
+}
+
+char*
+p11_unity_config_get_option (const char *module_name, const char *field)
+{
+	assert (0);
+	return NULL;
+}
+
+/* -----------------------------------------------------------------------------
+ * PKCS#11 PROXY MODULE
  */
 
 static CK_RV
@@ -441,13 +667,7 @@ unity_C_Finalize (CK_VOID_PTR reserved)
 
 	pthread_mutex_lock (&mutex);
 
-		if (gl.initialize_count == 0) {
-			rv = CKR_CRYPTOKI_NOT_INITIALIZED;
-		} else {
-			rv = finalize_unlocked (reserved);
-			if (rv == CKR_OK)
-				--gl.initialize_count;
-		}
+		rv = finalize_unlocked (reserved);
 
 	pthread_mutex_unlock (&mutex);
 
@@ -461,29 +681,10 @@ unity_C_Initialize (CK_VOID_PTR init_args)
 
 	pthread_mutex_lock (&mutex);
 
-		/*
-		 * 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;
-			rv = CKR_OK;
-		} else {
-			rv = initialize_unlocked (init_args);
-			gl.initialize_count = 1;
-		}
+		rv = initialize_unlocked (init_args);
 
 	pthread_mutex_unlock (&mutex);
 
-	/* Finalize anything that was half initialized */
-	if (rv != CKR_OK)
-		unity_C_Finalize (NULL);
-
 	return rv;
 }
 
diff --git a/module/p11-unity.h b/module/p11-unity.h
new file mode 100644
index 0000000..52855f3
--- /dev/null
+++ b/module/p11-unity.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011, Collabora Ltd.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above
+ *       copyright notice, this list of conditions and the
+ *       following disclaimer.
+ *     * Redistributions in binary form must reproduce the
+ *       above copyright notice, this list of conditions and
+ *       the following disclaimer in the documentation and/or
+ *       other materials provided with the distribution.
+ *     * The names of contributors to this software may not be
+ *       used to endorse or promote products derived from this
+ *       software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#ifndef __P11_UNITY_H__
+#define __P11_UNITY_H__
+
+CK_RV                    p11_unity_initialize          (void);
+
+CK_RV                    p11_unity_finalize            (void);
+
+char**                   p11_unity_module_names        (void);
+
+void                     p11_unity_free_names          (char **module_names);
+
+CK_FUNCTION_LIST_PTR     p11_unity_module_functions    (const char *module_name);
+
+int                      p11_unity_module_add          (const char *module_name,
+                                                        CK_FUNCTION_LIST_PTR module);
+
+int                      p11_unity_module_remove       (const char *module_name);
+
+char*                    p11_unity_config_get_option   (const char *module_name,
+                                                        const char *field);
+
+#endif /* __P11_UNITY_H__ */
-- 
cgit v1.1