diff options
Diffstat (limited to 'p11-kit/modules.c')
-rw-r--r-- | p11-kit/modules.c | 2704 |
1 files changed, 0 insertions, 2704 deletions
diff --git a/p11-kit/modules.c b/p11-kit/modules.c deleted file mode 100644 index 6e15c1d..0000000 --- a/p11-kit/modules.c +++ /dev/null @@ -1,2704 +0,0 @@ -/* - * Copyright (C) 2008 Stefan Walter - * Copyright (C) 2011 Collabora Ltd. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * * Redistributions in binary form must reproduce the - * above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * * The names of contributors to this software may not be - * used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -/* We use and define deprecated functions here */ -#define P11_KIT_NO_DEPRECATIONS -#define P11_DEBUG_FLAG P11_DEBUG_LIB - -#include "conf.h" -#include "debug.h" -#include "dict.h" -#include "library.h" -#include "log.h" -#include "message.h" -#include "modules.h" -#include "path.h" -#include "pkcs11.h" -#include "p11-kit.h" -#include "private.h" -#include "proxy.h" -#include "rpc.h" -#include "virtual.h" - -#include <sys/stat.h> -#include <sys/types.h> - -#include <assert.h> -#include <ctype.h> -#include <dirent.h> -#include <errno.h> -#include <limits.h> -#include <stdarg.h> -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -/** - * SECTION:p11-kit - * @title: Modules - * @short_description: Module loading and initializing - * - * PKCS\#11 modules are used by crypto libraries and applications to access - * crypto objects (like keys and certificates) and to perform crypto operations. - * - * In order for applications to behave consistently with regard to the user's - * installed PKCS\#11 modules, each module must be configured so that applications - * or libraries know that they should load it. - * - * When multiple consumers of a module (such as libraries or applications) are - * in the same process, coordination of the initialization and finalization - * of PKCS\#11 modules is required. To do this modules are managed by p11-kit. - * This means that various unsafe methods are coordinated between callers. Unmanaged - * modules are simply the raw PKCS\#11 module pointers without p11-kit getting in the - * way. It is highly recommended that the default managed behavior is used. - * - * The functions here provide support for initializing configured modules. The - * p11_kit_modules_load() function should be used to load and initialize - * the configured modules. When done, the p11_kit_modules_release() function - * should be used to release those modules and associated resources. - * - * In addition p11_kit_config_option() can be used to access other parts - * of the module configuration. - * - * If a consumer wishes to load an arbitrary PKCS\#11 module that's not - * configured use p11_kit_module_load() to do so. And use p11_kit_module_release() - * to later release it. - * - * Modules are represented by a pointer to their <code>CK_FUNCTION_LIST</code> - * entry points. - */ - -/** - * SECTION:p11-kit-deprecated - * @title: Deprecated - * @short_description: Deprecated functions - * - * These functions have been deprecated from p11-kit and are not recommended for - * general usage. In large part they were deprecated because they did not adequately - * insulate multiple callers of a PKCS\#11 module from another, and could not - * support the 'managed' mode needed to do this. - */ - -/** - * P11_KIT_MODULE_UNMANAGED: - * - * Module is loaded in non 'managed' mode. This is not recommended, - * disables many features, and prevents coordination between multiple - * callers of the same module. - */ - -/** - * P11_KIT_MODULE_CRITICAL: - * - * Flag to load a module in 'critical' mode. Failure to load a critical module - * will prevent all other modules from loading. A failure when loading a - * non-critical module skips that module. - */ - -typedef struct _Module { - /* - * When using managed modules, this forms the base of the - * virtual stack into which all the other modules call. This is also - * the first field in this structure so we can cast between them. - */ - p11_virtual virt; - - /* The initialize args built from configuration */ - CK_C_INITIALIZE_ARGS init_args; - int ref_count; - int init_count; - - /* Registered modules */ - char *name; - char *filename; - p11_dict *config; - bool critical; - - /* - * This is a pointer to the actual dl shared module, or perhaps - * the RPC client context. - */ - void *loaded_module; - p11_kit_destroyer loaded_destroy; - - /* Initialization, mutex must be held */ - p11_mutex_t initialize_mutex; - unsigned int initialize_called; - p11_thread_id_t initialize_thread; -} Module; - -/* - * Shared data between threads, protected by the mutex, a structure so - * we can audit thread safety easier. - */ -static struct _Shared { - p11_dict *modules; - p11_dict *unmanaged_by_funcs; - p11_dict *managed_by_closure; - p11_dict *config; -} gl = { NULL, NULL }; - -/* These are global variables to be overridden in tests */ -const char *p11_config_system_file = P11_SYSTEM_CONFIG_FILE; -const char *p11_config_user_file = P11_USER_CONFIG_FILE; -const char *p11_config_package_modules = P11_PACKAGE_CONFIG_MODULES; -const char *p11_config_system_modules = P11_SYSTEM_CONFIG_MODULES; -const char *p11_config_user_modules = P11_USER_CONFIG_MODULES; - -/* ----------------------------------------------------------------------------- - * P11-KIT FUNCTIONALITY - */ - -static CK_RV -create_mutex (CK_VOID_PTR_PTR mut) -{ - p11_mutex_t *pmutex; - - return_val_if_fail (mut != NULL, CKR_ARGUMENTS_BAD); - - pmutex = malloc (sizeof (p11_mutex_t)); - return_val_if_fail (pmutex != NULL, CKR_HOST_MEMORY); - - p11_mutex_init (pmutex); - *mut = pmutex; - return CKR_OK; -} - -static CK_RV -destroy_mutex (CK_VOID_PTR mut) -{ - p11_mutex_t *pmutex = mut; - - return_val_if_fail (mut != NULL, CKR_MUTEX_BAD); - - p11_mutex_uninit (pmutex); - free (pmutex); - return CKR_OK; -} - -static CK_RV -lock_mutex (CK_VOID_PTR mut) -{ - p11_mutex_t *pmutex = mut; - - return_val_if_fail (mut != NULL, CKR_MUTEX_BAD); - - p11_mutex_lock (pmutex); - return CKR_OK; -} - -static CK_RV -unlock_mutex (CK_VOID_PTR mut) -{ - p11_mutex_t *pmutex = mut; - - return_val_if_fail (mut != NULL, CKR_MUTEX_BAD); - - p11_mutex_unlock (pmutex); - return CKR_OK; -} - -static void -free_module_unlocked (void *data) -{ - Module *mod = data; - - assert (mod != NULL); - - /* Module must have no outstanding references */ - assert (mod->ref_count == 0); - - if (mod->init_count > 0) { - p11_debug_precond ("module unloaded without C_Finalize having been " - "called for each C_Initialize"); - } else { - assert (mod->initialize_thread == 0); - } - - if (mod->loaded_destroy) - mod->loaded_destroy (mod->loaded_module); - - p11_mutex_uninit (&mod->initialize_mutex); - p11_dict_free (mod->config); - free (mod->name); - free (mod->filename); - free (mod); -} - -static Module * -alloc_module_unlocked (void) -{ - Module *mod; - - mod = calloc (1, sizeof (Module)); - return_val_if_fail (mod != NULL, NULL); - - mod->init_args.CreateMutex = create_mutex; - mod->init_args.DestroyMutex = destroy_mutex; - mod->init_args.LockMutex = lock_mutex; - mod->init_args.UnlockMutex = unlock_mutex; - mod->init_args.flags = CKF_OS_LOCKING_OK; - p11_mutex_init (&mod->initialize_mutex); - - /* - * The default for configured modules is non-critical, but for - * modules loaded explicitly, and not from config, we treat them - * as critical. So this gets overridden for configured modules - * later when the config is loaded. - */ - mod->critical = true; - - return mod; -} - -static CK_RV -dlopen_and_get_function_list (Module *mod, - const char *path, - CK_FUNCTION_LIST **funcs) -{ - CK_C_GetFunctionList gfl; - dl_module_t dl; - char *error; - CK_RV rv; - - assert (mod != NULL); - assert (path != NULL); - assert (funcs != NULL); - - dl = p11_dl_open (path); - if (dl == NULL) { - error = p11_dl_error (); - p11_message ("couldn't load module: %s: %s", path, error); - free (error); - return CKR_GENERAL_ERROR; - } - - /* When the Module goes away, dlclose the loaded module */ - mod->loaded_destroy = (p11_kit_destroyer)p11_dl_close; - mod->loaded_module = dl; - - gfl = p11_dl_symbol (dl, "C_GetFunctionList"); - if (!gfl) { - error = p11_dl_error (); - p11_message ("couldn't find C_GetFunctionList entry point in module: %s: %s", - path, error); - free (error); - return CKR_GENERAL_ERROR; - } - - rv = gfl (funcs); - if (rv != CKR_OK) { - p11_message ("call to C_GetFunctiontList failed in module: %s: %s", - path, p11_kit_strerror (rv)); - return rv; - } - - if (p11_proxy_module_check (*funcs)) { - p11_message ("refusing to load the p11-kit-proxy.so module as a registered module"); - return CKR_FUNCTION_FAILED; - } - - p11_virtual_init (&mod->virt, &p11_virtual_base, *funcs, NULL); - p11_debug ("opened module: %s", path); - return CKR_OK; -} - -static CK_RV -load_module_from_file_inlock (const char *name, - const char *path, - Module **result) -{ - CK_FUNCTION_LIST *funcs; - char *expand = NULL; - Module *mod; - Module *prev; - CK_RV rv; - - assert (path != NULL); - assert (result != NULL); - - mod = alloc_module_unlocked (); - return_val_if_fail (mod != NULL, CKR_HOST_MEMORY); - - if (!p11_path_absolute (path)) { - p11_debug ("module path is relative, loading from: %s", P11_MODULE_PATH); - path = expand = p11_path_build (P11_MODULE_PATH, path, NULL); - return_val_if_fail (path != NULL, CKR_HOST_MEMORY); - } - - p11_debug ("loading module %s%sfrom path: %s", - name ? name : "", name ? " " : "", path); - - mod->filename = strdup (path); - - rv = dlopen_and_get_function_list (mod, path, &funcs); - free (expand); - - if (rv != CKR_OK) { - free_module_unlocked (mod); - return rv; - } - - /* Do we have a previous one like this, if so ignore load */ - prev = p11_dict_get (gl.unmanaged_by_funcs, funcs); - - /* If same module was loaded previously, just take over config */ - if (prev != NULL) { - if (!name || prev->name || prev->config) - p11_debug ("duplicate module %s, using previous", name); - free_module_unlocked (mod); - mod = prev; - - /* This takes ownership of the module */ - } else if (!p11_dict_set (gl.modules, mod, mod) || - !p11_dict_set (gl.unmanaged_by_funcs, funcs, mod)) { - return_val_if_reached (CKR_HOST_MEMORY); - } - - *result= mod; - return CKR_OK; -} - -static CK_RV -setup_module_for_remote_inlock (const char *name, - const char *remote, - Module **result) -{ - p11_rpc_transport *rpc; - Module *mod; - - p11_debug ("remoting module %s using: %s", name, remote); - - mod = alloc_module_unlocked (); - return_val_if_fail (mod != NULL, CKR_HOST_MEMORY); - - rpc = p11_rpc_transport_new (&mod->virt, remote, name); - if (rpc == NULL) { - free_module_unlocked (mod); - return CKR_DEVICE_ERROR; - } - - mod->filename = NULL; - mod->loaded_module = rpc; - mod->loaded_destroy = p11_rpc_transport_free; - - /* This takes ownership of the module */ - if (!p11_dict_set (gl.modules, mod, mod)) - return_val_if_reached (CKR_HOST_MEMORY); - - *result = mod; - return CKR_OK; -} - -static int -is_list_delimiter (char ch) -{ - return ch == ',' || isspace (ch); -} - -static bool -is_string_in_list (const char *list, - const char *string) -{ - const char *where; - - where = strstr (list, string); - if (where == NULL) - return false; - - /* Has to be at beginning/end of string, and delimiter before/after */ - if (where != list && !is_list_delimiter (*(where - 1))) - return false; - - where += strlen (string); - return (*where == '\0' || is_list_delimiter (*where)); -} - -static bool -is_module_enabled_unlocked (const char *name, - p11_dict *config) -{ - const char *progname; - const char *enable_in; - const char *disable_in; - bool enable = false; - - enable_in = p11_dict_get (config, "enable-in"); - disable_in = p11_dict_get (config, "disable-in"); - - /* Defaults to enabled if neither of these are set */ - if (!enable_in && !disable_in) - return true; - - progname = _p11_get_progname_unlocked (); - if (enable_in && disable_in) - p11_message ("module '%s' has both enable-in and disable-in options", name); - if (enable_in) - enable = (progname != NULL && is_string_in_list (enable_in, progname)); - else if (disable_in) - enable = (progname == NULL || !is_string_in_list (disable_in, progname)); - - p11_debug ("%s module '%s' running in '%s'", - enable ? "enabled" : "disabled", - name, - progname ? progname : "(null)"); - return enable; -} - -static CK_RV -take_config_and_load_module_inlock (char **name, - p11_dict **config, - bool critical) -{ - const char *filename = NULL; - const char *remote = NULL; - CK_RV rv = CKR_OK; - Module *mod; - - assert (name); - assert (*name); - assert (config); - assert (*config); - - if (!is_module_enabled_unlocked (*name, *config)) - goto out; - - remote = p11_dict_get (*config, "remote"); - if (remote == NULL) { - filename = p11_dict_get (*config, "module"); - if (filename == NULL) { - p11_debug ("no module path for module, skipping: %s", *name); - goto out; - } - } - - if (remote != NULL) { - rv = setup_module_for_remote_inlock (*name, remote, &mod); - if (rv != CKR_OK) - goto out; - - } else { - - rv = load_module_from_file_inlock (*name, filename, &mod); - if (rv != CKR_OK) - goto out; - } - - /* - * We support setting of CK_C_INITIALIZE_ARGS.pReserved from - * 'x-init-reserved' setting in the config. This only works with specific - * PKCS#11 modules, and is non-standard use of that field. - */ - mod->init_args.pReserved = p11_dict_get (*config, "x-init-reserved"); - - /* Take ownership of thes evariables */ - p11_dict_free (mod->config); - mod->config = *config; - *config = NULL; - free (mod->name); - mod->name = *name; - *name = NULL; - mod->critical = critical; - -out: - return rv; -} - -static CK_RV -load_registered_modules_unlocked (void) -{ - p11_dictiter iter; - p11_dict *configs; - void *key; - char *name; - p11_dict *config; - int mode; - CK_RV rv; - bool critical; - - if (gl.config) - return CKR_OK; - - /* Load the global configuration files */ - config = _p11_conf_load_globals (p11_config_system_file, p11_config_user_file, &mode); - if (config == NULL) - return CKR_GENERAL_ERROR; - - assert (mode != CONF_USER_INVALID); - - configs = _p11_conf_load_modules (mode, - p11_config_package_modules, - p11_config_system_modules, - p11_config_user_modules); - if (configs == NULL) { - rv = CKR_GENERAL_ERROR; - p11_dict_free (config); - return rv; - } - - assert (gl.config == NULL); - gl.config = config; - - /* - * Now go through each config and turn it into a module. As we iterate - * we steal the values of the config. - */ - p11_dict_iterate (configs, &iter); - while (p11_dict_next (&iter, &key, NULL)) { - if (!p11_dict_steal (configs, key, (void**)&name, (void**)&config)) - assert_not_reached (); - - /* Is this a critical module, should abort loading of others? */ - critical = _p11_conf_parse_boolean (p11_dict_get (config, "critical"), false); - rv = take_config_and_load_module_inlock (&name, &config, critical); - - /* - * These variables will be cleared if ownership is transeferred - * by the above function call. - */ - p11_dict_free (config); - - if (critical && rv != CKR_OK) { - p11_message ("aborting initialization because module '%s' was marked as critical", - name); - p11_dict_free (configs); - free (name); - return rv; - } - - free (name); - } - - p11_dict_free (configs); - return CKR_OK; -} - -static CK_RV -initialize_module_inlock_reentrant (Module *mod, CK_C_INITIALIZE_ARGS *init_args) -{ - CK_RV rv = CKR_OK; - p11_thread_id_t self; - - assert (mod); - - self = p11_thread_id_self (); - - if (mod->initialize_thread == self) { - p11_message ("p11-kit initialization called recursively"); - return CKR_FUNCTION_FAILED; - } - - /* - * Increase ref first, so module doesn't get freed out from - * underneath us when the mutex is unlocked below. - */ - ++mod->ref_count; - mod->initialize_thread = self; - - /* Change over to the module specific mutex */ - p11_unlock (); - p11_mutex_lock (&mod->initialize_mutex); - - if (mod->initialize_called != p11_forkid) { - p11_debug ("C_Initialize: calling"); - - /* The init_args argument takes precedence over mod->init_args */ - if (init_args == NULL) - init_args = &mod->init_args; - - rv = mod->virt.funcs.C_Initialize (&mod->virt.funcs, - init_args); - - p11_debug ("C_Initialize: result: %lu", rv); - - /* Module was initialized and C_Finalize should be called */ - if (rv == CKR_OK) - mod->initialize_called = p11_forkid; - else - mod->initialize_called = 0; - - /* Module was already initialized, we don't call C_Finalize */ - if (rv == CKR_CRYPTOKI_ALREADY_INITIALIZED) - rv = CKR_OK; - } - - p11_mutex_unlock (&mod->initialize_mutex); - p11_lock (); - - if (rv == CKR_OK) { - /* Matches the ref count in finalize_module_inlock_reentrant() */ - if (mod->init_count == 0) - mod->ref_count++; - mod->init_count++; - } - - mod->ref_count--; - mod->initialize_thread = 0; - return rv; -} - -static CK_RV -init_globals_unlocked (void) -{ - static bool once = false; - - if (!gl.modules) { - gl.modules = p11_dict_new (p11_dict_direct_hash, - p11_dict_direct_equal, - free_module_unlocked, NULL); - return_val_if_fail (gl.modules != NULL, CKR_HOST_MEMORY); - } - - if (!gl.unmanaged_by_funcs) { - gl.unmanaged_by_funcs = p11_dict_new (p11_dict_direct_hash, - p11_dict_direct_equal, - NULL, NULL); - return_val_if_fail (gl.unmanaged_by_funcs != NULL, CKR_HOST_MEMORY); - } - - if (!gl.managed_by_closure) { - gl.managed_by_closure = p11_dict_new (p11_dict_direct_hash, - p11_dict_direct_equal, - NULL, NULL); - return_val_if_fail (gl.managed_by_closure != NULL, CKR_HOST_MEMORY); - } - - if (once) - return CKR_OK; - - once = true; - - return CKR_OK; -} - -static void -free_modules_when_no_refs_unlocked (void) -{ - Module *mod; - p11_dictiter iter; - - /* Check if any modules have a ref count */ - p11_dict_iterate (gl.modules, &iter); - while (p11_dict_next (&iter, (void **)&mod, NULL)) { - if (mod->ref_count) - return; - } - - p11_dict_free (gl.unmanaged_by_funcs); - gl.unmanaged_by_funcs = NULL; - - p11_dict_free (gl.managed_by_closure); - gl.managed_by_closure = NULL; - - p11_dict_free (gl.modules); - gl.modules = NULL; - - p11_dict_free (gl.config); - gl.config = NULL; -} - -static CK_RV -finalize_module_inlock_reentrant (Module *mod) -{ - assert (mod); - - /* - * We leave module info around until all are finalized - * so we can encounter these zombie Module structures. - */ - if (mod->ref_count == 0) - return CKR_ARGUMENTS_BAD; - - if (--mod->init_count > 0) - return CKR_OK; - - /* - * Because of the mutex unlock below, we temporarily increase - * the ref count. This prevents module from being freed out - * from ounder us. - */ - - p11_unlock (); - p11_mutex_lock (&mod->initialize_mutex); - - if (mod->initialize_called == p11_forkid) { - mod->virt.funcs.C_Finalize (&mod->virt.funcs, NULL); - mod->initialize_called = 0; - } - - p11_mutex_unlock (&mod->initialize_mutex); - p11_lock (); - - /* Match the ref increment in initialize_module_inlock_reentrant() */ - mod->ref_count--; - - free_modules_when_no_refs_unlocked (); - return CKR_OK; -} - -static CK_RV -initialize_registered_inlock_reentrant (void) -{ - p11_dictiter iter; - Module *mod; - CK_RV rv; - - /* - * This is only called by deprecated code. The caller expects all - * configured and enabled modules to be initialized. - */ - - rv = init_globals_unlocked (); - if (rv != CKR_OK) - return rv; - - rv = load_registered_modules_unlocked (); - if (rv == CKR_OK) { - p11_dict_iterate (gl.unmanaged_by_funcs, &iter); - while (rv == CKR_OK && p11_dict_next (&iter, NULL, (void **)&mod)) { - - /* Skip all modules that aren't registered or enabled */ - if (mod->name == NULL || !is_module_enabled_unlocked (mod->name, mod->config)) - continue; - - rv = initialize_module_inlock_reentrant (mod, NULL); - if (rv != CKR_OK) { - if (mod->critical) { - p11_message ("initialization of critical module '%s' failed: %s", - mod->name, p11_kit_strerror (rv)); - } else { - p11_message ("skipping module '%s' whose initialization failed: %s", - mod->name, p11_kit_strerror (rv)); - rv = CKR_OK; - } - } - } - } - - return rv; -} - -static Module * -module_for_functions_inlock (CK_FUNCTION_LIST *funcs) -{ - if (p11_virtual_is_wrapper (funcs)) - return p11_dict_get (gl.managed_by_closure, funcs); - else - return p11_dict_get (gl.unmanaged_by_funcs, funcs); -} - -static CK_FUNCTION_LIST * -unmanaged_for_module_inlock (Module *mod) -{ - CK_FUNCTION_LIST *funcs; - - funcs = mod->virt.lower_module; - if (p11_dict_get (gl.unmanaged_by_funcs, funcs) == mod) - return funcs; - - return NULL; -} - -/** - * p11_kit_initialize_registered: - * - * Initialize all the registered PKCS\#11 modules. - * - * If this is the first time this function is called multiple times - * consecutively within a single process, then it merely increments an - * initialization reference count for each of these modules. - * - * Use p11_kit_finalize_registered() to finalize these registered modules once - * the caller is done with them. - * - * If this function fails, then an error message will be available via the - * p11_kit_message() function. - * - * Deprecated: Since: 0.19.0: Use p11_kit_modules_load() instead. - * - * Returns: CKR_OK if the initialization succeeded, or an error code. - */ -CK_RV -p11_kit_initialize_registered (void) -{ - CK_RV rv; - - p11_library_init_once (); - - /* WARNING: This function must be reentrant */ - p11_debug ("in"); - - p11_lock (); - - p11_message_clear (); - - /* WARNING: Reentrancy can occur here */ - rv = initialize_registered_inlock_reentrant (); - - _p11_kit_default_message (rv); - - p11_unlock (); - - /* Cleanup any partial initialization */ - if (rv != CKR_OK) - p11_kit_finalize_registered (); - - p11_debug ("out: %lu", rv); - return rv; -} - -static CK_RV -finalize_registered_inlock_reentrant (void) -{ - Module *mod; - p11_dictiter iter; - Module **to_finalize; - int i, count; - - /* - * This is only called from deprecated code. The caller expects all - * modules initialized earlier to be finalized (once). If non-critical - * modules failed to initialize, then it is not possible to completely - * guarantee the internal state. - */ - - if (!gl.modules) - return CKR_CRYPTOKI_NOT_INITIALIZED; - - /* WARNING: This function must be reentrant */ - - to_finalize = calloc (p11_dict_size (gl.unmanaged_by_funcs), sizeof (Module *)); - if (!to_finalize) - return CKR_HOST_MEMORY; - - count = 0; - p11_dict_iterate (gl.unmanaged_by_funcs, &iter); - while (p11_dict_next (&iter, NULL, (void **)&mod)) { - - /* Skip all modules that aren't registered */ - if (mod->name && mod->init_count) - to_finalize[count++] = mod; - } - - p11_debug ("finalizing %d modules", count); - - for (i = 0; i < count; ++i) { - /* WARNING: Reentrant calls can occur here */ - finalize_module_inlock_reentrant (to_finalize[i]); - } - - free (to_finalize); - - /* In case nothing loaded, free up internal memory */ - if (count == 0) - free_modules_when_no_refs_unlocked (); - - return CKR_OK; -} - -/** - * p11_kit_finalize_registered: - * - * Finalize all the registered PKCS\#11 modules. These should have been - * initialized with p11_kit_initialize_registered(). - * - * If p11_kit_initialize_registered() has been called more than once in this - * process, then this function must be called the same number of times before - * actual finalization will occur. - * - * If this function fails, then an error message will be available via the - * p11_kit_message() function. - * - * Deprecated: Since 0.19.0: Use p11_kit_modules_release() instead. - * - * Returns: CKR_OK if the finalization succeeded, or an error code. - */ - -CK_RV -p11_kit_finalize_registered (void) -{ - CK_RV rv; - - p11_library_init_once (); - - /* WARNING: This function must be reentrant */ - p11_debug ("in"); - - p11_lock (); - - p11_message_clear (); - - /* WARNING: Reentrant calls can occur here */ - rv = finalize_registered_inlock_reentrant (); - - _p11_kit_default_message (rv); - - p11_unlock (); - - p11_debug ("out: %lu", rv); - return rv; -} - -static int -compar_priority (const void *one, - const void *two) -{ - CK_FUNCTION_LIST_PTR f1 = *((CK_FUNCTION_LIST_PTR *)one); - CK_FUNCTION_LIST_PTR f2 = *((CK_FUNCTION_LIST_PTR *)two); - Module *m1, *m2; - const char *v1, *v2; - int o1, o2; - - m1 = module_for_functions_inlock (f1); - m2 = module_for_functions_inlock (f2); - assert (m1 != NULL && m2 != NULL); - - v1 = p11_dict_get (m1->config, "priority"); - v2 = p11_dict_get (m2->config, "priority"); - - o1 = atoi (v1 ? v1 : "0"); - o2 = atoi (v2 ? v2 : "0"); - - /* Priority is in descending order, highest first */ - if (o1 != o2) - return o1 > o2 ? -1 : 1; - - /* - * Otherwise use the names alphabetically in ascending order. This - * is really just to provide consistency between various loads of - * the configuration. - */ - if (m1->name == m2->name) - return 0; - if (!m1->name) - return -1; - if (!m2->name) - return 1; - return strcmp (m1->name, m2->name); -} - -static void -sort_modules_by_priority (CK_FUNCTION_LIST_PTR *modules, - int count) -{ - qsort (modules, count, sizeof (CK_FUNCTION_LIST_PTR), compar_priority); -} - -static CK_FUNCTION_LIST ** -list_registered_modules_inlock (void) -{ - CK_FUNCTION_LIST **result = NULL; - CK_FUNCTION_LIST *funcs; - Module *mod; - p11_dictiter iter; - int i = 0; - - /* - * This is only called by deprecated code. The caller expects to get - * a list of all registered enabled modules that have been initialized. - */ - - if (gl.unmanaged_by_funcs) { - result = calloc (p11_dict_size (gl.unmanaged_by_funcs) + 1, - sizeof (CK_FUNCTION_LIST *)); - return_val_if_fail (result != NULL, NULL); - - p11_dict_iterate (gl.unmanaged_by_funcs, &iter); - while (p11_dict_next (&iter, (void **)&funcs, (void **)&mod)) { - - /* - * We don't include unreferenced modules. We don't include - * modules that have been initialized but aren't in the - * registry. These have a NULL name. - * - * In addition we check again that the module isn't disabled - * using enable-in or disable-in. This is because a caller - * can change the progname we recognize the process as after - * having initialized. This is a corner case, but want to make - * sure to cover it. - */ - if (mod->ref_count && mod->name && mod->init_count && - is_module_enabled_unlocked (mod->name, mod->config)) { - result[i++] = funcs; - } - } - - sort_modules_by_priority (result, i); - } - - return result; -} - -/** - * p11_kit_registered_modules: - * - * Get a list of all the registered PKCS\#11 modules. This list will be valid - * once the p11_kit_initialize_registered() function has been called. - * - * The returned value is a <code>NULL</code> terminated array of - * <code>CK_FUNCTION_LIST_PTR</code> pointers. - * - * The returned modules are unmanaged. - * - * Deprecated: Since 0.19.0: Use p11_kit_modules_load() instead. - * - * Returns: A list of all the registered modules. Use the free() function to - * free the list. - */ -CK_FUNCTION_LIST_PTR_PTR -p11_kit_registered_modules (void) -{ - CK_FUNCTION_LIST_PTR_PTR result; - - p11_library_init_once (); - - p11_lock (); - - p11_message_clear (); - - result = list_registered_modules_inlock (); - - p11_unlock (); - - return result; -} - -/** - * p11_kit_registered_module_to_name: - * @module: pointer to a registered module - * - * Get the name of a registered PKCS\#11 module. - * - * You can use p11_kit_registered_modules() to get a list of all the registered - * modules. This name is specified by the registered module configuration. - * - * Deprecated: Since 0.19.0: Use p11_kit_module_get_name() instead. - * - * Returns: A newly allocated string containing the module name, or - * <code>NULL</code> if no such registered module exists. Use free() to - * free this string. - */ -char* -p11_kit_registered_module_to_name (CK_FUNCTION_LIST_PTR module) -{ - return_val_if_fail (module != NULL, NULL); - return p11_kit_module_get_name (module); -} - -/** - * p11_kit_module_get_name: - * @module: pointer to a loaded module - * - * Get the configured name of the PKCS\#11 module. - * - * Configured modules are loaded by p11_kit_modules_load(). The module - * passed to this function can be either managed or unmanaged. Non - * configured modules will return %NULL. - * - * Use free() to release the return value when you're done with it. - * - * Returns: a newly allocated string containing the module name, or - * <code>NULL</code> if the module is not a configured module - */ -char * -p11_kit_module_get_name (CK_FUNCTION_LIST *module) -{ - Module *mod; - char *name = NULL; - - return_val_if_fail (module != NULL, NULL); - - p11_library_init_once (); - - p11_lock (); - - p11_message_clear (); - - if (gl.modules) { - mod = module_for_functions_inlock (module); - if (mod && mod->name) - name = strdup (mod->name); - } - - p11_unlock (); - - return name; -} - -/** - * p11_kit_module_get_filename: - * @module: pointer to a loaded module - * - * Get the configured name of the PKCS\#11 module. - * - * Configured modules are loaded by p11_kit_modules_load(). The module - * passed to this function can be either managed or unmanaged. Non - * configured modules will return %NULL. - * - * Use free() to release the return value when you're done with it. - * - * Returns: a newly allocated string containing the module name, or - * <code>NULL</code> if the module is not a configured module - */ -char * -p11_kit_module_get_filename (CK_FUNCTION_LIST *module) -{ - Module *mod; - char *name = NULL; - - return_val_if_fail (module != NULL, NULL); - - p11_library_init_once (); - - p11_lock (); - - p11_message_clear (); - - if (gl.modules) { - mod = module_for_functions_inlock (module); - if (mod && mod->filename) - name = strdup (mod->filename); - } - - p11_unlock (); - - return name; -} - -static const char * -module_get_option_inlock (Module *mod, - const char *option) -{ - p11_dict *config; - - if (mod == NULL) - config = gl.config; - else - config = mod->config; - if (config == NULL) - return NULL; - return p11_dict_get (config, option); -} - -/** - * p11_kit_module_get_flags: - * @module: the module - * - * Get the flags for this module. - * - * The %P11_KIT_MODULE_UNMANAGED flag will be set if the module is not - * managed by p11-kit. It is a raw PKCS\#11 module function list. - * - * The %P11_KIT_MODULE_CRITICAL flag will be set if the module is configured - * to be critical, and not be skipped over if it fails to initialize or - * load. This flag is also set for modules that are not configured, but have - * been loaded in another fashion. - * - * Returns: the flags for the module - */ -int -p11_kit_module_get_flags (CK_FUNCTION_LIST *module) -{ - const char *trusted; - Module *mod; - int flags = 0; - - return_val_if_fail (module != NULL, 0); - - p11_library_init_once (); - - p11_lock (); - - p11_message_clear (); - - if (gl.modules) { - if (p11_virtual_is_wrapper (module)) { - mod = p11_dict_get (gl.managed_by_closure, module); - } else { - flags |= P11_KIT_MODULE_UNMANAGED; - mod = p11_dict_get (gl.unmanaged_by_funcs, module); - } - if (!mod || mod->critical) - flags |= P11_KIT_MODULE_CRITICAL; - if (mod) { - trusted = module_get_option_inlock (mod, "trust-policy"); - if (_p11_conf_parse_boolean (trusted, false)) - flags |= P11_KIT_MODULE_TRUSTED; - } - } - - p11_unlock (); - - return flags; -} - -/** - * p11_kit_registered_name_to_module: - * @name: name of a registered module - * - * Lookup a registered PKCS\#11 module by its name. This name is specified by - * the registered module configuration. - * - * Deprecated: Since 0.19.0: Use p11_kit_module_for_name() instead. - * - * Returns: a pointer to a PKCS\#11 module, or <code>NULL</code> if this name was - * not found. - */ -CK_FUNCTION_LIST_PTR -p11_kit_registered_name_to_module (const char *name) -{ - CK_FUNCTION_LIST_PTR module = NULL; - CK_FUNCTION_LIST_PTR funcs; - p11_dictiter iter; - Module *mod; - - return_val_if_fail (name != NULL, NULL); - - p11_lock (); - - p11_message_clear (); - - if (gl.modules) { - - assert (name); - - p11_dict_iterate (gl.unmanaged_by_funcs, &iter); - while (p11_dict_next (&iter, (void **)&funcs, (void **)&mod)) { - if (mod->ref_count && mod->name && strcmp (name, mod->name) == 0) { - module = funcs; - break; - } - } - } - - p11_unlock (); - - return module; -} - -/** - * p11_kit_module_for_name: - * @modules: a list of modules to look through - * @name: the name of the module to find - * - * Look through the list of @modules and return the module whose @name - * matches. - * - * Only configured modules have names. Configured modules are loaded by - * p11_kit_modules_load(). The module passed to this function can be either - * managed or unmanaged. - * - * The return value is not copied or duplicated in anyway. It is still - * 'owned' by the @modules list. - * - * Returns: the module which matches the name, or %NULL if no match. - */ -CK_FUNCTION_LIST * -p11_kit_module_for_name (CK_FUNCTION_LIST **modules, - const char *name) -{ - CK_FUNCTION_LIST *ret = NULL; - Module *mod; - int i; - - return_val_if_fail (name != NULL, NULL); - - if (!modules) - return NULL; - - p11_library_init_once (); - - p11_lock (); - - p11_message_clear (); - - for (i = 0; gl.modules && modules[i] != NULL; i++) { - mod = module_for_functions_inlock (modules[i]); - if (mod && mod->name && strcmp (mod->name, name) == 0) { - ret = modules[i]; - break; - } - } - - p11_unlock (); - - return ret; -} - -/** - * p11_kit_registered_option: - * @module: a pointer to a registered module - * @field: the name of the option to lookup. - * - * Lookup a configured option for a registered PKCS\#11 module. If a - * <code>NULL</code> module argument is specified, then this will lookup - * the configuration option in the global config file. - * - * Deprecated: Since 0.19.0: Use p11_kit_config_option() instead. - * - * Returns: A newly allocated string containing the option value, or - * <code>NULL</code> if the registered module or the option were not found. - * Use free() to free the returned string. - */ -char* -p11_kit_registered_option (CK_FUNCTION_LIST_PTR module, const char *field) -{ - Module *mod = NULL; - char *option = NULL; - const char *value; - - return_val_if_fail (field != NULL, NULL); - - p11_library_init_once (); - - p11_lock (); - - p11_message_clear (); - - if (module == NULL) - mod = NULL; - else - mod = gl.unmanaged_by_funcs ? p11_dict_get (gl.unmanaged_by_funcs, module) : NULL; - - value = module_get_option_inlock (mod, field); - if (value) - option = strdup (value); - - p11_unlock (); - - return option; -} - -/** - * p11_kit_config_option: - * @module: the module to retrieve the option for, or %NULL for global options - * @option: the option to retrieve - * - * Retrieve the value for a configured option. - * - * If @module is %NULL, then the global option with the given name will - * be retrieved. Otherwise @module should point to a configured loaded module. - * If no such @option or configured @module exists, then %NULL will be returned. - * - * Use free() to release the returned value. - * - * Returns: the option value or %NULL - */ -char * -p11_kit_config_option (CK_FUNCTION_LIST *module, - const char *option) -{ - Module *mod = NULL; - const char *value = NULL; - char *ret = NULL; - - return_val_if_fail (option != NULL, NULL); - - p11_library_init_once (); - - p11_lock (); - - p11_message_clear (); - - if (gl.modules) { - if (module != NULL) { - mod = module_for_functions_inlock (module); - if (mod == NULL) - goto cleanup; - } - - value = module_get_option_inlock (mod, option); - if (value) - ret = strdup (value); - } - - -cleanup: - p11_unlock (); - return ret; -} - -typedef struct { - p11_virtual virt; - Module *mod; - unsigned int initialized; - p11_dict *sessions; -} Managed; - -static CK_RV -managed_C_Initialize (CK_X_FUNCTION_LIST *self, - CK_VOID_PTR init_args) -{ - Managed *managed = ((Managed *)self); - p11_dict *sessions; - CK_RV rv; - - p11_debug ("in"); - p11_lock (); - - if (managed->initialized == p11_forkid) { - rv = CKR_CRYPTOKI_ALREADY_INITIALIZED; - - } else { - sessions = p11_dict_new (p11_dict_ulongptr_hash, - p11_dict_ulongptr_equal, - free, free); - if (!sessions) - rv = CKR_HOST_MEMORY; - else - rv = initialize_module_inlock_reentrant (managed->mod, init_args); - if (rv == CKR_OK) { - if (managed->sessions) - p11_dict_free (managed->sessions); - managed->sessions = sessions; - managed->initialized = p11_forkid; - } else { - p11_dict_free (sessions); - } - } - - p11_unlock (); - p11_debug ("out: %lu", rv); - - return rv; -} - -static CK_RV -managed_track_session_inlock (p11_dict *sessions, - CK_SLOT_ID slot_id, - CK_SESSION_HANDLE session) -{ - void *key; - void *value; - - key = memdup (&session, sizeof (CK_SESSION_HANDLE)); - return_val_if_fail (key != NULL, CKR_HOST_MEMORY); - - value = memdup (&slot_id, sizeof (CK_SESSION_HANDLE)); - return_val_if_fail (value != NULL, CKR_HOST_MEMORY); - - if (!p11_dict_set (sessions, key, value)) - return_val_if_reached (CKR_HOST_MEMORY); - - return CKR_OK; -} - -static void -managed_untrack_session_inlock (p11_dict *sessions, - CK_SESSION_HANDLE session) -{ - p11_dict_remove (sessions, &session); -} - -static CK_SESSION_HANDLE * -managed_steal_sessions_inlock (p11_dict *sessions, - bool matching_slot_id, - CK_SLOT_ID slot_id, - int *count) -{ - CK_SESSION_HANDLE *stolen; - CK_SESSION_HANDLE *key; - CK_SLOT_ID *value; - p11_dictiter iter; - int at, i; - - assert (sessions != NULL); - assert (count != NULL); - - stolen = calloc (p11_dict_size (sessions), sizeof (CK_SESSION_HANDLE)); - return_val_if_fail (stolen != NULL, NULL); - - at = 0; - p11_dict_iterate (sessions, &iter); - while (p11_dict_next (&iter, (void **)&key, (void **)&value)) { - if (!matching_slot_id || slot_id == *value) - stolen[at++] = *key; - } - - /* Removed them all, clear the whole array */ - if (at == p11_dict_size (sessions)) { - p11_dict_clear (sessions); - - /* Only removed some, go through and remove those */ - } else { - for (i = 0; i < at; i++) { - if (!p11_dict_remove (sessions, stolen + at)) - assert_not_reached (); - } - } - - *count = at; - return stolen; -} - -static void -managed_close_sessions (CK_X_FUNCTION_LIST *funcs, - CK_SESSION_HANDLE *stolen, - int count) -{ - CK_RV rv; - int i; - - for (i = 0; i < count; i++) { - rv = funcs->C_CloseSession (funcs, stolen[i]); - if (rv != CKR_OK) - p11_message ("couldn't close session: %s", p11_kit_strerror (rv)); - } -} - -static CK_RV -managed_C_Finalize (CK_X_FUNCTION_LIST *self, - CK_VOID_PTR reserved) -{ - Managed *managed = ((Managed *)self); - CK_SESSION_HANDLE *sessions; - int count; - CK_RV rv; - - p11_debug ("in"); - p11_lock (); - - if (managed->initialized == 0) { - rv = CKR_CRYPTOKI_NOT_INITIALIZED; - - } else if (managed->initialized != p11_forkid) { - /* - * In theory we should be returning CKR_CRYPTOKI_NOT_INITIALIZED here - * but enough callers are not completely aware of their forking. - * So we just clean up any state we have, rather than forcing callers - * to initialize just to finalize. - */ - p11_debug ("finalizing module in wrong process, skipping C_Finalize"); - rv = CKR_OK; - - } else { - sessions = managed_steal_sessions_inlock (managed->sessions, false, 0, &count); - - if (sessions && count) { - /* WARNING: reentrancy can occur here */ - p11_unlock (); - managed_close_sessions (&managed->mod->virt.funcs, sessions, count); - p11_lock (); - } - - free (sessions); - - /* WARNING: reentrancy can occur here */ - rv = finalize_module_inlock_reentrant (managed->mod); - } - - if (rv == CKR_OK) { - managed->initialized = 0; - p11_dict_free (managed->sessions); - managed->sessions = NULL; - } - - p11_unlock (); - p11_debug ("out: %lu", rv); - - return rv; -} - -static CK_RV -managed_C_OpenSession (CK_X_FUNCTION_LIST *self, - CK_SLOT_ID slot_id, - CK_FLAGS flags, - CK_VOID_PTR application, - CK_NOTIFY notify, - CK_SESSION_HANDLE_PTR session) -{ - Managed *managed = ((Managed *)self); - CK_RV rv; - - return_val_if_fail (session != NULL, CKR_ARGUMENTS_BAD); - - self = &managed->mod->virt.funcs; - rv = self->C_OpenSession (self, slot_id, flags, application, notify, session); - - if (rv == CKR_OK) { - p11_lock (); - rv = managed_track_session_inlock (managed->sessions, slot_id, *session); - p11_unlock (); - } - - return rv; -} - -static CK_RV -managed_C_CloseSession (CK_X_FUNCTION_LIST *self, - CK_SESSION_HANDLE session) -{ - Managed *managed = ((Managed *)self); - CK_RV rv; - - self = &managed->mod->virt.funcs; - rv = self->C_CloseSession (self, session); - - if (rv == CKR_OK) { - p11_lock (); - managed_untrack_session_inlock (managed->sessions, session); - p11_unlock (); - } - - return rv; -} - -static CK_RV -managed_C_CloseAllSessions (CK_X_FUNCTION_LIST *self, - CK_SLOT_ID slot_id) -{ - Managed *managed = ((Managed *)self); - CK_SESSION_HANDLE *stolen; - int count; - - p11_lock (); - stolen = managed_steal_sessions_inlock (managed->sessions, true, slot_id, &count); - p11_unlock (); - - self = &managed->mod->virt.funcs; - managed_close_sessions (self, stolen, count); - if (stolen) { - free (stolen); - return CKR_OK; - } else { - return CKR_GENERAL_ERROR; - } - -} - -static void -managed_free_inlock (void *data) -{ - Managed *managed = data; - managed->mod->ref_count--; - free (managed); -} - -static p11_virtual * -managed_create_inlock (Module *mod) -{ - Managed *managed; - - managed = calloc (1, sizeof (Managed)); - return_val_if_fail (managed != NULL, NULL); - - p11_virtual_init (&managed->virt, &p11_virtual_stack, - &mod->virt, NULL); - managed->virt.funcs.C_Initialize = managed_C_Initialize; - managed->virt.funcs.C_Finalize = managed_C_Finalize; - managed->virt.funcs.C_CloseAllSessions = managed_C_CloseAllSessions; - managed->virt.funcs.C_CloseSession = managed_C_CloseSession; - managed->virt.funcs.C_OpenSession = managed_C_OpenSession; - managed->mod = mod; - mod->ref_count++; - - return &managed->virt; -} - -static bool -lookup_managed_option (Module *mod, - bool supported, - const char *option, - bool def_value) -{ - const char *string; - bool value; - - string = module_get_option_inlock (NULL, option); - if (!string) - string = module_get_option_inlock (mod, option); - if (!string) { - if (!supported) - return false; - return def_value; - } - - value = _p11_conf_parse_boolean (string, def_value); - - if (!supported && value != supported) { - 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; - } - - return value; -} - -static CK_RV -release_module_inlock_rentrant (CK_FUNCTION_LIST *module, - const char *caller_func) -{ - Module *mod; - - assert (module != NULL); - - /* See if a managed module, and finalize if so */ - if (p11_virtual_is_wrapper (module)) { - mod = p11_dict_get (gl.managed_by_closure, module); - if (mod != NULL) { - if (!p11_dict_remove (gl.managed_by_closure, module)) - assert_not_reached (); - p11_virtual_unwrap (module); - } - - /* If an unmanaged module then caller should have finalized */ - } else { - mod = p11_dict_get (gl.unmanaged_by_funcs, module); - } - - if (mod == NULL) { - p11_debug_precond ("invalid module pointer passed to %s", caller_func); - return CKR_ARGUMENTS_BAD; - } - - /* Matches the ref in prepare_module_inlock_reentrant() */ - mod->ref_count--; - return CKR_OK; -} - -CK_RV -p11_modules_release_inlock_reentrant (CK_FUNCTION_LIST **modules) -{ - CK_RV ret = CKR_OK; - CK_RV rv; - int i; - - for (i = 0; modules[i] != NULL; i++) { - rv = release_module_inlock_rentrant (modules[i], __PRETTY_FUNCTION__); - if (rv != CKR_OK) - ret = rv; - } - - free (modules); - - /* In case nothing loaded, free up internal memory */ - free_modules_when_no_refs_unlocked (); - - return ret; -} - -static CK_RV -prepare_module_inlock_reentrant (Module *mod, - int flags, - CK_FUNCTION_LIST **module) -{ - p11_destroyer destroyer; - const char *trusted; - p11_virtual *virt; - bool is_managed; - bool with_log; - - assert (module != NULL); - - if (flags & P11_KIT_MODULE_TRUSTED) { - trusted = module_get_option_inlock (mod, "trust-policy"); - if (!_p11_conf_parse_boolean (trusted, false)) - return CKR_FUNCTION_NOT_SUPPORTED; - } - - if (flags & P11_KIT_MODULE_UNMANAGED) { - is_managed = false; - with_log = false; - } else { - is_managed = lookup_managed_option (mod, p11_virtual_can_wrap (), "managed", true); - with_log = lookup_managed_option (mod, is_managed, "log-calls", false); - } - - if (is_managed) { - virt = managed_create_inlock (mod); - return_val_if_fail (virt != NULL, CKR_HOST_MEMORY); - destroyer = managed_free_inlock; - - /* Add the logger if configured */ - if (p11_log_force || with_log) { - virt = p11_log_subclass (virt, destroyer); - destroyer = p11_log_release; - } - - *module = p11_virtual_wrap (virt, destroyer); - return_val_if_fail (*module != NULL, CKR_GENERAL_ERROR); - - if (!p11_dict_set (gl.managed_by_closure, *module, mod)) - return_val_if_reached (CKR_HOST_MEMORY); - - } else { - *module = unmanaged_for_module_inlock (mod); - if (*module == NULL) - return CKR_FUNCTION_NOT_SUPPORTED; - } - - /* Matches the deref in release_module_inlock_rentrant() */ - mod->ref_count++; - return CKR_OK; -} - -CK_RV -p11_modules_load_inlock_reentrant (int flags, - CK_FUNCTION_LIST ***results) -{ - CK_FUNCTION_LIST **modules; - Module *mod; - p11_dictiter iter; - CK_RV rv; - int at; - - rv = init_globals_unlocked (); - if (rv != CKR_OK) - return rv; - - rv = load_registered_modules_unlocked (); - if (rv != CKR_OK) - return rv; - - modules = calloc (p11_dict_size (gl.modules) + 1, sizeof (CK_FUNCTION_LIST *)); - return_val_if_fail (modules != NULL, CKR_HOST_MEMORY); - - at = 0; - rv = CKR_OK; - - p11_dict_iterate (gl.modules, &iter); - while (p11_dict_next (&iter, NULL, (void **)&mod)) { - - /* - * We don't include unreferenced modules. We don't include - * modules that have been initialized but aren't in the - * registry. These have a NULL name. - * - * In addition we check again that the module isn't disabled - * using enable-in or disable-in. This is because a caller - * can change the progname we recognize the process as after - * having initialized. This is a corner case, but want to make - * sure to cover it. - */ - if (!mod->name || !is_module_enabled_unlocked (mod->name, mod->config)) - continue; - - rv = prepare_module_inlock_reentrant (mod, flags, modules + at); - if (rv == CKR_OK) - at++; - else if (rv == CKR_FUNCTION_NOT_SUPPORTED) - rv = CKR_OK; - else - break; - } - - modules[at] = NULL; - - if (rv != CKR_OK) { - p11_modules_release_inlock_reentrant (modules); - return rv; - } - - sort_modules_by_priority (modules, at); - *results = modules; - return CKR_OK; -} - -/** - * p11_kit_modules_load: - * @reserved: set to %NULL - * @flags: flags to use to load the module - * - * Load the configured PKCS\#11 modules. - * - * If @flags contains the %P11_KIT_MODULE_UNMANAGED flag, then the - * modules will be not be loaded in 'managed' mode regardless of its - * configuration. This is not recommended for general usage. - * - * If @flags contains the %P11_KIT_MODULE_CRITICAL flag then the - * modules will all be treated as 'critical', regardless of the module - * configuration. This means that a failure to load any module will - * cause this function to fail. - * - * For unmanaged modules there is no guarantee to the state of the - * modules. Other callers may be using the modules. Using unmanaged - * modules haphazardly is not recommended for this reason. Some - * modules (such as those configured with RPC) cannot be loaded in - * unmanaged mode, and will be skipped. - * - * Use p11_kit_modules_release() to release the modules returned by - * this function. - * - * If this function fails, then an error message will be available via the - * p11_kit_message() function. - * - * Returns: a null terminated list of modules represented as PKCS\#11 - * function lists, or %NULL on failure - */ -CK_FUNCTION_LIST ** -p11_kit_modules_load (const char *reserved, - int flags) -{ - CK_FUNCTION_LIST **modules; - CK_RV rv; - - /* progname attribute not implemented yet */ - return_val_if_fail (reserved == NULL, NULL); - - p11_library_init_once (); - - /* WARNING: This function must be reentrant */ - p11_debug ("in"); - - p11_lock (); - - p11_message_clear (); - - /* WARNING: Reentrancy can occur here */ - rv = p11_modules_load_inlock_reentrant (flags, &modules); - - p11_unlock (); - - if (rv != CKR_OK) - modules = NULL; - - p11_debug ("out: %s", modules ? "success" : "fail"); - return modules; -} - -/** - * p11_kit_modules_initialize: - * @modules: a %NULL terminated list of modules - * @failure_callback: called with modules that fail to initialize - * - * Initialize all the modules in the @modules list by calling their - * <literal>C_Initialize</literal> function. - * - * For managed modules the <literal>C_Initialize</literal> function - * is overridden so that multiple callers can initialize the same - * modules. In addition for managed modules multiple callers can - * initialize from different threads, and still guarantee consistent - * thread-safe behavior. - * - * For unmanaged modules if multiple callers try to initialize - * a module, then one of the calls will return - * <literal>CKR_CRYPTOKI_ALREADY_INITIALIZED</literal> according to the - * PKCS\#11 specification. In addition there are no guarantees that - * thread-safe behavior will occur if multiple callers initialize from - * different threads. - * - * When a module fails to initialize it is removed from the @modules list. - * If the @failure_callback is not %NULL then it is called with the modules that - * fail to initialize. For example, you may pass p11_kit_module_release() - * as a @failure_callback if the @modules list was loaded wit p11_kit_modules_load(). - * - * The return value will return the failure code of the last critical - * module that failed to initialize. Non-critical module failures do not affect - * the return value. If no critical modules failed to initialize then the - * return value will be <literal>CKR_OK</literal>. - * - * When modules are removed, the list will be %NULL terminated at the - * appropriate place so it can continue to be used as a modules list. - * - * This function does not accept a <code>CK_C_INITIALIZE_ARGS</code> argument. - * Custom initialization arguments cannot be supported when multiple consumers - * load the same module. - * - * Returns: <literal>CKR_OK</literal> or the failure code of the last critical - * module that failed to initialize. - */ -CK_RV -p11_kit_modules_initialize (CK_FUNCTION_LIST **modules, - p11_kit_destroyer failure_callback) -{ - CK_RV ret = CKR_OK; - CK_RV rv; - bool critical; - char *name; - int i, out; - - return_val_if_fail (modules != NULL, CKR_ARGUMENTS_BAD); - - for (i = 0, out = 0; modules[i] != NULL; i++, out++) { - rv = modules[i]->C_Initialize (NULL); - if (rv != CKR_OK) { - name = p11_kit_module_get_name (modules[i]); - if (name == NULL) - name = strdup ("(unknown)"); - return_val_if_fail (name != NULL, CKR_HOST_MEMORY); - critical = (p11_kit_module_get_flags (modules[i]) & P11_KIT_MODULE_CRITICAL); - p11_message ("%s: module failed to initialize%s: %s", - name, critical ? "" : ", skipping", p11_kit_strerror (rv)); - if (critical) - ret = rv; - if (failure_callback) - failure_callback (modules[i]); - out--; - free (name); - } else { - modules[out] = modules[i]; - } - } - - /* NULL terminate after above changes */ - modules[out] = NULL; - return ret; -} - -/** - * p11_kit_modules_load_and_initialize: - * @flags: flags to use to load the modules - * - * Load and initialize configured modules. - * - * If a critical module fails to load or initialize then the function will - * return <literal>NULL</literal>. Non-critical modules will be skipped - * and not included in the returned module list. - * - * Use p11_kit_modules_finalize_and_release() when you're done with the - * modules returned by this function. - * - * Returns: a <literal>NULL</literal> terminated list of modules, or - * <literal>NULL</literal> on failure - */ -CK_FUNCTION_LIST ** -p11_kit_modules_load_and_initialize (int flags) -{ - CK_FUNCTION_LIST **modules; - CK_RV rv; - - modules = p11_kit_modules_load (NULL, flags); - if (modules == NULL) - return NULL; - - rv = p11_kit_modules_initialize (modules, (p11_destroyer)p11_kit_module_release); - if (rv != CKR_OK) { - p11_kit_modules_release (modules); - modules = NULL; - } - - return modules; -} - -/** - * p11_kit_modules_finalize: - * @modules: a <literal>NULL</literal> terminated list of modules - * - * Finalize each module in the @modules list by calling its - * <literal>C_Finalize</literal> function. Regardless of failures, all - * @modules will have their <literal>C_Finalize</literal> function called. - * - * If a module returns a failure from its <literal>C_Finalize</literal> - * method it will be returned. If multiple modules fail, the last failure - * will be returned. - * - * For managed modules the <literal>C_Finalize</literal> function - * is overridden so that multiple callers can finalize the same - * modules. In addition for managed modules multiple callers can - * finalize from different threads, and still guarantee consistent - * thread-safe behavior. - * - * For unmanaged modules if multiple callers try to finalize - * a module, then one of the calls will return - * <literal>CKR_CRYPTOKI_NOT_INITIALIZED</literal> according to the - * PKCS\#11 specification. In addition there are no guarantees that - * thread-safe behavior will occur if multiple callers finalize from - * different threads. - * - * Returns: <literal>CKR_OK</literal> or the failure code of the last - * module that failed to finalize - */ -CK_RV -p11_kit_modules_finalize (CK_FUNCTION_LIST **modules) -{ - CK_RV ret = CKR_OK; - CK_RV rv; - char *name; - int i; - - return_val_if_fail (modules != NULL, CKR_ARGUMENTS_BAD); - - for (i = 0; modules[i] != NULL; i++) { - rv = modules[i]->C_Finalize (NULL); - if (rv != CKR_OK) { - name = p11_kit_module_get_name (modules[i]); - p11_message ("%s: module failed to finalize: %s", - name ? name : "(unknown)", p11_kit_strerror (rv)); - free (name); - ret = rv; - } - } - - return ret; -} - -/** - * p11_kit_modules_release: - * @modules: the modules to release - * - * Release the a set of loaded PKCS\#11 modules. - * - * The modules may be either managed or unmanaged. The array containing - * the module pointers is also freed by this function. - * - * Managed modules will not be actually released until all - * callers using them have done so. If the modules were initialized, they - * should have been finalized first. - */ -void -p11_kit_modules_release (CK_FUNCTION_LIST **modules) -{ - p11_library_init_once (); - - return_if_fail (modules != NULL); - - /* WARNING: This function must be reentrant */ - p11_debug ("in"); - - p11_lock (); - - p11_message_clear (); - p11_modules_release_inlock_reentrant (modules); - - p11_unlock (); - - p11_debug ("out"); -} - -/** - * p11_kit_modules_finalize_and_release: - * @modules: the modules to release - * - * Finalize and then release the a set of loaded PKCS\#11 modules. - * - * The modules may be either managed or unmanaged. The array containing - * the module pointers is also freed by this function. - * - * Modules are released even if their finalization returns an error code. - * Managed modules will not be actually finalized or released until all - * callers using them have done so. - * - * For managed modules the <literal>C_Finalize</literal> function - * is overridden so that multiple callers can finalize the same - * modules. In addition for managed modules multiple callers can - * finalize from different threads, and still guarantee consistent - * thread-safe behavior. - * - * For unmanaged modules if multiple callers try to finalize - * a module, then one of the calls will return - * <literal>CKR_CRYPTOKI_NOT_INITIALIZED</literal> according to the - * PKCS\#11 specification. In addition there are no guarantees that - * thread-safe behavior will occur if multiple callers initialize from - * different threads. - */ -void -p11_kit_modules_finalize_and_release (CK_FUNCTION_LIST **modules) -{ - return_if_fail (modules != NULL); - p11_kit_modules_finalize (modules); - p11_kit_modules_release (modules); -} - -/** - * p11_kit_initialize_module: - * @module: loaded module to initialize. - * - * Initialize an arbitrary PKCS\#11 module. Normally using the - * p11_kit_initialize_registered() is preferred. - * - * Using this function to initialize modules allows coordination between - * multiple users of the same module in a single process. It should be called - * on modules that have been loaded (with dlopen() for example) but not yet - * initialized. The caller should not yet have called the module's - * <code>C_Initialize</code> method. This function will call - * <code>C_Initialize</code> as necessary. - * - * Subsequent calls to this function for the same module will result in an - * initialization count being incremented for the module. It is safe (although - * usually unnecessary) to use this function on registered modules. - * - * The module must be finalized with p11_kit_finalize_module() instead of - * calling its <code>C_Finalize</code> method directly. - * - * This function does not accept a <code>CK_C_INITIALIZE_ARGS</code> argument. - * Custom initialization arguments cannot be supported when multiple consumers - * load the same module. - * - * If this function fails, then an error message will be available via the - * p11_kit_message() function. - * - * Deprecated: Since 0.19.0: Use p11_kit_module_initialize() instead. - * - * Returns: CKR_OK if the initialization was successful. - */ -CK_RV -p11_kit_initialize_module (CK_FUNCTION_LIST_PTR module) -{ - CK_FUNCTION_LIST_PTR result; - Module *mod; - int flags; - CK_RV rv; - - return_val_if_fail (module != NULL, CKR_ARGUMENTS_BAD); - - p11_library_init_once (); - - /* WARNING: This function must be reentrant for the same arguments */ - p11_debug ("in"); - - p11_lock (); - - p11_message_clear (); - - flags = P11_KIT_MODULE_CRITICAL | P11_KIT_MODULE_UNMANAGED; - rv = p11_module_load_inlock_reentrant (module, flags, &result); - - /* An unmanaged module should return the same pointer */ - assert (rv != CKR_OK || result == module); - - if (rv == CKR_OK) { - mod = p11_dict_get (gl.unmanaged_by_funcs, module); - assert (mod != NULL); - rv = initialize_module_inlock_reentrant (mod, NULL); - if (rv != CKR_OK) { - p11_message ("module initialization failed: %s", p11_kit_strerror (rv)); - p11_module_release_inlock_reentrant (module); - } - } - - p11_unlock (); - - p11_debug ("out: %lu", rv); - return rv; -} - -CK_RV -p11_module_load_inlock_reentrant (CK_FUNCTION_LIST *module, - int flags, - CK_FUNCTION_LIST **result) -{ - Module *allocated = NULL; - Module *mod; - CK_RV rv = CKR_OK; - - rv = init_globals_unlocked (); - if (rv == CKR_OK) { - - mod = p11_dict_get (gl.unmanaged_by_funcs, module); - if (mod == NULL) { - p11_debug ("allocating new module"); - allocated = mod = alloc_module_unlocked (); - return_val_if_fail (mod != NULL, CKR_HOST_MEMORY); - p11_virtual_init (&mod->virt, &p11_virtual_base, module, NULL); - } - - /* If this was newly allocated, add it to the list */ - if (allocated) { - if (!p11_dict_set (gl.modules, allocated, allocated) || - !p11_dict_set (gl.unmanaged_by_funcs, module, allocated)) - return_val_if_reached (CKR_HOST_MEMORY); - allocated = NULL; - } - - /* WARNING: Reentrancy can occur here */ - rv = prepare_module_inlock_reentrant (mod, flags, result); - - free (allocated); - } - - /* - * If initialization failed, we may need to cleanup. - * If we added this module above, then this will - * clean things up as expected. - */ - if (rv != CKR_OK) - free_modules_when_no_refs_unlocked (); - - _p11_kit_default_message (rv); - return rv; -} - -/** - * p11_kit_module_load: - * @module_path: relative or full file path of module library - * @flags: flags to use when loading the module - * - * Load an arbitrary PKCS\#11 module from a dynamic library file, and - * initialize it. Normally using the p11_kit_modules_load() function - * is preferred. - * - * A full file path or just (path/)filename relative to - * P11_MODULE_PATH are accepted. - * - * Using this function to load modules allows coordination between multiple - * callers of the same module in a single process. If @flags contains the - * %P11_KIT_MODULE_UNMANAGED flag, then the modules will be not be loaded - * in 'managed' mode and not be coordinated. This is not recommended - * for general usage. - * - * Subsequent calls to this function for the same module will result in an - * initialization count being incremented for the module. It is safe (although - * usually unnecessary) to use this function on registered modules. - * - * The module should be released with p11_kit_module_release(). - * - * If this function fails, then an error message will be available via the - * p11_kit_message() function. - * - * Returns: the loaded module PKCS\#11 functions or %NULL on failure - */ -CK_FUNCTION_LIST * -p11_kit_module_load (const char *module_path, - int flags) -{ - CK_FUNCTION_LIST *module = NULL; - CK_RV rv; - Module *mod; - - return_val_if_fail (module_path != NULL, NULL); - - p11_library_init_once (); - - /* WARNING: This function must be reentrant for the same arguments */ - p11_debug ("in: %s", module_path); - - p11_lock (); - - p11_message_clear (); - - rv = init_globals_unlocked (); - if (rv == CKR_OK) { - - rv = load_module_from_file_inlock (NULL, module_path, &mod); - if (rv == CKR_OK) { - /* WARNING: Reentrancy can occur here */ - rv = prepare_module_inlock_reentrant (mod, flags, &module); - if (rv != CKR_OK) - module = NULL; - } - } - - /* - * If initialization failed, we may need to cleanup. - * If we added this module above, then this will - * clean things up as expected. - */ - if (rv != CKR_OK) - free_modules_when_no_refs_unlocked (); - - p11_unlock (); - - p11_debug ("out: %s", module ? "success" : "fail"); - return module; - -} - -/** - * p11_kit_finalize_module: - * @module: loaded module to finalize. - * - * Finalize an arbitrary PKCS\#11 module. The module must have been initialized - * using p11_kit_initialize_module(). In most cases callers will want to use - * p11_kit_finalize_registered() instead of this function. - * - * Using this function to finalize modules allows coordination between - * multiple users of the same module in a single process. The caller should not - * call the module's <code>C_Finalize</code> method. This function will call - * <code>C_Finalize</code> as necessary. - * - * If the module was initialized more than once, then this function will - * decrement an initialization count for the module. When the count reaches zero - * the module will be truly finalized. It is safe (although usually unnecessary) - * to use this function on registered modules if (and only if) they were - * initialized using p11_kit_initialize_module() for some reason. - * - * If this function fails, then an error message will be available via the - * p11_kit_message() function. - * - * Deprecated: Since 0.19.0: Use p11_kit_module_finalize() and - * p11_kit_module_release() instead. - * - * Returns: CKR_OK if the finalization was successful. - */ -CK_RV -p11_kit_finalize_module (CK_FUNCTION_LIST *module) -{ - Module *mod; - CK_RV rv = CKR_OK; - - return_val_if_fail (module != NULL, CKR_ARGUMENTS_BAD); - - p11_library_init_once (); - - /* WARNING: This function must be reentrant for the same arguments */ - p11_debug ("in"); - - p11_lock (); - - p11_message_clear (); - - mod = gl.unmanaged_by_funcs ? p11_dict_get (gl.unmanaged_by_funcs, module) : NULL; - if (mod == NULL) { - p11_debug ("module not found"); - rv = CKR_ARGUMENTS_BAD; - } else { - /* WARNING: Rentrancy can occur here */ - rv = finalize_module_inlock_reentrant (mod); - } - - _p11_kit_default_message (rv); - - p11_unlock (); - - p11_debug ("out: %lu", rv); - return rv; -} - -/** - * p11_kit_module_initialize: - * @module: the module to initialize - * - * Initialize a PKCS\#11 module by calling its <literal>C_Initialize</literal> - * function. - * - * For managed modules the <literal>C_Initialize</literal> function - * is overridden so that multiple callers can initialize the same - * modules. In addition for managed modules multiple callers can - * initialize from different threads, and still guarantee consistent - * thread-safe behavior. - * - * For unmanaged modules if multiple callers try to initialize - * a module, then one of the calls will return - * <literal>CKR_CRYPTOKI_ALREADY_INITIALIZED</literal> according to the - * PKCS\#11 specification. In addition there are no guarantees that - * thread-safe behavior will occur if multiple callers initialize from - * different threads. - * - * This function does not accept a <code>CK_C_INITIALIZE_ARGS</code> argument. - * Custom initialization arguments cannot be supported when multiple consumers - * load the same module. - * - * Returns: <literal>CKR_OK</literal> or a failure code - */ -CK_RV -p11_kit_module_initialize (CK_FUNCTION_LIST *module) -{ - char *name; - CK_RV rv; - - return_val_if_fail (module != NULL, CKR_ARGUMENTS_BAD); - - rv = module->C_Initialize (NULL); - if (rv != CKR_OK) { - name = p11_kit_module_get_name (module); - p11_message ("%s: module failed to initialize: %s", - name ? name : "(unknown)", p11_kit_strerror (rv)); - free (name); - } - - return rv; -} - -/** - * p11_kit_module_finalize: - * @module: the module to finalize - * - * Finalize a PKCS\#11 module by calling its <literal>C_Finalize</literal> - * function. - * - * For managed modules the <literal>C_Finalize</literal> function - * is overridden so that multiple callers can finalize the same - * modules. In addition for managed modules multiple callers can - * finalize from different threads, and still guarantee consistent - * thread-safe behavior. - * - * For unmanaged modules if multiple callers try to finalize - * a module, then one of the calls will return - * <literal>CKR_CRYPTOKI_NOT_INITIALIZED</literal> according to the - * PKCS\#11 specification. In addition there are no guarantees that - * thread-safe behavior will occur if multiple callers finalize from - * different threads. - * - * Returns: <literal>CKR_OK</literal> or a failure code - */ -CK_RV -p11_kit_module_finalize (CK_FUNCTION_LIST *module) -{ - char *name; - CK_RV rv; - - return_val_if_fail (module != NULL, CKR_ARGUMENTS_BAD); - - rv = module->C_Finalize (NULL); - if (rv != CKR_OK) { - name = p11_kit_module_get_name (module); - p11_message ("%s: module failed to finalize: %s", - name ? name : "(unknown)", p11_kit_strerror (rv)); - free (name); - } - - return rv; - -} - - -/** - * p11_kit_module_release: - * @module: the module to release - * - * Release the a loaded PKCS\#11 modules. - * - * The module may be either managed or unmanaged. The <literal>C_Finalize</literal> - * function will be called if no other callers are using this module. - */ -void -p11_kit_module_release (CK_FUNCTION_LIST *module) -{ - return_if_fail (module != NULL); - - p11_library_init_once (); - - /* WARNING: This function must be reentrant for the same arguments */ - p11_debug ("in"); - - p11_lock (); - - p11_message_clear (); - - release_module_inlock_rentrant (module, __PRETTY_FUNCTION__); - - p11_unlock (); - - p11_debug ("out"); -} - -CK_RV -p11_module_release_inlock_reentrant (CK_FUNCTION_LIST *module) -{ - return release_module_inlock_rentrant (module, __PRETTY_FUNCTION__); -} - -/** - * p11_kit_load_initialize_module: - * @module_path: full file path of module library - * @module: location to place loaded module pointer - * - * Load an arbitrary PKCS\#11 module from a dynamic library file, and - * initialize it. Normally using the p11_kit_initialize_registered() function - * is preferred. - * - * Using this function to load and initialize modules allows coordination between - * multiple users of the same module in a single process. The caller should not - * call the module's <code>C_Initialize</code> method. This function will call - * <code>C_Initialize</code> as necessary. - * - * If a module has already been loaded, then use of this function is unnecesasry. - * Instead use the p11_kit_initialize_module() function to initialize it. - * - * Subsequent calls to this function for the same module will result in an - * initialization count being incremented for the module. It is safe (although - * usually unnecessary) to use this function on registered modules. - * - * The module must be finalized with p11_kit_finalize_module() instead of - * calling its <code>C_Finalize</code> method directly. - * - * This function does not accept a <code>CK_C_INITIALIZE_ARGS</code> argument. - * Custom initialization arguments cannot be supported when multiple consumers - * load the same module. - * - * If this function fails, then an error message will be available via the - * p11_kit_message() function. - * - * Deprecated: Since 0.19.0: Use p11_kit_module_load() instead. - * - * Returns: CKR_OK if the initialization was successful. - */ -CK_RV -p11_kit_load_initialize_module (const char *module_path, - CK_FUNCTION_LIST_PTR_PTR module) -{ - Module *mod; - CK_RV rv = CKR_OK; - - return_val_if_fail (module_path != NULL, CKR_ARGUMENTS_BAD); - return_val_if_fail (module != NULL, CKR_ARGUMENTS_BAD); - - p11_library_init_once (); - - /* WARNING: This function must be reentrant for the same arguments */ - p11_debug ("in: %s", module_path); - - p11_lock (); - - p11_message_clear (); - - rv = init_globals_unlocked (); - if (rv == CKR_OK) { - - rv = load_module_from_file_inlock (NULL, module_path, &mod); - if (rv == CKR_OK) { - - /* WARNING: Reentrancy can occur here */ - rv = initialize_module_inlock_reentrant (mod, NULL); - } - } - - if (rv == CKR_OK && module) { - *module = unmanaged_for_module_inlock (mod); - assert (*module != NULL); - } - - /* - * If initialization failed, we may need to cleanup. - * If we added this module above, then this will - * clean things up as expected. - */ - if (rv != CKR_OK) - free_modules_when_no_refs_unlocked (); - - _p11_kit_default_message (rv); - - p11_unlock (); - - p11_debug ("out: %lu", rv); - return rv; -} |