17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*d3a28a55Sdinak  * Common Development and Distribution License (the "License").
6*d3a28a55Sdinak  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*d3a28a55Sdinak  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * Mechanism Manager - centralized knowledge of mechanisms.
287c478bd9Sstevel@tonic-gate  *
297c478bd9Sstevel@tonic-gate  * The core of the mechmanager is the "mechlist" data structure. It contains
307c478bd9Sstevel@tonic-gate  * information about all mechanisms available from providers that have been
317c478bd9Sstevel@tonic-gate  * exposed to the application.
327c478bd9Sstevel@tonic-gate  *
337c478bd9Sstevel@tonic-gate  * Each element in the array represents a particular mechanism type. The
347c478bd9Sstevel@tonic-gate  * array is sorted by type, so that searching by mechanism can be done
357c478bd9Sstevel@tonic-gate  * quickly. Each element also contains the mechanism data for each slot.
367c478bd9Sstevel@tonic-gate  *
377c478bd9Sstevel@tonic-gate  * The mechlist is constructed on an as-needed basis, entries are not added
387c478bd9Sstevel@tonic-gate  * until the application triggers an action that requires an entry to be
397c478bd9Sstevel@tonic-gate  * added (or updated).
407c478bd9Sstevel@tonic-gate  *
417c478bd9Sstevel@tonic-gate  */
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #include <string.h>
447c478bd9Sstevel@tonic-gate #include <strings.h>
457c478bd9Sstevel@tonic-gate #include "pkcs11Conf.h"
467c478bd9Sstevel@tonic-gate #include "metaGlobal.h"
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate /* Global data... */
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate #define	INITIAL_MECHLIST_SIZE	256
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate typedef struct mechliststruct {
547c478bd9Sstevel@tonic-gate 	CK_MECHANISM_TYPE type;
557c478bd9Sstevel@tonic-gate 	mechinfo_t *slots;
567c478bd9Sstevel@tonic-gate } mechlist_t;
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate static pthread_rwlock_t mechlist_lock = PTHREAD_RWLOCK_INITIALIZER;
597c478bd9Sstevel@tonic-gate static mechlist_t *mechlist;
607c478bd9Sstevel@tonic-gate static unsigned long num_mechs;
617c478bd9Sstevel@tonic-gate static unsigned long true_mechlist_size;
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /* Prototypes... */
657c478bd9Sstevel@tonic-gate static CK_RV meta_mechManager_update_mech(CK_MECHANISM_TYPE, boolean_t);
667c478bd9Sstevel@tonic-gate static CK_RV meta_mechManager_update_slot(CK_ULONG);
677c478bd9Sstevel@tonic-gate static CK_RV update_slotmech(CK_MECHANISM_TYPE, CK_ULONG, unsigned long);
687c478bd9Sstevel@tonic-gate static CK_RV meta_mechManager_allocmechs(CK_MECHANISM_TYPE *, unsigned long,
697c478bd9Sstevel@tonic-gate 	unsigned long *);
707c478bd9Sstevel@tonic-gate static boolean_t find_mech_index(CK_MECHANISM_TYPE, unsigned long *);
717c478bd9Sstevel@tonic-gate static int qsort_mechtypes(const void *, const void *);
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate /*
757c478bd9Sstevel@tonic-gate  * meta_mechManager_initialize
767c478bd9Sstevel@tonic-gate  *
777c478bd9Sstevel@tonic-gate  * Called from C_Initialize. Allocates and initializes storage needed
787c478bd9Sstevel@tonic-gate  * by the slot manager.
797c478bd9Sstevel@tonic-gate  */
807c478bd9Sstevel@tonic-gate CK_RV
meta_mechManager_initialize()817c478bd9Sstevel@tonic-gate meta_mechManager_initialize()
827c478bd9Sstevel@tonic-gate {
837c478bd9Sstevel@tonic-gate 	/* The mechlist can dynamically grow, but let's preallocate space. */
847c478bd9Sstevel@tonic-gate 	mechlist = calloc(INITIAL_MECHLIST_SIZE, sizeof (mechlist_t));
857c478bd9Sstevel@tonic-gate 	if (mechlist == NULL)
867c478bd9Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 	true_mechlist_size = INITIAL_MECHLIST_SIZE;
897c478bd9Sstevel@tonic-gate 	num_mechs = 0;
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 	return (CKR_OK);
927c478bd9Sstevel@tonic-gate }
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate /*
967c478bd9Sstevel@tonic-gate  * meta_mechManager_finalize
977c478bd9Sstevel@tonic-gate  *
987c478bd9Sstevel@tonic-gate  * Called from C_Finalize. Deallocates any storage held by the slot manager.
997c478bd9Sstevel@tonic-gate  */
1007c478bd9Sstevel@tonic-gate void
meta_mechManager_finalize()1017c478bd9Sstevel@tonic-gate meta_mechManager_finalize()
1027c478bd9Sstevel@tonic-gate {
1037c478bd9Sstevel@tonic-gate 	int i;
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	/* No need to lock list, we assume all sessions are closed. */
1067c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_mechs; i++) {
1077c478bd9Sstevel@tonic-gate 		free(mechlist[i].slots);
1087c478bd9Sstevel@tonic-gate 	}
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	free(mechlist);
1117c478bd9Sstevel@tonic-gate 	mechlist = NULL;
1127c478bd9Sstevel@tonic-gate 	num_mechs = 0;
1137c478bd9Sstevel@tonic-gate 	true_mechlist_size = 0;
1147c478bd9Sstevel@tonic-gate }
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate /*
1187c478bd9Sstevel@tonic-gate  * meta_mechManager_get_mechs
1197c478bd9Sstevel@tonic-gate  *
1207c478bd9Sstevel@tonic-gate  * Get list of all available mechanisms.
1217c478bd9Sstevel@tonic-gate  *
1227c478bd9Sstevel@tonic-gate  * Follows PKCS#11 semantics, where list may be NULL to only request a
1237c478bd9Sstevel@tonic-gate  * count of available mechanisms.
1247c478bd9Sstevel@tonic-gate  */
1257c478bd9Sstevel@tonic-gate CK_RV
meta_mechManager_get_mechs(CK_MECHANISM_TYPE * list,CK_ULONG * listsize)1267c478bd9Sstevel@tonic-gate meta_mechManager_get_mechs(CK_MECHANISM_TYPE *list, CK_ULONG *listsize)
1277c478bd9Sstevel@tonic-gate {
1287c478bd9Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
1297c478bd9Sstevel@tonic-gate 	CK_ULONG num_found = 0;
1307c478bd9Sstevel@tonic-gate 	CK_ULONG slotnum, num_slots;
1317c478bd9Sstevel@tonic-gate 	unsigned long i;
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 	/* get number of slots */
1347c478bd9Sstevel@tonic-gate 	num_slots = meta_slotManager_get_slotcount();
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	/*
1377c478bd9Sstevel@tonic-gate 	 * Update slot info. Ignore any errors.
1387c478bd9Sstevel@tonic-gate 	 *
1397c478bd9Sstevel@tonic-gate 	 * NOTE: Due to the PKCS#11 convention of calling C_GetMechanismList
1407c478bd9Sstevel@tonic-gate 	 * twice (once to get the count, again to get the actual list), this
1417c478bd9Sstevel@tonic-gate 	 * is somewhat inefficient... However, I don't see an easy way to fix
1427c478bd9Sstevel@tonic-gate 	 * that without impacting other cases (eg, when the first call contains
1437c478bd9Sstevel@tonic-gate 	 * an "optimistic" pre-allocated buffer).
1447c478bd9Sstevel@tonic-gate 	 */
1457c478bd9Sstevel@tonic-gate 	for (slotnum = 0; slotnum < num_slots; slotnum++) {
1467c478bd9Sstevel@tonic-gate 		(void) meta_mechManager_update_slot(slotnum);
1477c478bd9Sstevel@tonic-gate 	}
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	/*
1517c478bd9Sstevel@tonic-gate 	 * Count the number of mechanisms. We can't just use num_mechs,
1527c478bd9Sstevel@tonic-gate 	 * because some mechs may not currently be supported on any slot.
1537c478bd9Sstevel@tonic-gate 	 * Also, it may not be allowed based on the mechanism policy.
1547c478bd9Sstevel@tonic-gate 	 */
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_rdlock(&mechlist_lock);
1577c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_mechs; i++) {
1587c478bd9Sstevel@tonic-gate 		CK_ULONG j;
1597c478bd9Sstevel@tonic-gate 		boolean_t supported;
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 		if (pkcs11_is_dismech(METASLOT_FRAMEWORK_ID,
1627c478bd9Sstevel@tonic-gate 		    mechlist[i].type)) {
1637c478bd9Sstevel@tonic-gate 			/* skip mechs disabled by policy */
1647c478bd9Sstevel@tonic-gate 			continue;
1657c478bd9Sstevel@tonic-gate 		}
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 		supported = FALSE;
1687c478bd9Sstevel@tonic-gate 		for (j = 0; j < num_slots; j++) {
1697c478bd9Sstevel@tonic-gate 			if (!mechlist[i].slots[j].initialized)
1707c478bd9Sstevel@tonic-gate 				continue;
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 			if (mechlist[i].slots[j].supported) {
1737c478bd9Sstevel@tonic-gate 				supported = B_TRUE;
1747c478bd9Sstevel@tonic-gate 				break;
1757c478bd9Sstevel@tonic-gate 			}
1767c478bd9Sstevel@tonic-gate 		}
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 		if (supported) {
1797c478bd9Sstevel@tonic-gate 			num_found++;
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 			if (list && *listsize >= num_found) {
1827c478bd9Sstevel@tonic-gate 				list[num_found - 1] = mechlist[i].type;
1837c478bd9Sstevel@tonic-gate 			}
1847c478bd9Sstevel@tonic-gate 		}
1857c478bd9Sstevel@tonic-gate 	}
1867c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_unlock(&mechlist_lock);
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 	if (num_found > *listsize)
1897c478bd9Sstevel@tonic-gate 		rv = CKR_BUFFER_TOO_SMALL;
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	*listsize = num_found;
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	return (rv);
1947c478bd9Sstevel@tonic-gate }
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate /*
1987c478bd9Sstevel@tonic-gate  * meta_mechManager_get_slots
1997c478bd9Sstevel@tonic-gate  *
2007c478bd9Sstevel@tonic-gate  * Get list of all slots supporting the specified mechanism.
2017c478bd9Sstevel@tonic-gate  *
2027c478bd9Sstevel@tonic-gate  * The "mech_support_info" argument should have allocated enough
2037c478bd9Sstevel@tonic-gate  * space to accomodate the list of slots that supports the
2047c478bd9Sstevel@tonic-gate  * specified mechanism.  The "num_supporting_slots" field
2057c478bd9Sstevel@tonic-gate  * in the "mech_support_info" structure will indicate how
2067c478bd9Sstevel@tonic-gate  * many slots are found to support the mechanism.
2077c478bd9Sstevel@tonic-gate  *
2087c478bd9Sstevel@tonic-gate  * If any error occurred in getting the list, info in
2097c478bd9Sstevel@tonic-gate  * mech_support_info argument is not updated.
2107c478bd9Sstevel@tonic-gate  *
2117c478bd9Sstevel@tonic-gate  */
2127c478bd9Sstevel@tonic-gate CK_RV
meta_mechManager_get_slots(mech_support_info_t * mech_support_info,boolean_t force_update,CK_MECHANISM_INFO * mech_info)2137c478bd9Sstevel@tonic-gate meta_mechManager_get_slots(mech_support_info_t  *mech_support_info,
214*d3a28a55Sdinak     boolean_t force_update, CK_MECHANISM_INFO *mech_info)
2157c478bd9Sstevel@tonic-gate {
2167c478bd9Sstevel@tonic-gate 	CK_RV rv;
2177c478bd9Sstevel@tonic-gate 	boolean_t found;
2187c478bd9Sstevel@tonic-gate 	CK_ULONG i, num_slots;
2197c478bd9Sstevel@tonic-gate 	unsigned long index, num_found = 0;
220*d3a28a55Sdinak 	CK_MECHANISM_INFO info;
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	rv = meta_mechManager_update_mech(mech_support_info->mech,
2237c478bd9Sstevel@tonic-gate 	    force_update);
2247c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
2257c478bd9Sstevel@tonic-gate 		return (rv);
2267c478bd9Sstevel@tonic-gate 	}
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_rdlock(&mechlist_lock);
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	found = find_mech_index(mech_support_info->mech, &index);
2317c478bd9Sstevel@tonic-gate 	if (!found) {
2327c478bd9Sstevel@tonic-gate 		goto finish;
2337c478bd9Sstevel@tonic-gate 	}
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	num_slots = meta_slotManager_get_slotcount();
2367c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_slots; i++) {
2377c478bd9Sstevel@tonic-gate 		if (!mechlist[index].slots[i].initialized ||
2387c478bd9Sstevel@tonic-gate 		    !mechlist[index].slots[i].supported)
2397c478bd9Sstevel@tonic-gate 			continue;
2407c478bd9Sstevel@tonic-gate 
241*d3a28a55Sdinak 		if (mech_info) {
242*d3a28a55Sdinak 			info = mechlist[index].slots[i].mechanism_info;
243*d3a28a55Sdinak 			if (!(info.flags & mech_info->flags)) {
244*d3a28a55Sdinak 				continue;
245*d3a28a55Sdinak 			}
246*d3a28a55Sdinak 		}
247*d3a28a55Sdinak 
2487c478bd9Sstevel@tonic-gate 		num_found++;
2497c478bd9Sstevel@tonic-gate 		(mech_support_info->supporting_slots)[num_found - 1]
2507c478bd9Sstevel@tonic-gate 		    = &mechlist[index].slots[i];
2517c478bd9Sstevel@tonic-gate 	}
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate finish:
2547c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_unlock(&mechlist_lock);
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 	if (num_found == 0) {
2577c478bd9Sstevel@tonic-gate 		rv = CKR_MECHANISM_INVALID;
2587c478bd9Sstevel@tonic-gate 	} else {
2597c478bd9Sstevel@tonic-gate 		mech_support_info->num_supporting_slots = num_found;
2607c478bd9Sstevel@tonic-gate 	}
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	return (rv);
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate /*
2677c478bd9Sstevel@tonic-gate  * meta_mechManager_update_mech
2687c478bd9Sstevel@tonic-gate  *
2697c478bd9Sstevel@tonic-gate  * Updates a mechanism in the mechlist. If the mechanism is not
2707c478bd9Sstevel@tonic-gate  * listed, all providers will be queried. If the mechanism
2717c478bd9Sstevel@tonic-gate  * is present, but not initialized for some providers, those providers
2727c478bd9Sstevel@tonic-gate  * will be queried. Existing entries will not be updated unless the
2737c478bd9Sstevel@tonic-gate  * force_refresh flag is set.
2747c478bd9Sstevel@tonic-gate  *
2757c478bd9Sstevel@tonic-gate  * The force_refresh flag is used by C_GetMechanismInfo, to force an
2767c478bd9Sstevel@tonic-gate  * update. Updates are not forced during the common usage by operations
2777c478bd9Sstevel@tonic-gate  * [eg C_EncryptInit] to avoid poor performance.
2787c478bd9Sstevel@tonic-gate  */
2797c478bd9Sstevel@tonic-gate static CK_RV
meta_mechManager_update_mech(CK_MECHANISM_TYPE mech,boolean_t force_refresh)2807c478bd9Sstevel@tonic-gate meta_mechManager_update_mech(CK_MECHANISM_TYPE mech, boolean_t force_refresh)
2817c478bd9Sstevel@tonic-gate {
2827c478bd9Sstevel@tonic-gate 	CK_RV rv;
2837c478bd9Sstevel@tonic-gate 	CK_ULONG slot, num_slots;
2847c478bd9Sstevel@tonic-gate 	unsigned long index = 0;
2857c478bd9Sstevel@tonic-gate 	boolean_t found;
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	/* Ensure list contains the mechanism. */
2887c478bd9Sstevel@tonic-gate 	rv = meta_mechManager_allocmechs(&mech, 1, &index);
2897c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
2907c478bd9Sstevel@tonic-gate 		return (rv);
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_wrlock(&mechlist_lock);
2937c478bd9Sstevel@tonic-gate 	/*
2947c478bd9Sstevel@tonic-gate 	 * We didn't retain a lock after the first search, so it's possible
2957c478bd9Sstevel@tonic-gate 	 * that the mechlist was updated. Search again, but use the last
2967c478bd9Sstevel@tonic-gate 	 * index as a hint to quickly find the mechanism.
2977c478bd9Sstevel@tonic-gate 	 */
2987c478bd9Sstevel@tonic-gate 	found = find_mech_index(mech, &index);
2997c478bd9Sstevel@tonic-gate 	if (!found) {
3007c478bd9Sstevel@tonic-gate 		/* Shouldn't happen - entries are not removed from list. */
3017c478bd9Sstevel@tonic-gate 		rv = CKR_GENERAL_ERROR;
3027c478bd9Sstevel@tonic-gate 		goto finish;
3037c478bd9Sstevel@tonic-gate 	}
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 	num_slots = meta_slotManager_get_slotcount();
3067c478bd9Sstevel@tonic-gate 	for (slot = 0; slot < num_slots; slot++) {
3077c478bd9Sstevel@tonic-gate 		if (force_refresh || !mechlist[index].slots[slot].initialized) {
3087c478bd9Sstevel@tonic-gate 			rv = update_slotmech(mech, slot, index);
3097c478bd9Sstevel@tonic-gate 			if (rv != CKR_OK) {
3107c478bd9Sstevel@tonic-gate 				/* Ignore error and continue with next slot. */
3117c478bd9Sstevel@tonic-gate 				rv = CKR_OK;
3127c478bd9Sstevel@tonic-gate 			}
3137c478bd9Sstevel@tonic-gate 		}
3147c478bd9Sstevel@tonic-gate 	}
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate finish:
3177c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_unlock(&mechlist_lock);
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	return (rv);
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate /*
3247c478bd9Sstevel@tonic-gate  * meta_mechManager_update_slot
3257c478bd9Sstevel@tonic-gate  *
3267c478bd9Sstevel@tonic-gate  * Updates a slot in the mechlist. Called by C_GetMechanismList
3277c478bd9Sstevel@tonic-gate  * [by way of meta_mechManager_get_mechs()]. Unlike
3287c478bd9Sstevel@tonic-gate  * meta_mechManager_get_slots(), the context is always to force a refresh
3297c478bd9Sstevel@tonic-gate  * of the mechlist.
3307c478bd9Sstevel@tonic-gate  *
3317c478bd9Sstevel@tonic-gate  */
3327c478bd9Sstevel@tonic-gate static CK_RV
meta_mechManager_update_slot(CK_ULONG slotnum)3337c478bd9Sstevel@tonic-gate meta_mechManager_update_slot(CK_ULONG slotnum)
3347c478bd9Sstevel@tonic-gate {
3357c478bd9Sstevel@tonic-gate 	unsigned long index = 0;
3367c478bd9Sstevel@tonic-gate 	CK_MECHANISM_TYPE *slot_mechlist = NULL, *tmp_slot_mechlist = NULL;
3377c478bd9Sstevel@tonic-gate 	CK_ULONG slot_mechlistsize, mechnum, tmp_mechlistsize;
3387c478bd9Sstevel@tonic-gate 	CK_RV rv;
3397c478bd9Sstevel@tonic-gate 	boolean_t found;
3407c478bd9Sstevel@tonic-gate 	CK_SLOT_ID fw_st_id, true_id;
3417c478bd9Sstevel@tonic-gate 	int i;
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	fw_st_id = meta_slotManager_get_framework_table_id(slotnum);
3447c478bd9Sstevel@tonic-gate 	true_id = TRUEID(fw_st_id);
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	/* First, get the count. */
3477c478bd9Sstevel@tonic-gate 	rv = FUNCLIST(fw_st_id)->C_GetMechanismList(true_id, NULL,
3487c478bd9Sstevel@tonic-gate 	    &slot_mechlistsize);
3497c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
3507c478bd9Sstevel@tonic-gate 		goto finish;
3517c478bd9Sstevel@tonic-gate 	}
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	tmp_slot_mechlist = malloc(
3547c478bd9Sstevel@tonic-gate 	    slot_mechlistsize * sizeof (CK_MECHANISM_TYPE));
3557c478bd9Sstevel@tonic-gate 	if (tmp_slot_mechlist == NULL) {
3567c478bd9Sstevel@tonic-gate 		rv = CKR_HOST_MEMORY;
3577c478bd9Sstevel@tonic-gate 		goto finish;
3587c478bd9Sstevel@tonic-gate 	}
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	/* Next, get the actual list. */
3617c478bd9Sstevel@tonic-gate 	rv = FUNCLIST(fw_st_id)->C_GetMechanismList(true_id,
3627c478bd9Sstevel@tonic-gate 	    tmp_slot_mechlist, &slot_mechlistsize);
3637c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
3647c478bd9Sstevel@tonic-gate 		goto finish;
3657c478bd9Sstevel@tonic-gate 	}
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 	/*
3687c478bd9Sstevel@tonic-gate 	 * filter the list of mechanisms returned by the underlying slot
3697c478bd9Sstevel@tonic-gate 	 * to remove any mechanisms that are explicitly disabled
3707c478bd9Sstevel@tonic-gate 	 * in the configuration file.
3717c478bd9Sstevel@tonic-gate 	 */
3727c478bd9Sstevel@tonic-gate 	slot_mechlist = malloc(slot_mechlistsize * sizeof (CK_MECHANISM_TYPE));
3737c478bd9Sstevel@tonic-gate 	if (slot_mechlist == NULL) {
3747c478bd9Sstevel@tonic-gate 		rv = CKR_HOST_MEMORY;
3757c478bd9Sstevel@tonic-gate 		goto finish;
3767c478bd9Sstevel@tonic-gate 	}
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 	tmp_mechlistsize = 0;
3797c478bd9Sstevel@tonic-gate 	for (i = 0; i < slot_mechlistsize; i++) {
3807c478bd9Sstevel@tonic-gate 		/* filter out the disabled mechanisms */
3817c478bd9Sstevel@tonic-gate 		if (pkcs11_is_dismech(fw_st_id, tmp_slot_mechlist[i])) {
3827c478bd9Sstevel@tonic-gate 			continue;
3837c478bd9Sstevel@tonic-gate 		}
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 		slot_mechlist[tmp_mechlistsize] = tmp_slot_mechlist[i];
3867c478bd9Sstevel@tonic-gate 		tmp_mechlistsize++;
3877c478bd9Sstevel@tonic-gate 	}
3887c478bd9Sstevel@tonic-gate 	slot_mechlistsize = tmp_mechlistsize;
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	/* Sort the mechanisms by value. */
3917c478bd9Sstevel@tonic-gate 	qsort(slot_mechlist, slot_mechlistsize, sizeof (CK_MECHANISM_TYPE),
392*d3a28a55Sdinak 	    qsort_mechtypes);
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	/* Ensure list contains the mechanisms. */
3957c478bd9Sstevel@tonic-gate 	rv = meta_mechManager_allocmechs(slot_mechlist, slot_mechlistsize,
396*d3a28a55Sdinak 	    &index);
3977c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
3987c478bd9Sstevel@tonic-gate 		goto finish;
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	/* Update the mechanism info. */
4017c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_wrlock(&mechlist_lock);
4027c478bd9Sstevel@tonic-gate 	for (mechnum = 0; mechnum < slot_mechlistsize; mechnum++) {
4037c478bd9Sstevel@tonic-gate 		found = find_mech_index(slot_mechlist[mechnum], &index);
4047c478bd9Sstevel@tonic-gate 		if (!found) {
4057c478bd9Sstevel@tonic-gate 			/* This shouldn't happen. */
4067c478bd9Sstevel@tonic-gate 			rv = CKR_GENERAL_ERROR;
4077c478bd9Sstevel@tonic-gate 			goto finish;
4087c478bd9Sstevel@tonic-gate 		}
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 		rv = update_slotmech(slot_mechlist[mechnum], slotnum, index);
4117c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
4127c478bd9Sstevel@tonic-gate 			/* Ignore error, make best effort to finish update. */
4137c478bd9Sstevel@tonic-gate 			rv = CKR_OK;
4147c478bd9Sstevel@tonic-gate 			continue;
4157c478bd9Sstevel@tonic-gate 		}
4167c478bd9Sstevel@tonic-gate 	}
4177c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_unlock(&mechlist_lock);
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate finish:
4207c478bd9Sstevel@tonic-gate 	if (slot_mechlist) {
4217c478bd9Sstevel@tonic-gate 		free(slot_mechlist);
4227c478bd9Sstevel@tonic-gate 	}
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	if (tmp_slot_mechlist) {
4257c478bd9Sstevel@tonic-gate 		free(tmp_slot_mechlist);
4267c478bd9Sstevel@tonic-gate 	}
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	return (rv);
4297c478bd9Sstevel@tonic-gate }
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate /*
4337c478bd9Sstevel@tonic-gate  * update_slotmech
4347c478bd9Sstevel@tonic-gate  *
4357c478bd9Sstevel@tonic-gate  * Updates the information for a particular mechanism for a particular slot.
4367c478bd9Sstevel@tonic-gate  * (ie, slotlist[foo].slots[bar])
4377c478bd9Sstevel@tonic-gate  *
4387c478bd9Sstevel@tonic-gate  * It is assumed that the caller to this function (all of which are
4397c478bd9Sstevel@tonic-gate  * in this file) holds the write-lock to "mechlist_lock".
4407c478bd9Sstevel@tonic-gate  *
4417c478bd9Sstevel@tonic-gate  */
4427c478bd9Sstevel@tonic-gate static CK_RV
update_slotmech(CK_MECHANISM_TYPE mech,CK_ULONG slotnum,unsigned long index)4437c478bd9Sstevel@tonic-gate update_slotmech(CK_MECHANISM_TYPE mech, CK_ULONG slotnum,
4447c478bd9Sstevel@tonic-gate 	unsigned long index)
4457c478bd9Sstevel@tonic-gate {
4467c478bd9Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
4477c478bd9Sstevel@tonic-gate 	CK_MECHANISM_INFO info;
4487c478bd9Sstevel@tonic-gate 	CK_SLOT_ID fw_st_id, true_id;
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	mechlist[index].slots[slotnum].slotnum = slotnum;
4517c478bd9Sstevel@tonic-gate 	fw_st_id = meta_slotManager_get_framework_table_id(slotnum);
4527c478bd9Sstevel@tonic-gate 	true_id = TRUEID(fw_st_id);
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	/*
4557c478bd9Sstevel@tonic-gate 	 * Check if the specified mechanism is in the disabled list
4567c478bd9Sstevel@tonic-gate 	 * of the specified slot.  If so, we can immediately conclude
4577c478bd9Sstevel@tonic-gate 	 * that it is not supported by the specified slot.
4587c478bd9Sstevel@tonic-gate 	 */
4597c478bd9Sstevel@tonic-gate 	if (pkcs11_is_dismech(fw_st_id, mech)) {
4607c478bd9Sstevel@tonic-gate 		/*
4617c478bd9Sstevel@tonic-gate 		 * we mark this as initialized so that we won't try
4627c478bd9Sstevel@tonic-gate 		 * to do this check later
4637c478bd9Sstevel@tonic-gate 		 */
4647c478bd9Sstevel@tonic-gate 		mechlist[index].slots[slotnum].initialized = B_TRUE;
4657c478bd9Sstevel@tonic-gate 		mechlist[index].slots[slotnum].supported = B_FALSE;
4667c478bd9Sstevel@tonic-gate 		bzero(&mechlist[index].slots[slotnum].mechanism_info,
467*d3a28a55Sdinak 		    sizeof (CK_MECHANISM_INFO));
4687c478bd9Sstevel@tonic-gate 		goto finish;
4697c478bd9Sstevel@tonic-gate 	}
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	rv = FUNCLIST(fw_st_id)->C_GetMechanismInfo(true_id, mech, &info);
4727c478bd9Sstevel@tonic-gate 	if (rv == CKR_OK) {
4737c478bd9Sstevel@tonic-gate 		mechlist[index].slots[slotnum].initialized = B_TRUE;
4747c478bd9Sstevel@tonic-gate 		mechlist[index].slots[slotnum].supported = B_TRUE;
4757c478bd9Sstevel@tonic-gate 		mechlist[index].slots[slotnum].mechanism_info = info;
4767c478bd9Sstevel@tonic-gate 	} else {
4777c478bd9Sstevel@tonic-gate 		/* record that the mechanism isn't supported for the slot */
4787c478bd9Sstevel@tonic-gate 		mechlist[index].slots[slotnum].initialized = B_TRUE;
4797c478bd9Sstevel@tonic-gate 		mechlist[index].slots[slotnum].supported = B_FALSE;
4807c478bd9Sstevel@tonic-gate 		bzero(&mechlist[index].slots[slotnum].mechanism_info,
481*d3a28a55Sdinak 		    sizeof (CK_MECHANISM_INFO));
4827c478bd9Sstevel@tonic-gate 	}
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate finish:
4857c478bd9Sstevel@tonic-gate 	return (rv);
4867c478bd9Sstevel@tonic-gate }
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate /*
4907c478bd9Sstevel@tonic-gate  * meta_mechManager_allocmechs
4917c478bd9Sstevel@tonic-gate  *
4927c478bd9Sstevel@tonic-gate  * Ensures that all of the specified mechanisms are present in the
4937c478bd9Sstevel@tonic-gate  * mechlist. If a mechanism is not present, an uninitialized entry is
4947c478bd9Sstevel@tonic-gate  * added for it.
4957c478bd9Sstevel@tonic-gate  *
4967c478bd9Sstevel@tonic-gate  * The returned index can be used by the caller as a hint to where the
4977c478bd9Sstevel@tonic-gate  * first mechanism was located.
4987c478bd9Sstevel@tonic-gate  */
4997c478bd9Sstevel@tonic-gate static CK_RV
meta_mechManager_allocmechs(CK_MECHANISM_TYPE * new_mechs,unsigned long num_new_mechs,unsigned long * index_hint)5007c478bd9Sstevel@tonic-gate meta_mechManager_allocmechs(CK_MECHANISM_TYPE *new_mechs,
5017c478bd9Sstevel@tonic-gate 	unsigned long num_new_mechs, unsigned long *index_hint)
5027c478bd9Sstevel@tonic-gate {
5037c478bd9Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
5047c478bd9Sstevel@tonic-gate 	unsigned long i, index = 0;
5057c478bd9Sstevel@tonic-gate 	boolean_t found;
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	/* The optimistic assumption is that the mech is already present. */
5087c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_rdlock(&mechlist_lock);
5097c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_new_mechs; i++) {
5107c478bd9Sstevel@tonic-gate 		found = find_mech_index(new_mechs[i], &index);
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 		if (i == 0)
5137c478bd9Sstevel@tonic-gate 			*index_hint = index;
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 		if (!found)
5167c478bd9Sstevel@tonic-gate 			break;
5177c478bd9Sstevel@tonic-gate 	}
5187c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_unlock(&mechlist_lock);
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	if (found) {
5217c478bd9Sstevel@tonic-gate 		return (CKR_OK);
5227c478bd9Sstevel@tonic-gate 	}
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	/*
5257c478bd9Sstevel@tonic-gate 	 * We stopped searching when the first unknown mech was found. Now
5267c478bd9Sstevel@tonic-gate 	 * obtain a write-lock, and continue from where we left off, inserting
5277c478bd9Sstevel@tonic-gate 	 * unknown mechanisms.
5287c478bd9Sstevel@tonic-gate 	 */
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_wrlock(&mechlist_lock);
5317c478bd9Sstevel@tonic-gate 	for (; i < num_new_mechs; i++) {
5327c478bd9Sstevel@tonic-gate 		found = find_mech_index(new_mechs[i], &index);
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 		if (!found) {
5357c478bd9Sstevel@tonic-gate 			mechinfo_t *new_mechinfos;
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 			new_mechinfos = calloc(meta_slotManager_get_slotcount(),
538*d3a28a55Sdinak 			    sizeof (mechinfo_t));
5397c478bd9Sstevel@tonic-gate 			if (new_mechinfos == NULL) {
5407c478bd9Sstevel@tonic-gate 				rv = CKR_HOST_MEMORY;
5417c478bd9Sstevel@tonic-gate 				goto finish;
5427c478bd9Sstevel@tonic-gate 			}
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 			/*
5457c478bd9Sstevel@tonic-gate 			 * If the current storage for the mechlist is too
5467c478bd9Sstevel@tonic-gate 			 * small, allocate a new list twice as large.
5477c478bd9Sstevel@tonic-gate 			 */
5487c478bd9Sstevel@tonic-gate 			if (num_mechs == true_mechlist_size) {
5497c478bd9Sstevel@tonic-gate 				mechlist_t *newmechlist;
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 				newmechlist = realloc(mechlist,
552*d3a28a55Sdinak 				    2 * true_mechlist_size *
553*d3a28a55Sdinak 				    sizeof (mechlist_t));
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 				if (newmechlist == NULL) {
5567c478bd9Sstevel@tonic-gate 					rv = CKR_HOST_MEMORY;
5577c478bd9Sstevel@tonic-gate 					free(new_mechinfos);
5587c478bd9Sstevel@tonic-gate 					goto finish;
5597c478bd9Sstevel@tonic-gate 				}
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 				mechlist = newmechlist;
5627c478bd9Sstevel@tonic-gate 				true_mechlist_size *= 2;
5637c478bd9Sstevel@tonic-gate 			}
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 			/* Shift existing entries to make space. */
5667c478bd9Sstevel@tonic-gate 			(void) memmove(&mechlist[index+1], &mechlist[index],
567*d3a28a55Sdinak 			    (num_mechs - index) * sizeof (mechlist_t));
5687c478bd9Sstevel@tonic-gate 			num_mechs++;
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 			mechlist[index].type = new_mechs[i];
5717c478bd9Sstevel@tonic-gate 			mechlist[index].slots = new_mechinfos;
5727c478bd9Sstevel@tonic-gate 		}
5737c478bd9Sstevel@tonic-gate 	}
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate finish:
5767c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_unlock(&mechlist_lock);
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	return (rv);
5797c478bd9Sstevel@tonic-gate }
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate /*
5837c478bd9Sstevel@tonic-gate  * find_mech_index
5847c478bd9Sstevel@tonic-gate  *
5857c478bd9Sstevel@tonic-gate  * Performs a search of mechlist for the specified mechanism, and
5867c478bd9Sstevel@tonic-gate  * returns if the mechanism was found or not. The value of the "index"
5877c478bd9Sstevel@tonic-gate  * argument will be where the mech is (if found), or where it should
5887c478bd9Sstevel@tonic-gate  * be (if not found).
5897c478bd9Sstevel@tonic-gate  *
5907c478bd9Sstevel@tonic-gate  * The current value of "index" will be used as a starting point, if the
5917c478bd9Sstevel@tonic-gate  * caller already knows where the mechanism is likely to be.
5927c478bd9Sstevel@tonic-gate  *
5937c478bd9Sstevel@tonic-gate  * The caller is assumed to have a lock on the mechlist, preventing it
5947c478bd9Sstevel@tonic-gate  * from being changed while searching (also to ensure the returned index
5957c478bd9Sstevel@tonic-gate  * will remain valid until the list is unlocked).
5967c478bd9Sstevel@tonic-gate  *
5977c478bd9Sstevel@tonic-gate  * FUTURE: convert to binary search [from O(N) to a O(log(N))].
5987c478bd9Sstevel@tonic-gate  *
5997c478bd9Sstevel@tonic-gate  * NOTES:
6007c478bd9Sstevel@tonic-gate  * 1) This function assumes that mechMap is a sorted list.
6017c478bd9Sstevel@tonic-gate  */
6027c478bd9Sstevel@tonic-gate static boolean_t
find_mech_index(CK_MECHANISM_TYPE mechanism,unsigned long * index)6037c478bd9Sstevel@tonic-gate find_mech_index(CK_MECHANISM_TYPE mechanism, unsigned long *index)
6047c478bd9Sstevel@tonic-gate {
6057c478bd9Sstevel@tonic-gate 	boolean_t found = B_FALSE;
6067c478bd9Sstevel@tonic-gate 	unsigned long i;
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_mechs; i++) {
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 		if (mechlist[i].type == mechanism) {
6117c478bd9Sstevel@tonic-gate 			found = B_TRUE;
6127c478bd9Sstevel@tonic-gate 			break;
6137c478bd9Sstevel@tonic-gate 		}
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 		if (mechlist[i].type > mechanism)
6167c478bd9Sstevel@tonic-gate 			break;
6177c478bd9Sstevel@tonic-gate 	}
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	*index = i;
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	return (found);
6227c478bd9Sstevel@tonic-gate }
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate static int
qsort_mechtypes(const void * arg1,const void * arg2)6257c478bd9Sstevel@tonic-gate qsort_mechtypes(const void *arg1, const void *arg2)
6267c478bd9Sstevel@tonic-gate {
6277c478bd9Sstevel@tonic-gate 	CK_MECHANISM_TYPE mech1 = *((CK_MECHANISM_TYPE *)arg1);
6287c478bd9Sstevel@tonic-gate 	CK_MECHANISM_TYPE mech2 = *((CK_MECHANISM_TYPE *)arg2);
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	if (mech1 > mech2)
6317c478bd9Sstevel@tonic-gate 		return (1);
6327c478bd9Sstevel@tonic-gate 	if (mech1 < mech2)
6337c478bd9Sstevel@tonic-gate 		return (-1);
6347c478bd9Sstevel@tonic-gate 	return (0);
6357c478bd9Sstevel@tonic-gate }
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate /*
6387c478bd9Sstevel@tonic-gate  * Check if the specified mechanism is supported by the specified slot.
6397c478bd9Sstevel@tonic-gate  * The result is returned in the "supports" argument.  If the "slot_info"
6407c478bd9Sstevel@tonic-gate  * argument is not NULL, it will be filled with information about
6417c478bd9Sstevel@tonic-gate  * the slot.
6427c478bd9Sstevel@tonic-gate  */
6437c478bd9Sstevel@tonic-gate CK_RV
meta_mechManager_slot_supports_mech(CK_MECHANISM_TYPE mechanism,CK_ULONG slotnum,boolean_t * supports,mechinfo_t ** slot_info,boolean_t force_update,CK_MECHANISM_INFO * mech_info)6447c478bd9Sstevel@tonic-gate meta_mechManager_slot_supports_mech(CK_MECHANISM_TYPE mechanism,
6457c478bd9Sstevel@tonic-gate     CK_ULONG slotnum, boolean_t *supports, mechinfo_t **slot_info,
646*d3a28a55Sdinak     boolean_t force_update, CK_MECHANISM_INFO *mech_info)
6477c478bd9Sstevel@tonic-gate {
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 	boolean_t found;
6507c478bd9Sstevel@tonic-gate 	CK_RV rv;
6517c478bd9Sstevel@tonic-gate 	unsigned long index;
652*d3a28a55Sdinak 	CK_MECHANISM_INFO info;
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 	*supports = B_FALSE;
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	rv = meta_mechManager_update_mech(mechanism, force_update);
6577c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
6587c478bd9Sstevel@tonic-gate 		return (rv);
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_rdlock(&mechlist_lock);
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	found = find_mech_index(mechanism, &index);
6637c478bd9Sstevel@tonic-gate 	if (!found) {
6647c478bd9Sstevel@tonic-gate 		goto finish;
6657c478bd9Sstevel@tonic-gate 	}
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	if ((mechlist[index].slots[slotnum].initialized) &&
6687c478bd9Sstevel@tonic-gate 	    (mechlist[index].slots[slotnum].supported)) {
669*d3a28a55Sdinak 		if (mech_info) {
670*d3a28a55Sdinak 			info = mechlist[index].slots[slotnum].mechanism_info;
671*d3a28a55Sdinak 			if (!(info.flags & mech_info->flags)) {
672*d3a28a55Sdinak 				goto finish;
673*d3a28a55Sdinak 			}
674*d3a28a55Sdinak 		}
6757c478bd9Sstevel@tonic-gate 		*supports = B_TRUE;
6767c478bd9Sstevel@tonic-gate 		if (slot_info) {
6777c478bd9Sstevel@tonic-gate 			*slot_info = &(mechlist[index].slots[slotnum]);
6787c478bd9Sstevel@tonic-gate 		}
6797c478bd9Sstevel@tonic-gate 	}
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate finish:
6827c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_unlock(&mechlist_lock);
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	return (rv);
6857c478bd9Sstevel@tonic-gate }
686