]> granicus.if.org Git - p11-kit/commitdiff
build: Make libffi closure optional
authorDaiki Ueno <dueno@redhat.com>
Fri, 26 Aug 2016 15:20:06 +0000 (17:20 +0200)
committerDaiki Ueno <ueno@gnu.org>
Tue, 24 Jan 2017 11:36:06 +0000 (12:36 +0100)
libffi's closure support is not available on all platforms and may fail
at run time if running under a stricter SELinux policy.  Fallback to
pre-compiled closures if it is not usable.

https://bugs.freedesktop.org/show_bug.cgi?id=97611

configure.ac
doc/manual/Makefile.am
p11-kit/Makefile.am
p11-kit/modules.c
p11-kit/proxy.c
p11-kit/test-init.c
p11-kit/test-virtual.c
p11-kit/util.c
p11-kit/virtual-fixed.h [new file with mode: 0644]
p11-kit/virtual.c
p11-kit/virtual.h

index b6ac61c80c1a1e01f960daae8c4ead28970f811b..84cb7ef1169594736f02fe8250ea5d691fc1644c 100644 (file)
@@ -193,17 +193,6 @@ if test "$with_libffi" != "no"; then
        AC_SUBST(LIBFFI_CFLAGS)
        AC_SUBST(LIBFFI_LIBS)
 
-       SAVE_CFLAGS="$CFLAGS"
-       CFLAGS="$CFLAGS $LIBFFI_CFLAGS"
-       AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <ffi.h>],
-                         [ #if FFI_CLOSURES
-                           #else
-                           #error no closures
-                           #endif
-                         ])],
-       [], [AC_MSG_ERROR([the libffi on this system has no support for closures.])])
-       CFLAGS="$SAVE_CFLAGS"
-
        with_libffi="yes"
 fi
 
index c161b1945363484688e6a77d0db548d4da5194c8..ae59530f2b0803aba27c49db9220d1446ef5f0a2 100644 (file)
@@ -64,6 +64,7 @@ IGNORE_HFILES= \
        rpc-message.h \
        util.h \
        virtual.h \
+       virtual-fixed.h \
        array.h \
        compat.h \
        $(NULL)
index 507be5f04348bfc6a4ffa81d286066a3e5f4ab0a..c55746a16857087cd080a6c431247166b0039048 100644 (file)
@@ -25,6 +25,7 @@ MODULE_SRCS = \
        p11-kit/rpc-client.c p11-kit/rpc-server.c \
        p11-kit/uri.c \
        p11-kit/virtual.c p11-kit/virtual.h \
+       p11-kit/virtual-fixed.h \
        $(inc_HEADERS)
 
 lib_LTLIBRARIES += \
@@ -212,8 +213,6 @@ print_messages_LDADD = $(p11_kit_LIBS)
 frob_setuid_SOURCES = p11-kit/frob-setuid.c
 frob_setuid_LDADD = $(p11_kit_LIBS)
 
-if WITH_FFI
-
 CHECK_PROGS += \
        test-virtual \
        test-managed \
@@ -233,8 +232,6 @@ test_transport_LDADD = $(p11_kit_LIBS)
 test_virtual_SOURCES = p11-kit/test-virtual.c
 test_virtual_LDADD = $(p11_kit_LIBS)
 
-endif
-
 noinst_LTLIBRARIES += \
        mock-one.la \
        mock-two.la \
index 5cdc8b239dbf4bee50ea2d75d65cb7e3b06389c2..85eb53eed5a4acb9ac1e1190f589049231e78691 100644 (file)
@@ -1758,22 +1758,11 @@ lookup_managed_option (Module *mod,
        value = _p11_conf_parse_boolean (string, def_value);
 
        if (!supported && value != supported) {
-               if (!p11_virtual_can_wrap ()) {
-                       /*
-                        * 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);
-               } else {
-                       /*
-                        * This is because the module is running in unmanaged mode, so turn off the
-                        */
-                       p11_message ("the '%s' option for module '%s' is only supported for managed modules",
-                                    option, mod->name);
-               }
-               return false;
+         /*
+          * This is because the module is running in unmanaged mode, so turn off the
+          */
+         p11_message ("the '%s' option for module '%s' is only supported for managed modules",
+                      option, mod->name);
        }
 
        return value;
@@ -1855,7 +1844,7 @@ prepare_module_inlock_reentrant (Module *mod,
                is_managed = false;
                with_log = false;
        } else {
-               is_managed = lookup_managed_option (mod, p11_virtual_can_wrap (), "managed", true);
+               is_managed = lookup_managed_option (mod, true, "managed", true);
                with_log = lookup_managed_option (mod, is_managed, "log-calls", false);
        }
 
@@ -1871,7 +1860,8 @@ prepare_module_inlock_reentrant (Module *mod,
                }
 
                *module = p11_virtual_wrap (virt, destroyer);
-               return_val_if_fail (*module != NULL, CKR_GENERAL_ERROR);
+               if (*module == NULL)
+                       return CKR_GENERAL_ERROR;
 
                if (!p11_dict_set (gl.managed_by_closure, *module, mod))
                        return_val_if_reached (CKR_HOST_MEMORY);
index ad3caa554f8a4a63722ff020b24787d8761f3696..6f91fa446f29772bdd9af0d28f1a247a213e12d8 100644 (file)
@@ -2365,7 +2365,7 @@ C_GetFunctionList (CK_FUNCTION_LIST_PTR_PTR list)
                }
        }
 
