/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Mechanism Manager - centralized knowledge of mechanisms.
*
* The core of the mechmanager is the "mechlist" data structure. It contains
* information about all mechanisms available from providers that have been
* exposed to the application.
*
* Each element in the array represents a particular mechanism type. The
* array is sorted by type, so that searching by mechanism can be done
* quickly. Each element also contains the mechanism data for each slot.
*
* The mechlist is constructed on an as-needed basis, entries are not added
* until the application triggers an action that requires an entry to be
* added (or updated).
*
*/
#include <string.h>
#include <strings.h>
#include "pkcs11Conf.h"
#include "metaGlobal.h"
/* Global data... */
typedef struct mechliststruct {
} mechlist_t;
static unsigned long num_mechs;
static unsigned long true_mechlist_size;
/* Prototypes... */
unsigned long *);
static int qsort_mechtypes(const void *, const void *);
/*
* meta_mechManager_initialize
*
* Called from C_Initialize. Allocates and initializes storage needed
* by the slot manager.
*/
{
/* The mechlist can dynamically grow, but let's preallocate space. */
return (CKR_HOST_MEMORY);
num_mechs = 0;
return (CKR_OK);
}
/*
* meta_mechManager_finalize
*
* Called from C_Finalize. Deallocates any storage held by the slot manager.
*/
void
{
int i;
/* No need to lock list, we assume all sessions are closed. */
for (i = 0; i < num_mechs; i++) {
}
num_mechs = 0;
true_mechlist_size = 0;
}
/*
* meta_mechManager_get_mechs
*
* Get list of all available mechanisms.
*
* Follows PKCS#11 semantics, where list may be NULL to only request a
* count of available mechanisms.
*/
{
unsigned long i;
/* get number of slots */
/*
* Update slot info. Ignore any errors.
*
* NOTE: Due to the PKCS#11 convention of calling C_GetMechanismList
* twice (once to get the count, again to get the actual list), this
* is somewhat inefficient... However, I don't see an easy way to fix
* that without impacting other cases (eg, when the first call contains
* an "optimistic" pre-allocated buffer).
*/
(void) meta_mechManager_update_slot(slotnum);
}
/*
* Count the number of mechanisms. We can't just use num_mechs,
* because some mechs may not currently be supported on any slot.
* Also, it may not be allowed based on the mechanism policy.
*/
(void) pthread_rwlock_rdlock(&mechlist_lock);
for (i = 0; i < num_mechs; i++) {
CK_ULONG j;
/* skip mechs disabled by policy */
continue;
}
for (j = 0; j < num_slots; j++) {
continue;
break;
}
}
if (supported) {
num_found++;
}
}
}
(void) pthread_rwlock_unlock(&mechlist_lock);
return (rv);
}
/*
* meta_mechManager_get_slots
*
* Get list of all slots supporting the specified mechanism.
*
* The "mech_support_info" argument should have allocated enough
* space to accomodate the list of slots that supports the
* specified mechanism. The "num_supporting_slots" field
* in the "mech_support_info" structure will indicate how
* many slots are found to support the mechanism.
*
* If any error occurred in getting the list, info in
* mech_support_info argument is not updated.
*
*/
{
return (rv);
}
(void) pthread_rwlock_rdlock(&mechlist_lock);
if (!found) {
goto finish;
}
for (i = 0; i < num_slots; i++) {
continue;
if (mech_info) {
continue;
}
}
num_found++;
}
(void) pthread_rwlock_unlock(&mechlist_lock);
if (num_found == 0) {
} else {
}
return (rv);
}
/*
* meta_mechManager_update_mech
*
* Updates a mechanism in the mechlist. If the mechanism is not
* listed, all providers will be queried. If the mechanism
* is present, but not initialized for some providers, those providers
* will be queried. Existing entries will not be updated unless the
* force_refresh flag is set.
*
* The force_refresh flag is used by C_GetMechanismInfo, to force an
* update. Updates are not forced during the common usage by operations
* [eg C_EncryptInit] to avoid poor performance.
*/
static CK_RV
{
unsigned long index = 0;
/* Ensure list contains the mechanism. */
return (rv);
(void) pthread_rwlock_wrlock(&mechlist_lock);
/*
* We didn't retain a lock after the first search, so it's possible
* that the mechlist was updated. Search again, but use the last
* index as a hint to quickly find the mechanism.
*/
if (!found) {
/* Shouldn't happen - entries are not removed from list. */
goto finish;
}
/* Ignore error and continue with next slot. */
}
}
}
(void) pthread_rwlock_unlock(&mechlist_lock);
return (rv);
}
/*
* meta_mechManager_update_slot
*
* Updates a slot in the mechlist. Called by C_GetMechanismList
* [by way of meta_mechManager_get_mechs()]. Unlike
* meta_mechManager_get_slots(), the context is always to force a refresh
* of the mechlist.
*
*/
static CK_RV
{
unsigned long index = 0;
int i;
/* First, get the count. */
goto finish;
}
slot_mechlistsize * sizeof (CK_MECHANISM_TYPE));
if (tmp_slot_mechlist == NULL) {
goto finish;
}
/* Next, get the actual list. */
goto finish;
}
/*
* filter the list of mechanisms returned by the underlying slot
* to remove any mechanisms that are explicitly disabled
* in the configuration file.
*/
if (slot_mechlist == NULL) {
goto finish;
}
tmp_mechlistsize = 0;
for (i = 0; i < slot_mechlistsize; i++) {
/* filter out the disabled mechanisms */
continue;
}
}
/* Sort the mechanisms by value. */
/* Ensure list contains the mechanisms. */
&index);
goto finish;
/* Update the mechanism info. */
(void) pthread_rwlock_wrlock(&mechlist_lock);
if (!found) {
/* This shouldn't happen. */
goto finish;
}
/* Ignore error, make best effort to finish update. */
continue;
}
}
(void) pthread_rwlock_unlock(&mechlist_lock);
if (slot_mechlist) {
}
if (tmp_slot_mechlist) {
}
return (rv);
}
/*
* update_slotmech
*
* Updates the information for a particular mechanism for a particular slot.
* (ie, slotlist[foo].slots[bar])
*
* It is assumed that the caller to this function (all of which are
* in this file) holds the write-lock to "mechlist_lock".
*
*/
static CK_RV
unsigned long index)
{
/*
* Check if the specified mechanism is in the disabled list
* of the specified slot. If so, we can immediately conclude
* that it is not supported by the specified slot.
*/
/*
* we mark this as initialized so that we won't try
* to do this check later
*/
sizeof (CK_MECHANISM_INFO));
goto finish;
}
} else {
/* record that the mechanism isn't supported for the slot */
sizeof (CK_MECHANISM_INFO));
}
return (rv);
}
/*
* meta_mechManager_allocmechs
*
* Ensures that all of the specified mechanisms are present in the
* mechlist. If a mechanism is not present, an uninitialized entry is
* added for it.
*
* The returned index can be used by the caller as a hint to where the
* first mechanism was located.
*/
static CK_RV
unsigned long num_new_mechs, unsigned long *index_hint)
{
unsigned long i, index = 0;
/* The optimistic assumption is that the mech is already present. */
(void) pthread_rwlock_rdlock(&mechlist_lock);
for (i = 0; i < num_new_mechs; i++) {
if (i == 0)
*index_hint = index;
if (!found)
break;
}
(void) pthread_rwlock_unlock(&mechlist_lock);
if (found) {
return (CKR_OK);
}
/*
* We stopped searching when the first unknown mech was found. Now
* obtain a write-lock, and continue from where we left off, inserting
* unknown mechanisms.
*/
(void) pthread_rwlock_wrlock(&mechlist_lock);
for (; i < num_new_mechs; i++) {
if (!found) {
sizeof (mechinfo_t));
if (new_mechinfos == NULL) {
goto finish;
}
/*
* If the current storage for the mechlist is too
* small, allocate a new list twice as large.
*/
if (num_mechs == true_mechlist_size) {
2 * true_mechlist_size *
sizeof (mechlist_t));
if (newmechlist == NULL) {
goto finish;
}
true_mechlist_size *= 2;
}
/* Shift existing entries to make space. */
num_mechs++;
}
}
(void) pthread_rwlock_unlock(&mechlist_lock);
return (rv);
}
/*
* find_mech_index
*
* Performs a search of mechlist for the specified mechanism, and
* returns if the mechanism was found or not. The value of the "index"
* argument will be where the mech is (if found), or where it should
* be (if not found).
*
* The current value of "index" will be used as a starting point, if the
* caller already knows where the mechanism is likely to be.
*
* The caller is assumed to have a lock on the mechlist, preventing it
* from being changed while searching (also to ensure the returned index
* will remain valid until the list is unlocked).
*
* FUTURE: convert to binary search [from O(N) to a O(log(N))].
*
* NOTES:
* 1) This function assumes that mechMap is a sorted list.
*/
static boolean_t
{
unsigned long i;
for (i = 0; i < num_mechs; i++) {
break;
}
break;
}
*index = i;
return (found);
}
static int
{
return (1);
return (-1);
return (0);
}
/*
* Check if the specified mechanism is supported by the specified slot.
* The result is returned in the "supports" argument. If the "slot_info"
* argument is not NULL, it will be filled with information about
* the slot.
*/
{
unsigned long index;
return (rv);
(void) pthread_rwlock_rdlock(&mechlist_lock);
if (!found) {
goto finish;
}
if (mech_info) {
goto finish;
}
}
if (slot_info) {
}
}
(void) pthread_rwlock_unlock(&mechlist_lock);
return (rv);
}