]> granicus.if.org Git - p11-kit/commitdiff
p11-kit: Managed PKCS#11 module loading
authorStef Walter <stefw@gnome.org>
Wed, 6 Feb 2013 20:57:45 +0000 (21:57 +0100)
committerStef Walter <stefw@gnome.org>
Tue, 21 May 2013 08:47:51 +0000 (10:47 +0200)
Support a new managed style module loading for PKCS#11 modules. This
allows us to better coordinate between multiple callers of the same
PKCS#11 modules and provide hooks into their behavior.

This meant redoing the public facing API. The old methods are now
deprecated, marked and documented as such.

36 files changed:
common/compat.c
common/compat.h
common/mock.c
common/mock.h
doc/manual/Makefile.am
doc/manual/p11-kit-docs.xml
doc/manual/p11-kit-proxy.xml [new file with mode: 0644]
doc/manual/p11-kit-sections.txt
doc/manual/p11-kit-sharing.xml
doc/manual/pkcs11.conf.xml
gtk-doc.make
p11-kit/Makefile.am
p11-kit/deprecated.h [new file with mode: 0644]
p11-kit/docs.h [new file with mode: 0644]
p11-kit/modules.c
p11-kit/modules.h [new file with mode: 0644]
p11-kit/p11-kit.h
p11-kit/private.h
p11-kit/proxy.c
p11-kit/tests/Makefile.am
p11-kit/tests/files/system-pkcs11.conf
p11-kit/tests/files/user-modules/one.module
p11-kit/tests/test-deprecated.c [new file with mode: 0644]
p11-kit/tests/test-init.c
p11-kit/tests/test-iter.c
p11-kit/tests/test-managed.c [new file with mode: 0644]
p11-kit/tests/test-mock.c [new file with mode: 0644]
p11-kit/tests/test-modules.c
p11-kit/tests/test-proxy.c [new file with mode: 0644]
tools/extract.c
tools/list.c
tools/tests/test-extract.c
tools/tests/test-openssl.c
tools/tests/test-pem.c
tools/tests/test-x509.c
trust/tests/frob-nss-trust.c

index b8ed2ad3eab73b1804f7509220da122950fa2768..400e10bb0da870804cc5e184f808091954618e66 100644 (file)
@@ -245,6 +245,12 @@ p11_dl_error (void)
        return msg_buf;
 }
 
+void
+p11_dl_close (void *dl)
+{
+       FreeLibrary (dl);
+}
+
 int
 p11_thread_create (p11_thread_t *thread,
                    p11_thread_routine routine,
index 7435e07fac2d64ce9065d2aaec80a841c663f849..0f9677bd22d63d96c9e55d347dbe0704f1a8e9a0 100644 (file)
@@ -135,13 +135,13 @@ typedef HMODULE dl_module_t;
 
 #define p11_dl_open(f) \
        (LoadLibrary (f))
-#define p11_dl_close(d) \
-       (FreeLibrary (d))
 #define p11_dl_symbol(d, s) \
        ((void *)GetProcAddress ((d), (s)))
 
 char *    p11_dl_error       (void);
 
+void      p11_dl_close       (void * dl);
+
 #define p11_sleep_ms(ms) \
        (Sleep (ms))
 
index 6176fa9a8fe801bd964f84d583adc8eeb3d45405..4dbd6741775fcc85a04b516b974e49d05f370e2b 100644 (file)
@@ -183,8 +183,8 @@ mock_module_take_object (CK_SLOT_ID slot_id,
                return_if_reached ();
 }
 
-void
-mock_module_reset_objects (CK_SLOT_ID slot_id)
+static void
+module_reset_objects (CK_SLOT_ID slot_id)
 {
        return_if_fail (slot_id == MOCK_SLOT_ONE_ID);
 
@@ -291,6 +291,44 @@ mock_module_reset_objects (CK_SLOT_ID slot_id)
                p11_dict_set (the_objects, handle_to_pointer (MOCK_PUBLIC_KEY_PREFIX), p11_attrs_dup (attrs));
 
        }
+}
+
+static void
+module_finalize (void)
+{
+       p11_mutex_lock (&init_mutex);
+
+               /* This should stop all other calls in */
+               pkcs11_initialized = false;
+               pkcs11_initialized_pid = 0;
+
+               if (the_objects)
+                       p11_dict_free (the_objects);
+               the_objects = NULL;
+
+               if (the_sessions)
+                       p11_dict_free (the_sessions);
+               the_sessions = NULL;
+               logged_in = false;
+               the_user_type = 0;
+
+               free (the_pin);
+               the_pin = NULL;
+               n_the_pin = 0;
+
+       p11_mutex_unlock (&init_mutex);
+}
+
+bool
+mock_module_initialized (void)
+{
+       return pkcs11_initialized;
+}
+void
+mock_module_reset (void)
+{
+       module_finalize ();
+       module_reset_objects (MOCK_SLOT_ONE_ID);
 
 }
 
@@ -389,7 +427,7 @@ mock_C_Initialize (CK_VOID_PTR init_args)
                                             p11_dict_direct_equal,
                                             NULL, free_session);
 
-               mock_module_reset_objects (MOCK_SLOT_ONE_ID);
+               module_reset_objects (MOCK_SLOT_ONE_ID);
 
 done:
                /* Mark us as officially initialized */
@@ -425,24 +463,7 @@ mock_C_Finalize (CK_VOID_PTR reserved)
        return_val_if_fail (pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
        return_val_if_fail (reserved == NULL, CKR_ARGUMENTS_BAD);
 
-       p11_mutex_lock (&init_mutex);
-
-               /* This should stop all other calls in */
-               pkcs11_initialized = false;
-               pkcs11_initialized_pid = 0;
-
-               p11_dict_free (the_objects);
-               the_objects = NULL;
-
-               p11_dict_free (the_sessions);
-               the_sessions = NULL;
-               logged_in = false;
-               the_user_type = 0;
-
-               free (the_pin);
-
-       p11_mutex_unlock (&init_mutex);
-
+       module_finalize ();
        return CKR_OK;
 }
 
index d9ded00489449633a7c5b5087b2c9424f8fd3d43..5691fe0799a83c36121e3f039e697b14b1c7bde6 100644 (file)
@@ -108,11 +108,13 @@ void         mock_module_enumerate_objects               (CK_SESSION_HANDLE sess
 void         mock_module_add_object                      (CK_SLOT_ID slot_id,
                                                           const CK_ATTRIBUTE *attrs);
 
+void         mock_module_reset                           (void);
+
+bool         mock_module_initialized                     (void);
+
 void         mock_module_take_object                     (CK_SLOT_ID slot_id,
                                                           CK_ATTRIBUTE *attrs);
 
-void         mock_module_reset_objects                   (CK_SLOT_ID slot_id);
-
 CK_RV        mock_C_Initialize                           (CK_VOID_PTR init_args);
 
 CK_RV        mock_C_Initialize__fails                    (CK_VOID_PTR init_args);
index c10375a8b2a3423e6f69de8608e1559d27a109bd..b5b80f13f5d76de38d3b5b2205b82baae634e90f 100644 (file)
@@ -53,6 +53,7 @@ IGNORE_HFILES= \
        debug.h \
        dict.h \
        mock.h \
+       modules.h \
        pkcs11.h \
        pkcs11x.h \
        private.h \
@@ -70,6 +71,7 @@ HTML_IMAGES=
 # e.g. content_files=running.sgml building.sgml changes-2.0.sgml
 content_files=p11-kit-config.xml p11-kit-sharing.xml \
        p11-kit-devel.xml \
+       p11-kit-proxy.xml \
        p11-kit-trust.xml \
        p11-kit.xml \
        pkcs11.conf.xml \
index 0397169527e3d0f08a4820ebc95e62145c9e101d..5acfb97d0ccc9157f3d84b3a7a0c81746c346cdd 100644 (file)
@@ -13,6 +13,7 @@
 
        <xi:include href="p11-kit-config.xml"/>
        <xi:include href="p11-kit-sharing.xml"/>
+       <xi:include href="p11-kit-proxy.xml"/>
        <xi:include href="p11-kit-trust.xml"/>
 
        <chapter xml:id="tools">
@@ -28,6 +29,7 @@
                <xi:include href="xml/p11-kit-pin.xml"/>
                <xi:include href="xml/p11-kit-util.xml"/>
                <xi:include href="xml/p11-kit-future.xml"/>
+               <xi:include href="xml/p11-kit-deprecated.xml"/>
 
                <index id="api-index-full">
                        <title>API Index</title>
diff --git a/doc/manual/p11-kit-proxy.xml b/doc/manual/p11-kit-proxy.xml
new file mode 100644 (file)
index 0000000..7cc3615
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
+]>
+<chapter xml:id="sharing">
+       <title>Proxy Module</title>
+
+       <para>When an application is aware of the fact that coordination
+       is necessary between multiple consumers of a PKCS#11 module, and wants
+       to load standard configured PKCS#11 modules, it can link to
+       <literal>p11-kit</literal> and use the functions there to provide this
+       functionality.</para>
+
+       <para>However most current consumers of PKCS#11 are ignorant of
+       this problem, and do not link to p11-kit. In order to solve this
+       multiple initialization problem for all applications,
+       <literal>p11-kit</literal> provides a proxy compatibility
+       module.</para>
+
+       <para>This proxy module acts like a normal PKCS#11 module, but
+       internally loads a preconfigured set of PKCS#11 modules and
+       manages their features as described earlier. Each slot in the configured modules
+       is exposed as a slot of the <literal>p11-kit</literal> proxy module. The proxy
+       module is then used as a normal PKCS#11 module would be. It can be loaded by
+       crypto libraries like NSS and behaves as expected.</para>
+
+       <para>The <literal>C_GetFunctionList</literal> exported entry point of the
+       proxy module returns a new managed PKCS#11 module each time it is called. These
+       managed instances are released when the proxy module is unloaded.</para>
+</chapter>
index dc85f2df101f736e60149a69a588093ea41af714..84f084d6c8ed334830927c7fab5101792b45a799 100644 (file)
@@ -52,15 +52,22 @@ p11_kit_pin_file_callback
 
 <SECTION>
 <FILE>p11-kit</FILE>
-p11_kit_initialize_registered
-p11_kit_finalize_registered
-p11_kit_registered_modules
-p11_kit_registered_module_to_name
-p11_kit_registered_name_to_module
-p11_kit_registered_option
-p11_kit_initialize_module
-p11_kit_load_initialize_module
-p11_kit_finalize_module
+P11_KIT_MODULE_CRITICAL
+P11_KIT_MODULE_UNMANAGED
+p11_kit_modules_load_and_initialize
+p11_kit_modules_finalize_and_release
+p11_kit_modules_load
+p11_kit_modules_initialize
+p11_kit_modules_finalize
+p11_kit_modules_release
+p11_kit_module_load
+p11_kit_module_initialize
+p11_kit_module_finalize
+p11_kit_module_release
+p11_kit_module_for_name
+p11_kit_module_get_name
+p11_kit_module_get_flags
+p11_kit_config_option
 </SECTION>
 
 <SECTION>
@@ -104,3 +111,17 @@ p11_kit_iter_get_object
 p11_kit_iter_load_attributes
 p11_kit_iter_free
 </SECTION>
+
+<SECTION>
+<FILE>p11-kit-deprecated</FILE>
+p11_kit_initialize_registered
+p11_kit_finalize_registered
+p11_kit_registered_modules
+p11_kit_registered_module_to_name
+p11_kit_registered_name_to_module
+p11_kit_registered_option
+p11_kit_initialize_module
+p11_kit_load_initialize_module
+p11_kit_finalize_module
+P11_KIT_DEPRECATED_FOR
+</SECTION>
index e692e3dc136470334a311e805234fdaee2cb9f35..01b3c8b84cd327e5b7fe85bd6fd02a4e285b4331 100644 (file)
                loosely coupled, backwards compatible, and flexible way.</para>
        </section>
 
-       <section xml:id="sharing-initialize">
-               <title>Solution: p11-kit</title>
-
-               <para><literal>p11-kit</literal> provides functions to
-               coordinate initialization and finalization of any PKCS#11
-               module. A module may be initialized any number of times using
-               the p11_kit_initialize_module() function. The first time that
-               p11_kit_initialize_module() is called for a module, that module's
-               C_Initialize function is used. Later invocations for the same
-               module cause p11-kit to increment an internal initialization
-               count, rather than calling C_Initialize again.</para>
-
-               <para>The p11_kit_finalize_module() is used to finalize a module.
-               Each time it is called it decrements the internal initialization
-               count for that module. When the internal initialization count
-               reaches zero, the module's C_Finalize function is called.</para>
-
-               <para>This is done in a thread-safe manner. These functions can
-               be used on modules that the consumer loads themselves.</para>
-       </section>
-
-       <section xml:id="sharing-module">
-               <title>Solution: proxy module</title>
-
-               <para>When an application is aware of the fact that coordination
-               is necessary between multiple consumers of a PKCS#11 module, it
-               can link to p11-kit and use the functions there to provide
-               this coordination.</para>
-
-               <para>However most current consumers of PKCS#11 are ignorant of
-               this problem, and do not link to p11-kit. In order to solve this
-               multiple initialization problem for all applications,
-               <literal>p11-kit</literal> provides a proxy compatibility
-               module.</para>
-
-               <para>This proxy module acts like a normal PKCS#11 module, but
-               internally loads a preconfigured set of PKCS#11 modules and
-               coordinates their initialization and finalization. Each slot
-               in the configured modules is exposed as a slot of the
-               <literal>p11-kit</literal> proxy module. The proxy module is
-               then used as a normal PKCS#11 module would be. It can be loaded by
-               crypto libraries like NSS and behaves as expected.</para>
-
-               <para>The proxy module bends the PKCS#11 rules slightly. It does
-               not return the <literal>CKR_CRYPTOKI_ALREADY_INITIALIZED</literal>
-               error code as specified in PKCS#11. However this is a small
-               price to pay for this compatibility.</para>
+       <section xml:id="sharing-managed">
+               <title>Managed modules</title>
+
+               <para><literal>p11-kit</literal> wraps PKCS#11 modules to manage
+               them and customize their functionality so that they are able
+               to be shared between multiple callers in the same process.</para>
+
+               <para>Each caller that uses the
+               <link linkend="p11-kit-modules-load"><function>p11_kit_modules_load()</function></link>
+               or <link linkend="p11-kit-module-load"><function>p11_kit_module_load()</function></link>
+               function gets independent wrapped PKCS#11 module(s). This is unless a caller
+               or module configuration specifies that a module should be used in an
+               unmanaged fashion.</para>
+
+               <para>When modules are managed, the following aspects are wrapped and
+               coordinated:</para>
+
+               <itemizedlist>
+               <listitem>
+                       <para>Calls to <literal>C_Initialize</literal> and
+                       <literal>C_Finalize</literal> can be called by multiple
+                       callers.</para>
+
+                       <para>The first time that the managed module
+                       <literal>C_Initialize</literal> is called, the PKCS#11 module's actual
+                       <literal>C_Initialize</literal> function is called. Subsequent calls by
+                       other callers will cause <literal>p11-kit</literal> to increment an
+                       internal initialization count, rather than calling
+                       <literal>C_Initialize</literal> again.</para>
+
+                       <para>Multiple callers can call the managed
+                       <literal>C_Initialize</literal> function concurrently from different
+                       threads and <literal>p11-kit</literal> will guarantee that this managed
+                       in a thread-safe manner.</para>
+               </listitem>
+               <listitem>
+                       <para>When the managed module <literal>C_Finalize</literal> is used
+                       to finalize a module, each time it is called it decrements the internal
+                       initialization count for that module. When the internal initialization
+                       count reaches zero, the module's actual <literal>C_Finalize</literal>
+                       function is called.</para>
+
+                       <para>Multiple callers can call the managed <literal>C_Finalize</literal>
+                       function concurrently from different threads and <literal>p11-kit</literal>
+                       will guarantee that this managed in a thread-safe manner.</para>
+               </listitem>
+               </itemizedlist>
        </section>
 </chapter>
index 1814377e48175ad9f4d108d8c9e0c46907154aa8..1051ee1bde0008c0e0360d02e43384ce41f94802 100644 (file)
@@ -127,6 +127,16 @@ x-custom : text
                        not present, then any process will load the module.</para>
                </listitem>
        </varlistentry>
+       <varlistentry>
+               <term><option>managed:</option></term>
+               <listitem>
+                       <para>Set to <literal>no</literal> if the module is not to be managed by
+                       p11-kit. Making a module unmanaged is not recommended, and will cause
+                       problems if multiple callers in a single process share a PKCS#11 module.</para>
+
+                       <para>This argument is optonal and defaults to <literal>yes</literal>.</para>
+               </listitem>
+       </varlistentry>
        <varlistentry>
                <term><option>priority:</option></term>
                <listitem>
@@ -172,6 +182,20 @@ x-custom : text
                <literal>none</literal>, <literal>merge</literal>,
                <literal>only</literal>.</para></listitem>
        </varlistentry>
+       <varlistentry>
+               <term><option>managed:</option></term>
+               <listitem>
+                       <para>Set to <literal>yes</literal> or <literal>no</literal> to
+                       force all modules to be managed or unmanaged by p11-kit. Setting this
+                       setting in a global configuration file will override the
+                       <literal>managed</literal> setting in the individual module configuration
+                       files. Making modules unmanaged is not recommended, and will cause
+                       problems if multiple callers in a single process share a PKCS#11
+                       module.</para>
+
+                       <para>This argument is optonal.</para>
+               </listitem>
+       </varlistentry>
        </variablelist>
 
        <para>Other fields may be present, but it is recommended that field names
index cbef74b7bb9437ff9bda0fdd5b2798bb4d13b212..824d8d63ea0b8b2b85a55d0cf9247958cae686fd 100644 (file)
@@ -116,7 +116,7 @@ scan-build.stamp: $(HFILE_GLOB) $(CFILE_GLOB)
        fi
        @touch scan-build.stamp
 
-$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt: scan-build.stamp
+$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES): scan-build.stamp
        @true
 
 #### xml ####
index 027b7c8253a7e204792f2d3d25add7b0ad4b1285..d7e16947fcb15ac0b61781070c04890c4ef65ea3 100644 (file)
@@ -14,6 +14,7 @@ INCLUDES = \
 incdir = $(includedir)/p11-kit-1/p11-kit
 
 inc_HEADERS = \
+       deprecated.h \
        iter.h \
        p11-kit.h \
        pin.h \
@@ -24,7 +25,7 @@ MODULE_SRCS = \
        util.c \
        conf.c conf.h \
        iter.c \
-       modules.c \
+       modules.c modules.h \
        pkcs11.h \
        pin.c \
        pkcs11.h \
@@ -103,7 +104,9 @@ example_DATA = pkcs11.conf.example
 
 EXTRA_DIST = \
        p11-kit-1.pc.in \
-       pkcs11.conf.example.in
+       pkcs11.conf.example.in \
+       docs.h \
+       $(NULL)
 
 # Proxy module is actually same as library, so install a link
 install-exec-hook:
diff --git a/p11-kit/deprecated.h b/p11-kit/deprecated.h
new file mode 100644 (file)
index 0000000..ffe5d9d
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2013 Red Hat Inc.
+ *
+ * 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@redhat.com>
+ */
+
+#ifndef __P11_KIT_DEPRECATED_H__
+#define __P11_KIT_DEPRECATED_H__
+
+#ifndef __P11_KIT_H__
+#error "Please include <p11-kit/p11-kit.h> instead of this file."
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef P11_KIT_NO_DEPRECATIONS
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
+#define P11_KIT_DEPRECATED_FOR(f) __attribute__((deprecated("Use " #f " instead")))
+#elif __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
+#define P11_KIT_DEPRECATED_FOR(f) __attribute__((__deprecated__))
+#endif
+#endif
+
+#ifndef P11_KIT_DEPRECATED_FOR
+#define P11_KIT_DEPRECATED_FOR(f)
+#endif
+
+#ifndef P11_KIT_DISABLE_DEPRECATED
+
+P11_KIT_DEPRECATED_FOR (p11_kit_modules_load)
+CK_RV                    p11_kit_initialize_registered     (void);
+
+P11_KIT_DEPRECATED_FOR (p11_kit_modules_release)
+CK_RV                    p11_kit_finalize_registered       (void);
+
+P11_KIT_DEPRECATED_FOR (p11_kit_modules_release)
+CK_FUNCTION_LIST_PTR *   p11_kit_registered_modules        (void);
+
+P11_KIT_DEPRECATED_FOR (p11_kit_module_for_name)
+CK_FUNCTION_LIST_PTR     p11_kit_registered_name_to_module (const char *name);
+
+P11_KIT_DEPRECATED_FOR (p11_kit_module_get_name)
+char *                   p11_kit_registered_module_to_name (CK_FUNCTION_LIST_PTR module);
+
+P11_KIT_DEPRECATED_FOR (p11_kit_config_option)
+char *                   p11_kit_registered_option         (CK_FUNCTION_LIST_PTR module,
+                                                            const char *field);
+
+P11_KIT_DEPRECATED_FOR (module->C_Initialize)
+CK_RV                    p11_kit_initialize_module         (CK_FUNCTION_LIST_PTR module);
+
+P11_KIT_DEPRECATED_FOR (module->C_Finalize)
+CK_RV                    p11_kit_finalize_module           (CK_FUNCTION_LIST_PTR module);
+
+P11_KIT_DEPRECATED_FOR (p11_kit_module_load)
+CK_RV                    p11_kit_load_initialize_module    (const char *module_path,
+                                                            CK_FUNCTION_LIST_PTR *module);
+
+#endif /* P11_KIT_DISABLE_DEPRECATED */
+
+#undef P11_KIT_DEPRECATED_FOR
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* __P11_KIT_DEPRECATED_H__ */
diff --git a/p11-kit/docs.h b/p11-kit/docs.h
new file mode 100644 (file)
index 0000000..7b29e3d
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013 Red Hat Inc.
+ *
+ * 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@redhat.com>
+ */
+
+/* This header is not used by anything, and merely to help gtk-doc be sane */
+
+#define P11_KIT_MODULE_UNMANAGED 1
+#define P11_KIT_MODULE_CRITICAL 1
index e62a43cf21bf71cc8b21211a76100477dc482390..c6f1bee39c08ead1492e10c580cb6133f52f2f6f 100644 (file)
 
 #include "config.h"
 
-#include "conf.h"
+/* We use and define deprecated functions here */
+#define P11_KIT_NO_DEPRECATIONS
 #define P11_DEBUG_FLAG P11_DEBUG_LIB
+
+#include "conf.h"
 #include "debug.h"
 #include "dict.h"
 #include "library.h"
 #include "message.h"
+#include "modules.h"
 #include "path.h"
 #include "pkcs11.h"
 #include "p11-kit.h"
 #include "private.h"
+#include "virtual.h"
 
 #include <sys/stat.h>
 #include <sys/types.h>
  * crypto objects (like keys and certificates) and to perform crypto operations.
  *
  * In order for applications to behave consistently with regard to the user's
- * installed PKCS\#11 modules, each module must be registered so that applications
+ * installed PKCS\#11 modules, each module must be configured so that applications
  * or libraries know that they should load it.
  *
- * The functions here provide support for initializing registered modules. The
- * p11_kit_initialize_registered() function should be used to load and initialize
- * the registered modules. When done, the p11_kit_finalize_registered() function
+ * When multiple consumers of a module (such as libraries or applications) are
+ * in the same process, coordination of the initialization and finalization
+ * of PKCS\#11 modules is required. To do this modules are managed by p11-kit.
+ * This means that various unsafe methods are coordinated between callers. Unmanaged
+ * modules are simply the raw PKCS\#11 module pointers without p11-kit getting in the
+ * way. It is highly recommended that the default managed behavior is used.
+ *
+ * The functions here provide support for initializing configured modules. The
+ * p11_kit_modules_load() function should be used to load and initialize
+ * the configured modules. When done, the p11_kit_modules_release() function
  * should be used to release those modules and associated resources.
  *
- * In addition p11_kit_registered_option() can be used to access other parts
+ * In addition p11_kit_config_option() can be used to access other parts
  * of the module configuration.
  *
- * When multiple consumers of a module (such as libraries or applications) are
- * in the same process, coordination of the initialization and finalization
- * of PKCS\#11 modules is required. The functions here automatically provide
- * initialization reference counting to make this work.
- *
  * If a consumer wishes to load an arbitrary PKCS\#11 module that's not
- * registered, that module should be initialized with p11_kit_initialize_module()
- * and finalized with p11_kit_finalize_module(). The module's own
- * <code>C_Initialize</code> and <code>C_Finalize</code> methods should not
- * be called directly.
+ * configured use p11_kit_module_load() to do so. And use p11_kit_module_release()
+ * to later release it.
  *
  * Modules are represented by a pointer to their <code>CK_FUNCTION_LIST</code>
- * entry points. This means that callers can load modules elsewhere, using
- * dlopen() for example, and then still use these methods on them.
+ * entry points.
+ */
+
+/**
+ * SECTION:p11-kit-deprecated
+ * @title: Deprecated
+ * @short_description: Deprecated functions
+ *
+ * These functions have been deprecated from p11-kit and are not recommended for
+ * general usage. In large part they were deprecated because they did not adequately
+ * insulate multiple callers of a PKCS\#11 module from another, and could not
+ * support the 'managed' mode needed to do this.
+ */
+
+/**
+ * P11_KIT_MODULE_UNMANAGED:
+ *
+ * Module is loaded in non 'managed' mode. This is not recommended,
+ * disables many features, and prevents coordination between multiple
+ * callers of the same module.
+ */
+
+/**
+ * P11_KIT_MODULE_CRITICAL:
+ *
+ * Flag to load a module in 'critical' mode. Failure to load a critical module
+ * will prevent all other modules from loading. A failure when loading a
+ * non-critical module skips that module.
  */
 
 typedef struct _Module {
-       CK_FUNCTION_LIST_PTR funcs;
+       /*
+        * When using managed modules, this forms the base of the
+        * virtual stack into which all the other modules call. This is also
+        * the first field in this structure so we can cast between them.
+        */
+       p11_virtual virt;
+
+       /*
+        * The actual function pointers retrieved from the module. This is
+        * not necessarily populated. For non dl modules, such as rpc
+        * modules, this will be NULL.
+        */
+       CK_FUNCTION_LIST *funcs;
+
+       /* The initialize args built from configuration */
        CK_C_INITIALIZE_ARGS init_args;
        int ref_count;
+       int init_count;
 
        /* Registered modules */
        char *name;
        p11_dict *config;
+       bool critical;
 
-       /* Loaded modules */
-       dl_module_t dl_module;
+       /*
+        * This is a pointer to the actual dl shared module, or perhaps
+        * the RPC client context.
+        */
+       void *loaded_module;
+       p11_kit_destroyer loaded_destroy;
 
        /* Initialization, mutex must be held */
        p11_mutex_t initialize_mutex;
@@ -115,12 +166,18 @@ typedef struct _Module {
        p11_thread_id_t initialize_thread;
 } Module;
 
+typedef struct {
+       p11_virtual virt;
+       Module *mod;
+} Managed;
+
 /*
  * Shared data between threads, protected by the mutex, a structure so
  * we can audit thread safety easier.
  */
 static struct _Shared {
        p11_dict *modules;
+       p11_dict *managed;
        p11_dict *config;
 } gl = { NULL, NULL };
 
@@ -184,15 +241,19 @@ free_module_unlocked (void *data)
 
        assert (mod != NULL);
 
-       /* Module must be finalized */
-       assert (!mod->initialize_called);
-       assert (mod->initialize_thread == 0);
-
        /* Module must have no outstanding references */
        assert (mod->ref_count == 0);
 
-       if (mod->dl_module)
-               p11_dl_close (mod->dl_module);
+       if (mod->init_count > 0) {
+               p11_debug_precond ("module unloaded without C_Finalize having been "
+                                  "called for each C_Initialize");
+       } else {
+               assert (!mod->initialize_called);
+               assert (mod->initialize_thread == 0);
+       }
+
+       if (mod->loaded_destroy)
+               mod->loaded_destroy (mod->loaded_module);
 
        p11_mutex_uninit (&mod->initialize_mutex);
        p11_dict_free (mod->config);
@@ -215,28 +276,50 @@ alloc_module_unlocked (void)
        mod->init_args.flags = CKF_OS_LOCKING_OK;
        p11_mutex_init (&mod->initialize_mutex);
 
+       /*
+        * The default for configured modules is non-critical, but for
+        * modules loaded explicitly, and not from config, we treat them
+        * as critical. So this gets overridden for configured modules
+        * later when the config is loaded.
+        */
+       mod->critical = true;
+
        return mod;
 }
 