-       if (rv == CKR_OK && p11_virtual_can_wrap ()) {
+       if (rv == CKR_OK) {
                state = calloc (1, sizeof (State));
                if (!state) {
                        rv = CKR_HOST_MEMORY;
index c4fcecb875f5e254cf2f91615919bdb05795c5f5..18eb025d6e02b13de3f09ed92d59d541e7c2cf1a 100644 (file)
@@ -402,16 +402,14 @@ main (int argc,
        p11_library_init ();
 
        /* These only work when managed */
-       if (p11_virtual_can_wrap ()) {
-               p11_test (test_recursive_initialization, "/init/test_recursive_initialization");
-               p11_test (test_threaded_initialization, "/init/test_threaded_initialization");
-               p11_test (test_mutexes, "/init/test_mutexes");
-               p11_test (test_load_and_initialize, "/init/test_load_and_initialize");
+       p11_test (test_recursive_initialization, "/init/test_recursive_initialization");
+       p11_test (test_threaded_initialization, "/init/test_threaded_initialization");
+       p11_test (test_mutexes, "/init/test_mutexes");
+       p11_test (test_load_and_initialize, "/init/test_load_and_initialize");
 
 #ifdef OS_UNIX
-               p11_test (test_fork_initialization, "/init/test_fork_initialization");
+       p11_test (test_fork_initialization, "/init/test_fork_initialization");
 #endif
-       }
 
        p11_test (test_initalize_fail, "/init/test_initalize_fail");
        p11_test (test_finalize_fail, "/init/test_finalize_fail");
index e6428202e94d355d0e653dcde5195506eda0b499..fd9eba95c54596fa50093cb005d6c5ed9bbc8201 100644 (file)
@@ -162,7 +162,6 @@ main (int argc,
        mock_module_init ();
        p11_library_init ();
 
-       assert (p11_virtual_can_wrap ());
        p11_test (test_initialize, "/virtual/test_initialize");
        p11_test (test_fall_through, "/virtual/test_fall_through");
        p11_test (test_get_function_list, "/virtual/test_get_function_list");
index 325d66904c3576c84a4b6e179015c1edb5d82a6d..816952f4d226a6254103e834fe211f62485a439a 100644 (file)
@@ -45,6 +45,7 @@
 #include "p11-kit.h"
 #include "private.h"
 #include "proxy.h"
+#include "virtual.h"
 
 #include <assert.h>
 #include <stdarg.h>
@@ -251,6 +252,7 @@ void
 _p11_kit_init (void)
 {
        p11_library_init_once ();
+       p11_virtual_init_fixed ();
 }
 
 #ifdef __GNUC__
@@ -260,6 +262,7 @@ void
 _p11_kit_fini (void)
 {
        p11_proxy_module_cleanup ();
+       p11_virtual_uninit_fixed ();
        p11_library_uninit ();
 }
 
@@ -277,12 +280,14 @@ DllMain (HINSTANCE instance,
        switch (reason) {
        case DLL_PROCESS_ATTACH:
                p11_library_init ();
+               p11_virtual_init_fixed ();
                break;
        case DLL_THREAD_DETACH:
                p11_library_thread_cleanup ();
                break;
        case DLL_PROCESS_DETACH:
                p11_proxy_module_cleanup ();
+               p11_virtual_uninit_fixed ();
                p11_library_uninit ();
                break;
        default:
diff --git a/p11-kit/virtual-fixed.h b/p11-kit/virtual-fixed.h
new file mode 100644 (file)
index 0000000..1cb685d
--- /dev/null
@@ -0,0 +1,1135 @@
+/*
+ * Copyright (c) 2016 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: Daiki Ueno
+ */
+
+#define P11_VIRTUAL_MAX_FIXED 64
+
+#define P11_VIRTUAL_FIXED_FUNCTIONS(fixed_index)       \
+static CK_RV \
+fixed ## fixed_index ## _C_Initialize (CK_VOID_PTR init_args) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_Initialize (funcs, init_args); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_Finalize (CK_VOID_PTR reserved) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_Finalize (funcs, reserved); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_GetInfo (CK_INFO_PTR info) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_GetInfo (funcs, info); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_GetSlotList (CK_BBOOL token_present, \
+                                       CK_SLOT_ID_PTR slot_list, \
+                                       CK_ULONG_PTR count) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_GetSlotList (funcs, token_present, slot_list, count); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_GetSlotInfo (CK_SLOT_ID slot_id, \
+                                       CK_SLOT_INFO_PTR info) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_GetSlotInfo (funcs, slot_id, info); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_GetTokenInfo (CK_SLOT_ID slot_id, \
+                                        CK_TOKEN_INFO_PTR info) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_GetTokenInfo (funcs, slot_id, info); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_GetMechanismList (CK_SLOT_ID slot_id, \
+                                            CK_MECHANISM_TYPE_PTR mechanism_list, \
+                                            CK_ULONG_PTR count) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_GetMechanismList (funcs, slot_id, mechanism_list, count); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_GetMechanismInfo (CK_SLOT_ID slot_id, \
+                                            CK_MECHANISM_TYPE type, \
+                                            CK_MECHANISM_INFO_PTR info) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_GetMechanismInfo (funcs, slot_id, type, info); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_InitToken (CK_SLOT_ID slot_id, \
+                                     CK_BYTE_PTR pin, \
+                                     CK_ULONG pin_len, \
+                                     CK_BYTE_PTR label) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_InitToken (funcs, slot_id, pin, pin_len, label); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_InitPIN (CK_SESSION_HANDLE session, \
+                                   CK_BYTE_PTR pin, \
+                                   CK_ULONG pin_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_InitPIN (funcs, session, pin, pin_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_SetPIN (CK_SESSION_HANDLE session, \
+                                  CK_BYTE_PTR old_pin, \
+                                  CK_ULONG old_len, \
+                                  CK_BYTE_PTR new_pin, \
+                                  CK_ULONG new_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_SetPIN (funcs, session, old_pin, old_len, new_pin, new_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_OpenSession (CK_SLOT_ID slot_id, \
+                                       CK_FLAGS flags, \
+                                       CK_VOID_PTR application, \
+                                       CK_NOTIFY notify, \
+                                       CK_SESSION_HANDLE_PTR session) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_OpenSession (funcs, slot_id, flags, application, notify, session); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_CloseSession (CK_SESSION_HANDLE session) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_CloseSession (funcs, session); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_CloseAllSessions (CK_SLOT_ID slot_id) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_CloseAllSessions (funcs, slot_id); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_GetSessionInfo (CK_SESSION_HANDLE session, \
+                                          CK_SESSION_INFO_PTR info) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_GetSessionInfo (funcs, session, info); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_GetOperationState (CK_SESSION_HANDLE session, \
+                                             CK_BYTE_PTR operation_state, \
+                                             CK_ULONG_PTR operation_state_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_GetOperationState (funcs, session, operation_state, operation_state_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_SetOperationState (CK_SESSION_HANDLE session, \
+                                             CK_BYTE_PTR operation_state, \
+                                             CK_ULONG operation_state_len, \
+                                             CK_OBJECT_HANDLE encryption_key, \
+                                             CK_OBJECT_HANDLE authentiation_key) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_SetOperationState (funcs, session, operation_state, operation_state_len, encryption_key, authentiation_key); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_Login (CK_SESSION_HANDLE session, \
+                                 CK_USER_TYPE user_type, \
+                                 CK_BYTE_PTR pin, \
+                                 CK_ULONG pin_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_Login (funcs, session, user_type, pin, pin_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_Logout (CK_SESSION_HANDLE session) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_Logout (funcs, session); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_CreateObject (CK_SESSION_HANDLE session, \
+                                        CK_ATTRIBUTE_PTR templ, \
+                                        CK_ULONG count, \
+                                        CK_OBJECT_HANDLE_PTR object) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_CreateObject (funcs, session, templ, count, object); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_CopyObject (CK_SESSION_HANDLE session, \
+                                      CK_OBJECT_HANDLE object, \
+                                      CK_ATTRIBUTE_PTR templ, \
+                                      CK_ULONG count, \
+                                      CK_OBJECT_HANDLE_PTR new_object) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_CopyObject (funcs, session, object, templ, count, new_object); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_DestroyObject (CK_SESSION_HANDLE session, \
+                                         CK_OBJECT_HANDLE object) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_DestroyObject (funcs, session, object); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_GetObjectSize (CK_SESSION_HANDLE session, \
+                                         CK_OBJECT_HANDLE object, \
+                                         CK_ULONG_PTR size) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_GetObjectSize (funcs, session, object, size); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_GetAttributeValue (CK_SESSION_HANDLE session, \
+                                             CK_OBJECT_HANDLE object, \
+                                             CK_ATTRIBUTE_PTR templ, \
+                                             CK_ULONG count) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_GetAttributeValue (funcs, session, object, templ, count); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_SetAttributeValue (CK_SESSION_HANDLE session, \
+                                             CK_OBJECT_HANDLE object, \
+                                             CK_ATTRIBUTE_PTR templ, \
+                                             CK_ULONG count) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_SetAttributeValue (funcs, session, object, templ, count); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_FindObjectsInit (CK_SESSION_HANDLE session, \
+                                           CK_ATTRIBUTE_PTR templ, \
+                                           CK_ULONG count) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_FindObjectsInit (funcs, session, templ, count); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_FindObjects (CK_SESSION_HANDLE session, \
+                                       CK_OBJECT_HANDLE_PTR object, \
+                                       CK_ULONG max_object_count, \
+                                       CK_ULONG_PTR object_count) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_FindObjects (funcs, session, object, max_object_count, object_count); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_FindObjectsFinal (CK_SESSION_HANDLE session) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_FindObjectsFinal (funcs, session); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_EncryptInit (CK_SESSION_HANDLE session, \
+                                       CK_MECHANISM_PTR mechanism, \
+                                       CK_OBJECT_HANDLE key) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_EncryptInit (funcs, session, mechanism, key); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_Encrypt (CK_SESSION_HANDLE session, \
+                                   CK_BYTE_PTR data, \
+                                   CK_ULONG data_len, \
+                                   CK_BYTE_PTR encrypted_data, \
+                                   CK_ULONG_PTR encrypted_data_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_Encrypt (funcs, session, data, data_len, encrypted_data, encrypted_data_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_EncryptUpdate (CK_SESSION_HANDLE session, \
+                                         CK_BYTE_PTR part, \
+                                         CK_ULONG part_len, \
+                                         CK_BYTE_PTR encrypted_part, \
+                                         CK_ULONG_PTR encrypted_part_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_EncryptUpdate (funcs, session, part, part_len, encrypted_part, encrypted_part_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_EncryptFinal (CK_SESSION_HANDLE session, \
+                                        CK_BYTE_PTR last_encrypted_part, \
+                                        CK_ULONG_PTR last_encrypted_part_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_EncryptFinal (funcs, session, last_encrypted_part, last_encrypted_part_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_DecryptInit (CK_SESSION_HANDLE session, \
+                                       CK_MECHANISM_PTR mechanism, \
+                                       CK_OBJECT_HANDLE key) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_DecryptInit (funcs, session, mechanism, key); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_Decrypt (CK_SESSION_HANDLE session, \
+                                   CK_BYTE_PTR encrypted_data, \
+                                   CK_ULONG encrypted_data_len, \
+                                   CK_BYTE_PTR data, \
+                                   CK_ULONG_PTR data_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_Decrypt (funcs, session, encrypted_data, encrypted_data_len, data, data_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_DecryptUpdate (CK_SESSION_HANDLE session, \
+                                         CK_BYTE_PTR encrypted_part, \
+                                         CK_ULONG encrypted_part_len, \
+                                         CK_BYTE_PTR part, \
+                                         CK_ULONG_PTR part_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_DecryptUpdate (funcs, session, encrypted_part, encrypted_part_len, part, part_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_DecryptFinal (CK_SESSION_HANDLE session, \
+                                        CK_BYTE_PTR last_part, \
+                                        CK_ULONG_PTR last_part_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_DecryptFinal (funcs, session, last_part, last_part_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_DigestInit (CK_SESSION_HANDLE session, \
+                                      CK_MECHANISM_PTR mechanism) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_DigestInit (funcs, session, mechanism); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_Digest (CK_SESSION_HANDLE session, \
+                                  CK_BYTE_PTR data, \
+                                  CK_ULONG data_len, \
+                                  CK_BYTE_PTR digest, \
+                                  CK_ULONG_PTR digest_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_Digest (funcs, session, data, data_len, digest, digest_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_DigestUpdate (CK_SESSION_HANDLE session, \
+                                        CK_BYTE_PTR part, \
+                                        CK_ULONG part_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_DigestUpdate (funcs, session, part, part_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_DigestKey (CK_SESSION_HANDLE session, \
+                                     CK_OBJECT_HANDLE key) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_DigestKey (funcs, session, key); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_DigestFinal (CK_SESSION_HANDLE session, \
+                                       CK_BYTE_PTR digest, \
+                                       CK_ULONG_PTR digest_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_DigestFinal (funcs, session, digest, digest_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_SignInit (CK_SESSION_HANDLE session, \
+                                    CK_MECHANISM_PTR mechanism, \
+                                    CK_OBJECT_HANDLE key) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_SignInit (funcs, session, mechanism, key); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_Sign (CK_SESSION_HANDLE session, \
+                                CK_BYTE_PTR data, \
+                                CK_ULONG data_len, \
+                                CK_BYTE_PTR signature, \
+                                CK_ULONG_PTR signature_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_Sign (funcs, session, data, data_len, signature, signature_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_SignUpdate (CK_SESSION_HANDLE session, \
+                                      CK_BYTE_PTR part, \
+                                      CK_ULONG part_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_SignUpdate (funcs, session, part, part_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_SignFinal (CK_SESSION_HANDLE session, \
+                                     CK_BYTE_PTR signature, \
+                                     CK_ULONG_PTR signature_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_SignFinal (funcs, session, signature, signature_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_SignRecoverInit (CK_SESSION_HANDLE session, \
+                                           CK_MECHANISM_PTR mechanism, \
+                                           CK_OBJECT_HANDLE key) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_SignRecoverInit (funcs, session, mechanism, key); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_SignRecover (CK_SESSION_HANDLE session, \
+                                       CK_BYTE_PTR data, \
+                                       CK_ULONG data_len, \
+                                       CK_BYTE_PTR signature, \
+                                       CK_ULONG_PTR signature_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_SignRecover (funcs, session, data, data_len, signature, signature_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_VerifyInit (CK_SESSION_HANDLE session, \
+                                      CK_MECHANISM_PTR mechanism, \
+                                      CK_OBJECT_HANDLE key) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_VerifyInit (funcs, session, mechanism, key); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_Verify (CK_SESSION_HANDLE session, \
+                                  CK_BYTE_PTR data, \
+                                  CK_ULONG data_len, \
+                                  CK_BYTE_PTR signature, \
+                                  CK_ULONG signature_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_Verify (funcs, session, data, data_len, signature, signature_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_VerifyUpdate (CK_SESSION_HANDLE session, \
+                                        CK_BYTE_PTR part, \
+                                        CK_ULONG part_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_VerifyUpdate (funcs, session, part, part_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_VerifyFinal (CK_SESSION_HANDLE session, \
+                                       CK_BYTE_PTR signature, \
+                                       CK_ULONG signature_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_VerifyFinal (funcs, session, signature, signature_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_VerifyRecoverInit (CK_SESSION_HANDLE session, \
+                                             CK_MECHANISM_PTR mechanism, \
+                                             CK_OBJECT_HANDLE key) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_VerifyRecoverInit (funcs, session, mechanism, key); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_VerifyRecover (CK_SESSION_HANDLE session, \
+                                         CK_BYTE_PTR signature, \
+                                         CK_ULONG signature_len, \
+                                         CK_BYTE_PTR data, \
+                                         CK_ULONG_PTR data_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_VerifyRecover (funcs, session, signature, signature_len, data, data_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_DigestEncryptUpdate (CK_SESSION_HANDLE session, \
+                                               CK_BYTE_PTR part, \
+                                               CK_ULONG part_len, \
+                                               CK_BYTE_PTR encrypted_part, \
+                                               CK_ULONG_PTR encrypted_part_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_DigestEncryptUpdate (funcs, session, part, part_len, encrypted_part, encrypted_part_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_DecryptDigestUpdate (CK_SESSION_HANDLE session, \
+                                               CK_BYTE_PTR encrypted_part, \
+                                               CK_ULONG encrypted_part_len, \
+                                               CK_BYTE_PTR part, \
+                                               CK_ULONG_PTR part_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_DecryptDigestUpdate (funcs, session, encrypted_part, encrypted_part_len, part, part_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_SignEncryptUpdate (CK_SESSION_HANDLE session, \
+                                             CK_BYTE_PTR part, \
+                                             CK_ULONG part_len, \
+                                             CK_BYTE_PTR encrypted_part, \
+                                             CK_ULONG_PTR encrypted_part_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_SignEncryptUpdate (funcs, session, part, part_len, encrypted_part, encrypted_part_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_DecryptVerifyUpdate (CK_SESSION_HANDLE session, \
+                                               CK_BYTE_PTR encrypted_part, \
+                                               CK_ULONG encrypted_part_len, \
+                                               CK_BYTE_PTR part, \
+                                               CK_ULONG_PTR part_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_DecryptVerifyUpdate (funcs, session, encrypted_part, encrypted_part_len, part, part_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_GenerateKey (CK_SESSION_HANDLE session, \
+                                       CK_MECHANISM_PTR mechanism, \
+                                       CK_ATTRIBUTE_PTR templ, \
+                                       CK_ULONG count, \
+                                       CK_OBJECT_HANDLE_PTR key) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_GenerateKey (funcs, session, mechanism, templ, count, key); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_GenerateKeyPair (CK_SESSION_HANDLE session, \
+                                           CK_MECHANISM_PTR mechanism, \
+                                           CK_ATTRIBUTE_PTR public_key_template, \
+                                           CK_ULONG public_key_attribute_count, \
+                                           CK_ATTRIBUTE_PTR private_key_template, \
+                                           CK_ULONG private_key_attribute_count, \
+                                           CK_OBJECT_HANDLE_PTR public_key, \
+                                           CK_OBJECT_HANDLE_PTR private_key) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_GenerateKeyPair (funcs, session, mechanism, public_key_template, public_key_attribute_count, private_key_template, private_key_attribute_count, public_key, private_key); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_WrapKey (CK_SESSION_HANDLE session, \
+                                   CK_MECHANISM_PTR mechanism, \
+                                   CK_OBJECT_HANDLE wrapping_key, \
+                                   CK_OBJECT_HANDLE key, \
+                                   CK_BYTE_PTR wrapped_key, \
+                                   CK_ULONG_PTR wrapped_key_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_WrapKey (funcs, session, mechanism, wrapping_key, key, wrapped_key, wrapped_key_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_UnwrapKey (CK_SESSION_HANDLE session, \
+                                     CK_MECHANISM_PTR mechanism, \
+                                     CK_OBJECT_HANDLE unwrapping_key, \
+                                     CK_BYTE_PTR wrapped_key, \
+                                     CK_ULONG wrapped_key_len, \
+                                     CK_ATTRIBUTE_PTR templ, \
+                                     CK_ULONG attribute_count, \
+                                     CK_OBJECT_HANDLE_PTR key) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_UnwrapKey (funcs, session, mechanism, unwrapping_key, wrapped_key, wrapped_key_len, templ, attribute_count, key); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_DeriveKey (CK_SESSION_HANDLE session, \
+                                     CK_MECHANISM_PTR mechanism, \
+                                     CK_OBJECT_HANDLE base_key, \
+                                     CK_ATTRIBUTE_PTR templ, \
+                                     CK_ULONG attribute_count, \
+                                     CK_OBJECT_HANDLE_PTR key) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_DeriveKey (funcs, session, mechanism, base_key, templ, attribute_count, key); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_SeedRandom (CK_SESSION_HANDLE session, \
+                                      CK_BYTE_PTR seed, \
+                                      CK_ULONG seed_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_SeedRandom (funcs, session, seed, seed_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_GenerateRandom (CK_SESSION_HANDLE session, \
+                                          CK_BYTE_PTR random_data, \
+                                          CK_ULONG random_len) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_GenerateRandom (funcs, session, random_data, random_len); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_WaitForSlotEvent (CK_FLAGS flags, \
+                                            CK_SLOT_ID_PTR slot, \
+                                            CK_VOID_PTR reserved) \
+{ \
+        CK_FUNCTION_LIST *bound; \
+        Wrapper *wrapper; \
+        CK_X_FUNCTION_LIST *funcs; \
+        bound = fixed_closures[fixed_index]; \
+        return_val_if_fail (bound != NULL, CKR_GENERAL_ERROR); \
+        wrapper = (Wrapper *) bound; \
+        funcs = &wrapper->virt->funcs; \
+        return funcs->C_WaitForSlotEvent (funcs, flags, slot, reserved); \
+} \
+\
+static CK_RV \
+fixed ## fixed_index ## _C_GetFunctionList (CK_FUNCTION_LIST_PTR_PTR list);
+
+#define P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(fixed_index) \
+static CK_RV \
+fixed ## fixed_index ## _C_GetFunctionList (CK_FUNCTION_LIST_PTR_PTR list) \
+{ \
+        if (!list) \
+                return CKR_ARGUMENTS_BAD; \
+        *list = fixed_closures[fixed_index]; \
+        return CKR_OK; \
+}
+
+#define P11_VIRTUAL_FIXED_INITIALIZER(fixed_index) \
+{ \
+        { CRYPTOKI_VERSION_MAJOR, CRYPTOKI_VERSION_MINOR },  /* version */ \
+       fixed ## fixed_index ## _C_Initialize, \
+       fixed ## fixed_index ## _C_Finalize, \
+       fixed ## fixed_index ## _C_GetInfo, \
+       fixed ## fixed_index ## _C_GetFunctionList, \
+       fixed ## fixed_index ## _C_GetSlotList, \
+       fixed ## fixed_index ## _C_GetSlotInfo, \
+       fixed ## fixed_index ## _C_GetTokenInfo, \
+       fixed ## fixed_index ## _C_GetMechanismList, \
+       fixed ## fixed_index ## _C_GetMechanismInfo, \
+       fixed ## fixed_index ## _C_InitToken, \
+       fixed ## fixed_index ## _C_InitPIN, \
+       fixed ## fixed_index ## _C_SetPIN, \
+       fixed ## fixed_index ## _C_OpenSession, \
+       fixed ## fixed_index ## _C_CloseSession, \
+       fixed ## fixed_index ## _C_CloseAllSessions, \
+       fixed ## fixed_index ## _C_GetSessionInfo, \
+       fixed ## fixed_index ## _C_GetOperationState, \
+       fixed ## fixed_index ## _C_SetOperationState, \
+       fixed ## fixed_index ## _C_Login, \
+       fixed ## fixed_index ## _C_Logout, \
+       fixed ## fixed_index ## _C_CreateObject, \
+       fixed ## fixed_index ## _C_CopyObject, \
+       fixed ## fixed_index ## _C_DestroyObject, \
+       fixed ## fixed_index ## _C_GetObjectSize, \
+       fixed ## fixed_index ## _C_GetAttributeValue, \
+       fixed ## fixed_index ## _C_SetAttributeValue, \
+       fixed ## fixed_index ## _C_FindObjectsInit, \
+       fixed ## fixed_index ## _C_FindObjects, \
+       fixed ## fixed_index ## _C_FindObjectsFinal, \
+       fixed ## fixed_index ## _C_EncryptInit, \
+       fixed ## fixed_index ## _C_Encrypt, \
+       fixed ## fixed_index ## _C_EncryptUpdate, \
+       fixed ## fixed_index ## _C_EncryptFinal, \
+       fixed ## fixed_index ## _C_DecryptInit, \
+       fixed ## fixed_index ## _C_Decrypt, \
+       fixed ## fixed_index ## _C_DecryptUpdate, \
+       fixed ## fixed_index ## _C_DecryptFinal, \
+       fixed ## fixed_index ## _C_DigestInit, \
+       fixed ## fixed_index ## _C_Digest, \
+       fixed ## fixed_index ## _C_DigestUpdate, \
+       fixed ## fixed_index ## _C_DigestKey, \
+       fixed ## fixed_index ## _C_DigestFinal, \
+       fixed ## fixed_index ## _C_SignInit, \
+       fixed ## fixed_index ## _C_Sign, \
+       fixed ## fixed_index ## _C_SignUpdate, \
+       fixed ## fixed_index ## _C_SignFinal, \
+       fixed ## fixed_index ## _C_SignRecoverInit, \
+       fixed ## fixed_index ## _C_SignRecover, \
+       fixed ## fixed_index ## _C_VerifyInit, \
+       fixed ## fixed_index ## _C_Verify, \
+       fixed ## fixed_index ## _C_VerifyUpdate, \
+       fixed ## fixed_index ## _C_VerifyFinal, \
+       fixed ## fixed_index ## _C_VerifyRecoverInit, \
+       fixed ## fixed_index ## _C_VerifyRecover, \
+       fixed ## fixed_index ## _C_DigestEncryptUpdate, \
+       fixed ## fixed_index ## _C_DecryptDigestUpdate, \
+       fixed ## fixed_index ## _C_SignEncryptUpdate, \
+       fixed ## fixed_index ## _C_DecryptVerifyUpdate, \
+       fixed ## fixed_index ## _C_GenerateKey, \
+       fixed ## fixed_index ## _C_GenerateKeyPair, \
+       fixed ## fixed_index ## _C_WrapKey, \
+       fixed ## fixed_index ## _C_UnwrapKey, \
+       fixed ## fixed_index ## _C_DeriveKey, \
+       fixed ## fixed_index ## _C_SeedRandom, \
+       fixed ## fixed_index ## _C_GenerateRandom, \
+       short_C_GetFunctionStatus, \
+       short_C_CancelFunction, \
+       fixed ## fixed_index ## _C_WaitForSlotEvent \
+}
index bb0d845edb056abe23c4debec5a290f4895eb5c2..a9eae564ec2e722c54de3da60e4c8cf2ca29b5f6 100644 (file)
 #include "debug.h"
 #include "library.h"
 #include "virtual.h"
+#include "virtual-fixed.h"
 
 #include <assert.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
 
-#ifdef WITH_FFI
+#if defined(WITH_FFI) && WITH_FFI
 
 /*
  * We use libffi to build closures. Note that even with libffi certain
@@ -62,8 +63,6 @@
 #define LIBFFI_FREE_CLOSURES 0
 
 #include "ffi.h"
-#ifndef FFI_CLOSURES
-#error "FFI_CLOSURES should be checked in configure.ac"
 #endif
 
 /* There are 66 functions in PKCS#11, with a maximum of 8 args */
@@ -78,12 +77,47 @@ typedef struct {
        p11_virtual *virt;
        p11_destroyer destroyer;
 
+#if defined(FFI_CLOSURES) && FFI_CLOSURES
        /* A list of our libffi built closures, for cleanup later */
        ffi_closure *ffi_closures[MAX_FUNCTIONS];
        ffi_cif ffi_cifs[MAX_FUNCTIONS];
        int ffi_used;
+#endif /* FFI_CLOSURES */
+
+       /* The index in fixed_closures, or -1 when libffi closures are used */
+       int fixed_index;
 } Wrapper;
 
+static p11_mutex_t fixed_mutex;
+static CK_FUNCTION_LIST *fixed_closures[P11_VIRTUAL_MAX_FIXED];
+
+static Wrapper          *create_fixed_wrapper   (p11_virtual         *virt,
+                                                 size_t               index,
+                                                 p11_destroyer        destroyer);
+static CK_FUNCTION_LIST *
+                         p11_virtual_wrap_fixed (p11_virtual         *virt,
+                                                 p11_destroyer        destroyer);
+static void
+                         p11_virtual_unwrap_fixed
+                                                (CK_FUNCTION_LIST_PTR module);
+
+void
+p11_virtual_init_fixed (void)
+{
+       p11_lock ();
+       p11_mutex_init (&fixed_mutex);
+       memset (fixed_closures, 0, sizeof (fixed_closures));
+       p11_unlock ();
+}
+
+void
+p11_virtual_uninit_fixed (void)
+{
+       p11_lock ();
+       p11_mutex_uninit (&fixed_mutex);
+       p11_unlock ();
+}
+
 static CK_RV
 short_C_GetFunctionStatus (CK_SESSION_HANDLE handle)
 {
@@ -96,6 +130,8 @@ short_C_CancelFunction (CK_SESSION_HANDLE handle)
        return CKR_FUNCTION_NOT_PARALLEL;
 }
 
+#if defined(FFI_CLOSURES) && FFI_CLOSURES
+
 static void
 binding_C_GetFunctionList (ffi_cif *cif,
                            CK_RV *ret,
@@ -930,7 +966,7 @@ binding_C_GenerateRandom (ffi_cif *cif,
                                        *(CK_ULONG *)args[2]);
 }
 
-#endif /* WITH_FFI */
+#endif /* FFI_CLOSURES */
 
 static CK_RV
 stack_C_Initialize (CK_X_FUNCTION_LIST *self,
@@ -2494,16 +2530,12 @@ p11_virtual_uninit (p11_virtual *virt)
                (virt->lower_destroy) (virt->lower_module);
 }
 
-#ifdef WITH_FFI
-
 typedef struct {
        const char *name;
-       void *binding_function;
        void *stack_fallback;
        size_t virtual_offset;
        void *base_fallback;
        size_t module_offset;
-       ffi_type *types[MAX_ARGS];
 } FunctionInfo;
 
 #define STRUCT_OFFSET(struct_type, member) \
@@ -2514,77 +2546,77 @@ typedef struct {
        (*(member_type*) STRUCT_MEMBER_P ((struct_p), (struct_offset)))
 
 #define FUNCTION(name) \
-       #name, binding_C_##name, \
+       #name, \
        stack_C_##name, STRUCT_OFFSET (CK_X_FUNCTION_LIST, C_##name), \
        base_C_##name, STRUCT_OFFSET (CK_FUNCTION_LIST, C_##name)
 
 static const FunctionInfo function_info[] = {
-       { FUNCTION (Initialize), { &ffi_type_pointer, NULL } },
-       { FUNCTION (Finalize), { &ffi_type_pointer, NULL } },
-       { FUNCTION (GetInfo), { &ffi_type_pointer, NULL } },
-       { FUNCTION (GetSlotList), { &ffi_type_uchar, &ffi_type_pointer, &ffi_type_pointer, NULL } },
-       { FUNCTION (GetSlotInfo), { &ffi_type_ulong, &ffi_type_pointer, NULL } },
-       { FUNCTION (GetTokenInfo), { &ffi_type_ulong, &ffi_type_pointer, NULL } },
-       { FUNCTION (WaitForSlotEvent), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
-       { FUNCTION (GetMechanismList), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
-       { FUNCTION (GetMechanismInfo), { &ffi_type_ulong, &ffi_type_ulong, &ffi_type_pointer, NULL } },
-       { FUNCTION (InitToken), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, NULL } },
-       { FUNCTION (InitPIN), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
-       { FUNCTION (SetPIN), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
-       { FUNCTION (OpenSession), { &ffi_type_ulong, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, &ffi_type_pointer, NULL } },
-       { FUNCTION (CloseSession), { &ffi_type_ulong, NULL } },
-       { FUNCTION (CloseAllSessions), { &ffi_type_ulong, NULL } },
-       { FUNCTION (GetSessionInfo), { &ffi_type_ulong, &ffi_type_pointer, NULL } },
-       { FUNCTION (GetOperationState), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
-       { FUNCTION (SetOperationState), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_ulong, &ffi_type_ulong, NULL } },
-       { FUNCTION (Login), { &ffi_type_ulong, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
-       { FUNCTION (Logout), { &ffi_type_ulong, NULL } },
-       { FUNCTION (CreateObject), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, NULL } },
-       { FUNCTION (CopyObject), { &ffi_type_ulong, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, NULL } },
-       { FUNCTION (DestroyObject), { &ffi_type_ulong, &ffi_type_ulong, NULL } },
-       { FUNCTION (GetObjectSize), { &ffi_type_ulong, &ffi_type_ulong, &ffi_type_pointer, NULL } },
-       { FUNCTION (GetAttributeValue), { &ffi_type_ulong, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
-       { FUNCTION (SetAttributeValue), { &ffi_type_ulong, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
-       { FUNCTION (FindObjectsInit), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
-       { FUNCTION (FindObjects), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, NULL } },
-       { FUNCTION (FindObjectsFinal), { &ffi_type_ulong, NULL } },
-       { FUNCTION (EncryptInit), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
-       { FUNCTION (Encrypt), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
-       { FUNCTION (EncryptUpdate), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
-       { FUNCTION (EncryptFinal), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
-       { FUNCTION (DecryptInit), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
-       { FUNCTION (Decrypt), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
-       { FUNCTION (DecryptUpdate), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
-       { FUNCTION (DecryptFinal), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
-       { FUNCTION (DigestInit), { &ffi_type_ulong, &ffi_type_pointer, NULL } },
-       { FUNCTION (Digest), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
-       { FUNCTION (DigestUpdate), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
-       { FUNCTION (DigestKey), { &ffi_type_ulong, &ffi_type_ulong, NULL } },
-       { FUNCTION (DigestFinal), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
-       { FUNCTION (SignInit), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
-       { FUNCTION (Sign), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
-       { FUNCTION (SignUpdate), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
-       { FUNCTION (SignFinal), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
-       { FUNCTION (SignRecoverInit), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
-       { FUNCTION (SignRecover), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
-       { FUNCTION (VerifyInit), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
-       { FUNCTION (Verify), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
-       { FUNCTION (VerifyUpdate), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
-       { FUNCTION (VerifyFinal), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
-       { FUNCTION (VerifyRecoverInit), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
-       { FUNCTION (VerifyRecover), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
-       { FUNCTION (DigestEncryptUpdate), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
-       { FUNCTION (DecryptDigestUpdate), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
-       { FUNCTION (SignEncryptUpdate), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
-       { FUNCTION (DecryptVerifyUpdate), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
-       { FUNCTION (GenerateKey), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, NULL } },
-       { FUNCTION (GenerateKeyPair), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
-       { FUNCTION (WrapKey), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
-       { FUNCTION (UnwrapKey), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, NULL } },
-       { FUNCTION (DeriveKey), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, NULL } },
-       { FUNCTION (SeedRandom), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
-       { FUNCTION (GenerateRandom), { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
-       { 0, }
+        { FUNCTION (Initialize) },
+        { FUNCTION (Finalize) },
+        { FUNCTION (GetInfo) },
+        { FUNCTION (GetSlotList) },
+        { FUNCTION (GetSlotInfo) },
+        { FUNCTION (GetTokenInfo) },
+        { FUNCTION (GetMechanismList) },
+        { FUNCTION (GetMechanismInfo) },
+        { FUNCTION (InitToken) },
+        { FUNCTION (InitPIN) },
+        { FUNCTION (SetPIN) },
+        { FUNCTION (OpenSession) },
+        { FUNCTION (CloseSession) },
+        { FUNCTION (CloseAllSessions) },
+        { FUNCTION (GetSessionInfo) },
+        { FUNCTION (GetOperationState) },
+        { FUNCTION (SetOperationState) },
+        { FUNCTION (Login) },
+        { FUNCTION (Logout) },
+        { FUNCTION (CreateObject) },
+        { FUNCTION (CopyObject) },
+        { FUNCTION (DestroyObject) },
+        { FUNCTION (GetObjectSize) },
+        { FUNCTION (GetAttributeValue) },
+        { FUNCTION (SetAttributeValue) },
+        { FUNCTION (FindObjectsInit) },
+        { FUNCTION (FindObjects) },
+        { FUNCTION (FindObjectsFinal) },
+        { FUNCTION (EncryptInit) },
+        { FUNCTION (Encrypt) },
+        { FUNCTION (EncryptUpdate) },
+        { FUNCTION (EncryptFinal) },
+        { FUNCTION (DecryptInit) },
+        { FUNCTION (Decrypt) },
+        { FUNCTION (DecryptUpdate) },
+        { FUNCTION (DecryptFinal) },
+        { FUNCTION (DigestInit) },
+        { FUNCTION (Digest) },
+        { FUNCTION (DigestUpdate) },
+        { FUNCTION (DigestKey) },
+        { FUNCTION (DigestFinal) },
+        { FUNCTION (SignInit) },
+        { FUNCTION (Sign) },
+        { FUNCTION (SignUpdate) },
+        { FUNCTION (SignFinal) },
+        { FUNCTION (SignRecoverInit) },
+        { FUNCTION (SignRecover) },
+        { FUNCTION (VerifyInit) },
+        { FUNCTION (Verify) },
+        { FUNCTION (VerifyUpdate) },
+        { FUNCTION (VerifyFinal) },
+        { FUNCTION (VerifyRecoverInit) },
+        { FUNCTION (VerifyRecover) },
+        { FUNCTION (DigestEncryptUpdate) },
+        { FUNCTION (DecryptDigestUpdate) },
+        { FUNCTION (SignEncryptUpdate) },
+        { FUNCTION (DecryptVerifyUpdate) },
+        { FUNCTION (GenerateKey) },
+        { FUNCTION (GenerateKeyPair) },
+        { FUNCTION (WrapKey) },
+        { FUNCTION (UnwrapKey) },
+        { FUNCTION (DeriveKey) },
+        { FUNCTION (SeedRandom) },
+        { FUNCTION (GenerateRandom) },
+        { FUNCTION (WaitForSlotEvent) },
+        { 0, }
 };
 
 static bool
@@ -2621,6 +2653,82 @@ lookup_fall_through (p11_virtual *virt,
        return false;
 }
 
+#if defined(FFI_CLOSURES) && FFI_CLOSURES
+typedef struct {
+       void *function;
+       ffi_type *types[MAX_ARGS+1];
+} BindingInfo;
+
+static const BindingInfo binding_info[] = {
+        { binding_C_Initialize, { &ffi_type_pointer, NULL } },
+        { binding_C_Finalize, { &ffi_type_pointer, NULL } },
+        { binding_C_GetInfo, { &ffi_type_pointer, NULL } },
+        { binding_C_GetSlotList, { &ffi_type_uchar, &ffi_type_pointer, &ffi_type_pointer, NULL } },
+        { binding_C_GetSlotInfo, { &ffi_type_ulong, &ffi_type_pointer, NULL } },
+        { binding_C_GetTokenInfo, { &ffi_type_ulong, &ffi_type_pointer, NULL } },
+        { binding_C_GetMechanismList, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
+        { binding_C_GetMechanismInfo, { &ffi_type_ulong, &ffi_type_ulong, &ffi_type_pointer, NULL } },
+        { binding_C_InitToken, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, NULL } },
+        { binding_C_InitPIN, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
+        { binding_C_SetPIN, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
+        { binding_C_OpenSession, { &ffi_type_ulong, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, &ffi_type_pointer, NULL } },
+        { binding_C_CloseSession, { &ffi_type_ulong, NULL } },
+        { binding_C_CloseAllSessions, { &ffi_type_ulong, NULL } },
+        { binding_C_GetSessionInfo, { &ffi_type_ulong, &ffi_type_pointer, NULL } },
+        { binding_C_GetOperationState, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
+        { binding_C_SetOperationState, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_ulong, &ffi_type_ulong, NULL } },
+        { binding_C_Login, { &ffi_type_ulong, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
+        { binding_C_Logout, { &ffi_type_ulong, NULL } },
+        { binding_C_CreateObject, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, NULL } },
+        { binding_C_CopyObject, { &ffi_type_ulong, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, NULL } },
+        { binding_C_DestroyObject, { &ffi_type_ulong, &ffi_type_ulong, NULL } },
+        { binding_C_GetObjectSize, { &ffi_type_ulong, &ffi_type_ulong, &ffi_type_pointer, NULL } },
+        { binding_C_GetAttributeValue, { &ffi_type_ulong, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
+        { binding_C_SetAttributeValue, { &ffi_type_ulong, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
+        { binding_C_FindObjectsInit, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
+        { binding_C_FindObjects, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, NULL } },
+        { binding_C_FindObjectsFinal, { &ffi_type_ulong, NULL } },
+        { binding_C_EncryptInit, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
+        { binding_C_Encrypt, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
+        { binding_C_EncryptUpdate, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
+        { binding_C_EncryptFinal, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
+        { binding_C_DecryptInit, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
+        { binding_C_Decrypt, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
+        { binding_C_DecryptUpdate, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
+        { binding_C_DecryptFinal, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
+        { binding_C_DigestInit, { &ffi_type_ulong, &ffi_type_pointer, NULL } },
+        { binding_C_Digest, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
+        { binding_C_DigestUpdate, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
+        { binding_C_DigestKey, { &ffi_type_ulong, &ffi_type_ulong, NULL } },
+        { binding_C_DigestFinal, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
+        { binding_C_SignInit, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
+        { binding_C_Sign, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
+        { binding_C_SignUpdate, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
+        { binding_C_SignFinal, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
+        { binding_C_SignRecoverInit, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
+        { binding_C_SignRecover, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
+        { binding_C_VerifyInit, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
+        { binding_C_Verify, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
+        { binding_C_VerifyUpdate, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
+        { binding_C_VerifyFinal, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
+        { binding_C_VerifyRecoverInit, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
+        { binding_C_VerifyRecover, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
+        { binding_C_DigestEncryptUpdate, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
+        { binding_C_DecryptDigestUpdate, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
+        { binding_C_SignEncryptUpdate, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
+        { binding_C_DecryptVerifyUpdate, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
+        { binding_C_GenerateKey, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, NULL } },
+        { binding_C_GenerateKeyPair, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
+        { binding_C_WrapKey, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
+        { binding_C_UnwrapKey, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, NULL } },
+        { binding_C_DeriveKey, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, &ffi_type_pointer, NULL } },
+        { binding_C_SeedRandom, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
+        { binding_C_GenerateRandom, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_ulong, NULL } },
+        { binding_C_WaitForSlotEvent, { &ffi_type_ulong, &ffi_type_pointer, &ffi_type_pointer, NULL } },
+        { 0, }
+};
+
+
 static bool
 bind_ffi_closure (Wrapper *wrapper,
                   void *binding_data,
@@ -2698,9 +2806,10 @@ init_wrapper_funcs (Wrapper *wrapper)
                 * fall through, then this returns the original module function.
                 */
                if (!lookup_fall_through (wrapper->virt, info, bound)) {
+                       const BindingInfo *binding = binding_info + i;
                        if (!bind_ffi_closure (wrapper, over,
-                                              info->binding_function,
-                                              (ffi_type **)info->types, bound))
+                                              binding->function,
+                                              (ffi_type **)binding->types, bound))
                                return_val_if_reached (false);
                }
        }
@@ -2725,7 +2834,7 @@ init_wrapper_funcs (Wrapper *wrapper)
        return true;
 }
 
-#if LIBFFI_FREE_CLOSURES
+#if defined(LIBFFI_FREE_CLOSURES) && LIBFFI_FREE_CLOSURES
 static void
 uninit_wrapper_funcs (Wrapper *wrapper)
 {
@@ -2753,7 +2862,7 @@ p11_virtual_wrap (p11_virtual *virt,
        wrapper->bound.version.minor = CRYPTOKI_VERSION_MINOR;
 
        if (!init_wrapper_funcs (wrapper))
-               return_val_if_reached (NULL);
+               return p11_virtual_wrap_fixed (virt, destroyer);
 
        assert ((void *)wrapper == (void *)&wrapper->bound);
        assert (p11_virtual_is_wrapper (&wrapper->bound));
@@ -2761,12 +2870,17 @@ p11_virtual_wrap (p11_virtual *virt,
        return &wrapper->bound;
 }
 
-bool
-p11_virtual_can_wrap (void)
+#else /* !FFI_CLOSURES */
+
+CK_FUNCTION_LIST *
+p11_virtual_wrap (p11_virtual *virt,
+                  p11_destroyer destroyer)
 {
-       return TRUE;
+       return p11_virtual_wrap_fixed (virt, destroyer);
 }
 
+#endif /* !FFI_CLOSURES */
+
 bool
 p11_virtual_is_wrapper (CK_FUNCTION_LIST_PTR module)
 {
@@ -2791,6 +2905,9 @@ p11_virtual_unwrap (CK_FUNCTION_LIST_PTR module)
        /* The bound CK_FUNCTION_LIST_PTR sits at the front of Context */
        wrapper = (Wrapper *)module;
 
+       if (wrapper->fixed_index >= 0)
+               p11_virtual_unwrap_fixed (module);
+
        /*
         * Make sure that the CK_FUNCTION_LIST_PTR is invalid, and that
         * p11_virtual_is_wrapper() recognizes this. This is in case the
@@ -2801,41 +2918,12 @@ p11_virtual_unwrap (CK_FUNCTION_LIST_PTR module)
        if (wrapper->destroyer)
                (wrapper->destroyer) (wrapper->virt);
 
-#if LIBFFI_FREE_CLOSURES
+#if defined(LIBFFI_FREE_CLOSURES) && LIBFFI_FREE_CLOSURES
        uninit_wrapper_funcs (wrapper);
 #endif
        free (wrapper);
 }
 
-#else /* !WITH_FFI */
-
-CK_FUNCTION_LIST *
-p11_virtual_wrap (p11_virtual *virt,
-                  p11_destroyer destroyer)
-{
-       assert_not_reached ();
-}
-
-bool
-p11_virtual_can_wrap (void)
-{
-       return FALSE;
-}
-
-bool
-p11_virtual_is_wrapper (CK_FUNCTION_LIST_PTR module)
-{
-       return FALSE;
-}
-
-void
-p11_virtual_unwrap (CK_FUNCTION_LIST_PTR module)
-{
-       assert_not_reached ();
-}
-
-#endif /* !WITH_FFI */
-
 CK_X_FUNCTION_LIST p11_virtual_stack = {
        { CRYPTOKI_VERSION_MAJOR, CRYPTOKI_VERSION_MINOR },  /* version */
        stack_C_Initialize,
@@ -2973,3 +3061,305 @@ CK_X_FUNCTION_LIST p11_virtual_base = {
        base_C_GenerateRandom,
        base_C_WaitForSlotEvent
 };
+
+P11_VIRTUAL_FIXED_FUNCTIONS(0)
+P11_VIRTUAL_FIXED_FUNCTIONS(1)
+P11_VIRTUAL_FIXED_FUNCTIONS(2)
+P11_VIRTUAL_FIXED_FUNCTIONS(3)
+P11_VIRTUAL_FIXED_FUNCTIONS(4)
+P11_VIRTUAL_FIXED_FUNCTIONS(5)
+P11_VIRTUAL_FIXED_FUNCTIONS(6)
+P11_VIRTUAL_FIXED_FUNCTIONS(7)
+P11_VIRTUAL_FIXED_FUNCTIONS(8)
+P11_VIRTUAL_FIXED_FUNCTIONS(9)
+P11_VIRTUAL_FIXED_FUNCTIONS(10)
+P11_VIRTUAL_FIXED_FUNCTIONS(11)
+P11_VIRTUAL_FIXED_FUNCTIONS(12)
+P11_VIRTUAL_FIXED_FUNCTIONS(13)
+P11_VIRTUAL_FIXED_FUNCTIONS(14)
+P11_VIRTUAL_FIXED_FUNCTIONS(15)
+P11_VIRTUAL_FIXED_FUNCTIONS(16)
+P11_VIRTUAL_FIXED_FUNCTIONS(17)
+P11_VIRTUAL_FIXED_FUNCTIONS(18)
+P11_VIRTUAL_FIXED_FUNCTIONS(19)
+P11_VIRTUAL_FIXED_FUNCTIONS(20)
+P11_VIRTUAL_FIXED_FUNCTIONS(21)
+P11_VIRTUAL_FIXED_FUNCTIONS(22)
+P11_VIRTUAL_FIXED_FUNCTIONS(23)
+P11_VIRTUAL_FIXED_FUNCTIONS(24)
+P11_VIRTUAL_FIXED_FUNCTIONS(25)
+P11_VIRTUAL_FIXED_FUNCTIONS(26)
+P11_VIRTUAL_FIXED_FUNCTIONS(27)
+P11_VIRTUAL_FIXED_FUNCTIONS(28)
+P11_VIRTUAL_FIXED_FUNCTIONS(29)
+P11_VIRTUAL_FIXED_FUNCTIONS(30)
+P11_VIRTUAL_FIXED_FUNCTIONS(31)
+P11_VIRTUAL_FIXED_FUNCTIONS(32)
+P11_VIRTUAL_FIXED_FUNCTIONS(33)
+P11_VIRTUAL_FIXED_FUNCTIONS(34)
+P11_VIRTUAL_FIXED_FUNCTIONS(35)
+P11_VIRTUAL_FIXED_FUNCTIONS(36)
+P11_VIRTUAL_FIXED_FUNCTIONS(37)
+P11_VIRTUAL_FIXED_FUNCTIONS(38)
+P11_VIRTUAL_FIXED_FUNCTIONS(39)
+P11_VIRTUAL_FIXED_FUNCTIONS(40)
+P11_VIRTUAL_FIXED_FUNCTIONS(41)
+P11_VIRTUAL_FIXED_FUNCTIONS(42)
+P11_VIRTUAL_FIXED_FUNCTIONS(43)
+P11_VIRTUAL_FIXED_FUNCTIONS(44)
+P11_VIRTUAL_FIXED_FUNCTIONS(45)
+P11_VIRTUAL_FIXED_FUNCTIONS(46)
+P11_VIRTUAL_FIXED_FUNCTIONS(47)
+P11_VIRTUAL_FIXED_FUNCTIONS(48)
+P11_VIRTUAL_FIXED_FUNCTIONS(49)
+P11_VIRTUAL_FIXED_FUNCTIONS(50)
+P11_VIRTUAL_FIXED_FUNCTIONS(51)
+P11_VIRTUAL_FIXED_FUNCTIONS(52)
+P11_VIRTUAL_FIXED_FUNCTIONS(53)
+P11_VIRTUAL_FIXED_FUNCTIONS(54)
+P11_VIRTUAL_FIXED_FUNCTIONS(55)
+P11_VIRTUAL_FIXED_FUNCTIONS(56)
+P11_VIRTUAL_FIXED_FUNCTIONS(57)
+P11_VIRTUAL_FIXED_FUNCTIONS(58)
+P11_VIRTUAL_FIXED_FUNCTIONS(59)
+P11_VIRTUAL_FIXED_FUNCTIONS(60)
+P11_VIRTUAL_FIXED_FUNCTIONS(61)
+P11_VIRTUAL_FIXED_FUNCTIONS(62)
+P11_VIRTUAL_FIXED_FUNCTIONS(63)
+
+CK_FUNCTION_LIST p11_virtual_fixed[P11_VIRTUAL_MAX_FIXED] = {
+       P11_VIRTUAL_FIXED_INITIALIZER(0), \
+       P11_VIRTUAL_FIXED_INITIALIZER(1), \
+       P11_VIRTUAL_FIXED_INITIALIZER(2), \
+       P11_VIRTUAL_FIXED_INITIALIZER(3), \
+       P11_VIRTUAL_FIXED_INITIALIZER(4), \
+       P11_VIRTUAL_FIXED_INITIALIZER(5), \
+       P11_VIRTUAL_FIXED_INITIALIZER(6), \
+       P11_VIRTUAL_FIXED_INITIALIZER(7), \
+       P11_VIRTUAL_FIXED_INITIALIZER(8), \
+       P11_VIRTUAL_FIXED_INITIALIZER(9), \
+       P11_VIRTUAL_FIXED_INITIALIZER(10), \
+       P11_VIRTUAL_FIXED_INITIALIZER(11), \
+       P11_VIRTUAL_FIXED_INITIALIZER(12), \
+       P11_VIRTUAL_FIXED_INITIALIZER(13), \
+       P11_VIRTUAL_FIXED_INITIALIZER(14), \
+       P11_VIRTUAL_FIXED_INITIALIZER(15), \
+       P11_VIRTUAL_FIXED_INITIALIZER(16), \
+       P11_VIRTUAL_FIXED_INITIALIZER(17), \
+       P11_VIRTUAL_FIXED_INITIALIZER(18), \
+       P11_VIRTUAL_FIXED_INITIALIZER(19), \
+       P11_VIRTUAL_FIXED_INITIALIZER(20), \
+       P11_VIRTUAL_FIXED_INITIALIZER(21), \
+       P11_VIRTUAL_FIXED_INITIALIZER(22), \
+       P11_VIRTUAL_FIXED_INITIALIZER(23), \
+       P11_VIRTUAL_FIXED_INITIALIZER(24), \
+       P11_VIRTUAL_FIXED_INITIALIZER(25), \
+       P11_VIRTUAL_FIXED_INITIALIZER(26), \
+       P11_VIRTUAL_FIXED_INITIALIZER(27), \
+       P11_VIRTUAL_FIXED_INITIALIZER(28), \
+       P11_VIRTUAL_FIXED_INITIALIZER(29), \
+       P11_VIRTUAL_FIXED_INITIALIZER(30), \
+       P11_VIRTUAL_FIXED_INITIALIZER(31), \
+       P11_VIRTUAL_FIXED_INITIALIZER(32), \
+       P11_VIRTUAL_FIXED_INITIALIZER(33), \
+       P11_VIRTUAL_FIXED_INITIALIZER(34), \
+       P11_VIRTUAL_FIXED_INITIALIZER(35), \
+       P11_VIRTUAL_FIXED_INITIALIZER(36), \
+       P11_VIRTUAL_FIXED_INITIALIZER(37), \
+       P11_VIRTUAL_FIXED_INITIALIZER(38), \
+       P11_VIRTUAL_FIXED_INITIALIZER(39), \
+       P11_VIRTUAL_FIXED_INITIALIZER(40), \
+       P11_VIRTUAL_FIXED_INITIALIZER(41), \
+       P11_VIRTUAL_FIXED_INITIALIZER(42), \
+       P11_VIRTUAL_FIXED_INITIALIZER(43), \
+       P11_VIRTUAL_FIXED_INITIALIZER(44), \
+       P11_VIRTUAL_FIXED_INITIALIZER(45), \
+       P11_VIRTUAL_FIXED_INITIALIZER(46), \
+       P11_VIRTUAL_FIXED_INITIALIZER(47), \
+       P11_VIRTUAL_FIXED_INITIALIZER(48), \
+       P11_VIRTUAL_FIXED_INITIALIZER(49), \
+       P11_VIRTUAL_FIXED_INITIALIZER(50), \
+       P11_VIRTUAL_FIXED_INITIALIZER(51), \
+       P11_VIRTUAL_FIXED_INITIALIZER(52), \
+       P11_VIRTUAL_FIXED_INITIALIZER(53), \
+       P11_VIRTUAL_FIXED_INITIALIZER(54), \
+       P11_VIRTUAL_FIXED_INITIALIZER(55), \
+       P11_VIRTUAL_FIXED_INITIALIZER(56), \
+       P11_VIRTUAL_FIXED_INITIALIZER(57), \
+       P11_VIRTUAL_FIXED_INITIALIZER(58), \
+       P11_VIRTUAL_FIXED_INITIALIZER(59), \
+       P11_VIRTUAL_FIXED_INITIALIZER(60), \
+       P11_VIRTUAL_FIXED_INITIALIZER(61), \
+       P11_VIRTUAL_FIXED_INITIALIZER(62), \
+       P11_VIRTUAL_FIXED_INITIALIZER(63)
+};
+
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(0)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(1)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(2)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(3)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(4)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(5)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(6)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(7)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(8)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(9)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(10)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(11)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(12)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(13)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(14)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(15)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(16)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(17)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(18)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(19)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(20)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(21)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(22)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(23)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(24)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(25)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(26)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(27)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(28)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(29)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(30)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(31)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(32)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(33)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(34)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(35)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(36)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(37)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(38)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(39)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(40)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(41)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(42)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(43)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(44)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(45)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(46)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(47)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(48)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(49)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(50)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(51)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(52)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(53)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(54)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(55)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(56)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(57)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(58)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(59)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(60)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(61)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(62)
+P11_VIRTUAL_FIXED_GET_FUNCTION_LIST(63)
+
+static CK_FUNCTION_LIST *
+p11_virtual_wrap_fixed (p11_virtual *virt,
+                       p11_destroyer destroyer)
+{
+       CK_FUNCTION_LIST *result = NULL;
+       size_t i;
+
+       p11_mutex_lock (&fixed_mutex);
+       for (i = 0; i < P11_VIRTUAL_MAX_FIXED; i++) {
+               if (fixed_closures[i] == NULL) {
+                       Wrapper *wrapper;
+                       wrapper = create_fixed_wrapper (virt, i, destroyer);
+                       result = &wrapper->bound;
+                       fixed_closures[i] = result;
+                       break;
+               }
+       }
+       p11_mutex_unlock (&fixed_mutex);
+
+       return result;
+}
+
+static void
+p11_virtual_unwrap_fixed (CK_FUNCTION_LIST_PTR module)
+{
+       size_t i;
+
+       p11_mutex_lock (&fixed_mutex);
+       for (i = 0; i < P11_VIRTUAL_MAX_FIXED; i++) {
+               if (fixed_closures[i] == module) {
+                       fixed_closures[i] = NULL;
+                       break;
+               }
+       }
+       p11_mutex_unlock (&fixed_mutex);
+}
+
+static bool
+init_wrapper_funcs_fixed (Wrapper *wrapper, CK_FUNCTION_LIST *fixed)
+{
+       const FunctionInfo *info;
+       void **bound_to, **bound_from;
+       int i;
+
+       for (i = 0; function_info[i].name != NULL; i++) {
+               info = function_info + i;
+
+               /* Address to where we're placing the bound function */
+               bound_to = &STRUCT_MEMBER (void *, &wrapper->bound, info->module_offset);
+               bound_from = &STRUCT_MEMBER (void *, fixed, info->module_offset);
+
+               /*
+                * See if we can just shoot straight through to the module function
+                * without wrapping at all. If all the stacked virtual modules just
+                * fall through, then this returns the original module function.
+                */
+               if (!lookup_fall_through (wrapper->virt, info, bound_to))
+                       *bound_to = *bound_from;
+       }
+
+       /* Always bind the C_GetFunctionList function itself */
+       wrapper->bound.C_GetFunctionList = fixed->C_GetFunctionList;
+
+       /*
+        * These functions are used as a marker to indicate whether this is
+        * one of our CK_FUNCTION_LIST_PTR sets of functions or not. These
+        * functions are defined to always have the same standard implementation
+        * in PKCS#11 2.x so we don't need to call through to the base for
+        * these guys.
+        */
+       wrapper->bound.C_CancelFunction = short_C_CancelFunction;
+       wrapper->bound.C_GetFunctionStatus = short_C_GetFunctionStatus;
+
+       return true;
+}
+
+static Wrapper *
+create_fixed_wrapper (p11_virtual *virt,
+                     size_t index,
+                     p11_destroyer destroyer)
+{
+       Wrapper *wrapper;
+
+       return_val_if_fail (virt != NULL, NULL);
+
+       wrapper = calloc (1, sizeof (Wrapper));
+       return_val_if_fail (wrapper != NULL, NULL);
+
+       wrapper->virt = virt;
+       wrapper->destroyer = destroyer;
+       wrapper->bound.version.major = CRYPTOKI_VERSION_MAJOR;
+       wrapper->bound.version.minor = CRYPTOKI_VERSION_MINOR;
+       wrapper->fixed_index = index;
+
+       if (!init_wrapper_funcs_fixed (wrapper, &p11_virtual_fixed[index])) {
+              free (wrapper);
+               return NULL;
+       }
+
+       assert ((void *)wrapper == (void *)&wrapper->bound);
+       assert (p11_virtual_is_wrapper (&wrapper->bound));
+       assert (wrapper->bound.C_GetFunctionList != NULL);
+       return wrapper;
+}
index 97d2a7c0dc04de6b3d96fdf65a89c2fdb5cbe248..8083eb9241bfdfc2db2560f3319450aa1ed5d9f8 100644 (file)
@@ -56,8 +56,6 @@ void                    p11_virtual_init       (p11_virtual *virt,
 
 void                    p11_virtual_uninit     (p11_virtual *virt);
 
-bool                    p11_virtual_can_wrap   (void);
-
 CK_FUNCTION_LIST *      p11_virtual_wrap       (p11_virtual *virt,
                                                 p11_destroyer destroyer);
 
@@ -65,4 +63,8 @@ bool                    p11_virtual_is_wrapper (CK_FUNCTION_LIST *module);
 
 void                    p11_virtual_unwrap     (CK_FUNCTION_LIST *module);
 
+void                    p11_virtual_init_fixed (void);
+void                    p11_virtual_uninit_fixed
+                                               (void);
+
 #endif /* __P11_VIRTUAL_H__ */