+static void
+module_setup_with_functions (Module *mod,
+                             CK_FUNCTION_LIST *funcs)
+{
+       mod->funcs = funcs;
+       p11_virtual_init (&mod->virt, &p11_virtual_base, funcs, NULL);
+}
+
 static CK_RV
 dlopen_and_get_function_list (Module *mod, const char *path)
 {
+       CK_FUNCTION_LIST *funcs;
        CK_C_GetFunctionList gfl;
+       dl_module_t dl;
        char *error;
        CK_RV rv;
 
-       assert (mod);
-       assert (path);
+       assert (mod != NULL);
+       assert (path != NULL);
 
-       mod->dl_module = p11_dl_open (path);
-       if (mod->dl_module == NULL) {
+       dl = p11_dl_open (path);
+       if (dl == NULL) {
                error = p11_dl_error ();
                p11_message ("couldn't load module: %s: %s", path, error);
                free (error);
                return CKR_GENERAL_ERROR;
        }
 
-       gfl = p11_dl_symbol (mod->dl_module, "C_GetFunctionList");
+       /* When the Module goes away, dlclose the loaded module */
+       mod->loaded_destroy = (p11_kit_destroyer)p11_dl_close;
+       mod->loaded_module = dl;
+
+       gfl = p11_dl_symbol (dl, "C_GetFunctionList");
        if (!gfl) {
                error = p11_dl_error ();
                p11_message ("couldn't find C_GetFunctionList entry point in module: %s: %s",
@@ -245,13 +328,19 @@ dlopen_and_get_function_list (Module *mod, const char *path)
                return CKR_GENERAL_ERROR;
        }
 
-       rv = gfl (&mod->funcs);
+       rv = gfl (&funcs);
        if (rv != CKR_OK) {
                p11_message ("call to C_GetFunctiontList failed in module: %s: %s",
                             path, p11_kit_strerror (rv));
                return rv;
        }
 
+       if (mod->funcs == &_p11_proxy_function_list) {
+               p11_message ("refusing to load the p11-kit-proxy.so module as a registered module");
+               return CKR_FUNCTION_FAILED;
+       }
+
+       module_setup_with_functions (mod, funcs);
        p11_debug ("opened module: %s", path);
        return CKR_OK;
 }
@@ -273,6 +362,7 @@ load_module_from_file_unlocked (const char *path, Module **result)
        }
 
        /* Do we have a previous one like this, if so ignore load */
+       assert (mod->funcs != NULL);
        prev = p11_dict_get (gl.modules, mod->funcs);
 
        if (prev != NULL) {
@@ -360,8 +450,9 @@ is_module_enabled_unlocked (const char *name,
 }
 
 static CK_RV
-take_config_and_load_module_unlocked (char **name,
-                                      p11_dict **config)
+take_config_and_load_module_inlock (char **name,
+                                    p11_dict **config,
+                                    bool critical)
 {
        Module *mod, *prev;
        const char *module_filename;
@@ -401,6 +492,7 @@ take_config_and_load_module_unlocked (char **name,
        *config = NULL;
        mod->name = *name;
        *name = NULL;
+       mod->critical = critical;
 
        rv = dlopen_and_get_function_list (mod, path);
        if (rv != CKR_OK) {
@@ -415,6 +507,7 @@ take_config_and_load_module_unlocked (char **name,
         */
        mod->init_args.pReserved = p11_dict_get (mod->config, "x-init-reserved");
 
+       assert (mod->funcs != NULL);
        prev = p11_dict_get (gl.modules, mod->funcs);
 
        /* If same module was loaded previously, just take over config */
@@ -485,8 +578,7 @@ load_registered_modules_unlocked (void)
 
                /* Is this a critical module, should abort loading of others? */
                critical = _p11_conf_parse_boolean (p11_dict_get (config, "critical"), false);
-
-               rv = take_config_and_load_module_unlocked (&name, &config);
+               rv = take_config_and_load_module_inlock (&name, &config, critical);
 
                /*
                 * These variables will be cleared if ownership is transeferred
@@ -510,10 +602,11 @@ load_registered_modules_unlocked (void)
 }
 
 static CK_RV
-initialize_module_unlocked_reentrant (Module *mod)
+initialize_module_inlock_reentrant (Module *mod)
 {
        CK_RV rv = CKR_OK;
        p11_thread_id_t self;
+
        assert (mod);
 
        self = p11_thread_id_self ();
@@ -535,19 +628,12 @@ initialize_module_unlocked_reentrant (Module *mod)
        p11_mutex_lock (&mod->initialize_mutex);
 
        if (!mod->initialize_called) {
-               assert (mod->funcs);
-
-               if (mod->funcs == &_p11_proxy_function_list) {
-                       p11_message ("refusing to load the p11-kit-proxy.so module as a registered module");
-                       rv = CKR_FUNCTION_FAILED;
+               p11_debug ("C_Initialize: calling");
 
-               } else {
-                       p11_debug ("C_Initialize: calling");
-
-                       rv = mod->funcs->C_Initialize (&mod->init_args);
+               rv = mod->virt.funcs.C_Initialize (&mod->virt.funcs,
+                                                  &mod->init_args);
 
-                       p11_debug ("C_Initialize: result: %lu", rv);
-               }
+               p11_debug ("C_Initialize: result: %lu", rv);
 
                /* Module was initialized and C_Finalize should be called */
                if (rv == CKR_OK)
@@ -561,10 +647,14 @@ initialize_module_unlocked_reentrant (Module *mod)
        p11_mutex_unlock (&mod->initialize_mutex);
        p11_lock ();
 
-       /* Don't claim reference if failed */
-       if (rv != CKR_OK)
-               --mod->ref_count;
+       if (rv == CKR_OK) {
+               /* Matches the ref count in finalize_module_inlock_reentrant() */
+               if (mod->init_count == 0)
+                       mod->ref_count++;
+               mod->init_count++;
+       }
 
+       mod->ref_count--;
        mod->initialize_thread = 0;
        return rv;
 }
@@ -605,6 +695,11 @@ init_globals_unlocked (void)
                return_val_if_fail (gl.modules != NULL, CKR_HOST_MEMORY);
        }
 
+       if (!gl.managed) {
+               gl.managed = p11_dict_new (p11_dict_direct_hash, p11_dict_direct_equal, NULL, NULL);
+               return_val_if_fail (gl.managed != NULL, CKR_HOST_MEMORY);
+       }
+
        if (once)
                return CKR_OK;
 
@@ -631,12 +726,14 @@ free_modules_when_no_refs_unlocked (void)
 
        p11_dict_free (gl.modules);
        gl.modules = NULL;
+       p11_dict_free (gl.managed);
+       gl.managed = NULL;
        p11_dict_free (gl.config);
        gl.config = NULL;
 }
 
 static CK_RV
-finalize_module_unlocked_reentrant (Module *mod)
+finalize_module_inlock_reentrant (Module *mod)
 {
        assert (mod);
 
@@ -647,7 +744,7 @@ finalize_module_unlocked_reentrant (Module *mod)
        if (mod->ref_count == 0)
                return CKR_ARGUMENTS_BAD;
 
-       if (--mod->ref_count > 0)
+       if (--mod->init_count > 0)
                return CKR_OK;
 
        /*
@@ -655,24 +752,20 @@ finalize_module_unlocked_reentrant (Module *mod)
         * the ref count. This prevents module from being freed out
         * from ounder us.
         */
-       ++mod->ref_count;
 
-       p11_mutex_lock (&mod->initialize_mutex);
        p11_unlock ();
+       p11_mutex_lock (&mod->initialize_mutex);
 
        if (mod->initialize_called) {
-
-               assert (mod->funcs);
-               mod->funcs->C_Finalize (NULL);
-
+               mod->virt.funcs.C_Finalize (&mod->virt.funcs, NULL);
                mod->initialize_called = false;
        }
 
        p11_mutex_unlock (&mod->initialize_mutex);
        p11_lock ();
 
-       /* Match the increment above */
-       --mod->ref_count;
+       /* Match the ref increment in initialize_module_inlock_reentrant() */
+       mod->ref_count--;
 
        free_modules_when_no_refs_unlocked ();
        return CKR_OK;
@@ -693,14 +786,18 @@ find_module_for_name_unlocked (const char *name)
        return NULL;
 }
 
-CK_RV
-_p11_kit_initialize_registered_unlocked_reentrant (void)
+static CK_RV
+initialize_registered_inlock_reentrant (void)
 {
        Module *mod;
        p11_dictiter iter;
-       int critical;
        CK_RV rv;
 
+       /*
+        * This is only called by deprecated code. The caller expects all
+        * configured and enabled modules to be initialized.
+        */
+
        rv = init_globals_unlocked ();
        if (rv != CKR_OK)
                return rv;
@@ -708,25 +805,20 @@ _p11_kit_initialize_registered_unlocked_reentrant (void)
        rv = load_registered_modules_unlocked ();
        if (rv == CKR_OK) {
                p11_dict_iterate (gl.modules, &iter);
-               while (p11_dict_next (&iter, NULL, (void **)&mod)) {
+               while (rv == CKR_OK && p11_dict_next (&iter, NULL, (void **)&mod)) {
 
-                       /* Skip all modules that aren't registered */
+                       /* Skip all modules that aren't registered or enabled */
                        if (mod->name == NULL || !is_module_enabled_unlocked (mod->name, mod->config))
                                continue;
 
-                       rv = initialize_module_unlocked_reentrant (mod);
-
-                       /*
-                        * Module failed to initialize. If this is a critical module,
-                        * then this, should abort loading of others.
-                        */
+                       rv = initialize_module_inlock_reentrant (mod);
                        if (rv != CKR_OK) {
-                               p11_message ("failed to initialize module: %s: %s",
-                                            mod->name, p11_kit_strerror (rv));
-
-                               critical = _p11_conf_parse_boolean (p11_dict_get (mod->config, "critical"), false);
-                               if (!critical) {
-                                       p11_debug ("ignoring failure, non-critical module: %s", mod->name);
+                               if (mod->critical) {
+                                       p11_message ("initialization of critical module '%s' failed: %s",
+                                                    mod->name, p11_kit_strerror (rv));
+                               } else {
+                                       p11_message ("skipping module '%s' whose initialization failed: %s",
+                                                    mod->name, p11_kit_strerror (rv));
                                        rv = CKR_OK;
                                }
                        }
@@ -751,6 +843,8 @@ _p11_kit_initialize_registered_unlocked_reentrant (void)
  * If this function fails, then an error message will be available via the
  * p11_kit_message() function.
  *
+ * Deprecated: Since: 0.16: Use p11_kit_modules_load() instead.
+ *
  * Returns: CKR_OK if the initialization succeeded, or an error code.
  */
 CK_RV
@@ -768,7 +862,7 @@ p11_kit_initialize_registered (void)
                p11_message_clear ();
 
                /* WARNING: Reentrancy can occur here */
-               rv = _p11_kit_initialize_registered_unlocked_reentrant ();
+               rv = initialize_registered_inlock_reentrant ();
 
                _p11_kit_default_message (rv);
 
@@ -782,14 +876,21 @@ p11_kit_initialize_registered (void)
        return rv;
 }
 
-CK_RV
-_p11_kit_finalize_registered_unlocked_reentrant (void)
+static CK_RV
+finalize_registered_inlock_reentrant (void)
 {
        Module *mod;
        p11_dictiter iter;
        Module **to_finalize;
        int i, count;
 
+       /*
+        * This is only called from deprecated code. The caller expects all
+        * modules initialized earlier to be finalized (once). If non-critical
+        * modules failed to initialize, then it is not possible to completely
+        * guarantee the internal state.
+        */
+
        if (!gl.modules)
                return CKR_CRYPTOKI_NOT_INITIALIZED;
 
@@ -804,7 +905,7 @@ _p11_kit_finalize_registered_unlocked_reentrant (void)
        while (p11_dict_next (&iter, NULL, (void **)&mod)) {
 
                /* Skip all modules that aren't registered */
-               if (mod->name)
+               if (mod->name && mod->init_count)
                        to_finalize[count++] = mod;
        }
 
@@ -812,7 +913,7 @@ _p11_kit_finalize_registered_unlocked_reentrant (void)
 
        for (i = 0; i < count; ++i) {
                /* WARNING: Reentrant calls can occur here */
-               finalize_module_unlocked_reentrant (to_finalize[i]);
+               finalize_module_inlock_reentrant (to_finalize[i]);
        }
 
        free (to_finalize);
@@ -837,6 +938,8 @@ _p11_kit_finalize_registered_unlocked_reentrant (void)
  * If this function fails, then an error message will be available via the
  * p11_kit_message() function.
  *
+ * Deprecated: Since 0.16: Use p11_kit_modules_release() instead.
+ *
  * Returns: CKR_OK if the finalization succeeded, or an error code.
  */
 
@@ -855,7 +958,7 @@ p11_kit_finalize_registered (void)
                p11_message_clear ();
 
                /* WARNING: Reentrant calls can occur here */
-               rv = _p11_kit_finalize_registered_unlocked_reentrant ();
+               rv = finalize_registered_inlock_reentrant ();
 
                _p11_kit_default_message (rv);
 
@@ -875,8 +978,14 @@ compar_priority (const void *one,
        const char *v1, *v2;
        int o1, o2;
 
-       m1 = p11_dict_get (gl.modules, f1);
-       m2 = p11_dict_get (gl.modules, f2);
+       m1 = p11_dict_get (gl.managed, f1);
+       if (m1 == NULL)
+               m1 = p11_dict_get (gl.modules, f1);
+
+       m2 = p11_dict_get (gl.managed, f2);
+       if (m2 == NULL)
+               m2 = p11_dict_get (gl.modules, f2);
+
        assert (m1 != NULL && m2 != NULL);
 
        v1 = p11_dict_get (m1->config, "priority");
@@ -910,16 +1019,21 @@ sort_modules_by_priority (CK_FUNCTION_LIST_PTR *modules,
        qsort (modules, count, sizeof (CK_FUNCTION_LIST_PTR), compar_priority);
 }
 
-CK_FUNCTION_LIST_PTR_PTR
-_p11_kit_registered_modules_unlocked (void)
+static CK_FUNCTION_LIST **
+list_registered_modules_inlock (void)
 {
-       CK_FUNCTION_LIST_PTR_PTR result = NULL;
+       CK_FUNCTION_LIST **result = NULL;
        Module *mod;
        p11_dictiter iter;
        int i = 0;
 
+       /*
+        * This is only called by deprecated code. The caller expects to get
+        * a list of all registered enabled modules that have been initialized.
+        */
+
        if (gl.modules) {
-               result = calloc (p11_dict_size (gl.modules) + 1, sizeof (CK_FUNCTION_LIST_PTR));
+               result = calloc (p11_dict_size (gl.modules) + 1, sizeof (CK_FUNCTION_LIST *));
                return_val_if_fail (result != NULL, NULL);
 
                p11_dict_iterate (gl.modules, &iter);
@@ -936,7 +1050,7 @@ _p11_kit_registered_modules_unlocked (void)
                         * having initialized. This is a corner case, but want to make
                         * sure to cover it.
                         */
-                       if (mod->ref_count && mod->name &&
+                       if (mod->ref_count && mod->name && mod->init_count && mod->funcs &&
                            is_module_enabled_unlocked (mod->name, mod->config)) {
                                result[i++] = mod->funcs;
                        }
@@ -957,6 +1071,10 @@ _p11_kit_registered_modules_unlocked (void)
  * The returned value is a <code>NULL</code> terminated array of
  * <code>CK_FUNCTION_LIST_PTR</code> pointers.
  *
+ * The returned modules are unmanaged.
+ *
+ * Deprecated: Since 0.16: Use p11_kit_modules_load() instead.
+ *
  * Returns: A list of all the registered modules. Use the free() function to
  * free the list.
  */
@@ -971,7 +1089,7 @@ p11_kit_registered_modules (void)
 
                p11_message_clear ();
 
-               result = _p11_kit_registered_modules_unlocked ();
+               result = list_registered_modules_inlock ();
 
        p11_unlock ();
 
@@ -987,12 +1105,36 @@ p11_kit_registered_modules (void)
  * You can use p11_kit_registered_modules() to get a list of all the registered
  * modules. This name is specified by the registered module configuration.
  *
+ * Deprecated: Since 0.16: Use p11_kit_module_get_name() instead.
+ *
  * Returns: A newly allocated string containing the module name, or
  *     <code>NULL</code> if no such registered module exists. Use free() to
  *     free this string.
  */
 char*
 p11_kit_registered_module_to_name (CK_FUNCTION_LIST_PTR module)
+{
+       return_val_if_fail (module != NULL, NULL);
+       return p11_kit_module_get_name (module);
+}
+
+/**
+ * p11_kit_module_get_name:
+ * @module: pointer to a loaded module
+ *
+ * Get the configured name of the PKCS\#11 module.
+ *
+ * Configured modules are loaded by p11_kit_modules_load(). The module
+ * passed to this function can be either managed or unmanaged. Non
+ * configured modules will return %NULL.
+ *
+ * Use free() to release the return value when you're done with it.
+ *
+ * Returns: a newly allocated string containing the module name, or
+ *     <code>NULL</code> if the module is not a configured module
+ */
+char *
+p11_kit_module_get_name (CK_FUNCTION_LIST *module)
 {
        Module *mod;
        char *name = NULL;
@@ -1005,15 +1147,65 @@ p11_kit_registered_module_to_name (CK_FUNCTION_LIST_PTR module)
 
                p11_message_clear ();
 
-               mod = module && gl.modules ? p11_dict_get (gl.modules, module) : NULL;
-               if (mod && mod->name)
-                       name = strdup (mod->name);
+               if (gl.modules) {
+                       mod = p11_dict_get (gl.modules, module);
+                       if (mod == NULL)
+                               mod = p11_dict_get (gl.managed, module);
+                       if (mod && mod->name)
+                               name = strdup (mod->name);
+               }
 
        p11_unlock ();
 
        return name;
 }
 
+/**
+ * p11_kit_module_get_flags:
+ * @module: the module
+ *
+ * Get the flags for this module.
+ *
+ * The %P11_KIT_MODULE_UNMANAGED flag will be set if the module is not
+ * managed by p11-kit. It is a raw PKCS\#11 module function list.
+ *
+ * The %P11_KIT_MODULE_CRITICAL flag will be set if the module is configured
+ * to be critical, and not be skipped over if it fails to initialize or
+ * load. This flag is also set for modules that are not configured, but have
+ * been loaded in another fashion.
+ *
+ * Returns: the flags for the module
+ */
+int
+p11_kit_module_get_flags (CK_FUNCTION_LIST *module)
+{
+       Module *mod;
+       int flags = 0;
+
+       return_val_if_fail (module != NULL, 0);
+
+       p11_library_init_once ();
+
+       p11_lock ();
+
+               p11_message_clear ();
+
+               if (gl.modules) {
+                       if (p11_virtual_is_wrapper (module)) {
+                               mod = p11_dict_get (gl.managed, module);
+                       } else {
+                               flags |= P11_KIT_MODULE_UNMANAGED;
+                               mod = p11_dict_get (gl.modules, module);
+                       }
+                       if (!mod || mod->critical)
+                               flags |= P11_KIT_MODULE_CRITICAL;
+               }
+
+       p11_unlock ();
+
+       return flags;
+}
+
 /**
  * p11_kit_registered_name_to_module:
  * @name: name of a registered module
@@ -1021,6 +1213,8 @@ p11_kit_registered_module_to_name (CK_FUNCTION_LIST_PTR module)
  * Lookup a registered PKCS\#11 module by its name. This name is specified by
  * the registered module configuration.
  *
+ * Deprecated: Since 0.16: Use p11_kit_module_for_name() instead.
+ *
  * Returns: a pointer to a PKCS\#11 module, or <code>NULL</code> if this name was
  *     not found.
  */
@@ -1032,19 +1226,85 @@ p11_kit_registered_name_to_module (const char *name)
 
        return_val_if_fail (name != NULL, NULL);
 
+       p11_lock ();
+
+       p11_message_clear ();
+
+       if (gl.modules) {
+               mod = find_module_for_name_unlocked (name);
+               if (mod != NULL && mod->funcs && is_module_enabled_unlocked (name, mod->config))
+                       module = mod->funcs;
+       }
+
+       p11_unlock ();
+
+       return module;
+}
+
+/**
+ * p11_kit_module_for_name:
+ * @modules: a list of modules to look through
+ * @name: the name of the module to find
+ *
+ * Look through the list of @modules and return the module whose @name
+ * matches.
+ *
+ * Only configured modules have names. Configured modules are loaded by
+ * p11_kit_modules_load(). The module passed to this function can be either
+ * managed or unmanaged.
+ *
+ * The return value is not copied or duplicated in anyway. It is still
+ * 'owned' by the @modules list.
+ *
+ * Returns: the module which matches the name, or %NULL if no match.
+ */
+CK_FUNCTION_LIST *
+p11_kit_module_for_name (CK_FUNCTION_LIST **modules,
+                         const char *name)
+{
+       CK_FUNCTION_LIST *ret = NULL;
+       Module *mod;
+       int i;
+
+       return_val_if_fail (name != NULL, NULL);
+
+       if (!modules)
+               return NULL;
+
+       p11_library_init_once ();
+
        p11_lock ();
 
                p11_message_clear ();
 
-               if (gl.modules) {
-                       mod = find_module_for_name_unlocked (name);
-                       if (mod != NULL && is_module_enabled_unlocked (name, mod->config))
-                               module = mod->funcs;
+               for (i = 0; gl.modules && modules[i] != NULL; i++) {
+                       mod = p11_dict_get (gl.modules, modules[i]);
+                       if (mod == NULL)
+                               mod = p11_dict_get (gl.managed, modules[i]);
+                       if (mod && mod->name && strcmp (mod->name, name) == 0) {
+                               ret = modules[i];
+                               break;
+                       }
                }
 
        p11_unlock ();
 
-       return module;
+       return ret;
+}
+
+static const char *
+module_get_option_inlock (Module *mod,
+                          const char *option)
+{
+       p11_dict *config;
+
+       if (mod == NULL)
+               config = gl.config;
+       else
+               config = mod->config;
+       if (config == NULL)
+               return NULL;
+       return p11_dict_get (config, option);
 }
 
 /**
@@ -1056,6 +1316,8 @@ p11_kit_registered_name_to_module (const char *name)
  * <code>NULL</code> module argument is specified, then this will lookup
  * the configuration option in the global config file.
  *
+ * Deprecated: Since 0.16: Use p11_kit_config_option() instead.
+ *
  * Returns: A newly allocated string containing the option value, or
  *     <code>NULL</code> if the registered module or the option were not found.
  *     Use free() to free the returned string.
@@ -1065,7 +1327,7 @@ p11_kit_registered_option (CK_FUNCTION_LIST_PTR module, const char *field)
 {
        Module *mod = NULL;
        char *option = NULL;
-       p11_dict *config = NULL;
+       const char *value;
 
        return_val_if_fail (field != NULL, NULL);
 
@@ -1075,20 +1337,14 @@ p11_kit_registered_option (CK_FUNCTION_LIST_PTR module, const char *field)
 
                p11_message_clear ();
 
-               if (module == NULL) {
-                       config = gl.config;
-
-               } else {
+               if (module == NULL)
+                       mod = NULL;
+               else
                        mod = gl.modules ? p11_dict_get (gl.modules, module) : NULL;
-                       if (mod)
-                               config = mod->config;
-               }
 
-               if (config && field) {
-                       option = p11_dict_get (config, field);
-                       if (option)
-                               option = strdup (option);
-               }
+               value = module_get_option_inlock (mod, field);
+               if (value)
+                       option = strdup (value);
 
        p11_unlock ();
 
@@ -1096,125 +1352,823 @@ p11_kit_registered_option (CK_FUNCTION_LIST_PTR module, const char *field)
 }
 
 /**
- * p11_kit_initialize_module:
- * @module: loaded module to initialize.
- *
- * Initialize an arbitrary PKCS\#11 module. Normally using the
- * p11_kit_initialize_registered() is preferred.
- *
- * Using this function to initialize modules allows coordination between
- * multiple users of the same module in a single process. It should be called
- * on modules that have been loaded (with dlopen() for example) but not yet
- * initialized. The caller should not yet have called the module's
- * <code>C_Initialize</code> method. This function will call
- * <code>C_Initialize</code> as necessary.
- *
- * Subsequent calls to this function for the same module will result in an
- * initialization count being incremented for the module. It is safe (although
- * usually unnecessary) to use this function on registered modules.
+ * p11_kit_config_option:
+ * @module: the module to retrieve the option for, or %NULL for global options
+ * @option: the option to retrieve
  *
- * The module must be finalized with p11_kit_finalize_module() instead of
- * calling its <code>C_Finalize</code> method directly.
+ * Retrieve the value for a configured option.
  *
- * This function does not accept a <code>CK_C_INITIALIZE_ARGS</code> argument.
- * Custom initialization arguments cannot be supported when multiple consumers
- * load the same module.
+ * If @module is %NULL, then the global option with the given name will
+ * be retrieved. Otherwise @module should point to a configured loaded module.
+ * If no such @option or configured @module exists, then %NULL will be returned.
  *
- * If this function fails, then an error message will be available via the
- * p11_kit_message() function.
+ * Use free() to release the returned value.
  *
- * Returns: CKR_OK if the initialization was successful.
+ * Returns: the option value or %NULL
  */
-CK_RV
-p11_kit_initialize_module (CK_FUNCTION_LIST_PTR module)
+char *
+p11_kit_config_option (CK_FUNCTION_LIST *module,
+                       const char *option)
 {
-       Module *allocated = NULL;
-       Module *mod;
-       CK_RV rv = CKR_OK;
+       Module *mod = NULL;
+       const char *value = NULL;
+       char *ret = NULL;
 
-       return_val_if_fail (module != NULL, CKR_ARGUMENTS_BAD);
+       return_val_if_fail (option != NULL, NULL);
 
        p11_library_init_once ();
 
-       /* WARNING: This function must be reentrant for the same arguments */
-       p11_debug ("in");
-
        p11_lock ();
 
                p11_message_clear ();
 
-               rv = init_globals_unlocked ();
-               if (rv == CKR_OK) {
-
-                       mod = p11_dict_get (gl.modules, module);
-                       if (mod == NULL) {
-                               p11_debug ("allocating new module");
-                               allocated = mod = alloc_module_unlocked ();
-                               if (mod == NULL)
-                                       rv = CKR_HOST_MEMORY;
-                               else
-                                       mod->funcs = module;
+               if (gl.modules) {
+                       if (module != NULL) {
+                               mod = p11_dict_get (gl.managed, module);
+                               if (mod == NULL) {
+                                       mod = p11_dict_get (gl.modules, module);
+                                       if (mod == NULL)
+                                               goto cleanup;
+                               }
                        }
 
-                       /* If this was newly allocated, add it to the list */
-                       if (rv == CKR_OK && allocated) {
-                               if (p11_dict_set (gl.modules, allocated->funcs, allocated))
-                                       allocated = NULL;
-                               else
-                                       rv = CKR_HOST_MEMORY;
-                       }
+                       value = module_get_option_inlock (mod, option);
+                       if (value)
+                               ret = strdup (value);
+               }
 
-                       if (rv == CKR_OK) {
 
-                               /* WARNING: Reentrancy can occur here */
-                               rv = initialize_module_unlocked_reentrant (mod);
-                       }
+cleanup:
+       p11_unlock ();
+       return ret;
+}
 
-                       free (allocated);
-               }
+static CK_RV
+managed_C_Initialize (CK_X_FUNCTION_LIST *self,
+                      CK_VOID_PTR init_args)
+{
+       Module *mod = ((Managed *)self)->mod;
+       CK_RV rv;
 
-               /*
-                * If initialization failed, we may need to cleanup.
-                * If we added this module above, then this will
-                * clean things up as expected.
-                */
-               if (rv != CKR_OK)
-                       free_modules_when_no_refs_unlocked ();
+       p11_debug ("in");
+       p11_lock ();
 
-               _p11_kit_default_message (rv);
+       rv = initialize_module_inlock_reentrant (mod);
 
        p11_unlock ();
-
        p11_debug ("out: %lu", rv);
+
        return rv;
 }
 
-/**
- * p11_kit_finalize_module:
- * @module: loaded module to finalize.
- *
- * Finalize an arbitrary PKCS\#11 module. The module must have been initialized
- * using p11_kit_initialize_module(). In most cases callers will want to use
- * p11_kit_finalize_registered() instead of this function.
- *
- * Using this function to finalize modules allows coordination between
- * multiple users of the same module in a single process. The caller should
- * call the module's <code>C_Finalize</code> method. This function will call
- * <code>C_Finalize</code> as necessary.
- *
- * If the module was initialized more than once, then this function will
- * decrement an initialization count for the module. When the count reaches zero
- * the module will be truly finalized. It is safe (although usually unnecessary)
- * to use this function on registered modules if (and only if) they were
- * initialized using p11_kit_initialize_module() for some reason.
- *
- * If this function fails, then an error message will be available via the
- * p11_kit_message() function.
- *
- * Returns: CKR_OK if the finalization was successful.
- */
-CK_RV
-p11_kit_finalize_module (CK_FUNCTION_LIST_PTR module)
+static CK_RV
+managed_C_Finalize (CK_X_FUNCTION_LIST *self,
+                    CK_VOID_PTR reserved)
+{
+       Module *mod = ((Managed *)self)->mod;
+       CK_RV rv;
+
+       p11_debug ("in");
+       p11_lock ();
+
+       rv = finalize_module_inlock_reentrant (mod);
+
+       p11_unlock ();
+       p11_debug ("out: %lu", rv);
+
+       return rv;
+}
+
+static void
+managed_free_inlock (void *data)
+{
+       Managed *managed = data;
+       managed->mod->ref_count--;
+       free (managed);
+}
+
+static p11_virtual *
+managed_create_inlock (Module *mod)
+{
+       Managed *managed;
+
+       managed = calloc (1, sizeof (Managed));
+       return_val_if_fail (managed != NULL, NULL);
+
+       p11_virtual_init (&managed->virt, &p11_virtual_stack,
+                         &mod->virt, NULL);
+       managed->virt.funcs.C_Initialize = managed_C_Initialize;
+       managed->virt.funcs.C_Finalize = managed_C_Finalize;
+       managed->mod = mod;
+       mod->ref_count++;
+
+       return &managed->virt;
+}
+
+static bool
+lookup_managed_option (Module *mod,
+                       const char *option,
+                       bool def_value)
+{
+       const char *string;
+       bool supported;
+       bool value;
+
+       /* Whether managed stuff is supported or not */
+       supported = p11_virtual_can_wrap ();
+
+       string = module_get_option_inlock (NULL, option);
+       if (!string)
+               string = module_get_option_inlock (mod, option);
+       if (!string) {
+               if (!supported)
+                       return false;
+               return def_value;
+       }
+
+       value = _p11_conf_parse_boolean (string, def_value);
+
+       if (!supported && value != supported) {
+               /*
+                * This is because libffi dependency was not built. The libffi dependency
+                * is highly recommended and building without it results in a large loss
+                * of functionality.
+                */
+               p11_message ("the '%s' option for module '%s' is not supported on this system",
+                            option, mod->name);
+               return false;
+       }
+
+       return value;
+}
+
+static CK_RV
+release_module_inlock_rentrant (CK_FUNCTION_LIST *module,
+                                const char *caller_func)
+{
+       Module *mod;
+
+       assert (module != NULL);
+
+       /* See if a managed module, and finalize if so */
+       mod = p11_dict_get (gl.managed, module);
+       if (mod != NULL) {
+               if (!p11_dict_remove (gl.managed, module))
+                       assert_not_reached ();
+               p11_virtual_unwrap (module);
+
+       /* If an unmanaged module then caller should have finalized */
+       } else {
+               mod = p11_dict_get (gl.modules, module);
+               if (mod == NULL) {
+                       p11_debug_precond ("invalid module pointer passed to %s", caller_func);
+                       return CKR_ARGUMENTS_BAD;
+               }
+       }
+
+       /* Matches the ref in prepare_module_inlock_reentrant() */
+       mod->ref_count--;
+       return CKR_OK;
+}
+
+CK_RV
+p11_modules_release_inlock_reentrant (CK_FUNCTION_LIST **modules)
+{
+       CK_RV ret = CKR_OK;
+       CK_RV rv;
+       int i;
+
+       for (i = 0; modules[i] != NULL; i++) {
+               rv = release_module_inlock_rentrant (modules[i], __PRETTY_FUNCTION__);
+               if (rv != CKR_OK)
+                       ret = rv;
+       }
+
+       free (modules);
+
+       /* In case nothing loaded, free up internal memory */
+       free_modules_when_no_refs_unlocked ();
+
+       return ret;
+}
+
+static CK_RV
+prepare_module_inlock_reentrant (Module *mod,
+                                 int flags,
+                                 CK_FUNCTION_LIST **module)
+{
+       p11_destroyer destroyer;
+       p11_virtual *virt;
+       bool is_managed;
+
+       assert (module != NULL);
+
+       if (flags & P11_KIT_MODULE_UNMANAGED)
+               is_managed = false;
+       else
+               is_managed = lookup_managed_option (mod, "managed", true);
+
+       if (is_managed) {
+               virt = managed_create_inlock (mod);
+               return_val_if_fail (virt != NULL, CKR_HOST_MEMORY);
+               destroyer = managed_free_inlock;
+
+               *module = p11_virtual_wrap (virt, destroyer);
+               return_val_if_fail (*module != NULL, CKR_GENERAL_ERROR);
+
+               if (!p11_dict_set (gl.managed, *module, mod))
+                       return_val_if_reached (CKR_HOST_MEMORY);
+
+       } else if (mod->funcs) {
+               *module = mod->funcs;
+
+       } else {
+               return CKR_FUNCTION_NOT_SUPPORTED;
+       }
+
+       /* Matches the deref in release_module_inlock_rentrant() */
+       mod->ref_count++;
+       return CKR_OK;
+}
+
+CK_RV
+p11_modules_load_inlock_reentrant (int flags,
+                                   CK_FUNCTION_LIST ***results)
+{
+       CK_FUNCTION_LIST **modules;
+       Module *mod;
+       p11_dictiter iter;
+       CK_RV rv;
+       int at;
+
+       rv = init_globals_unlocked ();
+       if (rv != CKR_OK)
+               return rv;
+
+       rv = load_registered_modules_unlocked ();
+       if (rv != CKR_OK)
+               return rv;
+
+       modules = calloc (p11_dict_size (gl.modules) + 1, sizeof (CK_FUNCTION_LIST *));
+       return_val_if_fail (modules != NULL, CKR_HOST_MEMORY);
+
+       at = 0;
+       rv = CKR_OK;
+
+       p11_dict_iterate (gl.modules, &iter);
+       while (p11_dict_next (&iter, NULL, (void **)&mod)) {
+
+               /*
+                * We don't include unreferenced modules. We don't include
+                * modules that have been initialized but aren't in the
+                * registry. These have a NULL name.
+                *
+                * In addition we check again that the module isn't disabled
+                * using enable-in or disable-in. This is because a caller
+                * can change the progname we recognize the process as after
+                * having initialized. This is a corner case, but want to make
+                * sure to cover it.
+                */
+               if (!mod->name || !is_module_enabled_unlocked (mod->name, mod->config))
+                       continue;
+
+               rv = prepare_module_inlock_reentrant (mod, flags, modules + at);
+               if (rv == CKR_OK)
+                       at++;
+               else if (rv != CKR_FUNCTION_NOT_SUPPORTED)
+                       break;
+       }
+
+       modules[at] = NULL;
+
+       if (rv != CKR_OK) {
+               p11_modules_release_inlock_reentrant (modules);
+               return rv;
+       }
+
+       sort_modules_by_priority (modules, at);
+       *results = modules;
+       return CKR_OK;
+}
+
+/**
+ * p11_kit_modules_load:
+ * @reserved: set to %NULL
+ * @flags: flags to use to load the module
+ *
+ * Load the configured PKCS\#11 modules.
+ *
+ * If @flags contains the %P11_KIT_MODULE_UNMANAGED flag, then the
+ * modules will be not be loaded in 'managed' mode regardless of its
+ * configuration. This is not recommended for general usage.
+ *
+ * If @flags contains the %P11_KIT_MODULE_CRITICAL flag then the
+ * modules will all be treated as 'critical', regardless of the module
+ * configuration. This means that a failure to load any module will
+ * cause this funtion to fail.
+ *
+ * For unmanaged modules there is no guarantee to the state of the
+ * modules. Other callers may be using the modules. Using unmanaged
+ * modules haphazardly is not recommended for this reason. Some
+ * modules (such as those configured with RPC) cannot be loaded in
+ * unmanaged mode, and will be skipped.
+ *
+ * Use p11_kit_modules_release() to release the modules returned by
+ * this function.
+ *
+ * If this function fails, then an error message will be available via the
+ * p11_kit_message() function.
+ *
+ * Returns: a null terminated list of modules represented as PKCS\#11
+ *     function lists, or %NULL on failure
+ */
+CK_FUNCTION_LIST **
+p11_kit_modules_load (const char *reserved,
+                      int flags)
+{
+       CK_FUNCTION_LIST **modules;
+       CK_RV rv;
+
+       /* progname attribute not implemented yet */
+       return_val_if_fail (reserved == NULL, NULL);
+
+       p11_library_init_once ();
+
+       /* WARNING: This function must be reentrant */
+       p11_debug ("in");
+
+       p11_lock ();
+
+               p11_message_clear ();
+
+               /* WARNING: Reentrancy can occur here */
+               rv = p11_modules_load_inlock_reentrant (flags, &modules);
+
+       p11_unlock ();
+
+       if (rv != CKR_OK)
+               modules = NULL;
+
+       p11_debug ("out: %s", modules ? "success" : "fail");
+       return modules;
+}
+
+/**
+ * p11_kit_modules_initialize:
+ * @modules: a %NULL terminated list of modules
+ * @failure_callback: called with modules that fail to initialize
+ *
+ * Initialize all the modules in the @modules list by calling their
+ * <literal>C_Initialize</literal> function.
+ *
+ * For managed modules the <literal>C_Initialize</literal> function
+ * is overridden so that multiple callers can initialize the same
+ * modules. In addition for managed modules multiple callers can
+ * initialize from different threads, and still guarantee consistent
+ * thread-safe behavior.
+ *
+ * For unmanaged modules if multiple callers try to initialize
+ * a module, then one of the calls will return
+ * <literal>CKR_CRYPTOKI_ALREADY_INITIALIZED</literal> according to the
+ * PKCS\#11 specification. In addition there are no guarantees that
+ * thread-safe behavior will occur if multiple callers initialize from
+ * different threads.
+ *
+ * When a module fails to initialize it is removed from the @modules list.
+ * If the @failure_callback is not %NULL then it is called with the modules that
+ * fail to initialize. For example, you may pass p11_kit_module_release()
+ * as a @failure_callback if the @modules list was loaded wit p11_kit_modules_load().
+ *
+ * The return value will return the failure code of the last critical
+ * module that failed to initialize. Non-critical module failures do not affect
+ * the return value. If no critical modules failed to initialize then the
+ * return value will be <literal>CKR_OK</literal>.
+ *
+ * When modules are removed, the list will be %NULL terminated at the
+ * appropriate place so it can continue to be used as a modules list.
+ *
+ * This function does not accept a <code>CK_C_INITIALIZE_ARGS</code> argument.
+ * Custom initialization arguments cannot be supported when multiple consumers
+ * load the same module.
+ *
+ * Returns: <literal>CKR_OK</literal> or the failure code of the last critical
+ *     module that failed to initialize.
+ */
+CK_RV
+p11_kit_modules_initialize (CK_FUNCTION_LIST **modules,
+                            p11_kit_destroyer failure_callback)
+{
+       CK_RV ret = CKR_OK;
+       CK_RV rv;
+       bool critical;
+       char *name;
+       int i, out;
+
+       return_val_if_fail (modules != NULL, CKR_ARGUMENTS_BAD);
+
+       for (i = 0, out = 0; modules[i] != NULL; i++, out++) {
+               rv = modules[i]->C_Initialize (NULL);
+               if (rv != CKR_OK) {
+                       name = p11_kit_module_get_name (modules[i]);
+                       if (name == NULL)
+                               name = strdup ("(unknown)");
+                       return_val_if_fail (name != NULL, CKR_HOST_MEMORY);
+                       critical = (p11_kit_module_get_flags (modules[i]) & P11_KIT_MODULE_CRITICAL);
+                       p11_message ("%s: module failed to initialize%s: %s",
+                                    name, critical ? "" : ", skipping", p11_kit_strerror (rv));
+                       if (critical)
+                               ret = rv;
+                       if (failure_callback)
+                               failure_callback (modules[i]);
+                       out--;
+                       free (name);
+               }
+       }
+
+       /* NULL terminate after above changes */
+       modules[out] = NULL;
+       return ret;
+}
+
+/**
+ * p11_kit_modules_load_and_initialize:
+ * @flags: flags to use to load the modules
+ *
+ * Load and initialize configured modules.
+ *
+ * If a critical module fails to load or initialize then the function will
+ * return <literal>NULL</literal>. Non-critical modules will be skipped
+ * and not included in the returned module list.
+ *
+ * Use p11_kit_modules_finalize_and_release() when you're done with the
+ * modules returned by this function.
+ *
+ * Returns: a <literal>NULL</literal> terminated list of modules, or
+ *     <literal>NULL</literal> on failure
+ */
+CK_FUNCTION_LIST **
+p11_kit_modules_load_and_initialize (int flags)
+{
+       CK_FUNCTION_LIST **modules;
+       CK_RV rv;
+
+       modules = p11_kit_modules_load (NULL, flags);
+       if (modules == NULL)
+               return NULL;
+
+       rv = p11_kit_modules_initialize (modules, (p11_destroyer)p11_kit_module_release);
+       if (rv != CKR_OK) {
+               p11_kit_modules_release (modules);
+               modules = NULL;
+       }
+
+       return modules;
+}
+
+/**
+ * p11_kit_modules_finalize:
+ * @modules: a <literal>NULL</literal> terminated list of modules
+ *
+ * Finalize each module in the @modules list by calling its
+ * <literal>C_Finalize</literal> function. Regardless of failures, all
+ * @modules will have their <literal>C_Finalize</literal> function called.
+ *
+ * If a module returns a failure from its <literal>C_Finalize</literal>
+ * method it will be returned. If multiple modules fail, the last failure
+ * will be returned.
+ *
+ * For managed modules the <literal>C_Finalize</literal> function
+ * is overridden so that multiple callers can finalize the same
+ * modules. In addition for managed modules multiple callers can
+ * finalize from different threads, and still guarantee consistent
+ * thread-safe behavior.
+ *
+ * For unmanaged modules if multiple callers try to finalize
+ * a module, then one of the calls will return
+ * <literal>CKR_CRYPTOKI_NOT_INITIALIZED</literal> according to the
+ * PKCS\#11 specification. In addition there are no guarantees that
+ * thread-safe behavior will occur if multiple callers finalize from
+ * different threads.
+ *
+ * Returns: <literal>CKR_OK</literal> or the failure code of the last
+ *     module that failed to finalize
+ */
+CK_RV
+p11_kit_modules_finalize (CK_FUNCTION_LIST **modules)
+{
+       CK_RV ret = CKR_OK;
+       CK_RV rv;
+       char *name;
+       int i;
+
+       return_val_if_fail (modules != NULL, CKR_ARGUMENTS_BAD);
+
+       for (i = 0; modules[i] != NULL; i++) {
+               rv = modules[i]->C_Finalize (NULL);
+               if (rv != CKR_OK) {
+                       name = p11_kit_module_get_name (modules[i]);
+                       p11_message ("%s: module failed to finalize: %s",
+                                    name ? name : "(unknown)", p11_kit_strerror (rv));
+                       free (name);
+                       ret = rv;
+               }
+       }
+
+       return ret;
+}
+
+/**
+ * p11_kit_modules_release:
+ * @modules: the modules to release
+ *
+ * Release the a set of loaded PKCS\#11 modules.
+ *
+ * The modules may be either managed or unmanaged. The array containing
+ * the module pointers is also freed by this function.
+ *
+ * Managed modules will not be actually released until all
+ * callers using them have done so. If the modules were initialized, they
+ * should have been finalized first.
+ */
+void
+p11_kit_modules_release (CK_FUNCTION_LIST **modules)
+{
+       p11_library_init_once ();
+
+       return_if_fail (modules != NULL);
+
+       /* WARNING: This function must be reentrant */
+       p11_debug ("in");
+
+       p11_lock ();
+
+               p11_message_clear ();
+               p11_modules_release_inlock_reentrant (modules);
+
+       p11_unlock ();
+
+       p11_debug ("out");
+}
+
+/**
+ * p11_kit_modules_finalize_and_release:
+ * @modules: the modules to release
+ *
+ * Finalize and then release the a set of loaded PKCS\#11 modules.
+ *
+ * The modules may be either managed or unmanaged. The array containing
+ * the module pointers is also freed by this function.
+ *
+ * Modules are released even if their finalization returns an error code.
+ * Managed modules will not be actually finalized or released until all
+ * callers using them have done so.
+ *
+ * For managed modules the <literal>C_Finalize</literal> function
+ * is overridden so that multiple callers can finalize the same
+ * modules. In addition for managed modules multiple callers can
+ * finalize from different threads, and still guarantee consistent
+ * thread-safe behavior.
+ *
+ * For unmanaged modules if multiple callers try to finalize
+ * a module, then one of the calls will return
+ * <literal>CKR_CRYPTOKI_NOT_INITIALIZED</literal> according to the
+ * PKCS\#11 specification. In addition there are no guarantees that
+ * thread-safe behavior will occur if multiple callers initialize from
+ * different threads.
+ */
+void
+p11_kit_modules_finalize_and_release (CK_FUNCTION_LIST **modules)
+{
+       return_if_fail (modules != NULL);
+       p11_kit_modules_finalize (modules);
+       p11_kit_modules_release (modules);
+}
+
+/**
+ * p11_kit_initialize_module:
+ * @module: loaded module to initialize.
+ *
+ * Initialize an arbitrary PKCS\#11 module. Normally using the
+ * p11_kit_initialize_registered() is preferred.
+ *
+ * Using this function to initialize modules allows coordination between
+ * multiple users of the same module in a single process. It should be called
+ * on modules that have been loaded (with dlopen() for example) but not yet
+ * initialized. The caller should not yet have called the module's
+ * <code>C_Initialize</code> method. This function will call
+ * <code>C_Initialize</code> as necessary.
+ *
+ * Subsequent calls to this function for the same module will result in an
+ * initialization count being incremented for the module. It is safe (although
+ * usually unnecessary) to use this function on registered modules.
+ *
+ * The module must be finalized with p11_kit_finalize_module() instead of
+ * calling its <code>C_Finalize</code> method directly.
+ *
+ * This function does not accept a <code>CK_C_INITIALIZE_ARGS</code> argument.
+ * Custom initialization arguments cannot be supported when multiple consumers
+ * load the same module.
+ *
+ * If this function fails, then an error message will be available via the
+ * p11_kit_message() function.
+ *
+ * Deprecated: Since 0.16: Use p11_kit_module_initialize() instead.
+ *
+ * Returns: CKR_OK if the initialization was successful.
+ */
+CK_RV
+p11_kit_initialize_module (CK_FUNCTION_LIST_PTR module)
+{
+       CK_FUNCTION_LIST_PTR result;
+       Module *mod;
+       int flags;
+       CK_RV rv;
+
+       return_val_if_fail (module != NULL, CKR_ARGUMENTS_BAD);
+
+       p11_library_init_once ();
+
+       /* WARNING: This function must be reentrant for the same arguments */
+       p11_debug ("in");
+
+       p11_lock ();
+
+               p11_message_clear ();
+
+               flags = P11_KIT_MODULE_CRITICAL | P11_KIT_MODULE_UNMANAGED;
+               rv = p11_module_load_inlock_reentrant (module, flags, &result);
+
+               /* An unmanaged module should return the same pointer */
+               assert (rv != CKR_OK || result == module);
+
+               if (rv == CKR_OK) {
+                       mod = p11_dict_get (gl.modules, module);
+                       assert (mod != NULL);
+                       rv = initialize_module_inlock_reentrant (mod);
+                       if (rv != CKR_OK) {
+                               p11_message ("module initialization failed: %s", p11_kit_strerror (rv));
+                               p11_module_release_inlock_reentrant (module);
+                       }
+               }
+
+       p11_unlock ();
+
+       p11_debug ("out: %lu", rv);
+       return rv;
+}
+
+CK_RV
+p11_module_load_inlock_reentrant (CK_FUNCTION_LIST *module,
+                                  int flags,
+                                  CK_FUNCTION_LIST **result)
+{
+       Module *allocated = NULL;
+       Module *mod;
+       CK_RV rv = CKR_OK;
+
+       rv = init_globals_unlocked ();
+       if (rv == CKR_OK) {
+
+               mod = p11_dict_get (gl.modules, module);
+               if (mod == NULL) {
+                       p11_debug ("allocating new module");
+                       allocated = mod = alloc_module_unlocked ();
+                       if (mod == NULL)
+                               rv = CKR_HOST_MEMORY;
+                       else
+                               module_setup_with_functions (mod, module);
+               }
+
+               /* If this was newly allocated, add it to the list */
+               if (rv == CKR_OK && allocated) {
+                       if (p11_dict_set (gl.modules, allocated->funcs, allocated))
+                               allocated = NULL;
+                       else
+                               rv = CKR_HOST_MEMORY;
+               }
+
+               if (rv == CKR_OK) {
+                       /* WARNING: Reentrancy can occur here */
+                       rv = prepare_module_inlock_reentrant (mod, flags, result);
+               }
+
+               free (allocated);
+       }
+
+       /*
+        * If initialization failed, we may need to cleanup.
+        * If we added this module above, then this will
+        * clean things up as expected.
+        */
+       if (rv != CKR_OK)
+               free_modules_when_no_refs_unlocked ();
+
+       _p11_kit_default_message (rv);
+       return rv;
+}
+
+/**
+ * p11_kit_module_load:
+ * @module_path: full file path of module library
+ * @flags: flags to use when loading the module
+ *
+ * Load an arbitrary PKCS\#11 module from a dynamic library file, and
+ * initialize it. Normally using the p11_kit_modules_load() function
+ * is preferred.
+ *
+ * Using this function to load modules allows coordination between multiple
+ * callers of the same module in a single process. If @flags contains the
+ * %P11_KIT_MODULE_UNMANAGED flag, then the modules will be not be loaded
+ * in 'managed' mode and not be coordinated. This is not recommended
+ * for general usage.
+ *
+ * Subsequent calls to this function for the same module will result in an
+ * initialization count being incremented for the module. It is safe (although
+ * usually unnecessary) to use this function on registered modules.
+ *
+ * The module should be released with p11_kit_module_release().
+ *
+ * If this function fails, then an error message will be available via the
+ * p11_kit_message() function.
+ *
+ * Returns: the loaded module PKCS\#11 functions or %NULL on failure
+ */
+CK_FUNCTION_LIST *
+p11_kit_module_load (const char *module_path,
+                     int flags)
+{
+       CK_FUNCTION_LIST *module;
+       CK_RV rv;
+       Module *mod;
+
+       return_val_if_fail (module_path != NULL, NULL);
+
+       p11_library_init_once ();
+
+       /* WARNING: This function must be reentrant for the same arguments */
+       p11_debug ("in: %s", module_path);
+
+       p11_lock ();
+
+               p11_message_clear ();
+
+               rv = init_globals_unlocked ();
+               if (rv == CKR_OK) {
+
+                       rv = load_module_from_file_unlocked (module_path, &mod);
+                       if (rv == CKR_OK) {
+
+                               /* WARNING: Reentrancy can occur here */
+                               rv = prepare_module_inlock_reentrant (mod, flags, &module);
+                               if (rv != CKR_OK)
+                                       module = NULL;
+                       }
+               }
+
+               /*
+                * If initialization failed, we may need to cleanup.
+                * If we added this module above, then this will
+                * clean things up as expected.
+                */
+               if (rv != CKR_OK)
+                       free_modules_when_no_refs_unlocked ();
+
+       p11_unlock ();
+
+       p11_debug ("out: %s", module ? "success" : "fail");
+       return module;
+
+}
+
+/**
+ * p11_kit_finalize_module:
+ * @module: loaded module to finalize.
+ *
+ * Finalize an arbitrary PKCS\#11 module. The module must have been initialized
+ * using p11_kit_initialize_module(). In most cases callers will want to use
+ * p11_kit_finalize_registered() instead of this function.
+ *
+ * Using this function to finalize modules allows coordination between
+ * multiple users of the same module in a single process. The caller should not
+ * call the module's <code>C_Finalize</code> method. This function will call
+ * <code>C_Finalize</code> as necessary.
+ *
+ * If the module was initialized more than once, then this function will
+ * decrement an initialization count for the module. When the count reaches zero
+ * the module will be truly finalized. It is safe (although usually unnecessary)
+ * to use this function on registered modules if (and only if) they were
+ * initialized using p11_kit_initialize_module() for some reason.
+ *
+ * If this function fails, then an error message will be available via the
+ * p11_kit_message() function.
+ *
+ * Deprecated: Since 0.16: Use p11_kit_module_finalize() and
+ *     p11_kit_module_release() instead.
+ *
+ * Returns: CKR_OK if the finalization was successful.
+ */
+CK_RV
+p11_kit_finalize_module (CK_FUNCTION_LIST *module)
 {
        Module *mod;
        CK_RV rv = CKR_OK;
@@ -1236,7 +2190,7 @@ p11_kit_finalize_module (CK_FUNCTION_LIST_PTR module)
                        rv = CKR_ARGUMENTS_BAD;
                } else {
                        /* WARNING: Rentrancy can occur here */
-                       rv = finalize_module_unlocked_reentrant (mod);
+                       rv = finalize_module_inlock_reentrant (mod);
                }
 
                _p11_kit_default_message (rv);
@@ -1247,6 +2201,130 @@ p11_kit_finalize_module (CK_FUNCTION_LIST_PTR module)
        return rv;
 }
 
+/**
+ * p11_kit_module_initialize:
+ * @module: the module to initialize
+ *
+ * Initialize a PKCS\#11 module by calling its <literal>C_Initialize</literal>
+ * function.
+ *
+ * For managed modules the <literal>C_Initialize</literal> function
+ * is overridden so that multiple callers can initialize the same
+ * modules. In addition for managed modules multiple callers can
+ * initialize from different threads, and still guarantee consistent
+ * thread-safe behavior.
+ *
+ * For unmanaged modules if multiple callers try to initialize
+ * a module, then one of the calls will return
+ * <literal>CKR_CRYPTOKI_ALREADY_INITIALIZED</literal> according to the
+ * PKCS\#11 specification. In addition there are no guarantees that
+ * thread-safe behavior will occur if multiple callers initialize from
+ * different threads.
+ *
+ * This function does not accept a <code>CK_C_INITIALIZE_ARGS</code> argument.
+ * Custom initialization arguments cannot be supported when multiple consumers
+ * load the same module.
+ *
+ * Returns: <literal>CKR_OK</literal> or a failure code
+ */
+CK_RV
+p11_kit_module_initialize (CK_FUNCTION_LIST *module)
+{
+       char *name;
+       CK_RV rv;
+
+       return_val_if_fail (module != NULL, CKR_ARGUMENTS_BAD);
+
+       rv = module->C_Initialize (NULL);
+       if (rv != CKR_OK) {
+               name = p11_kit_module_get_name (module);
+               p11_message ("%s: module failed to initialize: %s",
+                            name ? name : "(unknown)", p11_kit_strerror (rv));
+               free (name);
+       }
+
+       return rv;
+}
+
+/**
+ * p11_kit_module_finalize:
+ * @module: the module to finalize
+ *
+ * Finalize a PKCS\#11 module by calling its <literal>C_Finalize</literal>
+ * function.
+ *
+ * For managed modules the <literal>C_Finalize</literal> function
+ * is overridden so that multiple callers can finalize the same
+ * modules. In addition for managed modules multiple callers can
+ * finalize from different threads, and still guarantee consistent
+ * thread-safe behavior.
+ *
+ * For unmanaged modules if multiple callers try to finalize
+ * a module, then one of the calls will return
+ * <literal>CKR_CRYPTOKI_NOT_INITIALIZED</literal> according to the
+ * PKCS\#11 specification. In addition there are no guarantees that
+ * thread-safe behavior will occur if multiple callers finalize from
+ * different threads.
+ *
+ * Returns: <literal>CKR_OK</literal> or a failure code
+ */
+CK_RV
+p11_kit_module_finalize (CK_FUNCTION_LIST *module)
+{
+       char *name;
+       CK_RV rv;
+
+       return_val_if_fail (module != NULL, CKR_ARGUMENTS_BAD);
+
+       rv = module->C_Finalize (NULL);
+       if (rv != CKR_OK) {
+               name = p11_kit_module_get_name (module);
+               p11_message ("%s: module failed to finalize: %s",
+                            name ? name : "(unknown)", p11_kit_strerror (rv));
+               free (name);
+       }
+
+       return rv;
+
+}
+
+
+/**
+ * p11_kit_module_release:
+ * @module: the module to release
+ *
+ * Release the a loaded PKCS\#11 modules.
+ *
+ * The module may be either managed or unmanaged. The <literal>C_Finalize</literal>
+ * function will be called if no other callers are using this module.
+ */
+void
+p11_kit_module_release (CK_FUNCTION_LIST *module)
+{
+       return_if_fail (module != NULL);
+
+       p11_library_init_once ();
+
+       /* WARNING: This function must be reentrant for the same arguments */
+       p11_debug ("in");
+
+       p11_lock ();
+
+               p11_message_clear ();
+
+               release_module_inlock_rentrant (module, __PRETTY_FUNCTION__);
+
+       p11_unlock ();
+
+       p11_debug ("out");
+}
+
+CK_RV
+p11_module_release_inlock_reentrant (CK_FUNCTION_LIST *module)
+{
+       return release_module_inlock_rentrant (module, __PRETTY_FUNCTION__);
+}
+
 /**
  * p11_kit_load_initialize_module:
  * @module_path: full file path of module library
@@ -1278,6 +2356,8 @@ p11_kit_finalize_module (CK_FUNCTION_LIST_PTR module)
  * If this function fails, then an error message will be available via the
  * p11_kit_message() function.
  *
+ * Deprecated: Since 0.16: Use p11_kit_module_load() instead.
+ *
  * Returns: CKR_OK if the initialization was successful.
  */
 CK_RV
@@ -1306,12 +2386,14 @@ p11_kit_load_initialize_module (const char *module_path,
                        if (rv == CKR_OK) {
 
                                /* WARNING: Reentrancy can occur here */
-                               rv = initialize_module_unlocked_reentrant (mod);
+                               rv = initialize_module_inlock_reentrant (mod);
                        }
                }
 
-               if (rv == CKR_OK && module)
+               if (rv == CKR_OK && module) {
+                       assert (mod->funcs != NULL);
                        *module = mod->funcs;
+               }
 
                /*
                 * If initialization failed, we may need to cleanup.
diff --git a/p11-kit/modules.h b/p11-kit/modules.h
new file mode 100644 (file)
index 0000000..ca8dac3
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013 Red Hat Inc.
+ *
+ * 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@redhat.com>
+ */
+
+#ifndef __P11_MODULES_H__
+#define __P11_MODULES_H__
+
+#include "pkcs11.h"
+
+CK_RV      p11_modules_load_inlock_reentrant         (int flags,
+                                                      CK_FUNCTION_LIST_PTR **results);
+
+CK_RV      p11_modules_release_inlock_reentrant      (CK_FUNCTION_LIST_PTR *modules);
+
+CK_RV      p11_module_load_inlock_reentrant          (CK_FUNCTION_LIST_PTR module,
+                                                      int flags,
+                                                      CK_FUNCTION_LIST_PTR *result);
+
+CK_RV      p11_module_release_inlock_reentrant       (CK_FUNCTION_LIST_PTR module);
+
+#endif /* __P11_MODULES_H__ */
index f83cbd0db63649b68a5dddcb298e42fc7f403d40..b8edcc2f4ef8d201751109bf25e745a8b60ae7e9 100644 (file)
@@ -36,6 +36,7 @@
 #define __P11_KIT_H__
 
 #include "p11-kit/pkcs11.h"
+#include "deprecated.h"
 
 /*
  * If the caller is using the PKCS#11 GNU calling convention, then we cater
@@ -50,45 +51,63 @@ typedef struct ck_function_list* CK_FUNCTION_LIST_PTR;
 extern "C" {
 #endif
 
-CK_RV                    p11_kit_initialize_registered     (void);
+enum {
+       P11_KIT_MODULE_UNMANAGED = 1 << 0,
+       P11_KIT_MODULE_CRITICAL = 1 << 1,
+};
 
-CK_RV                    p11_kit_finalize_registered       (void);
+typedef void        (* p11_kit_destroyer)                   (void *data);
 
-CK_FUNCTION_LIST_PTR*    p11_kit_registered_modules        (void);
+CK_FUNCTION_LIST **    p11_kit_modules_load                 (const char *reserved,
+                                                             int flags);
 
-char*                    p11_kit_registered_module_to_name (CK_FUNCTION_LIST_PTR module);
+CK_RV                  p11_kit_modules_initialize           (CK_FUNCTION_LIST **modules,
+                                                             p11_kit_destroyer failure_callback);
 
-CK_FUNCTION_LIST_PTR     p11_kit_registered_name_to_module (const char *name);
+CK_FUNCTION_LIST **    p11_kit_modules_load_and_initialize  (int flags);
 
-char*                    p11_kit_registered_option         (CK_FUNCTION_LIST_PTR module,
-                                                            const char *field);
+CK_RV                  p11_kit_modules_finalize             (CK_FUNCTION_LIST **modules);
 
-CK_RV                    p11_kit_initialize_module         (CK_FUNCTION_LIST_PTR module);
+void                   p11_kit_modules_release              (CK_FUNCTION_LIST **modules);
 
-CK_RV                    p11_kit_finalize_module           (CK_FUNCTION_LIST_PTR module);
+void                   p11_kit_modules_finalize_and_release (CK_FUNCTION_LIST **modules);
 
-CK_RV                    p11_kit_load_initialize_module    (const char *module_path,
-                                                            CK_FUNCTION_LIST_PTR *module);
+CK_FUNCTION_LIST *     p11_kit_module_for_name              (CK_FUNCTION_LIST **modules,
+                                                             const char *name);
 
-const char*              p11_kit_strerror                  (CK_RV rv);
+char *                 p11_kit_module_get_name              (CK_FUNCTION_LIST *module);
 
-size_t                   p11_kit_space_strlen              (const unsigned char *string,
-                                                            size_t max_length);
+int                    p11_kit_module_get_flags             (CK_FUNCTION_LIST *module);
 
-char*                    p11_kit_space_strdup              (const unsigned char *string,
-                                                            size_t max_length);
+CK_FUNCTION_LIST *     p11_kit_module_load                  (const char *module_path,
+                                                             int flags);
 
-#ifdef P11_KIT_FUTURE_UNSTABLE_API
+CK_RV                  p11_kit_module_initialize            (CK_FUNCTION_LIST *module);
+
+CK_RV                  p11_kit_module_finalize              (CK_FUNCTION_LIST *module);
+
+void                   p11_kit_module_release               (CK_FUNCTION_LIST *module);
+
+char *                 p11_kit_config_option                (CK_FUNCTION_LIST *module,
+                                                             const char *option);
 
-void                     p11_kit_set_progname              (const char *progname);
+const char*            p11_kit_strerror                     (CK_RV rv);
+
+size_t                 p11_kit_space_strlen                 (const unsigned char *string,
+                                                             size_t max_length);
+
+char*                  p11_kit_space_strdup                 (const unsigned char *string,
+                                                             size_t max_length);
+
+#ifdef P11_KIT_FUTURE_UNSTABLE_API
 
-void                     p11_kit_be_quiet                  (void);
+void                   p11_kit_set_progname                 (const char *progname);
 
-void                     p11_kit_be_loud                   (void);
+void                   p11_kit_be_quiet                     (void);
 
-const char*              p11_kit_message                   (void);
+void                   p11_kit_be_loud                      (void);
 
-typedef void          (* p11_kit_destroyer)                (void *data);
+const char *           p11_kit_message                      (void);
 
 #endif
 
index f862975b65894bd8bb9ff469b35ad731b0b61247..b44ae2457a795adb1ca8016be9f5b2f810d647d4 100644 (file)
 
 extern CK_FUNCTION_LIST _p11_proxy_function_list;
 
-CK_FUNCTION_LIST_PTR_PTR   _p11_kit_registered_modules_unlocked (void);
-
-CK_RV       _p11_kit_initialize_registered_unlocked_reentrant   (void);
-
-CK_RV       _p11_kit_finalize_registered_unlocked_reentrant     (void);
-
 void        _p11_kit_proxy_after_fork                           (void);
 
 CK_RV       _p11_load_config_files_unlocked                     (const char *system_conf,
index 1908d34f360331866a4776fce72a472f3255932a..8ae6b7f448e919db9c30c7769c0b45da43544c73 100644 (file)
 #include "config.h"
 
 #define P11_DEBUG_FLAG P11_DEBUG_PROXY
+#define CRYPTOKI_EXPORTS
+
 #include "debug.h"
 #include "dict.h"
 #include "library.h"
 #include "message.h"
-#define CRYPTOKI_EXPORTS
+#include "modules.h"
 #include "pkcs11.h"
 #include "p11-kit.h"
 #include "private.h"
@@ -70,17 +72,16 @@ typedef struct _Session {
        CK_SLOT_ID wrap_slot;
 } Session;
 
-/*
- * Shared data between threads, protected by the mutex, a structure so
- * we can audit thread safety easier.
- */
-static struct _Shared {
+typedef struct {
+       int refs;
        Mapping *mappings;
        unsigned int n_mappings;
-       int mappings_refs;
        p11_dict *sessions;
        CK_ULONG last_handle;
-} gl = { NULL, 0, 0, NULL, FIRST_HANDLE };
+       CK_FUNCTION_LIST_PTR *modules;
+} Proxy;
+
+static Proxy *px = NULL;
 
 #define MANUFACTURER_ID         "PKCS#11 Kit                     "
 #define LIBRARY_DESCRIPTION     "PKCS#11 Kit Proxy Module        "
@@ -94,17 +95,18 @@ static struct _Shared {
 static CK_RV
 map_slot_unlocked (CK_SLOT_ID slot, Mapping *mapping)
 {
+       assert (px != NULL);
        assert (mapping);
 
        if (slot < MAPPING_OFFSET)
                return CKR_SLOT_ID_INVALID;
        slot -= MAPPING_OFFSET;
 
-       if (slot > gl.n_mappings) {
+       if (slot > px->n_mappings) {
                return CKR_SLOT_ID_INVALID;
        } else {
-               assert (gl.mappings);
-               memcpy (mapping, &gl.mappings[slot], sizeof (Mapping));
+               assert (px->mappings);
+               memcpy (mapping, &px->mappings[slot], sizeof (Mapping));
                return CKR_OK;
        }
 }
@@ -118,7 +120,7 @@ map_slot_to_real (CK_SLOT_ID_PTR slot, Mapping *mapping)
 
        p11_lock ();
 
-               if (!gl.mappings)
+               if (!px)
                        rv = CKR_CRYPTOKI_NOT_INITIALIZED;
                else
                        rv = map_slot_unlocked (*slot, mapping);
@@ -141,11 +143,11 @@ map_session_to_real (CK_SESSION_HANDLE_PTR handle, Mapping *mapping, Session *se
 
        p11_lock ();
 
-               if (!gl.sessions) {
+               if (!px) {
                        rv = CKR_CRYPTOKI_NOT_INITIALIZED;
                } else {
-                       assert (gl.sessions);
-                       sess = p11_dict_get (gl.sessions, handle);
+                       assert (px->sessions);
+                       sess = p11_dict_get (px->sessions, handle);
                        if (sess != NULL) {
                                *handle = sess->real_session;
                                rv = map_slot_unlocked (sess->wrap_slot, mapping);
@@ -162,26 +164,21 @@ map_session_to_real (CK_SESSION_HANDLE_PTR handle, Mapping *mapping, Session *se
 }
 
 static void
-finalize_mappings_unlocked (void)
+proxy_free (Proxy *py)
 {
-       assert (gl.mappings_refs);
-
-       if (--gl.mappings_refs)
-               return;
-
-       /* No more mappings */
-       free (gl.mappings);
-       gl.mappings = NULL;
-       gl.n_mappings = 0;
-
-       /* no more sessions */
-       p11_dict_free (gl.sessions);
-       gl.sessions = NULL;
+       if (py) {
+               p11_kit_modules_finalize_and_release (py->modules);
+               p11_dict_free (py->sessions);
+               free (py->mappings);
+               free (py);
+       }
 }
 
 void
 _p11_kit_proxy_after_fork (void)
 {
+       Proxy *py;
+
        /*
         * After a fork the callers are supposed to call C_Initialize and all.
         * In addition the underlying libraries may change their state so free
@@ -190,17 +187,23 @@ _p11_kit_proxy_after_fork (void)
 
        p11_lock ();
 
-               gl.mappings_refs = 1;
-               finalize_mappings_unlocked ();
-               assert (!gl.mappings);
+               py = px;
+               px = NULL;
 
        p11_unlock ();
+
+       if (py) {
+               p11_kit_modules_release (py->modules);
+               py->modules = NULL;
+               proxy_free (py);
+       }
 }
 
 static CK_RV
 proxy_C_Finalize (CK_VOID_PTR reserved)
 {
-       CK_RV rv;
+       Proxy *py = NULL;
+       CK_RV rv = CKR_OK;
 
        p11_debug ("in");
 
@@ -212,17 +215,16 @@ proxy_C_Finalize (CK_VOID_PTR reserved)
        } else {
                p11_lock ();
 
-                       /* WARNING: Reentrancy can occur here */
-                       rv = _p11_kit_finalize_registered_unlocked_reentrant ();
-
-                       /*
-                        * If modules are all gone, then this was the last
-                        * finalize, so cleanup our mappings
-                        */
-                       if (gl.mappings_refs)
-                               finalize_mappings_unlocked ();
+                       if (!px) {
+                               rv = CKR_CRYPTOKI_NOT_INITIALIZED;
+                       } else if (px->refs-- == 1) {
+                               py = px;
+                               px = NULL;
+                       }
 
                p11_unlock ();
+
+               proxy_free (py);
        }
 
        p11_debug ("out: %lu", rv);
@@ -230,35 +232,50 @@ proxy_C_Finalize (CK_VOID_PTR reserved)
 }
 
 static CK_RV
-initialize_mappings_unlocked_reentrant (void)
+proxy_create (Proxy **res)
 {
-       CK_FUNCTION_LIST_PTR *funcss, *f;
+       CK_FUNCTION_LIST_PTR *f;
        CK_FUNCTION_LIST_PTR funcs;
-       Mapping *mappings = NULL;
-       int n_mappings = 0;
        CK_SLOT_ID_PTR slots;
        CK_ULONG i, count;
        CK_RV rv = CKR_OK;
+       Proxy *py;
 
-       assert (!gl.mappings);
+       py = calloc (1, sizeof (Proxy));
+       return_val_if_fail (py != NULL, CKR_HOST_MEMORY);
 
-       funcss = _p11_kit_registered_modules_unlocked ();
-       for (f = funcss; *f; ++f) {
-               funcs = *f;
+       p11_lock ();
 
-               assert (funcs);
-               slots = NULL;
+               /* WARNING: Reentrancy can occur here */
+               rv = p11_modules_load_inlock_reentrant (0, &py->modules);
 
-               p11_unlock ();
+       p11_unlock ();
 
-                       /* Ask module for its slots */
-                       rv = (funcs->C_GetSlotList) (FALSE, NULL, &count);
-                       if (rv == CKR_OK && count) {
-                               slots = calloc (sizeof (CK_SLOT_ID), count);
-                               rv = (funcs->C_GetSlotList) (FALSE, slots, &count);
-                       }
+       if (rv != CKR_OK) {
+               proxy_free (py);
+               free (py);
+               return rv;
+       }
 
-               p11_lock ();
+       rv = p11_kit_modules_initialize (py->modules, (p11_destroyer)p11_kit_module_release);
+       if (rv != CKR_OK) {
+               p11_kit_modules_release (py->modules);
+               free (py);
+               return rv;
+       }
+
+       for (f = py->modules; *f; ++f) {
+               funcs = *f;
+
+               assert (funcs != NULL);
+               slots = NULL;
+
+               /* Ask module for its slots */
+               rv = (funcs->C_GetSlotList) (FALSE, NULL, &count);
+               if (rv == CKR_OK && count) {
+                       slots = calloc (sizeof (CK_SLOT_ID), count);
+                       rv = (funcs->C_GetSlotList) (FALSE, slots, &count);
+               }
 
                if (rv != CKR_OK) {
                        free (slots);
@@ -267,41 +284,38 @@ initialize_mappings_unlocked_reentrant (void)
 
                return_val_if_fail (count == 0 || slots != NULL, CKR_GENERAL_ERROR);
 
-               mappings = realloc (mappings, sizeof (Mapping) * (n_mappings + count));
-               return_val_if_fail (mappings != NULL, CKR_HOST_MEMORY);
+               py->mappings = realloc (py->mappings, sizeof (Mapping) * (py->n_mappings + count));
+               return_val_if_fail (py->mappings != NULL, CKR_HOST_MEMORY);
 
                /* 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;
+                       py->mappings[py->n_mappings].funcs = funcs;
+                       py->mappings[py->n_mappings].wrap_slot = py->n_mappings + MAPPING_OFFSET;
+                       py->mappings[py->n_mappings].real_slot = slots[i];
+                       ++py->n_mappings;
                }
 
                free (slots);
        }
 
-       free (funcss);
-
-       /* Another thread raced us here due to above reentrancy */
-       if (gl.mappings) {
-               free (mappings);
-               return CKR_OK;
+       if (rv != CKR_OK) {
+               proxy_free (py);
+               return rv;
        }
 
-       assert (!gl.sessions);
-       gl.mappings = mappings;
-       gl.n_mappings = n_mappings;
-       gl.sessions = p11_dict_new (p11_dict_ulongptr_hash, p11_dict_ulongptr_equal, NULL, free);
-       ++gl.mappings_refs;
+       py->sessions = p11_dict_new (p11_dict_ulongptr_hash, p11_dict_ulongptr_equal, NULL, free);
+       return_val_if_fail (py->sessions != NULL, CKR_HOST_MEMORY);
+       py->refs = 1;
 
-       /* Any cleanup necessary for failure will happen at caller */
-       return rv;
+       *res = py;
+       return CKR_OK;
 }
 
 static CK_RV
 proxy_C_Initialize (CK_VOID_PTR init_args)
 {
+       bool initialize = false;
+       Proxy *py;
        CK_RV rv;
 
        p11_library_init_once ();
@@ -312,21 +326,35 @@ proxy_C_Initialize (CK_VOID_PTR init_args)
 
        p11_lock ();
 
-               /* WARNING: Reentrancy can occur here */
-               rv = _p11_kit_initialize_registered_unlocked_reentrant ();
-
-               /* WARNING: Reentrancy can occur here */
-               if (rv == CKR_OK && gl.mappings_refs == 0)
-                       rv = initialize_mappings_unlocked_reentrant ();
+               if (px == NULL)
+                       initialize = true;
+               else
+                       px->refs++;
 
        p11_unlock ();
 
-       p11_debug ("here");
+       if (!initialize) {
+               p11_debug ("out: already: %lu", CKR_OK);
+               return CKR_OK;
+       }
 
-       if (rv != CKR_OK)
-               proxy_C_Finalize (NULL);
+       rv = proxy_create (&py);
+       if (rv != CKR_OK) {
+               p11_debug ("out: %lu", rv);
+               return rv;
+       }
 
-       p11_debug ("out: %lu", rv);
+       p11_lock ();
+
+               if (px == NULL) {
+                       px = py;
+                       py = NULL;
+               }
+
+       p11_unlock ();
+
+       proxy_free (py);
+       p11_debug ("out: 0");
        return rv;
 }
 
@@ -341,7 +369,7 @@ proxy_C_GetInfo (CK_INFO_PTR info)
 
        p11_lock ();
 
-               if (!gl.mappings)
+               if (!px)
                        rv = CKR_CRYPTOKI_NOT_INITIALIZED;
 
        p11_unlock ();
@@ -383,14 +411,14 @@ proxy_C_GetSlotList (CK_BBOOL token_present, CK_SLOT_ID_PTR slot_list,
 
        p11_lock ();
 
-               if (!gl.mappings) {
+               if (!px->mappings) {
                        rv = CKR_CRYPTOKI_NOT_INITIALIZED;
                } else {
                        index = 0;
 
                        /* Go through and build up a map */
-                       for (i = 0; i < gl.n_mappings; ++i) {
-                               mapping = &gl.mappings[i];
+                       for (i = 0; i < px->n_mappings; ++i) {
+                               mapping = &px->mappings[i];
 
                                /* Skip ones without a token if requested */
                                if (token_present) {
@@ -506,7 +534,7 @@ proxy_C_OpenSession (CK_SLOT_ID id, CK_FLAGS flags, CK_VOID_PTR user_data,
        if (rv == CKR_OK) {
                p11_lock ();
 
-                       if (!gl.sessions) {
+                       if (!px) {
                                /*
                                 * The underlying module should have returned an error, so this
                                 * code should never be reached with properly behaving modules.
@@ -519,8 +547,8 @@ proxy_C_OpenSession (CK_SLOT_ID id, CK_FLAGS flags, CK_VOID_PTR user_data,
                                sess = calloc (1, sizeof (Session));
                                sess->wrap_slot = map.wrap_slot;
                                sess->real_session = *handle;
-                               sess->wrap_session = ++gl.last_handle; /* TODO: Handle wrapping, and then collisions */
-                               p11_dict_set (gl.sessions, &sess->wrap_session, sess);
+                               sess->wrap_session = ++px->last_handle; /* TODO: Handle wrapping, and then collisions */
+                               p11_dict_set (px->sessions, &sess->wrap_session, sess);
                                *handle = sess->wrap_session;
                        }
 
@@ -546,8 +574,8 @@ proxy_C_CloseSession (CK_SESSION_HANDLE handle)
        if (rv == CKR_OK) {
                p11_lock ();
 
-                       if (gl.sessions)
-                               p11_dict_remove (gl.sessions, &key);
+                       if (px)
+                               p11_dict_remove (px->sessions, &key);
 
                p11_unlock ();
        }
@@ -566,14 +594,15 @@ proxy_C_CloseAllSessions (CK_SLOT_ID id)
 
        p11_lock ();
 
-               if (!gl.sessions) {
+               if (!px) {
                        rv = CKR_CRYPTOKI_NOT_INITIALIZED;
                } else {
-                       to_close = calloc (sizeof (CK_SESSION_HANDLE), p11_dict_size (gl.sessions));
+                       assert (px->sessions);
+                       to_close = calloc (sizeof (CK_SESSION_HANDLE), p11_dict_size (px->sessions));
                        if (!to_close) {
                                rv = CKR_HOST_MEMORY;
                        } else {
-                               p11_dict_iterate (gl.sessions, &iter);
+                               p11_dict_iterate (px->sessions, &iter);
                                count = 0;
                                while (p11_dict_next (&iter, NULL, (void**)&sess)) {
                                        if (sess->wrap_slot == id && to_close)
index 715fca09f36bc1115e2cf47b54d0666afe6fe681..0c5c246a140f645ffceb895324f338c89d1ad2cf 100644 (file)
@@ -23,13 +23,17 @@ CHECK_PROGS = \
        pin-test \
        test-init \
        test-modules \
+       test-deprecated \
+       test-proxy \
        test-iter \
        $(NULL)
 
 if WITH_FFI
 
 CHECK_PROGS += \
-       test-virtual
+       test-virtual \
+       test-managed \
+       $(NULL)
 
 endif
 
@@ -75,4 +79,6 @@ mock_four_la_LDFLAGS = $(mock_one_la_LDFLAGS)
 mock_four_la_LIBADD = $(mock_one_la_LIBADD)
 
 EXTRA_DIST = \
-       files
+       files \
+       test-mock.c \
+       $(NULL)
index 20741e735344a19b4e033524683b2433dc271125..a3aa27311575dd72c4364a57b0cbcb93367be79a 100644 (file)
@@ -1,3 +1,6 @@
 
 # Merge in user config
-user-config: merge
\ No newline at end of file
+user-config: merge
+
+# Another option
+new: world
\ No newline at end of file
index c371e4a4dd9c3f8c894e8ecd3024d9d2a4491b44..6f1a2e8dfe642ec1c37b5d8e2ddced5fb698ab2e 100644 (file)
@@ -1,2 +1,3 @@
 
-setting: user1
\ No newline at end of file
+setting: user1
+managed: yes
\ No newline at end of file
diff --git a/p11-kit/tests/test-deprecated.c b/p11-kit/tests/test-deprecated.c
new file mode 100644 (file)
index 0000000..4509241
--- /dev/null
@@ -0,0 +1,521 @@
+/*
+ * Copyright (c) 2011, Collabora Ltd.
+ * Copyright (c) 2012 Red Hat Inc
+ *
+ * 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@redhat.com>
+ */
+
+#define P11_KIT_NO_DEPRECATIONS
+
+#include "config.h"
+#include "CuTest.h"
+
+#include "dict.h"
+#include "library.h"
+#include "p11-kit.h"
+#include "private.h"
+#include "mock.h"
+
+#include <sys/types.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+static CK_FUNCTION_LIST_PTR_PTR
+initialize_and_get_modules (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR_PTR modules;
+       CK_RV rv;
+
+       rv = p11_kit_initialize_registered ();
+       CuAssertIntEquals (tc, CKR_OK, rv);
+       modules = p11_kit_registered_modules ();
+       CuAssertTrue (tc, modules != NULL && modules[0] != NULL);
+
+       return modules;
+}
+
+static void
+finalize_and_free_modules (CuTest *tc,
+                           CK_FUNCTION_LIST_PTR_PTR modules)
+{
+       CK_RV rv;
+
+       free (modules);
+       rv = p11_kit_finalize_registered ();
+       CuAssertIntEquals (tc, CKR_OK, rv);
+
+}
+
+static void
+test_no_duplicates (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR_PTR modules;
+       p11_dict *paths;
+       p11_dict *funcs;
+       char *path;
+       int i;
+
+       modules = initialize_and_get_modules (tc);
+       paths = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, NULL, NULL);
+       funcs = p11_dict_new (p11_dict_direct_hash, p11_dict_direct_equal, NULL, NULL);
+
+       /* The loaded modules should not contain duplicates */
+       for (i = 0; modules[i] != NULL; i++) {
+               path = p11_kit_registered_option (modules[i], "module");
+
+               if (p11_dict_get (funcs, modules[i]))
+                       CuAssert (tc, "found duplicate function list pointer", 0);
+               if (p11_dict_get (paths, path))
+                       CuAssert (tc, "found duplicate path name", 0);
+
+               if (!p11_dict_set (funcs, modules[i], ""))
+                       CuAssert (tc, "shouldn't be reached", 0);
+               if (!p11_dict_set (paths, path, ""))
+                       CuAssert (tc, "shouldn't be reached", 0);
+
+               free (path);
+       }
+
+       p11_dict_free (paths);
+       p11_dict_free (funcs);
+       finalize_and_free_modules (tc, modules);
+}
+
+static CK_FUNCTION_LIST_PTR
+lookup_module_with_name (CuTest *tc,
+                         CK_FUNCTION_LIST_PTR_PTR modules,
+                         const char *name)
+{
+       CK_FUNCTION_LIST_PTR match = NULL;
+       CK_FUNCTION_LIST_PTR module;
+       char *module_name;
+       int i;
+
+       for (i = 0; match == NULL && modules[i] != NULL; i++) {
+               module_name = p11_kit_registered_module_to_name (modules[i]);
+               CuAssertPtrNotNull (tc, module_name);
+               if (strcmp (module_name, name) == 0)
+                       match = modules[i];
+               free (module_name);
+       }
+
+       /*
+        * As a side effect, we should check that the results of this function
+        * matches the above search.
+        */
+       module = p11_kit_registered_name_to_module (name);
+       CuAssert(tc, "different result from p11_kit_registered_name_to_module()",
+                module == match);
+
+       return match;
+}
+
+static void
+test_disable (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR_PTR modules;
+
+       /*
+        * The module four should be present, as we don't match any prognames
+        * that it has disabled.
+        */
+
+       modules = initialize_and_get_modules (tc);
+       CuAssertTrue (tc, lookup_module_with_name (tc, modules, "four") != NULL);
+       finalize_and_free_modules (tc, modules);
+
+       /*
+        * The module two shouldn't have been loaded, because in its config
+        * file we have:
+        *
+        * disable-in: test-disable
+        */
+
+       p11_kit_set_progname ("test-disable");
+
+       modules = initialize_and_get_modules (tc);
+       CuAssertTrue (tc, lookup_module_with_name (tc, modules, "four") == NULL);
+       finalize_and_free_modules (tc, modules);
+
+       p11_kit_set_progname (NULL);
+}
+
+static void
+test_disable_later (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR_PTR modules;
+       CK_RV rv;
+
+       /*
+        * The module two shouldn't be matched, because in its config
+        * file we have:
+        *
+        * disable-in: test-disable
+        */
+
+       rv = p11_kit_initialize_registered ();
+       CuAssertIntEquals (tc, CKR_OK, rv);
+
+       p11_kit_set_progname ("test-disable");
+
+       modules = p11_kit_registered_modules ();
+       CuAssertTrue (tc, modules != NULL && modules[0] != NULL);
+
+       CuAssertTrue (tc, lookup_module_with_name (tc, modules, "two") == NULL);
+       finalize_and_free_modules (tc, modules);
+
+       p11_kit_set_progname (NULL);
+}
+
+static void
+test_enable (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR_PTR modules;
+
+       /*
+        * The module three should not be present, as we don't match the current
+        * program.
+        */
+
+       modules = initialize_and_get_modules (tc);
+       CuAssertTrue (tc, lookup_module_with_name (tc, modules, "three") == NULL);
+       finalize_and_free_modules (tc, modules);
+
+       /*
+        * The module three should be loaded here , because in its config
+        * file we have:
+        *
+        * enable-in: test-enable
+        */
+
+       p11_kit_set_progname ("test-enable");
+
+       modules = initialize_and_get_modules (tc);
+       CuAssertTrue (tc, lookup_module_with_name (tc, modules, "three") != NULL);
+       finalize_and_free_modules (tc, modules);
+
+       p11_kit_set_progname (NULL);
+}
+
+CK_FUNCTION_LIST module;
+
+#ifdef OS_UNIX
+
+#include <sys/wait.h>
+
+static CK_RV
+mock_C_Initialize__with_fork (CK_VOID_PTR init_args)
+{
+       struct timespec ts = { 0, 100 * 1000 * 1000 };
+       CK_RV rv;
+       pid_t child;
+       pid_t ret;
+       int status;
+
+       rv = mock_C_Initialize (init_args);
+       assert (rv == CKR_OK);
+
+       /* Fork during the initialization */
+       child = fork ();
+       if (child == 0) {
+               nanosleep (&ts, NULL);
+               exit (66);
+       }
+
+       ret = waitpid (child, &status, 0);
+       assert (ret == child);
+       assert (WIFEXITED (status));
+       assert (WEXITSTATUS (status) == 66);
+
+       return CKR_OK;
+}
+
+static void
+test_fork_initialization (CuTest *tc)
+{
+       CK_RV rv;
+
+       CuAssertTrue (tc, !mock_module_initialized ());
+
+       /* Build up our own function list */
+       memcpy (&module, &mock_module_no_slots, sizeof (CK_FUNCTION_LIST));
+       module.C_Initialize = mock_C_Initialize__with_fork;
+
+       rv = p11_kit_initialize_module (&module);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = p11_kit_finalize_module (&module);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertTrue (tc, !mock_module_initialized ());
+}
+
+#endif /* OS_UNIX */
+
+static CK_RV
+mock_C_Initialize__with_recursive (CK_VOID_PTR init_args)
+{
+       /* Recursively initialize, this is broken */
+       return p11_kit_initialize_module (&module);
+}
+
+static void
+test_recursive_initialization (CuTest *tc)
+{
+       CK_RV rv;
+
+       CuAssertTrue (tc, !mock_module_initialized ());
+
+       /* Build up our own function list */
+       memcpy (&module, &mock_module_no_slots, sizeof (CK_FUNCTION_LIST));
+       module.C_Initialize = mock_C_Initialize__with_recursive;
+
+       rv = p11_kit_initialize_module (&module);
+       CuAssertTrue (tc, rv == CKR_FUNCTION_FAILED);
+
+       CuAssertTrue (tc, !mock_module_initialized ());
+}
+
+static p11_mutex_t race_mutex;
+static int initialization_count = 0;
+static int finalization_count = 0;
+
+static CK_RV
+mock_C_Initialize__threaded_race (CK_VOID_PTR init_args)
+{
+       /* Atomically increment value */
+       p11_mutex_lock (&race_mutex);
+       initialization_count += 1;
+       p11_mutex_unlock (&race_mutex);
+
+       p11_sleep_ms (100);
+       return CKR_OK;
+}
+
+static CK_RV
+mock_C_Finalize__threaded_race (CK_VOID_PTR reserved)
+{
+       /* Atomically increment value */
+       p11_mutex_lock (&race_mutex);
+       finalization_count += 1;
+       p11_mutex_unlock (&race_mutex);
+
+       p11_sleep_ms (100);
+       return CKR_OK;
+}
+
+static void *
+initialization_thread (void *data)
+{
+       CuTest *tc = data;
+       CK_RV rv;
+
+       rv = p11_kit_initialize_module (&module);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       return tc;
+}
+
+static void *
+finalization_thread (void *data)
+{
+       CuTest *tc = data;
+       CK_RV rv;
+
+       rv = p11_kit_finalize_module (&module);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       return tc;
+}
+
+static void
+test_threaded_initialization (CuTest *tc)
+{
+       static const int num_threads = 2;
+       p11_thread_t threads[num_threads];
+       int ret;
+       int i;
+
+       CuAssertTrue (tc, !mock_module_initialized ());
+
+       /* Build up our own function list */
+       memcpy (&module, &mock_module_no_slots, sizeof (CK_FUNCTION_LIST));
+       module.C_Initialize = mock_C_Initialize__threaded_race;
+       module.C_Finalize = mock_C_Finalize__threaded_race;
+
+       initialization_count = 0;
+       finalization_count = 0;
+
+       for (i = 0; i < num_threads; i++) {
+               ret = p11_thread_create (&threads[i], initialization_thread, tc);
+               CuAssertIntEquals (tc, 0, ret);
+               CuAssertTrue (tc, threads[i] != 0);
+       }
+
+       for (i = 0; i < num_threads; i++) {
+               ret = p11_thread_join (threads[i]);
+               CuAssertIntEquals (tc, 0, ret);
+               threads[i] = 0;
+       }
+
+       for (i = 0; i < num_threads; i++) {
+               ret = p11_thread_create (&threads[i], finalization_thread, tc);
+               CuAssertIntEquals (tc, 0, ret);
+               CuAssertTrue (tc, threads[i] != 0);
+       }
+
+       for (i = 0; i < num_threads; i++) {
+               ret = p11_thread_join (threads[i]);
+               CuAssertIntEquals (tc, 0, ret);
+               threads[i] = 0;
+       }
+
+       /* C_Initialize should have been called exactly once */
+       CuAssertIntEquals (tc, 1, initialization_count);
+       CuAssertIntEquals (tc, 1, finalization_count);
+
+       CuAssertTrue (tc, !mock_module_initialized ());
+}
+
+static CK_RV
+mock_C_Initialize__test_mutexes (CK_VOID_PTR args)
+{
+       CK_C_INITIALIZE_ARGS_PTR init_args;
+       void *mutex = NULL;
+       CK_RV rv;
+
+       rv = mock_C_Initialize (NULL);
+       if (rv != CKR_OK)
+               return rv;
+
+       assert (args != NULL);
+       init_args = args;
+
+       rv = (init_args->CreateMutex) (&mutex);
+       assert (rv == CKR_OK);
+
+       rv = (init_args->LockMutex) (mutex);
+       assert (rv == CKR_OK);
+
+       rv = (init_args->UnlockMutex) (mutex);
+       assert (rv == CKR_OK);
+
+       rv = (init_args->DestroyMutex) (mutex);
+       assert (rv == CKR_OK);
+
+       return CKR_OK;
+}
+
+static void
+test_mutexes (CuTest *tc)
+{
+       CK_RV rv;
+
+       CuAssertTrue (tc, !mock_module_initialized ());
+
+       /* Build up our own function list */
+       memcpy (&module, &mock_module_no_slots, sizeof (CK_FUNCTION_LIST));
+       module.C_Initialize = mock_C_Initialize__test_mutexes;
+
+       rv = p11_kit_initialize_module (&module);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = p11_kit_finalize_module (&module);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertTrue (tc, !mock_module_initialized ());
+}
+
+static void
+test_load_and_initialize (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_INFO info;
+       CK_RV rv;
+       int ret;
+
+       rv = p11_kit_load_initialize_module (BUILDDIR "/.libs/mock-one" SHLEXT, &module);
+       CuAssertTrue (tc, rv == CKR_OK);
+       CuAssertTrue (tc, module != NULL);
+
+       rv = (module->C_GetInfo) (&info);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       ret = memcmp (info.manufacturerID, "MOCK MANUFACTURER               ", 32);
+       CuAssertTrue (tc, ret == 0);
+
+       rv = p11_kit_finalize_module (module);
+       CuAssertTrue (tc, ret == CKR_OK);
+}
+
+int
+main (void)
+{
+       CuString *output = CuStringNew ();
+       CuSuite* suite = CuSuiteNew ();
+       int ret;
+
+       putenv ("P11_KIT_STRICT=1");
+       p11_mutex_init (&race_mutex);
+       mock_module_init ();
+       p11_library_init ();
+
+       SUITE_ADD_TEST (suite, test_no_duplicates);
+       SUITE_ADD_TEST (suite, test_disable);
+       SUITE_ADD_TEST (suite, test_disable_later);
+       SUITE_ADD_TEST (suite, test_enable);
+
+#ifdef OS_UNIX
+       SUITE_ADD_TEST (suite, test_fork_initialization);
+#endif
+
+       SUITE_ADD_TEST (suite, test_recursive_initialization);
+       SUITE_ADD_TEST (suite, test_threaded_initialization);
+       SUITE_ADD_TEST (suite, test_mutexes);
+       SUITE_ADD_TEST (suite, test_load_and_initialize);
+
+       p11_kit_be_quiet ();
+
+       CuSuiteRun (suite);
+       CuSuiteSummary (suite, output);
+       CuSuiteDetails (suite, output);
+       printf ("%s\n", output->buffer);
+       ret = suite->failCount;
+       CuSuiteDelete (suite);
+       CuStringDelete (output);
+       return ret;
+}
index 7df4be9e997da8adba77c188f708149da0e597e9..f2347c8a04f657c9d03b000540578bb092509532 100644 (file)
 #include <sys/types.h>
 
 #include "library.h"
+#include "mock.h"
+#include "modules.h"
+#include "p11-kit.h"
+#include "private.h"
+#include "virtual.h"
 
 #include <assert.h>
 #include <stdio.h>
 #include <time.h>
 #include <unistd.h>
 
-#include "p11-kit/p11-kit.h"
-
-#include "mock.h"
-
-CK_FUNCTION_LIST module;
+static CK_FUNCTION_LIST module;
+static p11_mutex_t race_mutex;
 
 #ifdef OS_UNIX
 
@@ -86,21 +88,40 @@ mock_C_Initialize__with_fork (CK_VOID_PTR init_args)
 static void
 test_fork_initialization (CuTest *tc)
 {
+       CK_FUNCTION_LIST_PTR result;
        CK_RV rv;
 
+       mock_module_reset ();
+
        /* Build up our own function list */
        memcpy (&module, &mock_module_no_slots, sizeof (CK_FUNCTION_LIST));
        module.C_Initialize = mock_C_Initialize__with_fork;
 
-       rv = p11_kit_initialize_module (&module);
+       p11_lock ();
+
+       rv = p11_module_load_inlock_reentrant (&module, 0, &result);
        CuAssertTrue (tc, rv == CKR_OK);
 
-       rv = p11_kit_finalize_module (&module);
+       p11_unlock ();
+
+       rv = p11_kit_module_initialize (result);
        CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = p11_kit_module_finalize (result);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       p11_lock ();
+
+       rv = p11_module_release_inlock_reentrant (result);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       p11_unlock ();
 }
 
 #endif /* OS_UNIX */
 
+static CK_FUNCTION_LIST *recursive_managed;
+
 static CK_RV
 mock_C_Initialize__with_recursive (CK_VOID_PTR init_args)
 {
@@ -109,8 +130,7 @@ mock_C_Initialize__with_recursive (CK_VOID_PTR init_args)
        rv = mock_C_Initialize (init_args);
        assert (rv == CKR_OK);
 
-       /* Recursively initialize, this is broken */
-       return p11_kit_initialize_module (&module);
+       return p11_kit_module_initialize (recursive_managed);
 }
 
 static void
@@ -122,16 +142,24 @@ test_recursive_initialization (CuTest *tc)
        memcpy (&module, &mock_module_no_slots, sizeof (CK_FUNCTION_LIST));
        module.C_Initialize = mock_C_Initialize__with_recursive;
 
-       rv = p11_kit_initialize_module (&module);
+       p11_kit_be_quiet ();
+
+       p11_lock ();
+
+       rv = p11_module_load_inlock_reentrant (&module, 0, &recursive_managed);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       p11_unlock ();
+
+       rv = p11_kit_module_initialize (recursive_managed);
        CuAssertTrue (tc, rv == CKR_FUNCTION_FAILED);
+
+       p11_kit_be_loud ();
 }
 
-static p11_mutex_t race_mutex;
 static int initialization_count = 0;
 static int finalization_count = 0;
 
-#include "private.h"
-
 static CK_RV
 mock_C_Initialize__threaded_race (CK_VOID_PTR init_args)
 {
@@ -156,35 +184,44 @@ mock_C_Finalize__threaded_race (CK_VOID_PTR reserved)
        return CKR_OK;
 }
 
+typedef struct {
+       CuTest *cu;
+       CK_FUNCTION_LIST_PTR module;
+} ThreadData;
+
 static void *
 initialization_thread (void *data)
 {
-       CuTest *tc = data;
+       ThreadData *td = data;
        CK_RV rv;
 
-       rv = p11_kit_initialize_module (&module);
-       CuAssertTrue (tc, rv == CKR_OK);
+       assert (td->module != NULL);
+       rv = p11_kit_module_initialize (td->module);
+       CuAssertTrue (td->cu, rv == CKR_OK);
 
-       return tc;
+       return td->cu;
 }
 
 static void *
 finalization_thread (void *data)
 {
-       CuTest *tc = data;
+       ThreadData *td = data;
        CK_RV rv;
 
-       rv = p11_kit_finalize_module (&module);
-       CuAssertTrue (tc, rv == CKR_OK);
+       assert (td->module != NULL);
+       rv = p11_kit_module_finalize (td->module);
+       CuAssertTrue (td->cu, rv == CKR_OK);
 
-       return tc;
+       return td->cu;
 }
 
 static void
 test_threaded_initialization (CuTest *tc)
 {
-       static const int num_threads = 2;
+       static const int num_threads = 1;
+       ThreadData data[num_threads];
        p11_thread_t threads[num_threads];
+       CK_RV rv;
        int ret;
        int i;
 
@@ -193,11 +230,23 @@ test_threaded_initialization (CuTest *tc)
        module.C_Initialize = mock_C_Initialize__threaded_race;
        module.C_Finalize = mock_C_Finalize__threaded_race;
 
+       memset (&data, 0, sizeof (data));
        initialization_count = 0;
        finalization_count = 0;
 
+       p11_lock ();
+
        for (i = 0; i < num_threads; i++) {
-               ret = p11_thread_create (&threads[i], initialization_thread, tc);
+               assert (data[i].module == NULL);
+               rv = p11_module_load_inlock_reentrant (&module, 0, &data[i].module);
+               CuAssertTrue (tc, rv == CKR_OK);
+       }
+
+       p11_unlock ();
+
+       for (i = 0; i < num_threads; i++) {
+               data[i].cu = tc;
+               ret = p11_thread_create (&threads[i], initialization_thread, data + i);
                CuAssertIntEquals (tc, 0, ret);
                CuAssertTrue (tc, threads[i] != 0);
        }
@@ -209,7 +258,7 @@ test_threaded_initialization (CuTest *tc)
        }
 
        for (i = 0; i < num_threads; i++) {
-               ret = p11_thread_create (&threads[i], finalization_thread, tc);
+               ret = p11_thread_create (&threads[i], finalization_thread, data + i);
                CuAssertIntEquals (tc, 0, ret);
                CuAssertTrue (tc, threads[i] != 0);
        }
@@ -220,6 +269,16 @@ test_threaded_initialization (CuTest *tc)
                threads[i] = 0;
        }
 
+       p11_lock ();
+
+       for (i = 0; i < num_threads; i++) {
+               assert (data[i].module != NULL);
+               rv = p11_module_release_inlock_reentrant (data[i].module);
+               CuAssertTrue (tc, rv == CKR_OK);
+       }
+
+       p11_unlock ();
+
        /* C_Initialize should have been called exactly once */
        CuAssertIntEquals (tc, 1, initialization_count);
        CuAssertIntEquals (tc, 1, finalization_count);
@@ -253,17 +312,22 @@ mock_C_Initialize__test_mutexes (CK_VOID_PTR args)
 static void
 test_mutexes (CuTest *tc)
 {
+       CK_FUNCTION_LIST_PTR result;
        CK_RV rv;
 
        /* Build up our own function list */
        memcpy (&module, &mock_module_no_slots, sizeof (CK_FUNCTION_LIST));
        module.C_Initialize = mock_C_Initialize__test_mutexes;
 
-       rv = p11_kit_initialize_module (&module);
+       p11_lock ();
+
+       rv = p11_module_load_inlock_reentrant (&module, 0, &result);
        CuAssertTrue (tc, rv == CKR_OK);
 
-       rv = p11_kit_finalize_module (&module);
+       rv = p11_module_release_inlock_reentrant (result);
        CuAssertTrue (tc, rv == CKR_OK);
+
+       p11_unlock ();
 }
 
 static void
@@ -274,18 +338,54 @@ test_load_and_initialize (CuTest *tc)
        CK_RV rv;
        int ret;
 
-       rv = p11_kit_load_initialize_module (BUILDDIR "/.libs/mock-one" SHLEXT, &module);
-       CuAssertTrue (tc, rv == CKR_OK);
+       module = p11_kit_module_load (BUILDDIR "/.libs/mock-one" SHLEXT, 0);
        CuAssertTrue (tc, module != NULL);
 
+       rv = p11_kit_module_initialize (module);
+       CuAssertTrue (tc, rv == CKR_OK);
+
        rv = (module->C_GetInfo) (&info);
        CuAssertTrue (tc, rv == CKR_OK);
 
        ret = memcmp (info.manufacturerID, "MOCK MANUFACTURER               ", 32);
        CuAssertTrue (tc, ret == 0);
 
-       rv = p11_kit_finalize_module (module);
-       CuAssertTrue (tc, ret == CKR_OK);
+       rv = p11_kit_module_finalize (module);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       p11_kit_module_release (module);
+}
+
+static void
+test_initalize_fail (CuTest *tc)
+{
+       CK_FUNCTION_LIST failer;
+       CK_FUNCTION_LIST *modules[3] = { &mock_module_no_slots, &failer, NULL };
+       CK_RV rv;
+
+       memcpy (&failer, &mock_module, sizeof (CK_FUNCTION_LIST));
+       failer.C_Initialize = mock_C_Initialize__fails;
+
+       mock_module_reset ();
+       p11_kit_be_quiet ();
+
+       rv = p11_kit_modules_initialize (modules, NULL);
+       CuAssertIntEquals (tc, CKR_FUNCTION_FAILED, rv);
+
+       p11_kit_be_loud ();
+
+       /* Failed modules get removed from the list */
+       CuAssertPtrEquals (tc, &mock_module_no_slots, modules[0]);
+       CuAssertPtrEquals (tc, NULL, modules[1]);
+       CuAssertPtrEquals (tc, NULL, modules[2]);
+
+       p11_kit_modules_finalize (modules);
+}
+
+static void
+test_finalize_fail (CuTest *tc)
+{
+
 }
 
 int
@@ -300,14 +400,20 @@ main (void)
        mock_module_init ();
        p11_library_init ();
 
+       /* These only work when managed */
+       if (p11_virtual_can_wrap ()) {
+               SUITE_ADD_TEST (suite, test_recursive_initialization);
+               SUITE_ADD_TEST (suite, test_threaded_initialization);
+               SUITE_ADD_TEST (suite, test_mutexes);
+               SUITE_ADD_TEST (suite, test_load_and_initialize);
+
 #ifdef OS_UNIX
-       SUITE_ADD_TEST (suite, test_fork_initialization);
+               SUITE_ADD_TEST (suite, test_fork_initialization);
 #endif
+       }
 
-       SUITE_ADD_TEST (suite, test_recursive_initialization);
-       SUITE_ADD_TEST (suite, test_threaded_initialization);
-       SUITE_ADD_TEST (suite, test_mutexes);
-       SUITE_ADD_TEST (suite, test_load_and_initialize);
+       SUITE_ADD_TEST (suite, test_initalize_fail);
+       SUITE_ADD_TEST (suite, test_finalize_fail);
 
        CuSuiteRun (suite);
        CuSuiteSummary (suite, output);
index 08e43b30e8c8d6b39aaf2c0ca40455008cde49c2..451f4bed087f926847e4e5ca57863be3f82a352d 100644 (file)
@@ -52,13 +52,10 @@ static CK_FUNCTION_LIST_PTR_PTR
 initialize_and_get_modules (CuTest *tc)
 {
        CK_FUNCTION_LIST_PTR_PTR modules;
-       CK_RV rv;
 
        p11_message_quiet ();
 
-       rv = p11_kit_initialize_registered ();
-       CuAssertIntEquals (tc, CKR_OK, rv);
-       modules = p11_kit_registered_modules ();
+       modules = p11_kit_modules_load_and_initialize (0);
        CuAssertTrue (tc, modules != NULL && modules[0] != NULL);
 
        p11_message_loud ();
@@ -70,11 +67,8 @@ static void
 finalize_and_free_modules (CuTest *tc,
                            CK_FUNCTION_LIST_PTR_PTR modules)
 {
-       CK_RV rv;
-
-       free (modules);
-       rv = p11_kit_finalize_registered ();
-       CuAssertIntEquals (tc, CKR_OK, rv);
+       p11_kit_modules_finalize (modules);
+       p11_kit_modules_release (modules);
 }
 
 static int
@@ -282,7 +276,8 @@ test_with_session (CuTest *tc)
        CK_RV rv;
        int at;
 
-       rv = p11_kit_initialize_module (&mock_module);
+       mock_module_reset ();
+       rv = mock_module.C_Initialize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 
        rv = mock_C_OpenSession (MOCK_SLOT_ONE_ID, CKF_SERIAL_SESSION, NULL, NULL, &session);
@@ -323,7 +318,7 @@ test_with_session (CuTest *tc)
        rv = mock_module.C_CloseSession (session);
        CuAssertTrue (tc, rv == CKR_OK);
 
-       rv = p11_kit_finalize_module (&mock_module);
+       rv = mock_module.C_Finalize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 }
 
@@ -337,7 +332,8 @@ test_with_slot (CuTest *tc)
        CK_RV rv;
        int at;
 
-       rv = p11_kit_initialize_module (&mock_module);
+       mock_module_reset ();
+       rv = mock_module.C_Initialize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 
        iter = p11_kit_iter_new (NULL);
@@ -369,7 +365,7 @@ test_with_slot (CuTest *tc)
 
        p11_kit_iter_free (iter);
 
-       rv = p11_kit_finalize_module (&mock_module);
+       rv = (mock_module.C_Finalize) (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 }
 
@@ -382,7 +378,8 @@ test_with_module (CuTest *tc)
        CK_RV rv;
        int at;
 
-       rv = p11_kit_initialize_module (&mock_module);
+       mock_module_reset ();
+       rv = mock_module.C_Initialize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 
        iter = p11_kit_iter_new (NULL);
@@ -411,7 +408,7 @@ test_with_module (CuTest *tc)
 
        p11_kit_iter_free (iter);
 
-       rv = p11_kit_finalize_module (&mock_module);
+       rv = mock_module.C_Finalize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 }
 
@@ -422,7 +419,8 @@ test_keep_session (CuTest *tc)
        P11KitIter *iter;
        CK_RV rv;
 
-       rv = p11_kit_initialize_module (&mock_module);
+       mock_module_reset ();
+       rv = mock_module.C_Initialize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 
        iter = p11_kit_iter_new (NULL);
@@ -438,7 +436,7 @@ test_keep_session (CuTest *tc)
        rv = mock_module.C_CloseSession (session);
        CuAssertTrue (tc, rv == CKR_OK);
 
-       rv = p11_kit_finalize_module (&mock_module);
+       rv = mock_module.C_Finalize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 }
 
@@ -750,7 +748,8 @@ test_getslotlist_fail_first (CuTest *tc)
        CK_RV rv;
        int at;
 
-       rv = p11_kit_initialize_module (&mock_module);
+       mock_module_reset ();
+       rv = mock_module.C_Initialize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 
        memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST));
@@ -770,7 +769,7 @@ test_getslotlist_fail_first (CuTest *tc)
 
        p11_kit_iter_free (iter);
 
-       rv = p11_kit_finalize_module (&mock_module);
+       rv = mock_module.C_Finalize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 }
 
@@ -782,7 +781,8 @@ test_getslotlist_fail_late (CuTest *tc)
        CK_RV rv;
        int at;
 
-       rv = p11_kit_initialize_module (&mock_module);
+       mock_module_reset ();
+       rv = mock_module.C_Initialize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 
        memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST));
@@ -802,7 +802,7 @@ test_getslotlist_fail_late (CuTest *tc)
 
        p11_kit_iter_free (iter);
 
-       rv = p11_kit_finalize_module (&mock_module);
+       rv = mock_module.C_Finalize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 }
 
@@ -814,7 +814,8 @@ test_open_session_fail (CuTest *tc)
        CK_RV rv;
        int at;
 
-       rv = p11_kit_initialize_module (&mock_module);
+       mock_module_reset ();
+       rv = mock_module.C_Initialize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 
        memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST));
@@ -834,7 +835,7 @@ test_open_session_fail (CuTest *tc)
 
        p11_kit_iter_free (iter);
 
-       rv = p11_kit_finalize_module (&mock_module);
+       rv = mock_module.C_Finalize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 }
 
@@ -846,7 +847,8 @@ test_find_init_fail (CuTest *tc)
        CK_RV rv;
        int at;
 
-       rv = p11_kit_initialize_module (&mock_module);
+       mock_module_reset ();
+       rv = mock_module.C_Initialize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 
        memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST));
@@ -866,7 +868,7 @@ test_find_init_fail (CuTest *tc)
 
        p11_kit_iter_free (iter);
 
-       rv = p11_kit_finalize_module (&mock_module);
+       rv = mock_module.C_Finalize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 }
 
@@ -878,7 +880,8 @@ test_find_objects_fail (CuTest *tc)
        CK_RV rv;
        int at;
 
-       rv = p11_kit_initialize_module (&mock_module);
+       mock_module_reset ();
+       rv = mock_module.C_Initialize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 
        memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST));
@@ -898,7 +901,7 @@ test_find_objects_fail (CuTest *tc)
 
        p11_kit_iter_free (iter);
 
-       rv = p11_kit_finalize_module (&mock_module);
+       rv = mock_module.C_Finalize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 }
 
@@ -972,7 +975,8 @@ test_load_attributes_none (CuTest *tc)
        CK_ATTRIBUTE *attrs;
        CK_RV rv;
 
-       rv = p11_kit_initialize_module (&mock_module);
+       mock_module_reset ();
+       rv = mock_module.C_Initialize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 
        memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST));
@@ -991,7 +995,7 @@ test_load_attributes_none (CuTest *tc)
 
        p11_kit_iter_free (iter);
 
-       rv = p11_kit_finalize_module (&mock_module);
+       rv = mock_module.C_Finalize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 }
 
@@ -1004,7 +1008,8 @@ test_load_attributes_fail_first (CuTest *tc)
        CK_ATTRIBUTE *attrs;
        CK_RV rv;
 
-       rv = p11_kit_initialize_module (&mock_module);
+       mock_module_reset ();
+       rv = mock_module.C_Initialize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 
        memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST));
@@ -1024,7 +1029,7 @@ test_load_attributes_fail_first (CuTest *tc)
 
        p11_kit_iter_free (iter);
 
-       rv = p11_kit_finalize_module (&mock_module);
+       rv = mock_module.C_Finalize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 }
 
@@ -1037,7 +1042,8 @@ test_load_attributes_fail_late (CuTest *tc)
        CK_ATTRIBUTE *attrs;
        CK_RV rv;
 
-       rv = p11_kit_initialize_module (&mock_module);
+       mock_module_reset ();
+       rv = mock_module.C_Initialize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 
        memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST));
@@ -1057,7 +1063,7 @@ test_load_attributes_fail_late (CuTest *tc)
 
        p11_kit_iter_free (iter);
 
-       rv = p11_kit_finalize_module (&mock_module);
+       rv = mock_module.C_Finalize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 }
 
diff --git a/p11-kit/tests/test-managed.c b/p11-kit/tests/test-managed.c
new file mode 100644 (file)
index 0000000..8a6a1e8
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2012 Red Hat Inc
+ *
+ * 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@redhat.com>
+ */
+
+#include "config.h"
+#include "CuTest.h"
+
+#include "dict.h"
+#include "library.h"
+#include "mock.h"
+#include "modules.h"
+#include "p11-kit.h"
+#include "virtual.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+static CK_FUNCTION_LIST_PTR
+setup_mock_module (CuTest *tc,
+                   CK_SESSION_HANDLE *session)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_RV rv;
+
+       p11_lock ();
+
+       rv = p11_module_load_inlock_reentrant (&mock_module, 0, &module);
+       CuAssertTrue (tc, rv == CKR_OK);
+       CuAssertPtrNotNull (tc, module);
+       CuAssertTrue (tc, p11_virtual_is_wrapper (module));
+
+       p11_unlock ();
+
+       rv = p11_kit_module_initialize (module);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       if (session) {
+               rv = (module->C_OpenSession) (MOCK_SLOT_ONE_ID,
+                                             CKF_RW_SESSION | CKF_SERIAL_SESSION,
+                                             NULL, NULL, session);
+               CuAssertTrue (tc, rv == CKR_OK);
+       }
+
+       return module;
+}
+
+static void
+teardown_mock_module (CuTest *tc,
+                      CK_FUNCTION_LIST_PTR module)
+{
+       CK_RV rv;
+
+       rv = p11_kit_module_finalize (module);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       p11_lock ();
+
+       rv = p11_module_release_inlock_reentrant (module);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       p11_unlock ();
+}
+
+static CK_RV
+fail_C_Initialize (void *init_reserved)
+{
+       return CKR_FUNCTION_FAILED;
+}
+
+static void
+test_initialize_finalize (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, NULL);
+
+       rv = module->C_Initialize (NULL);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = module->C_Finalize (NULL);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_initialize_fail (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_FUNCTION_LIST base;
+       CK_RV rv;
+
+       memcpy (&base, &mock_module, sizeof (CK_FUNCTION_LIST));
+       base.C_Initialize = fail_C_Initialize;
+
+       p11_lock ();
+
+       rv = p11_module_load_inlock_reentrant (&base, 0, &module);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       p11_unlock ();
+
+       rv = p11_kit_module_initialize (module);
+       CuAssertTrue (tc, rv == CKR_FUNCTION_FAILED);
+}
+
+/* Bring in all the mock module tests */
+#include "test-mock.c"
+
+int
+main (void)
+{
+       CuString *output = CuStringNew ();
+       CuSuite* suite = CuSuiteNew ();
+       int ret;
+
+       putenv ("P11_KIT_STRICT=1");
+       mock_module_init ();
+       p11_library_init ();
+
+       SUITE_ADD_TEST (suite, test_initialize_finalize);
+       SUITE_ADD_TEST (suite, test_initialize_fail);
+       test_mock_add_tests (suite);
+
+       p11_kit_be_quiet ();
+
+       CuSuiteRun (suite);
+       CuSuiteSummary (suite, output);
+       CuSuiteDetails (suite, output);
+       printf ("%s\n", output->buffer);
+       ret = suite->failCount;
+       CuSuiteDelete (suite);
+       CuStringDelete (output);
+       return ret;
+}
diff --git a/p11-kit/tests/test-mock.c b/p11-kit/tests/test-mock.c
new file mode 100644 (file)
index 0000000..955174f
--- /dev/null
@@ -0,0 +1,1687 @@
+/*
+ * Copyright (c) 2012 Stefan Walter
+ * Copyright (c) 2012-2013 Red Hat Inc.
+ *
+ * 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 <stef@thewalter.net>
+ */
+
+#include "CuTest.h"
+
+#include "library.h"
+#include "mock.h"
+#include "p11-kit.h"
+
+#include <sys/types.h>
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static void
+test_get_info (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_INFO info;
+       CK_RV rv;
+       char *string;
+
+       module = setup_mock_module (tc, NULL);
+
+       rv = (module->C_GetInfo) (&info);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, CRYPTOKI_VERSION_MAJOR, info.cryptokiVersion.major);
+       CuAssertIntEquals (tc, CRYPTOKI_VERSION_MINOR, info.cryptokiVersion.minor);
+       string = p11_kit_space_strdup (info.manufacturerID, sizeof (info.manufacturerID));
+       CuAssertStrEquals (tc, "MOCK MANUFACTURER", string);
+       free (string);
+       string = p11_kit_space_strdup (info.libraryDescription, sizeof (info.libraryDescription));
+       CuAssertStrEquals (tc, "MOCK LIBRARY", string);
+       free (string);
+       CuAssertIntEquals (tc, 0, info.flags);
+       CuAssertIntEquals (tc, 45, info.libraryVersion.major);
+       CuAssertIntEquals (tc, 145, info.libraryVersion.minor);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_get_slot_list (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SLOT_ID slot_list[8];
+       CK_ULONG count;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, NULL);
+
+       /* Normal module has 2 slots, one with token present */
+       rv = (module->C_GetSlotList) (CK_TRUE, NULL, &count);
+       CuAssertTrue (tc, rv == CKR_OK);
+       CuAssertIntEquals (tc, 1, count);
+       rv = (module->C_GetSlotList) (CK_FALSE, NULL, &count);
+       CuAssertTrue (tc, rv == CKR_OK);
+       CuAssertIntEquals (tc, 2, count);
+
+       count = 8;
+       rv = (module->C_GetSlotList) (CK_TRUE, slot_list, &count);
+       CuAssertTrue (tc, rv == CKR_OK);
+       CuAssertIntEquals (tc, 1, count);
+       CuAssertIntEquals (tc, MOCK_SLOT_ONE_ID, slot_list[0]);
+
+       count = 8;
+       rv = (module->C_GetSlotList) (CK_FALSE, slot_list, &count);
+       CuAssertTrue (tc, rv == CKR_OK);
+       CuAssertIntEquals (tc, 2, count);
+       CuAssertIntEquals (tc, MOCK_SLOT_ONE_ID, slot_list[0]);
+       CuAssertIntEquals (tc, MOCK_SLOT_TWO_ID, slot_list[1]);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_get_slot_info (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SLOT_INFO info;
+       char *string;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, NULL);
+
+       rv = (module->C_GetSlotInfo) (MOCK_SLOT_ONE_ID, &info);
+       CuAssertTrue (tc, rv == CKR_OK);
+       string = p11_kit_space_strdup (info.slotDescription, sizeof (info.slotDescription));
+       CuAssertStrEquals (tc, "TEST SLOT", string);
+       free (string);
+       string = p11_kit_space_strdup (info.manufacturerID, sizeof (info.manufacturerID));
+       CuAssertStrEquals (tc, "TEST MANUFACTURER", string);
+       free (string);
+       CuAssertIntEquals (tc, CKF_TOKEN_PRESENT | CKF_REMOVABLE_DEVICE, info.flags);
+       CuAssertIntEquals (tc, 55, info.hardwareVersion.major);
+       CuAssertIntEquals (tc, 155, info.hardwareVersion.minor);
+       CuAssertIntEquals (tc, 65, info.firmwareVersion.major);
+       CuAssertIntEquals (tc, 165, info.firmwareVersion.minor);
+
+       rv = (module->C_GetSlotInfo) (MOCK_SLOT_TWO_ID, &info);
+       CuAssertTrue (tc, rv == CKR_OK);
+       CuAssertIntEquals (tc, CKF_REMOVABLE_DEVICE, info.flags);
+
+       rv = (module->C_GetSlotInfo) (0, &info);
+       CuAssertTrue (tc, rv == CKR_SLOT_ID_INVALID);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_get_token_info (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_TOKEN_INFO info;
+       char *string;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, NULL);
+
+       rv = (module->C_GetTokenInfo) (MOCK_SLOT_ONE_ID, &info);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       string = p11_kit_space_strdup (info.label, sizeof (info.label));
+       CuAssertStrEquals (tc, "TEST LABEL", string);
+       free (string);
+       string = p11_kit_space_strdup (info.manufacturerID, sizeof (info.manufacturerID));
+       CuAssertStrEquals (tc, "TEST MANUFACTURER", string);
+       free (string);
+       string = p11_kit_space_strdup (info.model, sizeof (info.model));
+       CuAssertStrEquals (tc, "TEST MODEL", string);
+       free (string);
+       string = p11_kit_space_strdup (info.serialNumber, sizeof (info.serialNumber));
+       CuAssertStrEquals (tc, "TEST SERIAL", string);
+       free (string);
+       CuAssertIntEquals (tc, CKF_LOGIN_REQUIRED | CKF_USER_PIN_INITIALIZED | CKF_CLOCK_ON_TOKEN | CKF_TOKEN_INITIALIZED, info.flags);
+       CuAssertIntEquals (tc, 1, info.ulMaxSessionCount);
+       CuAssertIntEquals (tc, 2, info.ulSessionCount);
+       CuAssertIntEquals (tc, 3, info.ulMaxRwSessionCount);
+       CuAssertIntEquals (tc, 4, info.ulRwSessionCount);
+       CuAssertIntEquals (tc, 5, info.ulMaxPinLen);
+       CuAssertIntEquals (tc, 6, info.ulMinPinLen);
+       CuAssertIntEquals (tc, 7, info.ulTotalPublicMemory);
+       CuAssertIntEquals (tc, 8, info.ulFreePublicMemory);
+       CuAssertIntEquals (tc, 9, info.ulTotalPrivateMemory);
+       CuAssertIntEquals (tc, 10, info.ulFreePrivateMemory);
+       CuAssertIntEquals (tc, 75, info.hardwareVersion.major);
+       CuAssertIntEquals (tc, 175, info.hardwareVersion.minor);
+       CuAssertIntEquals (tc, 85, info.firmwareVersion.major);
+       CuAssertIntEquals (tc, 185, info.firmwareVersion.minor);
+       CuAssertTrue (tc, memcmp (info.utcTime, "1999052509195900", sizeof (info.utcTime)) == 0);
+
+       rv = (module->C_GetTokenInfo) (MOCK_SLOT_TWO_ID, &info);
+       CuAssertTrue (tc, rv == CKR_TOKEN_NOT_PRESENT);
+
+       rv = (module->C_GetTokenInfo) (0, &info);
+       CuAssertTrue (tc, rv == CKR_SLOT_ID_INVALID);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_get_mechanism_list (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_MECHANISM_TYPE mechs[8];
+       CK_ULONG count;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, NULL);
+
+       rv = (module->C_GetMechanismList) (MOCK_SLOT_ONE_ID, NULL, &count);
+       CuAssertTrue (tc, rv == CKR_OK);
+       CuAssertIntEquals (tc, 2, count);
+       rv = (module->C_GetMechanismList) (MOCK_SLOT_TWO_ID, NULL, &count);
+       CuAssertTrue (tc, rv == CKR_TOKEN_NOT_PRESENT);
+       rv = (module->C_GetMechanismList) (0, NULL, &count);
+       CuAssertTrue (tc, rv == CKR_SLOT_ID_INVALID);
+
+       count = 8;
+       rv = (module->C_GetMechanismList) (MOCK_SLOT_ONE_ID, mechs, &count);
+       CuAssertTrue (tc, rv == CKR_OK);
+       CuAssertIntEquals (tc, 2, count);
+       CuAssertIntEquals (tc, mechs[0], CKM_MOCK_CAPITALIZE);
+       CuAssertIntEquals (tc, mechs[1], CKM_MOCK_PREFIX);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_get_mechanism_info (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_MECHANISM_INFO info;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, NULL);
+
+       rv = (module->C_GetMechanismInfo) (MOCK_SLOT_ONE_ID, CKM_MOCK_CAPITALIZE, &info);
+       CuAssertTrue (tc, rv == CKR_OK);
+       CuAssertIntEquals (tc, 512, info.ulMinKeySize);
+       CuAssertIntEquals (tc, 4096, info.ulMaxKeySize);
+       CuAssertIntEquals (tc, CKF_ENCRYPT | CKF_DECRYPT, info.flags);
+
+       rv = (module->C_GetMechanismInfo) (MOCK_SLOT_ONE_ID, CKM_MOCK_PREFIX, &info);
+       CuAssertTrue (tc, rv == CKR_OK);
+       CuAssertIntEquals (tc, 2048, info.ulMinKeySize);
+       CuAssertIntEquals (tc, 2048, info.ulMaxKeySize);
+       CuAssertIntEquals (tc, CKF_SIGN | CKF_VERIFY, info.flags);
+
+       rv = (module->C_GetMechanismInfo) (MOCK_SLOT_TWO_ID, CKM_MOCK_PREFIX, &info);
+       CuAssertTrue (tc, rv == CKR_TOKEN_NOT_PRESENT);
+       rv = (module->C_GetMechanismInfo) (MOCK_SLOT_ONE_ID, 0, &info);
+       CuAssertTrue (tc, rv == CKR_MECHANISM_INVALID);
+       rv = (module->C_GetMechanismInfo) (0, CKM_MOCK_PREFIX, &info);
+       CuAssertTrue (tc, rv == CKR_SLOT_ID_INVALID);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_init_token (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, NULL);
+
+       rv = (module->C_InitToken) (MOCK_SLOT_ONE_ID, (CK_UTF8CHAR_PTR)"TEST PIN", 8, (CK_UTF8CHAR_PTR)"TEST LABEL");
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_InitToken) (MOCK_SLOT_ONE_ID, (CK_UTF8CHAR_PTR)"OTHER", 5, (CK_UTF8CHAR_PTR)"TEST LABEL");
+       CuAssertTrue (tc, rv == CKR_PIN_INVALID);
+       rv = (module->C_InitToken) (MOCK_SLOT_TWO_ID, (CK_UTF8CHAR_PTR)"TEST PIN", 8, (CK_UTF8CHAR_PTR)"TEST LABEL");
+       CuAssertTrue (tc, rv == CKR_TOKEN_NOT_PRESENT);
+       rv = (module->C_InitToken) (0, (CK_UTF8CHAR_PTR)"TEST PIN", 8, (CK_UTF8CHAR_PTR)"TEST LABEL");
+       CuAssertTrue (tc, rv == CKR_SLOT_ID_INVALID);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_wait_for_slot_event (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SLOT_ID slot;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, NULL);
+
+       rv = (module->C_WaitForSlotEvent) (0, &slot, NULL);
+       CuAssertTrue (tc, rv == CKR_OK);
+       CuAssertIntEquals (tc, slot, MOCK_SLOT_TWO_ID);
+
+       rv = (module->C_WaitForSlotEvent) (CKF_DONT_BLOCK, &slot, NULL);
+       CuAssertTrue (tc, rv == CKR_NO_EVENT);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_open_close_session (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, NULL);
+
+       rv = (module->C_OpenSession) (MOCK_SLOT_TWO_ID, CKF_SERIAL_SESSION, NULL, NULL, &session);
+       CuAssertTrue (tc, rv == CKR_TOKEN_NOT_PRESENT);
+       rv = (module->C_OpenSession) (0, CKF_SERIAL_SESSION, NULL, NULL, &session);
+       CuAssertTrue (tc, rv == CKR_SLOT_ID_INVALID);
+
+       rv = (module->C_OpenSession) (MOCK_SLOT_ONE_ID, CKF_SERIAL_SESSION, NULL, NULL, &session);
+       CuAssertTrue (tc, rv == CKR_OK);
+       CuAssertTrue (tc, session != 0);
+
+       rv = (module->C_CloseSession) (session);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_CloseSession) (session);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_close_all_sessions (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, NULL);
+
+       rv = (module->C_OpenSession) (MOCK_SLOT_ONE_ID, CKF_SERIAL_SESSION, NULL, NULL, &session);
+       CuAssertTrue (tc, rv == CKR_OK);
+       CuAssertTrue (tc, session != 0);
+
+       rv = (module->C_CloseAllSessions) (MOCK_SLOT_ONE_ID);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_CloseSession) (session);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_get_function_status (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       rv = (module->C_GetFunctionStatus) (session);
+       CuAssertTrue (tc, rv == CKR_FUNCTION_NOT_PARALLEL);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_cancel_function (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       rv = (module->C_CancelFunction) (session);
+       CuAssertTrue (tc, rv == CKR_FUNCTION_NOT_PARALLEL);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_get_session_info (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_SESSION_INFO info;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, NULL);
+
+       rv = (module->C_GetSessionInfo) (0, &info);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = (module->C_OpenSession) (MOCK_SLOT_ONE_ID, CKF_SERIAL_SESSION, NULL, NULL, &session);
+       CuAssertTrue (tc, rv == CKR_OK);
+       CuAssertTrue (tc, session != 0);
+
+       rv = (module->C_GetSessionInfo) (session, &info);
+       CuAssertTrue (tc, rv == CKR_OK);
+       CuAssertIntEquals (tc, MOCK_SLOT_ONE_ID, info.slotID);
+       CuAssertIntEquals (tc, CKS_RO_PUBLIC_SESSION, info.state);
+       CuAssertIntEquals (tc, CKF_SERIAL_SESSION, info.flags);
+       CuAssertIntEquals (tc, 1414, info.ulDeviceError);
+
+       rv = (module->C_OpenSession) (MOCK_SLOT_ONE_ID, CKF_RW_SESSION | CKF_SERIAL_SESSION, NULL, NULL, &session);
+       CuAssertTrue (tc, rv == CKR_OK);
+       CuAssertTrue (tc, session != 0);
+
+       rv = (module->C_GetSessionInfo) (session, &info);
+       CuAssertTrue (tc, rv == CKR_OK);
+       CuAssertIntEquals (tc, MOCK_SLOT_ONE_ID, info.slotID);
+       CuAssertIntEquals (tc, CKS_RW_PUBLIC_SESSION, info.state);
+       CuAssertIntEquals (tc, CKF_SERIAL_SESSION | CKF_RW_SESSION, info.flags);
+       CuAssertIntEquals (tc, 1414, info.ulDeviceError);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_init_pin (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       rv = (module->C_InitPIN) (0, (CK_UTF8CHAR_PTR)"TEST PIN", 8);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = (module->C_InitPIN) (session, (CK_UTF8CHAR_PTR)"TEST PIN", 8);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_InitPIN) (session, (CK_UTF8CHAR_PTR)"OTHER", 5);
+       CuAssertTrue (tc, rv == CKR_PIN_INVALID);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_set_pin (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       rv = (module->C_SetPIN) (0, (CK_UTF8CHAR_PTR)"booo", 4, (CK_UTF8CHAR_PTR)"TEST PIN", 8);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = (module->C_SetPIN) (session, (CK_UTF8CHAR_PTR)"booo", 4, (CK_UTF8CHAR_PTR)"TEST PIN", 8);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_SetPIN) (session, (CK_UTF8CHAR_PTR)"other", 5, (CK_UTF8CHAR_PTR)"OTHER", 5);
+       CuAssertTrue (tc, rv == CKR_PIN_INCORRECT);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_operation_state (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_BYTE state[128];
+       CK_ULONG state_len;
+       CK_SESSION_HANDLE session = 0;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       state_len = sizeof (state);
+       rv = (module->C_GetOperationState) (0, state, &state_len);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       state_len = sizeof (state);
+       rv = (module->C_GetOperationState) (session, state, &state_len);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_SetOperationState) (session, state, state_len, 355, 455);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_SetOperationState) (0, state, state_len, 355, 455);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_login_logout (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       rv = (module->C_Login) (0, CKU_USER, (CK_UTF8CHAR_PTR)"booo", 4);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = (module->C_Login) (session, CKU_USER, (CK_UTF8CHAR_PTR)"bo", 2);
+       CuAssertTrue (tc, rv == CKR_PIN_INCORRECT);
+
+       rv = (module->C_Login) (session, CKU_USER, (CK_UTF8CHAR_PTR)"booo", 4);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_Logout) (session);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_Logout) (session);
+       CuAssertTrue (tc, rv == CKR_USER_NOT_LOGGED_IN);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_get_attribute_value (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_ATTRIBUTE attrs[8];
+       char label[32];
+       CK_OBJECT_CLASS klass;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       attrs[0].type = CKA_CLASS;
+       attrs[0].pValue = &klass;
+       attrs[0].ulValueLen = sizeof (klass);
+       attrs[1].type = CKA_LABEL;
+       attrs[1].pValue = label;
+       attrs[1].ulValueLen = 2; /* too small */
+       attrs[2].type = CKA_BITS_PER_PIXEL;
+       attrs[2].pValue = NULL;
+       attrs[2].ulValueLen = 0;
+
+       rv = (module->C_GetAttributeValue) (session, MOCK_PRIVATE_KEY_CAPITALIZE, attrs, 3);
+       CuAssertTrue (tc, rv == CKR_USER_NOT_LOGGED_IN);
+
+       rv = (module->C_GetAttributeValue) (session, MOCK_PUBLIC_KEY_CAPITALIZE, attrs, 2);
+       CuAssertTrue (tc, rv == CKR_BUFFER_TOO_SMALL);
+
+       /* Get right size */
+       attrs[1].pValue = NULL;
+       attrs[1].ulValueLen = 0;
+
+       rv = (module->C_GetAttributeValue) (session, MOCK_PUBLIC_KEY_CAPITALIZE, attrs, 2);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_GetAttributeValue) (session, MOCK_PUBLIC_KEY_CAPITALIZE, attrs, 3);
+       CuAssertTrue (tc, rv == CKR_ATTRIBUTE_TYPE_INVALID);
+
+       CuAssertIntEquals (tc, CKO_PUBLIC_KEY, klass);
+       CuAssertIntEquals (tc, 21, attrs[1].ulValueLen);
+       CuAssertPtrEquals (tc, NULL, attrs[1].pValue);
+       attrs[1].pValue = label;
+       attrs[1].ulValueLen = sizeof (label);
+       CuAssertTrue (tc, (CK_ULONG)-1 == attrs[2].ulValueLen);
+       CuAssertPtrEquals (tc, NULL, attrs[2].pValue);
+
+       rv = (module->C_GetAttributeValue) (session, MOCK_PUBLIC_KEY_CAPITALIZE, attrs, 3);
+       CuAssertTrue (tc, rv == CKR_ATTRIBUTE_TYPE_INVALID);
+
+       CuAssertIntEquals (tc, CKO_PUBLIC_KEY, klass);
+       CuAssertIntEquals (tc, 21, attrs[1].ulValueLen);
+       CuAssertPtrEquals (tc, label, attrs[1].pValue);
+       CuAssertTrue (tc, memcmp (label, "Public Capitalize Key", attrs[1].ulValueLen) == 0);
+       CuAssertTrue (tc, (CK_ULONG)-1 == attrs[2].ulValueLen);
+       CuAssertPtrEquals (tc, NULL, attrs[2].pValue);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_set_attribute_value (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_ATTRIBUTE attrs[8];
+       char label[32];
+       CK_ULONG bits;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       strcpy (label, "Blahooo");
+       bits = 1555;
+
+       attrs[0].type = CKA_LABEL;
+       attrs[0].pValue = label;
+       attrs[0].ulValueLen = strlen (label);
+       attrs[1].type = CKA_BITS_PER_PIXEL;
+       attrs[1].pValue = &bits;
+       attrs[1].ulValueLen = sizeof (bits);
+
+       rv = (module->C_SetAttributeValue) (session, MOCK_PRIVATE_KEY_CAPITALIZE, attrs, 2);
+       CuAssertTrue (tc, rv == CKR_USER_NOT_LOGGED_IN);
+
+       rv = (module->C_SetAttributeValue) (session, MOCK_PUBLIC_KEY_CAPITALIZE, attrs, 2);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       memset (label, 0, sizeof (label));
+       bits = 0;
+
+       rv = (module->C_GetAttributeValue) (session, MOCK_PUBLIC_KEY_CAPITALIZE, attrs, 2);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, bits, 1555);
+       CuAssertIntEquals (tc, 7, attrs[0].ulValueLen);
+       CuAssertTrue (tc, memcmp (label, "Blahooo", attrs[0].ulValueLen) == 0);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_create_object (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_OBJECT_HANDLE object;
+       CK_ATTRIBUTE attrs[8];
+       char label[32];
+       CK_ULONG bits;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       strcpy (label, "Blahooo");
+       bits = 1555;
+
+       attrs[0].type = CKA_LABEL;
+       attrs[0].pValue = label;
+       attrs[0].ulValueLen = strlen (label);
+       attrs[1].type = CKA_BITS_PER_PIXEL;
+       attrs[1].pValue = &bits;
+       attrs[1].ulValueLen = sizeof (bits);
+
+       rv = (module->C_CreateObject) (0, attrs, 2, &object);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = (module->C_CreateObject) (session, attrs, 2, &object);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       attrs[0].ulValueLen = sizeof (label);
+       memset (label, 0, sizeof (label));
+       bits = 0;
+
+       rv = (module->C_GetAttributeValue) (session, object, attrs, 2);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, bits, 1555);
+       CuAssertIntEquals (tc, 7, attrs[0].ulValueLen);
+       CuAssertTrue (tc, memcmp (label, "Blahooo", attrs[0].ulValueLen) == 0);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_copy_object (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_OBJECT_HANDLE object;
+       CK_ATTRIBUTE attrs[8];
+       char label[32];
+       CK_ULONG bits;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       bits = 1555;
+
+       attrs[0].type = CKA_BITS_PER_PIXEL;
+       attrs[0].pValue = &bits;
+       attrs[0].ulValueLen = sizeof (bits);
+
+       rv = (module->C_CopyObject) (session, 1333, attrs, 1, &object);
+       CuAssertTrue (tc, rv == CKR_OBJECT_HANDLE_INVALID);
+
+       rv = (module->C_CopyObject) (session, MOCK_PUBLIC_KEY_CAPITALIZE, attrs, 1, &object);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       attrs[1].type = CKA_LABEL;
+       attrs[1].pValue = label;
+       attrs[1].ulValueLen = sizeof (label);
+       bits = 0;
+
+       rv = (module->C_GetAttributeValue) (session, object, attrs, 2);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, bits, 1555);
+       CuAssertIntEquals (tc, 21, attrs[1].ulValueLen);
+       CuAssertTrue (tc, memcmp (label, "Public Capitalize Key", attrs[1].ulValueLen) == 0);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_destroy_object (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_ATTRIBUTE attrs[8];
+       char label[32];
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       attrs[0].type = CKA_LABEL;
+       attrs[0].pValue = label;
+       attrs[0].ulValueLen = sizeof (label);
+
+       rv = (module->C_GetAttributeValue) (session, MOCK_PUBLIC_KEY_CAPITALIZE, attrs, 1);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_DestroyObject) (0, MOCK_PUBLIC_KEY_CAPITALIZE);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = (module->C_DestroyObject) (session, MOCK_PUBLIC_KEY_CAPITALIZE);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_GetAttributeValue) (session, MOCK_PUBLIC_KEY_CAPITALIZE, attrs, 1);
+       CuAssertTrue (tc, rv == CKR_OBJECT_HANDLE_INVALID);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_get_object_size (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_ULONG size;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       rv = (module->C_GetObjectSize) (session, 1333, &size);
+       CuAssertTrue (tc, rv == CKR_OBJECT_HANDLE_INVALID);
+
+       rv = (module->C_GetObjectSize) (session, MOCK_PUBLIC_KEY_CAPITALIZE, &size);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       /* The number here is the length of all attributes added up */
+       CuAssertIntEquals (tc, sizeof (CK_ULONG) == 8 ? 44 : 36, size);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_find_objects (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_OBJECT_CLASS klass = CKO_PUBLIC_KEY;
+       CK_ATTRIBUTE attr = { CKA_CLASS, &klass, sizeof (klass) };
+       CK_OBJECT_HANDLE objects[16];
+       CK_ULONG count;
+       CK_ULONG i;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       rv = (module->C_FindObjectsInit) (0, &attr, 1);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = (module->C_FindObjectsInit) (session, &attr, 1);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_FindObjects) (0, objects, 16, &count);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = (module->C_FindObjects) (session, objects, 16, &count);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertTrue (tc, count < 16);
+
+       /* Make sure we get the capitalize public key */
+       for (i = 0; i < count; i++) {
+               if (objects[i] == MOCK_PUBLIC_KEY_CAPITALIZE)
+                       break;
+       }
+       CuAssertTrue (tc, i != count);
+
+       /* Make sure we get the prefix public key */
+       for (i = 0; i < count; i++) {
+               if (objects[i] == MOCK_PUBLIC_KEY_PREFIX)
+                       break;
+       }
+       CuAssertTrue (tc, i != count);
+
+       /* Make sure all public keys */
+       for (i = 0; i < count; i++) {
+               klass = (CK_ULONG)-1;
+               rv = (module->C_GetAttributeValue) (session, objects[i], &attr, 1);
+               CuAssertTrue (tc, rv == CKR_OK);
+               CuAssertIntEquals (tc, CKO_PUBLIC_KEY, klass);
+       }
+
+       rv = (module->C_FindObjectsFinal) (session);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_FindObjectsFinal) (session);
+       CuAssertTrue (tc, rv == CKR_OPERATION_NOT_INITIALIZED);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_encrypt (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_MECHANISM mech = { CKM_MOCK_CAPITALIZE, NULL, 0 };
+       CK_BYTE data[128];
+       CK_ULONG length;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       rv = (module->C_EncryptInit) (session, &mech, MOCK_PUBLIC_KEY_PREFIX);
+       CuAssertTrue (tc, rv == CKR_KEY_HANDLE_INVALID);
+
+       rv = (module->C_EncryptInit) (session, &mech, MOCK_PUBLIC_KEY_CAPITALIZE);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       length = sizeof (data);
+       rv = (module->C_Encrypt) (0, (CK_BYTE_PTR)"blah", 4, data, &length);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       length = sizeof (data);
+       rv = (module->C_Encrypt) (session, (CK_BYTE_PTR)"blah", 4, data, &length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, 4, length);
+       CuAssertTrue (tc, memcmp (data, "BLAH", 4) == 0);
+
+       rv = (module->C_EncryptInit) (session, &mech, MOCK_PUBLIC_KEY_CAPITALIZE);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       length = sizeof (data);
+       rv = (module->C_EncryptUpdate) (0, (CK_BYTE_PTR)"blah", 4, data, &length);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       length = sizeof (data);
+       rv = (module->C_EncryptUpdate) (session, (CK_BYTE_PTR)"sLurm", 5, data, &length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, 5, length);
+       CuAssertTrue (tc, memcmp (data, "SLURM", 5) == 0);
+
+       length = sizeof (data);
+       rv = (module->C_EncryptFinal) (0, data, &length);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       length = sizeof (data);
+       rv = (module->C_EncryptFinal) (session, data, &length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_decrypt (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_MECHANISM mech = { CKM_MOCK_CAPITALIZE, NULL, 0 };
+       CK_BYTE data[128];
+       CK_ULONG length;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       rv = (module->C_Login) (session, CKU_USER, (CK_BYTE_PTR)"booo", 4);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_DecryptInit) (session, &mech, MOCK_PRIVATE_KEY_PREFIX);
+       CuAssertTrue (tc, rv == CKR_KEY_HANDLE_INVALID);
+
+       rv = (module->C_DecryptInit) (session, &mech, MOCK_PRIVATE_KEY_CAPITALIZE);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       length = sizeof (data);
+       rv = (module->C_Decrypt) (0, (CK_BYTE_PTR)"bLAH", 4, data, &length);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       length = sizeof (data);
+       rv = (module->C_Decrypt) (session, (CK_BYTE_PTR)"BLAh", 4, data, &length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, 4, length);
+       CuAssertTrue (tc, memcmp (data, "blah", 4) == 0);
+
+       rv = (module->C_DecryptInit) (session, &mech, MOCK_PRIVATE_KEY_CAPITALIZE);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       length = sizeof (data);
+       rv = (module->C_DecryptUpdate) (0, (CK_BYTE_PTR)"blah", 4, data, &length);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       length = sizeof (data);
+       rv = (module->C_DecryptUpdate) (session, (CK_BYTE_PTR)"sLuRM", 5, data, &length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, 5, length);
+       CuAssertTrue (tc, memcmp (data, "slurm", 5) == 0);
+
+       length = sizeof (data);
+       rv = (module->C_DecryptFinal) (0, data, &length);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       length = sizeof (data);
+       rv = (module->C_DecryptFinal) (session, data, &length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_digest (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_MECHANISM mech = { CKM_MOCK_COUNT, NULL, 0 };
+       CK_BYTE digest[128];
+       CK_ULONG length;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       rv = (module->C_DigestInit) (0, &mech);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = (module->C_DigestInit) (session, &mech);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       length = sizeof (digest);
+       rv = (module->C_Digest) (0, (CK_BYTE_PTR)"bLAH", 4, digest, &length);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       length = sizeof (digest);
+       rv = (module->C_Digest) (session, (CK_BYTE_PTR)"BLAh", 4, digest, &length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, 1, length);
+       CuAssertTrue (tc, memcmp (digest, "4", 1) == 0);
+
+       rv = (module->C_DigestInit) (session, &mech);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_DigestUpdate) (0, (CK_BYTE_PTR)"blah", 4);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = (module->C_DigestUpdate) (session, (CK_BYTE_PTR)"sLuRM", 5);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       /* Adds the the value of object handle to hash: 6 */
+       CuAssertIntEquals (tc, 6, MOCK_PUBLIC_KEY_PREFIX);
+       rv = (module->C_DigestKey) (session, MOCK_PUBLIC_KEY_PREFIX);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_DigestUpdate) (session, (CK_BYTE_PTR)"Other", 5);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       length = sizeof (digest);
+       rv = (module->C_DigestFinal) (0, digest, &length);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       length = sizeof (digest);
+       rv = (module->C_DigestFinal) (session, digest, &length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, 2, length);
+       CuAssertTrue (tc, memcmp (digest, "16", 2) == 0);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_sign (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_MECHANISM mech = { CKM_MOCK_PREFIX, "prefix:", 7 };
+       CK_BYTE signature[128];
+       CK_ULONG length;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       rv = (module->C_Login) (session, CKU_USER, (CK_BYTE_PTR)"booo", 4);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_SignInit) (0, &mech, MOCK_PRIVATE_KEY_PREFIX);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = (module->C_SignInit) (session, &mech, MOCK_PRIVATE_KEY_PREFIX);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_Login) (session, CKU_CONTEXT_SPECIFIC, (CK_BYTE_PTR)"booo", 4);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       length = sizeof (signature);
+       rv = (module->C_Sign) (0, (CK_BYTE_PTR)"bLAH", 4, signature, &length);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       length = sizeof (signature);
+       rv = (module->C_Sign) (session, (CK_BYTE_PTR)"BLAh", 4, signature, &length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, 13, length);
+       CuAssertTrue (tc, memcmp (signature, "prefix:value4", 13) == 0);
+
+       rv = (module->C_SignInit) (session, &mech, MOCK_PRIVATE_KEY_PREFIX);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_Login) (session, CKU_CONTEXT_SPECIFIC, (CK_BYTE_PTR)"booo", 4);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_SignUpdate) (0, (CK_BYTE_PTR)"blah", 4);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = (module->C_SignUpdate) (session, (CK_BYTE_PTR)"sLuRM", 5);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_SignUpdate) (session, (CK_BYTE_PTR)"Other", 5);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       length = sizeof (signature);
+       rv = (module->C_SignFinal) (0, signature, &length);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       length = sizeof (signature);
+       rv = (module->C_SignFinal) (session, signature, &length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, 14, length);
+       CuAssertTrue (tc, memcmp (signature, "prefix:value10", 2) == 0);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_sign_recover (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_MECHANISM mech = { CKM_MOCK_PREFIX, "prefix:", 7 };
+       CK_BYTE signature[128];
+       CK_ULONG length;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       rv = (module->C_Login) (session, CKU_USER, (CK_BYTE_PTR)"booo", 4);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_SignRecoverInit) (0, &mech, MOCK_PRIVATE_KEY_PREFIX);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = (module->C_SignRecoverInit) (session, &mech, MOCK_PRIVATE_KEY_PREFIX);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_Login) (session, CKU_CONTEXT_SPECIFIC, (CK_BYTE_PTR)"booo", 4);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       length = sizeof (signature);
+       rv = (module->C_SignRecover) (0, (CK_BYTE_PTR)"bLAH", 4, signature, &length);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       length = sizeof (signature);
+       rv = (module->C_SignRecover) (session, (CK_BYTE_PTR)"BLAh", 4, signature, &length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, 16, length);
+       CuAssertTrue (tc, memcmp (signature, "prefix:valueBLAh", 16) == 0);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_verify (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_MECHANISM mech = { CKM_MOCK_PREFIX, "prefix:", 7 };
+       CK_BYTE signature[128];
+       CK_ULONG length;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       rv = (module->C_VerifyInit) (0, &mech, MOCK_PUBLIC_KEY_PREFIX);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = (module->C_VerifyInit) (session, &mech, MOCK_PUBLIC_KEY_PREFIX);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       length = 13;
+       memcpy (signature, "prefix:value4", length);
+       rv = (module->C_Verify) (0, (CK_BYTE_PTR)"bLAH", 4, signature, 5);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = (module->C_Verify) (session, (CK_BYTE_PTR)"BLAh", 4, signature, length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_VerifyInit) (session, &mech, MOCK_PUBLIC_KEY_PREFIX);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_VerifyUpdate) (0, (CK_BYTE_PTR)"blah", 4);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = (module->C_VerifyUpdate) (session, (CK_BYTE_PTR)"sLuRM", 5);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_VerifyUpdate) (session, (CK_BYTE_PTR)"Other", 5);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       length = 14;
+       memcpy (signature, "prefix:value10", length);
+
+       rv = (module->C_VerifyFinal) (session, signature, 5);
+       CuAssertTrue (tc, rv == CKR_SIGNATURE_LEN_RANGE);
+
+       rv = (module->C_VerifyFinal) (session, signature, length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_verify_recover (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_MECHANISM mech = { CKM_MOCK_PREFIX, "prefix:", 7 };
+       CK_BYTE data[128];
+       CK_ULONG length;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       rv = (module->C_VerifyRecoverInit) (0, &mech, MOCK_PUBLIC_KEY_PREFIX);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = (module->C_VerifyRecoverInit) (session, &mech, MOCK_PUBLIC_KEY_PREFIX);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       length = sizeof (data);
+       rv = (module->C_VerifyRecover) (0, (CK_BYTE_PTR)"prefix:valueBLah", 16, data, &length);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       length = sizeof (data);
+       rv = (module->C_VerifyRecover) (session, (CK_BYTE_PTR)"prefix:valueBLah", 16, data, &length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, 4, length);
+       CuAssertTrue (tc, memcmp (data, "BLah", 4) == 0);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_digest_encrypt (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_MECHANISM mech = { CKM_MOCK_CAPITALIZE, NULL, 0 };
+       CK_MECHANISM dmech = { CKM_MOCK_COUNT, NULL, 0 };
+       CK_BYTE data[128];
+       CK_ULONG length;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       rv = (module->C_EncryptInit) (session, &mech, MOCK_PUBLIC_KEY_CAPITALIZE);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_DigestInit) (session, &dmech);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       length = sizeof (data);
+       rv = (module->C_DigestEncryptUpdate) (0, (CK_BYTE_PTR)"blah", 4, data, &length);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       length = sizeof (data);
+       rv = (module->C_DigestEncryptUpdate) (session, (CK_BYTE_PTR)"blah", 4, data, &length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, 4, length);
+       CuAssertTrue (tc, memcmp (data, "BLAH", 4) == 0);
+
+       length = sizeof (data);
+       rv = (module->C_EncryptFinal) (session, data, &length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       length = sizeof (data);
+       rv = (module->C_DigestFinal) (session, data, &length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, 1, length);
+       CuAssertTrue (tc, memcmp (data, "4", 1) == 0);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_decrypt_digest (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_MECHANISM mech = { CKM_MOCK_CAPITALIZE, NULL, 0 };
+       CK_MECHANISM dmech = { CKM_MOCK_COUNT, NULL, 0 };
+       CK_BYTE data[128];
+       CK_ULONG length;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       rv = (module->C_Login) (session, CKU_USER, (CK_BYTE_PTR)"booo", 4);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_DecryptInit) (session, &mech, MOCK_PRIVATE_KEY_CAPITALIZE);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_DigestInit) (session, &dmech);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       length = sizeof (data);
+       rv = (module->C_DecryptDigestUpdate) (0, (CK_BYTE_PTR)"BLAH", 4, data, &length);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       length = sizeof (data);
+       rv = (module->C_DecryptDigestUpdate) (session, (CK_BYTE_PTR)"BLAH", 4, data, &length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, 4, length);
+       CuAssertTrue (tc, memcmp (data, "blah", 4) == 0);
+
+       length = sizeof (data);
+       rv = (module->C_DecryptFinal) (session, data, &length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       length = sizeof (data);
+       rv = (module->C_DigestFinal) (session, data, &length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, 1, length);
+       CuAssertTrue (tc, memcmp (data, "4", 1) == 0);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_sign_encrypt (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_MECHANISM mech = { CKM_MOCK_CAPITALIZE, NULL, 0 };
+       CK_MECHANISM smech = { CKM_MOCK_PREFIX, "p:", 2 };
+       CK_BYTE data[128];
+       CK_ULONG length;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       rv = (module->C_Login) (session, CKU_USER, (CK_BYTE_PTR)"booo", 4);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_EncryptInit) (session, &mech, MOCK_PUBLIC_KEY_CAPITALIZE);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_SignInit) (session, &smech, MOCK_PRIVATE_KEY_PREFIX);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_Login) (session, CKU_CONTEXT_SPECIFIC, (CK_BYTE_PTR)"booo", 4);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       length = sizeof (data);
+       rv = (module->C_SignEncryptUpdate) (0, (CK_BYTE_PTR)"blah", 4, data, &length);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       length = sizeof (data);
+       rv = (module->C_SignEncryptUpdate) (session, (CK_BYTE_PTR)"blah", 4, data, &length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, 4, length);
+       CuAssertTrue (tc, memcmp (data, "BLAH", 4) == 0);
+
+       length = sizeof (data);
+       rv = (module->C_EncryptFinal) (session, data, &length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       length = sizeof (data);
+       rv = (module->C_SignFinal) (session, data, &length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, 8, length);
+       CuAssertTrue (tc, memcmp (data, "p:value4", 1) == 0);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_decrypt_verify (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_MECHANISM mech = { CKM_MOCK_CAPITALIZE, NULL, 0 };
+       CK_MECHANISM vmech = { CKM_MOCK_PREFIX, "p:", 2 };
+       CK_BYTE data[128];
+       CK_ULONG length;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       rv = (module->C_Login) (session, CKU_USER, (CK_BYTE_PTR)"booo", 4);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_DecryptInit) (session, &mech, MOCK_PRIVATE_KEY_CAPITALIZE);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_VerifyInit) (session, &vmech, MOCK_PUBLIC_KEY_PREFIX);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       length = sizeof (data);
+       rv = (module->C_DecryptVerifyUpdate) (0, (CK_BYTE_PTR)"BLAH", 4, data, &length);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       length = sizeof (data);
+       rv = (module->C_DecryptVerifyUpdate) (session, (CK_BYTE_PTR)"BLAH", 4, data, &length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, 4, length);
+       CuAssertTrue (tc, memcmp (data, "blah", 4) == 0);
+
+       length = sizeof (data);
+       rv = (module->C_DecryptFinal) (session, data, &length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_VerifyFinal) (session, (CK_BYTE_PTR)"p:value4", 8);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_generate_key (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_OBJECT_HANDLE object;
+       CK_MECHANISM mech = { CKM_MOCK_GENERATE, NULL, 0 };
+       CK_ATTRIBUTE attrs[8];
+       char label[32];
+       char value[64];
+       CK_ULONG bits;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       strcpy (label, "Blahooo");
+       bits = 1555;
+
+       attrs[0].type = CKA_LABEL;
+       attrs[0].pValue = label;
+       attrs[0].ulValueLen = strlen (label);
+       attrs[1].type = CKA_BITS_PER_PIXEL;
+       attrs[1].pValue = &bits;
+       attrs[1].ulValueLen = sizeof (bits);
+
+       rv = (module->C_GenerateKey) (session, &mech, attrs, 2, &object);
+       CuAssertTrue (tc, rv == CKR_MECHANISM_PARAM_INVALID);
+
+       mech.pParameter = "generate";
+       mech.ulParameterLen = 9;
+
+       rv = (module->C_GenerateKey) (session, &mech, attrs, 2, &object);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       attrs[0].ulValueLen = sizeof (label);
+       memset (label, 0, sizeof (label));
+       bits = 0;
+       attrs[2].type = CKA_VALUE;
+       attrs[2].pValue = value;
+       attrs[2].ulValueLen = sizeof (value);
+
+       rv = (module->C_GetAttributeValue) (session, object, attrs, 3);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, bits, 1555);
+       CuAssertIntEquals (tc, 7, attrs[0].ulValueLen);
+       CuAssertTrue (tc, memcmp (label, "Blahooo", attrs[0].ulValueLen) == 0);
+       CuAssertIntEquals (tc, 9, attrs[2].ulValueLen);
+       CuAssertTrue (tc, memcmp (value, "generated", attrs[2].ulValueLen) == 0);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_generate_key_pair (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_OBJECT_HANDLE pub_object;
+       CK_OBJECT_HANDLE priv_object;
+       CK_MECHANISM mech = { CKM_MOCK_GENERATE, "generated", 9 };
+       CK_ATTRIBUTE pub_attrs[8];
+       CK_ATTRIBUTE priv_attrs[8];
+       char pub_label[32];
+       char pub_value[64];
+       char priv_label[32];
+       char priv_value[64];
+       CK_ULONG pub_bits;
+       CK_ULONG priv_bits;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       strcpy (pub_label, "Blahooo");
+       pub_bits = 1555;
+       pub_attrs[0].type = CKA_LABEL;
+       pub_attrs[0].pValue = pub_label;
+       pub_attrs[0].ulValueLen = strlen (pub_label);
+       pub_attrs[1].type = CKA_BITS_PER_PIXEL;
+       pub_attrs[1].pValue = &pub_bits;
+       pub_attrs[1].ulValueLen = sizeof (pub_bits);
+
+       strcpy (priv_label, "Private");
+       priv_bits = 1666;
+       priv_attrs[0].type = CKA_LABEL;
+       priv_attrs[0].pValue = priv_label;
+       priv_attrs[0].ulValueLen = strlen (priv_label);
+       priv_attrs[1].type = CKA_BITS_PER_PIXEL;
+       priv_attrs[1].pValue = &priv_bits;
+       priv_attrs[1].ulValueLen = sizeof (priv_bits);
+
+       rv = (module->C_GenerateKeyPair) (0, &mech, pub_attrs, 2, priv_attrs, 2,
+                                         &pub_object, &priv_object);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       mech.pParameter = "generate";
+       mech.ulParameterLen = 9;
+
+       rv = (module->C_GenerateKeyPair) (session, &mech, pub_attrs, 2, priv_attrs, 2,
+                                         &pub_object, &priv_object);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       pub_bits = 0;
+       pub_attrs[0].ulValueLen = sizeof (pub_label);
+       memset (pub_label, 0, sizeof (pub_label));
+       pub_attrs[2].type = CKA_VALUE;
+       pub_attrs[2].pValue = pub_value;
+       pub_attrs[2].ulValueLen = sizeof (pub_value);
+
+       rv = (module->C_GetAttributeValue) (session, pub_object, pub_attrs, 3);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, 1555, pub_bits);
+       CuAssertIntEquals (tc, 7, pub_attrs[0].ulValueLen);
+       CuAssertTrue (tc, memcmp (pub_label, "Blahooo", pub_attrs[0].ulValueLen) == 0);
+       CuAssertIntEquals (tc, 9, pub_attrs[2].ulValueLen);
+       CuAssertTrue (tc, memcmp (pub_value, "generated", pub_attrs[2].ulValueLen) == 0);
+
+       priv_bits = 0;
+       priv_attrs[0].ulValueLen = sizeof (priv_label);
+       memset (priv_label, 0, sizeof (priv_label));
+       priv_attrs[2].type = CKA_VALUE;
+       priv_attrs[2].pValue = priv_value;
+       priv_attrs[2].ulValueLen = sizeof (priv_value);
+
+       rv = (module->C_GetAttributeValue) (session, priv_object, priv_attrs, 3);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, 1666, priv_bits);
+       CuAssertIntEquals (tc, 7, priv_attrs[0].ulValueLen);
+       CuAssertTrue (tc, memcmp (priv_label, "Private", priv_attrs[0].ulValueLen) == 0);
+       CuAssertIntEquals (tc, 9, priv_attrs[2].ulValueLen);
+       CuAssertTrue (tc, memcmp (priv_value, "generated", priv_attrs[2].ulValueLen) == 0);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_wrap_key (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_MECHANISM mech = { CKM_MOCK_WRAP, NULL, 0 };
+       CK_BYTE data[128];
+       CK_ULONG length;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       length = sizeof (data);
+       rv = (module->C_WrapKey) (session, &mech, MOCK_PUBLIC_KEY_PREFIX, MOCK_PUBLIC_KEY_PREFIX, data, &length);
+       CuAssertTrue (tc, rv == CKR_MECHANISM_PARAM_INVALID);
+
+       mech.pParameter = "wrap";
+       mech.ulParameterLen = 4;
+
+       rv = (module->C_WrapKey) (session, &mech, MOCK_PUBLIC_KEY_PREFIX, MOCK_PUBLIC_KEY_PREFIX, data, &length);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, 5, length);
+       CuAssertTrue (tc, memcmp (data, "value", 5) == 0);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_unwrap_key (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_OBJECT_HANDLE object;
+       CK_MECHANISM mech = { CKM_MOCK_WRAP, NULL, 0 };
+       CK_ATTRIBUTE attrs[8];
+       char label[32];
+       char value[64];
+       CK_ULONG bits;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       strcpy (label, "Blahooo");
+       bits = 1555;
+
+       attrs[0].type = CKA_LABEL;
+       attrs[0].pValue = label;
+       attrs[0].ulValueLen = strlen (label);
+       attrs[1].type = CKA_BITS_PER_PIXEL;
+       attrs[1].pValue = &bits;
+       attrs[1].ulValueLen = sizeof (bits);
+
+       rv = (module->C_UnwrapKey) (session, &mech, MOCK_PUBLIC_KEY_PREFIX,
+                                   (CK_BYTE_PTR)"wheee", 5, attrs, 2, &object);
+       CuAssertTrue (tc, rv == CKR_MECHANISM_PARAM_INVALID);
+
+       mech.pParameter = "wrap";
+       mech.ulParameterLen = 4;
+
+       rv = (module->C_UnwrapKey) (session, &mech, MOCK_PUBLIC_KEY_PREFIX,
+                                   (CK_BYTE_PTR)"wheee", 5, attrs, 2, &object);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       attrs[0].ulValueLen = sizeof (label);
+       memset (label, 0, sizeof (label));
+       bits = 0;
+       attrs[2].type = CKA_VALUE;
+       attrs[2].pValue = value;
+       attrs[2].ulValueLen = sizeof (value);
+
+       rv = (module->C_GetAttributeValue) (session, object, attrs, 3);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, bits, 1555);
+       CuAssertIntEquals (tc, 7, attrs[0].ulValueLen);
+       CuAssertTrue (tc, memcmp (label, "Blahooo", attrs[0].ulValueLen) == 0);
+       CuAssertIntEquals (tc, 5, attrs[2].ulValueLen);
+       CuAssertTrue (tc, memcmp (value, "wheee", attrs[2].ulValueLen) == 0);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_derive_key (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_OBJECT_HANDLE object;
+       CK_MECHANISM mech = { CKM_MOCK_DERIVE, NULL, 0 };
+       CK_ATTRIBUTE attrs[8];
+       char label[32];
+       char value[64];
+       CK_ULONG bits;
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       strcpy (label, "Blahooo");
+       bits = 1555;
+
+       attrs[0].type = CKA_LABEL;
+       attrs[0].pValue = label;
+       attrs[0].ulValueLen = strlen (label);
+       attrs[1].type = CKA_BITS_PER_PIXEL;
+       attrs[1].pValue = &bits;
+       attrs[1].ulValueLen = sizeof (bits);
+
+       rv = (module->C_DeriveKey) (session, &mech, MOCK_PUBLIC_KEY_PREFIX,
+                                       attrs, 2, &object);
+       CuAssertTrue (tc, rv == CKR_MECHANISM_PARAM_INVALID);
+
+       mech.pParameter = "derive";
+       mech.ulParameterLen = 6;
+
+       rv = (module->C_DeriveKey) (session, &mech, MOCK_PUBLIC_KEY_PREFIX,
+                                   attrs, 2, &object);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       attrs[0].ulValueLen = sizeof (label);
+       memset (label, 0, sizeof (label));
+       bits = 0;
+       attrs[2].type = CKA_VALUE;
+       attrs[2].pValue = value;
+       attrs[2].ulValueLen = sizeof (value);
+
+       rv = (module->C_GetAttributeValue) (session, object, attrs, 3);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertIntEquals (tc, bits, 1555);
+       CuAssertIntEquals (tc, 7, attrs[0].ulValueLen);
+       CuAssertTrue (tc, memcmp (label, "Blahooo", attrs[0].ulValueLen) == 0);
+       CuAssertIntEquals (tc, 7, attrs[2].ulValueLen);
+       CuAssertTrue (tc, memcmp (value, "derived", attrs[2].ulValueLen) == 0);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_random (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR module;
+       CK_SESSION_HANDLE session = 0;
+       CK_BYTE data[10];
+       CK_RV rv;
+
+       module = setup_mock_module (tc, &session);
+
+       rv = (module->C_SeedRandom) (0, (CK_BYTE_PTR)"seed", 4);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = (module->C_SeedRandom) (session, (CK_BYTE_PTR)"seed", 4);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = (module->C_GenerateRandom) (0, data, sizeof (data));
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = (module->C_GenerateRandom) (session, data, sizeof (data));
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       CuAssertTrue (tc, memcmp (data, "seedseedse", sizeof (data)) == 0);
+
+       teardown_mock_module (tc, module);
+}
+
+static void
+test_mock_add_tests (CuSuite *suite)
+{
+       SUITE_ADD_TEST (suite, test_get_info);
+       SUITE_ADD_TEST (suite, test_get_slot_list);
+       SUITE_ADD_TEST (suite, test_get_slot_info);
+       SUITE_ADD_TEST (suite, test_get_token_info);
+       SUITE_ADD_TEST (suite, test_get_mechanism_list);
+       SUITE_ADD_TEST (suite, test_get_mechanism_info);
+       SUITE_ADD_TEST (suite, test_init_token);
+       SUITE_ADD_TEST (suite, test_wait_for_slot_event);
+       SUITE_ADD_TEST (suite, test_open_close_session);
+       SUITE_ADD_TEST (suite, test_close_all_sessions);
+       SUITE_ADD_TEST (suite, test_get_function_status);
+       SUITE_ADD_TEST (suite, test_cancel_function);
+       SUITE_ADD_TEST (suite, test_get_session_info);
+       SUITE_ADD_TEST (suite, test_init_pin);
+       SUITE_ADD_TEST (suite, test_set_pin);
+       SUITE_ADD_TEST (suite, test_operation_state);
+       SUITE_ADD_TEST (suite, test_login_logout);
+       SUITE_ADD_TEST (suite, test_get_attribute_value);
+       SUITE_ADD_TEST (suite, test_set_attribute_value);
+       SUITE_ADD_TEST (suite, test_create_object);
+       SUITE_ADD_TEST (suite, test_copy_object);
+       SUITE_ADD_TEST (suite, test_destroy_object);
+       SUITE_ADD_TEST (suite, test_get_object_size);
+       SUITE_ADD_TEST (suite, test_find_objects);
+       SUITE_ADD_TEST (suite, test_encrypt);
+       SUITE_ADD_TEST (suite, test_decrypt);
+       SUITE_ADD_TEST (suite, test_digest);
+       SUITE_ADD_TEST (suite, test_sign);
+       SUITE_ADD_TEST (suite, test_sign_recover);
+       SUITE_ADD_TEST (suite, test_verify);
+       SUITE_ADD_TEST (suite, test_verify_recover);
+       SUITE_ADD_TEST (suite, test_digest_encrypt);
+       SUITE_ADD_TEST (suite, test_decrypt_digest);
+       SUITE_ADD_TEST (suite, test_sign_encrypt);
+       SUITE_ADD_TEST (suite, test_decrypt_verify);
+       SUITE_ADD_TEST (suite, test_generate_key);
+       SUITE_ADD_TEST (suite, test_generate_key_pair);
+       SUITE_ADD_TEST (suite, test_wrap_key);
+       SUITE_ADD_TEST (suite, test_unwrap_key);
+       SUITE_ADD_TEST (suite, test_derive_key);
+       SUITE_ADD_TEST (suite, test_random);
+}
index 3a6e968acfa0e21b769ea21eadb9f3636ec08684..d6b4753ef3234e59a7cf5375e28d97dca9849682 100644 (file)
@@ -50,11 +50,8 @@ static CK_FUNCTION_LIST_PTR_PTR
 initialize_and_get_modules (CuTest *tc)
 {
        CK_FUNCTION_LIST_PTR_PTR modules;
-       CK_RV rv;
 
-       rv = p11_kit_initialize_registered ();
-       CuAssertIntEquals (tc, CKR_OK, rv);
-       modules = p11_kit_registered_modules ();
+       modules = p11_kit_modules_load_and_initialize (0);
        CuAssertTrue (tc, modules != NULL && modules[0] != NULL);
 
        return modules;
@@ -64,11 +61,7 @@ static void
 finalize_and_free_modules (CuTest *tc,
                            CK_FUNCTION_LIST_PTR_PTR modules)
 {
-       CK_RV rv;
-
-       free (modules);
-       rv = p11_kit_finalize_registered ();
-       CuAssertIntEquals (tc, CKR_OK, rv);
+       p11_kit_modules_finalize_and_release (modules);
 }
 
 static void
@@ -86,7 +79,7 @@ test_no_duplicates (CuTest *tc)
 
        /* The loaded modules should not contain duplicates */
        for (i = 0; modules[i] != NULL; i++) {
-               path = p11_kit_registered_option (modules[i], "module");
+               path = p11_kit_config_option (modules[i], "module");
 
                if (p11_dict_get (funcs, modules[i]))
                        CuAssert (tc, "found duplicate function list pointer", 0);
@@ -117,7 +110,7 @@ lookup_module_with_name (CuTest *tc,
        int i;
 
        for (i = 0; match == NULL && modules[i] != NULL; i++) {
-               module_name = p11_kit_registered_module_to_name (modules[i]);
+               module_name = p11_kit_module_get_name (modules[i]);
                CuAssertPtrNotNull (tc, module_name);
                if (strcmp (module_name, name) == 0)
                        match = modules[i];
@@ -128,8 +121,8 @@ lookup_module_with_name (CuTest *tc,
         * As a side effect, we should check that the results of this function
         * matches the above search.
         */
-       module = p11_kit_registered_name_to_module (name);
-       CuAssert(tc, "different result from p11_kit_registered_name_to_module()",
+       module = p11_kit_module_for_name (modules, name);
+       CuAssert(tc, "different result from p11_kit_module_for_name ()",
                 module == match);
 
        return match;
@@ -169,7 +162,6 @@ static void
 test_disable_later (CuTest *tc)
 {
        CK_FUNCTION_LIST_PTR_PTR modules;
-       CK_RV rv;
 
        /*
         * The module two shouldn't be matched, because in its config
@@ -178,12 +170,9 @@ test_disable_later (CuTest *tc)
         * disable-in: test-disable
         */
 
-       rv = p11_kit_initialize_registered ();
-       CuAssertIntEquals (tc, CKR_OK, rv);
-
        p11_kit_set_progname ("test-disable");
 
-       modules = p11_kit_registered_modules ();
+       modules = p11_kit_modules_load_and_initialize (0);
        CuAssertTrue (tc, modules != NULL && modules[0] != NULL);
 
        CuAssertTrue (tc, lookup_module_with_name (tc, modules, "two") == NULL);
@@ -246,7 +235,7 @@ test_priority (CuTest *tc)
 
        /* The loaded modules should not contain duplicates */
        for (i = 0; modules[i] != NULL; i++) {
-               name = p11_kit_registered_module_to_name (modules[i]);
+               name = p11_kit_module_get_name (modules[i]);
                CuAssertPtrNotNull (tc, name);
 
                /* Either one of these can be loaded, as this is a duplicate module */
@@ -263,6 +252,100 @@ test_priority (CuTest *tc)
        finalize_and_free_modules (tc, modules);
 }
 
+static void
+test_module_name (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR_PTR modules;
+       CK_FUNCTION_LIST_PTR module;
+       char *name;
+
+       /*
+        * The module three should not be present, as we don't match the current
+        * program.
+        */
+
+       modules = initialize_and_get_modules (tc);
+
+       module = p11_kit_module_for_name (modules, "one");
+       CuAssertPtrNotNull (tc, module);
+       name = p11_kit_module_get_name (module);
+       CuAssertStrEquals (tc, "one", name);
+       free (name);
+
+       module = p11_kit_module_for_name (modules, "invalid");
+       CuAssertPtrEquals (tc, NULL, module);
+
+       module = p11_kit_module_for_name (NULL, "one");
+       CuAssertPtrEquals (tc, NULL, module);
+
+       finalize_and_free_modules (tc, modules);
+}
+
+static void
+test_module_flags (CuTest *tc)
+{
+       CK_FUNCTION_LIST **modules;
+       CK_FUNCTION_LIST **unmanaged;
+       int flags;
+
+       /*
+        * The module three should not be present, as we don't match the current
+        * program.
+        */
+
+       modules = initialize_and_get_modules (tc);
+
+       flags = p11_kit_module_get_flags (modules[0]);
+       CuAssertIntEquals (tc, 0, flags);
+
+       unmanaged = p11_kit_modules_load (NULL, P11_KIT_MODULE_UNMANAGED);
+       CuAssertTrue (tc, unmanaged != NULL && unmanaged[0] != NULL);
+
+       flags = p11_kit_module_get_flags (unmanaged[0]);
+       CuAssertIntEquals (tc, P11_KIT_MODULE_UNMANAGED, flags);
+
+       finalize_and_free_modules (tc, modules);
+       p11_kit_modules_release (unmanaged);
+}
+
+static void
+test_config_option (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR_PTR modules;
+       CK_FUNCTION_LIST_PTR module;
+       char *value;
+
+       /*
+        * The module three should not be present, as we don't match the current
+        * program.
+        */
+
+       modules = initialize_and_get_modules (tc);
+
+       value = p11_kit_config_option (NULL, "new");
+       CuAssertStrEquals (tc, "world", value);
+       free (value);
+
+       module = p11_kit_module_for_name (modules, "one");
+       CuAssertPtrNotNull (tc, module);
+
+       value = p11_kit_config_option (module, "setting");
+       CuAssertStrEquals (tc, "user1", value);
+       free (value);
+
+       value = p11_kit_config_option (NULL, "invalid");
+       CuAssertPtrEquals (tc, NULL, value);
+
+       value = p11_kit_config_option (module, "invalid");
+       CuAssertPtrEquals (tc, NULL, value);
+
+       /* Invalid but non-NULL module pointer */
+       value = p11_kit_config_option (module + 1, "setting");
+       CuAssertPtrEquals (tc, NULL, value);
+
+       finalize_and_free_modules (tc, modules);
+}
+
 int
 main (void)
 {
@@ -278,6 +361,9 @@ main (void)
        SUITE_ADD_TEST (suite, test_disable_later);
        SUITE_ADD_TEST (suite, test_enable);
        SUITE_ADD_TEST (suite, test_priority);
+       SUITE_ADD_TEST (suite, test_module_name);
+       SUITE_ADD_TEST (suite, test_module_flags);
+       SUITE_ADD_TEST (suite, test_config_option);
 
        p11_kit_be_quiet ();
 
diff --git a/p11-kit/tests/test-proxy.c b/p11-kit/tests/test-proxy.c
new file mode 100644 (file)
index 0000000..99b2431
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2013 Red Hat Inc
+ *
+ * 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@redhat.com>
+ */
+
+#define CRYPTOKI_EXPORTS
+
+#include "config.h"
+#include "CuTest.h"
+
+#include "library.h"
+#include "pkcs11.h"
+#include "p11-kit.h"
+
+#include <sys/types.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+/* This is the proxy module entry point in proxy.c, and linked to this test */
+CK_RV C_GetFunctionList (CK_FUNCTION_LIST_PTR_PTR list);
+
+static void
+test_initialize_finalize (CuTest *tc)
+{
+       CK_FUNCTION_LIST_PTR proxy;
+       CK_RV rv;
+
+       rv = C_GetFunctionList (&proxy);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = proxy->C_Initialize (NULL);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = proxy->C_Finalize (NULL);
+       CuAssertTrue (tc, rv == CKR_OK);
+}
+
+int
+main (void)
+{
+       CuString *output = CuStringNew ();
+       CuSuite* suite = CuSuiteNew ();
+       int ret;
+
+       putenv ("P11_KIT_STRICT=1");
+       p11_library_init ();
+       p11_kit_be_quiet ();
+
+       SUITE_ADD_TEST (suite, test_initialize_finalize);
+
+       CuSuiteRun (suite);
+       CuSuiteSummary (suite, output);
+       CuSuiteDetails (suite, output);
+       printf ("%s\n", output->buffer);
+       ret = suite->failCount;
+       CuSuiteDelete (suite);
+       CuStringDelete (output);
+       return ret;
+}
index cd0f369d6bd4663341cd8b8effc1f6243724e45b..3d1fee715ac04bf05e43d85b5e31c39cbc5be398 100644 (file)
@@ -231,7 +231,7 @@ limit_modules_if_necessary (CK_FUNCTION_LIST_PTR *modules,
 
        /* TODO: This logic will move once we merge our p11-kit managed code */
        for (i = 0, out = 0; modules[i] != NULL; i++) {
-               string = p11_kit_registered_option (modules[i], "trust-policy");
+               string = p11_kit_config_option (modules[i], "trust-policy");
                if (string && strcmp (string, "yes") == 0)
                        modules[out++] = modules[i];
                else if (string && strcmp (string, "no") != 0)
@@ -305,7 +305,6 @@ p11_tool_extract (int argc,
        CK_ATTRIBUTE *match;
        P11KitUri *uri;
        int opt = 0;
-       CK_RV rv;
        int ret;
 
        enum {
@@ -435,13 +434,10 @@ p11_tool_extract (int argc,
        if (uri && p11_kit_uri_any_unrecognized (uri))
                p11_message ("uri contained unrecognized components, nothing will be extracted");
 
-       rv = p11_kit_initialize_registered ();
-       if (rv != CKR_OK) {
-               p11_message ("couldn't initialize registered modules: %s", p11_kit_strerror (rv));
+       modules = p11_kit_modules_load_and_initialize (0);
+       if (!modules)
                return 1;
-       }
 
-       modules = p11_kit_registered_modules ();
        limit_modules_if_necessary (modules, ex.flags);
 
        iter = p11_kit_iter_new (uri);
@@ -456,8 +452,9 @@ p11_tool_extract (int argc,
        p11_extract_info_cleanup (&ex);
        p11_kit_iter_free (iter);
        p11_kit_uri_free (uri);
-       free (modules);
 
-       p11_kit_finalize_registered ();
+       p11_kit_modules_finalize (modules);
+       p11_kit_modules_release (modules);
+
        return ret;
 }
index da99940db5541bead4965a3edb6cd8c225242ff6..fe028ae57b13886ea0c9b42e1497633e48816777 100644 (file)
@@ -203,20 +203,15 @@ print_modules (void)
        CK_FUNCTION_LIST_PTR *module_list;
        char *name;
        char *path;
-       CK_RV rv;
        int i;
 
-       rv = p11_kit_initialize_registered ();
-       if (rv != CKR_OK) {
-               p11_message ("couldn't initialize registered modules: %s",
-                            p11_kit_strerror (rv));
+       module_list = p11_kit_modules_load_and_initialize (0);
+       if (!module_list)
                return 1;
-       }
 
-       module_list = p11_kit_registered_modules ();
        for (i = 0; module_list[i]; i++) {
-               name = p11_kit_registered_module_to_name (module_list[i]);
-               path = p11_kit_registered_option (module_list[i], "module");
+               name = p11_kit_module_get_name (module_list[i]);
+               path = p11_kit_config_option (module_list[i], "module");
 
                printf ("%s: %s\n",
                        name ? name : "(null)",
@@ -226,9 +221,8 @@ print_modules (void)
                free (name);
                free (path);
        }
-       free (module_list);
 
-       p11_kit_finalize_registered ();
+       p11_kit_modules_finalize_and_release (module_list);
        return 0;
 }
 
index 74e3c9c730ca7f0543e890db048b7b374e5550ae..a3db8d8e64ceab16b587d9ab51ea6eba5b535218 100644 (file)
@@ -32,6 +32,8 @@
  * Author: Stef Walter <stefw@collabora.co.uk>
  */
 
+#define P11_KIT_DISABLE_DEPRECATED
+
 #include "config.h"
 #include "CuTest.h"
 
@@ -145,9 +147,10 @@ setup (CuTest *tc)
 {
        CK_RV rv;
 
+       mock_module_reset ();
        memcpy (&test.module, &mock_module, sizeof (CK_FUNCTION_LIST));
 
-       rv = p11_kit_initialize_module (&test.module);
+       rv = test.module.C_Initialize (NULL);
        CuAssertIntEquals (tc, CKR_OK, rv);
 
        test.iter = p11_kit_iter_new (NULL);
@@ -164,7 +167,7 @@ teardown (CuTest *tc)
 
        p11_kit_iter_free (test.iter);
 
-       rv = p11_kit_finalize_module (&test.module);
+       rv = test.module.C_Finalize (NULL);
        CuAssertIntEquals (tc, CKR_OK, rv);
 }
 
index 215e0da3add2457da4cb9e268bdcae7e82469481..c778aa72196f011a3beef45e2bbe729f144ed4fa 100644 (file)
@@ -32,6 +32,8 @@
  * Author: Stef Walter <stefw@collabora.co.uk>
  */
 
+#define P11_KIT_DISABLE_DEPRECATED
+
 #include "config.h"
 #include "CuTest.h"
 
@@ -69,12 +71,11 @@ setup (CuTest *tc)
 {
        CK_RV rv;
 
+       mock_module_reset ();
        memcpy (&test.module, &mock_module, sizeof (CK_FUNCTION_LIST));
-       rv = p11_kit_initialize_module (&test.module);
+       rv = test.module.C_Initialize (NULL);
        CuAssertIntEquals (tc, CKR_OK, rv);
 
-       mock_module_reset_objects (MOCK_SLOT_ONE_ID);
-
        test.iter = p11_kit_iter_new (NULL);
 
        p11_extract_info_init (&test.ex);
@@ -96,7 +97,7 @@ teardown (CuTest *tc)
        p11_extract_info_cleanup (&test.ex);
        p11_kit_iter_free (test.iter);
 
-       rv = p11_kit_finalize_module (&test.module);
+       rv = test.module.C_Finalize (NULL);
        CuAssertIntEquals (tc, CKR_OK, rv);
 }
 
index dc1cb081b1884b41f3525cbd790f31ae31f8567a..4024bac3bdfdc7de78801969aa97dfa1c6811226 100644 (file)
@@ -32,6 +32,8 @@
  * Author: Stef Walter <stefw@collabora.co.uk>
  */
 
+#define P11_KIT_DISABLE_DEPRECATED
+
 #include "config.h"
 #include "CuTest.h"
 
@@ -66,12 +68,11 @@ setup (CuTest *tc)
 {
        CK_RV rv;
 
+       mock_module_reset ();
        memcpy (&test.module, &mock_module, sizeof (CK_FUNCTION_LIST));
-       rv = p11_kit_initialize_module (&test.module);
+       rv = test.module.C_Initialize (NULL);
        CuAssertIntEquals (tc, CKR_OK, rv);
 
-       mock_module_reset_objects (MOCK_SLOT_ONE_ID);
-
        test.iter = p11_kit_iter_new (NULL);
 
        p11_extract_info_init (&test.ex);
@@ -93,7 +94,7 @@ teardown (CuTest *tc)
        p11_extract_info_cleanup (&test.ex);
        p11_kit_iter_free (test.iter);
 
-       rv = p11_kit_finalize_module (&test.module);
+       rv = test.module.C_Finalize (NULL);
        CuAssertIntEquals (tc, CKR_OK, rv);
 }
 
index e952e532782fd6be338116ae0e27b1b1a2eb4642..5093743216c388d756cf520959858be29c2a9d71 100644 (file)
@@ -32,6 +32,8 @@
  * Author: Stef Walter <stefw@collabora.co.uk>
  */
 
+#define P11_KIT_DISABLE_DEPRECATED
+
 #include "config.h"
 #include "CuTest.h"
 
@@ -66,12 +68,11 @@ setup (CuTest *tc)
 {
        CK_RV rv;
 
+       mock_module_reset ();
        memcpy (&test.module, &mock_module, sizeof (CK_FUNCTION_LIST));
-       rv = p11_kit_initialize_module (&test.module);
+       rv = test.module.C_Initialize (NULL);
        CuAssertIntEquals (tc, CKR_OK, rv);
 
-       mock_module_reset_objects (MOCK_SLOT_ONE_ID);
-
        test.iter = p11_kit_iter_new (NULL);
 
        p11_extract_info_init (&test.ex);
@@ -93,7 +94,7 @@ teardown (CuTest *tc)
        p11_extract_info_cleanup (&test.ex);
        p11_kit_iter_free (test.iter);
 
-       rv = p11_kit_finalize_module (&test.module);
+       rv = test.module.C_Finalize (NULL);
        CuAssertIntEquals (tc, CKR_OK, rv);
 }
 
index da7679514cc149a0dce22addbf09a56af47745ac..a81b5e2730df8e365d47b1937894900eb6720b96 100644 (file)
@@ -102,7 +102,10 @@ dump_trust_module (const char *path)
 
        CK_ULONG count = p11_attrs_count (template);
 
-       rv = p11_kit_load_initialize_module (path, &module);
+       module = p11_kit_module_load (path, 0);
+       return_val_if_fail (module != NULL, 1);
+
+       rv = p11_kit_module_initialize (module);
        return_val_if_fail (rv == CKR_OK, 1);
 
        iter = p11_kit_iter_new (NULL);
@@ -120,7 +123,8 @@ dump_trust_module (const char *path)
 
        return_val_if_fail (rv == CKR_CANCEL, 1);
 
-       p11_kit_finalize_module (module);
+       p11_kit_module_finalize (module);
+       p11_kit_module_release (module);
 
        return 0;
 }
@@ -152,10 +156,16 @@ compare_trust_modules (const char *path1,
                { CKA_INVALID, }
        };
 
-       rv = p11_kit_load_initialize_module (path1, &module1);
+       module1 = p11_kit_module_load (path1, 0);
+       return_val_if_fail (module1 != NULL, 1);
+
+       rv = p11_kit_module_initialize (module1);
        return_val_if_fail (rv == CKR_OK, 1);
 
-       rv = p11_kit_load_initialize_module (path2, &module2);
+       module2 = p11_kit_module_load (path2, 0);
+       return_val_if_fail (module2 != NULL, 1);
+
+       rv = p11_kit_module_initialize (module2);
        return_val_if_fail (rv == CKR_OK, 1);
 
        iter = p11_kit_iter_new (NULL);
@@ -185,8 +195,11 @@ compare_trust_modules (const char *path1,
        }
 
        return_val_if_fail (rv == CKR_CANCEL, 1);
-       p11_kit_finalize_module (module1);
-       p11_kit_finalize_module (module2);
+       p11_kit_module_finalize (module1);
+       p11_kit_module_release (module1);
+
+       p11_kit_module_finalize (module2);
+       p11_kit_module_release (module2);
 
        return 0;
 }