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*d288ba74SAnthony Scarpino  * Common Development and Distribution License (the "License").
6*d288ba74SAnthony Scarpino  * 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*d288ba74SAnthony Scarpino  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <stdio.h>
277c478bd9Sstevel@tonic-gate #include <stdlib.h>
287c478bd9Sstevel@tonic-gate #include <pthread.h>
297c478bd9Sstevel@tonic-gate #include <time.h>
307c478bd9Sstevel@tonic-gate #include <security/cryptoki.h>
317c478bd9Sstevel@tonic-gate #include "pkcs11Global.h"
327c478bd9Sstevel@tonic-gate #include "pkcs11Conf.h"
337c478bd9Sstevel@tonic-gate #include "pkcs11Slot.h"
347c478bd9Sstevel@tonic-gate #include "metaGlobal.h"
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate static void *listener_waitforslotevent(void *arg);
377c478bd9Sstevel@tonic-gate static void *child_waitforslotevent(void *arg);
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate /*
407c478bd9Sstevel@tonic-gate  * C_GetSlotList is implemented entirely within this framework,
417c478bd9Sstevel@tonic-gate  * using the slottable that was created during the call to
427c478bd9Sstevel@tonic-gate  * C_Initialize in pkcs11_slot_mapping().  The plugged in providers
437c478bd9Sstevel@tonic-gate  * are only queried when tokenPresent is set.
447c478bd9Sstevel@tonic-gate  *
457c478bd9Sstevel@tonic-gate  * If metaslot is enabled, the slot that provides keystore support
467c478bd9Sstevel@tonic-gate  * needs to be hidden.  Therefore, even when fastpath is enabled,
477c478bd9Sstevel@tonic-gate  * we can't go through fastpath because the slot needs to be
487c478bd9Sstevel@tonic-gate  * hidden.
497c478bd9Sstevel@tonic-gate  */
507c478bd9Sstevel@tonic-gate CK_RV
C_GetSlotList(CK_BBOOL tokenPresent,CK_SLOT_ID_PTR pSlotList,CK_ULONG_PTR pulCount)517c478bd9Sstevel@tonic-gate C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList,
527c478bd9Sstevel@tonic-gate     CK_ULONG_PTR pulCount)
537c478bd9Sstevel@tonic-gate {
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate 	CK_RV rv;
567c478bd9Sstevel@tonic-gate 	CK_RV prov_rv;
577c478bd9Sstevel@tonic-gate 	CK_SLOT_ID true_id;
587c478bd9Sstevel@tonic-gate 	CK_SLOT_INFO_PTR pinfo;
597c478bd9Sstevel@tonic-gate 	CK_SLOT_ID count = 0, i;
607c478bd9Sstevel@tonic-gate 	CK_SLOT_ID slot_id; /* slot ID for returning to the application */
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate 	/* Check for a fastpath */
637c478bd9Sstevel@tonic-gate 	if ((purefastpath || policyfastpath) && (!metaslot_enabled)) {
647c478bd9Sstevel@tonic-gate 		return (fast_funcs->C_GetSlotList(tokenPresent, pSlotList,
65*d288ba74SAnthony Scarpino 		    pulCount));
667c478bd9Sstevel@tonic-gate 	}
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate 	if (!pkcs11_initialized) {
697c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
707c478bd9Sstevel@tonic-gate 	}
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 	if (pulCount == NULL) {
737c478bd9Sstevel@tonic-gate 		return (CKR_ARGUMENTS_BAD);
747c478bd9Sstevel@tonic-gate 	}
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 	if (tokenPresent) {
777c478bd9Sstevel@tonic-gate 		/* Need to allocate memory for pinfo */
787c478bd9Sstevel@tonic-gate 		pinfo = malloc(sizeof (CK_SLOT_INFO));
797c478bd9Sstevel@tonic-gate 		if (pinfo == NULL) {
807c478bd9Sstevel@tonic-gate 			return (CKR_HOST_MEMORY);
817c478bd9Sstevel@tonic-gate 		}
827c478bd9Sstevel@tonic-gate 	}
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 	/*
857c478bd9Sstevel@tonic-gate 	 * Count the number of valid slots for returning to the application.
867c478bd9Sstevel@tonic-gate 	 * If metaslot is enabled, the slot providing keystore support for
877c478bd9Sstevel@tonic-gate 	 * metaslot is skipped.  Therefore, we can't simply sequentially
887c478bd9Sstevel@tonic-gate 	 * assign "i" as the slot id to be returned to the application.
897c478bd9Sstevel@tonic-gate 	 * The variable "slot_id" is used for keeping track of the
907c478bd9Sstevel@tonic-gate 	 * next slot id to be assigned.
917c478bd9Sstevel@tonic-gate 	 */
927c478bd9Sstevel@tonic-gate 	slot_id = slottable->st_first;
937c478bd9Sstevel@tonic-gate 	for (i = slottable->st_first; i <= slottable->st_last; i++) {
947c478bd9Sstevel@tonic-gate 		if ((pkcs11_is_valid_slot(i) == CKR_OK) &&
957c478bd9Sstevel@tonic-gate 		    ((!metaslot_enabled) || (i != metaslot_keystore_slotid))) {
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 			/* Check if token present is required */
987c478bd9Sstevel@tonic-gate 			if (tokenPresent) {
997c478bd9Sstevel@tonic-gate 				/* Check with provider */
1007c478bd9Sstevel@tonic-gate 				true_id = TRUEID(i);
1017c478bd9Sstevel@tonic-gate 				prov_rv = FUNCLIST(i)->
1027c478bd9Sstevel@tonic-gate 				    C_GetSlotInfo(true_id, pinfo);
1037c478bd9Sstevel@tonic-gate 				if ((prov_rv != CKR_OK) ||
1047c478bd9Sstevel@tonic-gate 				    !(pinfo->flags & CKF_TOKEN_PRESENT)) {
1057c478bd9Sstevel@tonic-gate 					continue;
1067c478bd9Sstevel@tonic-gate 				}
1077c478bd9Sstevel@tonic-gate 			}
1087c478bd9Sstevel@tonic-gate 			/* Fill in the given buffer if it is sufficient */
1097c478bd9Sstevel@tonic-gate 			if (pSlotList && (*pulCount > count)) {
1107c478bd9Sstevel@tonic-gate 				pSlotList[count] = slot_id;
1117c478bd9Sstevel@tonic-gate 				slot_id++;
1127c478bd9Sstevel@tonic-gate 			}
1137c478bd9Sstevel@tonic-gate 			count++;
1147c478bd9Sstevel@tonic-gate 		}
1157c478bd9Sstevel@tonic-gate 	}
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 	/* pSlotList set to NULL means caller only wants count */
1187c478bd9Sstevel@tonic-gate 	if ((*pulCount < count) && (pSlotList != NULL)) {
1197c478bd9Sstevel@tonic-gate 		rv = CKR_BUFFER_TOO_SMALL;
1207c478bd9Sstevel@tonic-gate 	} else {
1217c478bd9Sstevel@tonic-gate 		rv = CKR_OK;
1227c478bd9Sstevel@tonic-gate 	}
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	*pulCount = count;
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	if (tokenPresent) {
1277c478bd9Sstevel@tonic-gate 		free(pinfo);
1287c478bd9Sstevel@tonic-gate 	}
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 	return (rv);
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate CK_RV
C_GetSlotInfo(CK_SLOT_ID slotID,CK_SLOT_INFO_PTR pInfo)1347c478bd9Sstevel@tonic-gate C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate 	CK_RV rv;
1387c478bd9Sstevel@tonic-gate 	CK_SLOT_ID fw_st_id; /* id for accessing framework's slottable */
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	if (!pkcs11_initialized) {
1417c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
1427c478bd9Sstevel@tonic-gate 	}
1437c478bd9Sstevel@tonic-gate 
144*d288ba74SAnthony Scarpino 	/* Check for a fastpath */
145*d288ba74SAnthony Scarpino 	if ((purefastpath || policyfastpath) && !metaslot_enabled)
146*d288ba74SAnthony Scarpino 		return (fast_funcs->C_GetSlotInfo(slotID, pInfo));
147*d288ba74SAnthony Scarpino 
1487c478bd9Sstevel@tonic-gate 	if (slotID == METASLOT_FRAMEWORK_ID) {
1497c478bd9Sstevel@tonic-gate 		/* just need to get metaslot information */
1507c478bd9Sstevel@tonic-gate 		return (meta_GetSlotInfo(METASLOT_SLOTID, pInfo));
1517c478bd9Sstevel@tonic-gate 	}
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	/* Check that slotID is valid */
1547c478bd9Sstevel@tonic-gate 	if (pkcs11_validate_and_convert_slotid(slotID, &fw_st_id) != CKR_OK) {
1557c478bd9Sstevel@tonic-gate 		return (CKR_SLOT_ID_INVALID);
1567c478bd9Sstevel@tonic-gate 	}
1577c478bd9Sstevel@tonic-gate 
158*d288ba74SAnthony Scarpino 	rv = FUNCLIST(fw_st_id)->C_GetSlotInfo(TRUEID(fw_st_id), pInfo);
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	/* Present consistent interface to the application */
1617c478bd9Sstevel@tonic-gate 	if (rv == CKR_FUNCTION_NOT_SUPPORTED) {
1627c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
1637c478bd9Sstevel@tonic-gate 	}
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	return (rv);
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate CK_RV
C_GetTokenInfo(CK_SLOT_ID slotID,CK_TOKEN_INFO_PTR pInfo)1697c478bd9Sstevel@tonic-gate C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo)
1707c478bd9Sstevel@tonic-gate {
1717c478bd9Sstevel@tonic-gate 	CK_RV rv;
1727c478bd9Sstevel@tonic-gate 	CK_SLOT_ID fw_st_id; /* id for accessing framework's slottable */
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	if (!pkcs11_initialized) {
1757c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
1767c478bd9Sstevel@tonic-gate 	}
1777c478bd9Sstevel@tonic-gate 
178*d288ba74SAnthony Scarpino 	/* Check for a fastpath */
179*d288ba74SAnthony Scarpino 	if ((purefastpath || policyfastpath) && !metaslot_enabled)
180*d288ba74SAnthony Scarpino 		return (fast_funcs->C_GetTokenInfo(slotID, pInfo));
181*d288ba74SAnthony Scarpino 
1827c478bd9Sstevel@tonic-gate 	if (slotID == METASLOT_FRAMEWORK_ID) {
1837c478bd9Sstevel@tonic-gate 		/* just need to get metaslot information */
1847c478bd9Sstevel@tonic-gate 		return (meta_GetTokenInfo(METASLOT_SLOTID, pInfo));
1857c478bd9Sstevel@tonic-gate 	}
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	/* Check that slotID is valid */
1887c478bd9Sstevel@tonic-gate 	if (pkcs11_validate_and_convert_slotid(slotID, &fw_st_id) != CKR_OK) {
1897c478bd9Sstevel@tonic-gate 		return (CKR_SLOT_ID_INVALID);
1907c478bd9Sstevel@tonic-gate 	}
1917c478bd9Sstevel@tonic-gate 
192*d288ba74SAnthony Scarpino 	rv = FUNCLIST(fw_st_id)->C_GetTokenInfo(TRUEID(fw_st_id), pInfo);
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	/* Present consistent interface to the application */
1957c478bd9Sstevel@tonic-gate 	if (rv == CKR_FUNCTION_NOT_SUPPORTED) {
1967c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
1977c478bd9Sstevel@tonic-gate 	}
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	return (rv);
2007c478bd9Sstevel@tonic-gate }
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate /*
2037c478bd9Sstevel@tonic-gate  * C_WaitForSlotEvent cannot be a direct pass through to the underlying
2047c478bd9Sstevel@tonic-gate  * provider (except in the case of fastpath), due to the complex nature
2057c478bd9Sstevel@tonic-gate  * of this function.  The calling application is asking to be alerted
2067c478bd9Sstevel@tonic-gate  * when an event has occurred on any of the slots in the framework, so
2077c478bd9Sstevel@tonic-gate  * we need to check with all underlying providers and ask for events
2087c478bd9Sstevel@tonic-gate  * on any of their slots.  If this is called in blocking mode, we will
2097c478bd9Sstevel@tonic-gate  * need to start threads to wait for slot events for each provider
2107c478bd9Sstevel@tonic-gate  * plugged into the framework.
2117c478bd9Sstevel@tonic-gate  */
2127c478bd9Sstevel@tonic-gate CK_RV
C_WaitForSlotEvent(CK_FLAGS flags,CK_SLOT_ID_PTR pSlot,CK_VOID_PTR pReserved)2137c478bd9Sstevel@tonic-gate C_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved)
2147c478bd9Sstevel@tonic-gate {
2157c478bd9Sstevel@tonic-gate 	CK_SLOT_ID i, j;
2167c478bd9Sstevel@tonic-gate 	uint32_t prov_id;
2177c478bd9Sstevel@tonic-gate 	int32_t last_prov_id = -1;
2187c478bd9Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
2197c478bd9Sstevel@tonic-gate 	CK_SLOT_ID event_slot;
2207c478bd9Sstevel@tonic-gate 	pkcs11_slot_t *cur_slot;
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	/* Check for a fastpath */
2237c478bd9Sstevel@tonic-gate 	if (purefastpath || policyfastpath) {
2247c478bd9Sstevel@tonic-gate 		return (fast_funcs->C_WaitForSlotEvent(flags, pSlot,
225*d288ba74SAnthony Scarpino 		    pReserved));
2267c478bd9Sstevel@tonic-gate 	}
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	if (!pkcs11_initialized) {
2297c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
2307c478bd9Sstevel@tonic-gate 	}
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	if (pReserved != NULL) {
2337c478bd9Sstevel@tonic-gate 		return (CKR_ARGUMENTS_BAD);
2347c478bd9Sstevel@tonic-gate 	}
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	/*
2377c478bd9Sstevel@tonic-gate 	 * Check to see if we're already blocking on another threads
2387c478bd9Sstevel@tonic-gate 	 * call to this function.  If so, behaviour is undefined so
2397c478bd9Sstevel@tonic-gate 	 * we should return to application.
2407c478bd9Sstevel@tonic-gate 	 */
2417c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&slottable->st_mutex);
2427c478bd9Sstevel@tonic-gate 	if ((slottable->st_blocking) || (slottable->st_wfse_active)) {
2437c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&slottable->st_mutex);
2447c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
2457c478bd9Sstevel@tonic-gate 	} else {
2467c478bd9Sstevel@tonic-gate 		slottable->st_wfse_active = B_TRUE;
2477c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&slottable->st_mutex);
2487c478bd9Sstevel@tonic-gate 	}
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 	/*
2517c478bd9Sstevel@tonic-gate 	 * Check first to see if any events have been recorded
2527c478bd9Sstevel@tonic-gate 	 * already on any of the slots, regardless of blocking or
2537c478bd9Sstevel@tonic-gate 	 * thread status.
2547c478bd9Sstevel@tonic-gate 	 */
2557c478bd9Sstevel@tonic-gate 	for (i = slottable->st_first; i <= slottable->st_last; i++) {
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 		cur_slot = slottable->st_slots[i];
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 		if (cur_slot->sl_wfse_state == WFSE_EVENT) {
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 			/* found one, clear event and notify application */
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_lock(&cur_slot->sl_mutex);
2647c478bd9Sstevel@tonic-gate 			cur_slot->sl_wfse_state = WFSE_CLEAR;
2657c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&cur_slot->sl_mutex);
2667c478bd9Sstevel@tonic-gate 			*pSlot = i;
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 			/*
2697c478bd9Sstevel@tonic-gate 			 * This event has been captured, clear the function's
2707c478bd9Sstevel@tonic-gate 			 * active status.  Other threads may now enter this
2717c478bd9Sstevel@tonic-gate 			 * function.
2727c478bd9Sstevel@tonic-gate 			 */
2737c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_lock(&slottable->st_mutex);
2747c478bd9Sstevel@tonic-gate 			slottable->st_wfse_active = B_FALSE;
2757c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&slottable->st_mutex);
2767c478bd9Sstevel@tonic-gate 			return (CKR_OK);
2777c478bd9Sstevel@tonic-gate 		}
2787c478bd9Sstevel@tonic-gate 	}
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	/*
2817c478bd9Sstevel@tonic-gate 	 * We could not find any existing event, so let's see
2827c478bd9Sstevel@tonic-gate 	 * if we can block and start threads to watch for events.
2837c478bd9Sstevel@tonic-gate 	 */
2847c478bd9Sstevel@tonic-gate 	if (flags & CKF_DONT_BLOCK) {
2857c478bd9Sstevel@tonic-gate 		/*
2867c478bd9Sstevel@tonic-gate 		 * Application does not want us to block so check with
2877c478bd9Sstevel@tonic-gate 		 * underlying providers to see if any events have occurred.
2887c478bd9Sstevel@tonic-gate 		 * Not every provider will have implemented this function,
2897c478bd9Sstevel@tonic-gate 		 * so error codes or CKR_NO_EVENT can be ignored.
2907c478bd9Sstevel@tonic-gate 		 */
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 		for (i = slottable->st_first; i <= slottable->st_last; i++) {
2937c478bd9Sstevel@tonic-gate 			prov_id = slottable->st_slots[i]->sl_prov_id;
2947c478bd9Sstevel@tonic-gate 			cur_slot = slottable->st_slots[i];
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 			/*
2977c478bd9Sstevel@tonic-gate 			 * Only do process once per provider.
2987c478bd9Sstevel@tonic-gate 			 */
2997c478bd9Sstevel@tonic-gate 			if (prov_id == last_prov_id) {
3007c478bd9Sstevel@tonic-gate 				continue;
3017c478bd9Sstevel@tonic-gate 			}
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 			/*
3047c478bd9Sstevel@tonic-gate 			 * Check to make sure a child thread is not already
3057c478bd9Sstevel@tonic-gate 			 * running, due to another of the application's
3067c478bd9Sstevel@tonic-gate 			 * thread calling this function.
3077c478bd9Sstevel@tonic-gate 			 */
3087c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_lock(&cur_slot->sl_mutex);
3097c478bd9Sstevel@tonic-gate 			if (cur_slot->sl_wfse_state == WFSE_ACTIVE) {
3107c478bd9Sstevel@tonic-gate 				(void) pthread_mutex_unlock(
311*d288ba74SAnthony Scarpino 				    &cur_slot->sl_mutex);
3127c478bd9Sstevel@tonic-gate 				continue;
3137c478bd9Sstevel@tonic-gate 			}
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 			cur_slot->sl_wfse_state = WFSE_ACTIVE;
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 			/*
3197c478bd9Sstevel@tonic-gate 			 * Release the hold on the slot's mutex while we
3207c478bd9Sstevel@tonic-gate 			 * are waiting for this function to complete.
3217c478bd9Sstevel@tonic-gate 			 */
3227c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&cur_slot->sl_mutex);
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 			rv = FUNCLIST(i)->C_WaitForSlotEvent(flags,
3257c478bd9Sstevel@tonic-gate 			    pSlot, pReserved);
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_lock(&cur_slot->sl_mutex);
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 			cur_slot->sl_wfse_state = WFSE_CLEAR;
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&cur_slot->sl_mutex);
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 			/* See if we've found a slot with an event */
3347c478bd9Sstevel@tonic-gate 			if ((rv == CKR_OK) && (pSlot != NULL)) {
3357c478bd9Sstevel@tonic-gate 				/*
3367c478bd9Sstevel@tonic-gate 				 * Try to map the returned slotid to a slot
3377c478bd9Sstevel@tonic-gate 				 * allocated by the framework.  All slots from
3387c478bd9Sstevel@tonic-gate 				 * one provider are adjacent in the framework's
3397c478bd9Sstevel@tonic-gate 				 * slottable, so search for a mapping while
3407c478bd9Sstevel@tonic-gate 				 * the prov_id field is the same.
3417c478bd9Sstevel@tonic-gate 				 */
3427c478bd9Sstevel@tonic-gate 				j = i;
3437c478bd9Sstevel@tonic-gate 				while (prov_id ==
3447c478bd9Sstevel@tonic-gate 				    slottable->st_slots[j]->sl_prov_id) {
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 					/* Find the slot, remap pSlot */
3477c478bd9Sstevel@tonic-gate 					if (*pSlot == TRUEID(j)) {
3487c478bd9Sstevel@tonic-gate 						*pSlot = j;
3497c478bd9Sstevel@tonic-gate 						(void) pthread_mutex_lock(
350*d288ba74SAnthony Scarpino 						    &slottable->st_mutex);
3517c478bd9Sstevel@tonic-gate 						slottable->st_wfse_active =
3527c478bd9Sstevel@tonic-gate 						    B_FALSE;
3537c478bd9Sstevel@tonic-gate 						(void) pthread_mutex_unlock(
354*d288ba74SAnthony Scarpino 						    &slottable->st_mutex);
3557c478bd9Sstevel@tonic-gate 						return (CKR_OK);
3567c478bd9Sstevel@tonic-gate 					}
3577c478bd9Sstevel@tonic-gate 					j++;
3587c478bd9Sstevel@tonic-gate 				}
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 			}
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 			/*
3637c478bd9Sstevel@tonic-gate 			 * If we reach this part of the loop, this
3647c478bd9Sstevel@tonic-gate 			 * provider either had no events, did not support
3657c478bd9Sstevel@tonic-gate 			 * this function, or set pSlot to a value we
3667c478bd9Sstevel@tonic-gate 			 * could not find in the slots associated with
3677c478bd9Sstevel@tonic-gate 			 * this provider. Continue checking with remaining
3687c478bd9Sstevel@tonic-gate 			 * providers.
3697c478bd9Sstevel@tonic-gate 			 */
3707c478bd9Sstevel@tonic-gate 			last_prov_id = prov_id;
3717c478bd9Sstevel@tonic-gate 		}
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 		/* No provider had any events */
3747c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&slottable->st_mutex);
3757c478bd9Sstevel@tonic-gate 		slottable->st_wfse_active = B_FALSE;
3767c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&slottable->st_mutex);
3777c478bd9Sstevel@tonic-gate 		return (CKR_NO_EVENT);
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	} else if (!(flags & CKF_DONT_BLOCK) && (pkcs11_cant_create_threads)) {
3807c478bd9Sstevel@tonic-gate 		/*
3817c478bd9Sstevel@tonic-gate 		 * Application has asked us to block, but forbidden
3827c478bd9Sstevel@tonic-gate 		 * us from creating threads.  This is too risky to perform
3837c478bd9Sstevel@tonic-gate 		 * with underlying providers (we may block indefinitely),
3847c478bd9Sstevel@tonic-gate 		 * so will return an error in this case.
3857c478bd9Sstevel@tonic-gate 		 */
3867c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&slottable->st_mutex);
3877c478bd9Sstevel@tonic-gate 		slottable->st_wfse_active = B_FALSE;
3887c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&slottable->st_mutex);
3897c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
3907c478bd9Sstevel@tonic-gate 	}
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 	/*
3937c478bd9Sstevel@tonic-gate 	 * Grab the st_start_mutex now, which will prevent the listener
3947c478bd9Sstevel@tonic-gate 	 * thread from signaling on st_start_cond before we're ready to
3957c478bd9Sstevel@tonic-gate 	 * wait for it.
3967c478bd9Sstevel@tonic-gate 	 */
3977c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&slottable->st_start_mutex);
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	/*
4007c478bd9Sstevel@tonic-gate 	 * Application allows us to create threads and has
4017c478bd9Sstevel@tonic-gate 	 * asked us to block.  Create listener thread to wait for
4027c478bd9Sstevel@tonic-gate 	 * child threads to return.
4037c478bd9Sstevel@tonic-gate 	 */
4047c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&slottable->st_mutex);
4057c478bd9Sstevel@tonic-gate 	if (pthread_create(&slottable->st_tid, NULL,
406*d288ba74SAnthony Scarpino 	    listener_waitforslotevent, NULL) != 0) {
4077c478bd9Sstevel@tonic-gate 		slottable->st_wfse_active = B_FALSE;
4087c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&slottable->st_mutex);
4097c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&slottable->st_start_mutex);
4107c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
4117c478bd9Sstevel@tonic-gate 	}
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&slottable->st_mutex);
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	/*
4167c478bd9Sstevel@tonic-gate 	 * Wait for the listening thread to get started before
4177c478bd9Sstevel@tonic-gate 	 * we spawn child threads.
4187c478bd9Sstevel@tonic-gate 	 */
4197c478bd9Sstevel@tonic-gate 	(void) pthread_cond_wait(&slottable->st_start_cond,
4207c478bd9Sstevel@tonic-gate 	    &slottable->st_start_mutex);
4217c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&slottable->st_start_mutex);
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	/*
4247c478bd9Sstevel@tonic-gate 	 * Need to hold the mutex on the entire slottable for the
4257c478bd9Sstevel@tonic-gate 	 * entire setup of the child threads.  Otherwise, the first
4267c478bd9Sstevel@tonic-gate 	 * child thread may complete before a later child thread is
4277c478bd9Sstevel@tonic-gate 	 * fully started, resulting in an inaccurate value of
4287c478bd9Sstevel@tonic-gate 	 * st_thr_count and a potential race condition.
4297c478bd9Sstevel@tonic-gate 	 */
4307c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&slottable->st_mutex);
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	/*
4337c478bd9Sstevel@tonic-gate 	 * Create child threads to check with the plugged in providers
4347c478bd9Sstevel@tonic-gate 	 * to check for events.  Keep a count of the current open threads,
4357c478bd9Sstevel@tonic-gate 	 * so the listener thread knows when there are no more children
4367c478bd9Sstevel@tonic-gate 	 * to listen for.  Also, make sure a thread is not already active
4377c478bd9Sstevel@tonic-gate 	 * for that provider.
4387c478bd9Sstevel@tonic-gate 	 */
4397c478bd9Sstevel@tonic-gate 	for (i = slottable->st_first; i <= slottable->st_last; i++) {
4407c478bd9Sstevel@tonic-gate 		prov_id = slottable->st_slots[i]->sl_prov_id;
4417c478bd9Sstevel@tonic-gate 		cur_slot = slottable->st_slots[i];
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 		/*
4447c478bd9Sstevel@tonic-gate 		 * Only do process once per provider.
4457c478bd9Sstevel@tonic-gate 		 */
4467c478bd9Sstevel@tonic-gate 		if (prov_id == last_prov_id) {
4477c478bd9Sstevel@tonic-gate 			continue;
4487c478bd9Sstevel@tonic-gate 		}
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 		/*
4517c478bd9Sstevel@tonic-gate 		 * Check to make sure a child thread is not already running,
4527c478bd9Sstevel@tonic-gate 		 * due to another of the application's threads calling
4537c478bd9Sstevel@tonic-gate 		 * this function. Also, check that the provider has actually
4547c478bd9Sstevel@tonic-gate 		 * implemented this function.
4557c478bd9Sstevel@tonic-gate 		 */
4567c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&cur_slot->sl_mutex);
4577c478bd9Sstevel@tonic-gate 		if ((cur_slot->sl_wfse_state == WFSE_ACTIVE) ||
4587c478bd9Sstevel@tonic-gate 		    (cur_slot->sl_no_wfse)) {
4597c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&cur_slot->sl_mutex);
4607c478bd9Sstevel@tonic-gate 			last_prov_id = prov_id;
4617c478bd9Sstevel@tonic-gate 			continue;
4627c478bd9Sstevel@tonic-gate 		}
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 		/* Set slot to active */
4657c478bd9Sstevel@tonic-gate 		cur_slot->sl_wfse_state = WFSE_ACTIVE;
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 		/*
4687c478bd9Sstevel@tonic-gate 		 * set up variable to pass arguments to child threads.
4697c478bd9Sstevel@tonic-gate 		 * Only need to set up once, as values will remain the
4707c478bd9Sstevel@tonic-gate 		 * same for each successive call.
4717c478bd9Sstevel@tonic-gate 		 */
4727c478bd9Sstevel@tonic-gate 		if (cur_slot->sl_wfse_args == NULL) {
4737c478bd9Sstevel@tonic-gate 			cur_slot->sl_wfse_args = malloc(sizeof (wfse_args_t));
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 			if (cur_slot->sl_wfse_args == NULL) {
4767c478bd9Sstevel@tonic-gate 				(void) pthread_mutex_unlock(
477*d288ba74SAnthony Scarpino 				    &cur_slot->sl_mutex);
4787c478bd9Sstevel@tonic-gate 				slottable->st_wfse_active = B_FALSE;
4797c478bd9Sstevel@tonic-gate 				(void) pthread_mutex_unlock(
480*d288ba74SAnthony Scarpino 				    &slottable->st_mutex);
4817c478bd9Sstevel@tonic-gate 				return (CKR_HOST_MEMORY);
4827c478bd9Sstevel@tonic-gate 			}
4837c478bd9Sstevel@tonic-gate 			cur_slot->sl_wfse_args->flags = flags;
4847c478bd9Sstevel@tonic-gate 			cur_slot->sl_wfse_args->pReserved = pReserved;
4857c478bd9Sstevel@tonic-gate 			cur_slot->sl_wfse_args->slotid = i;
4867c478bd9Sstevel@tonic-gate 		}
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 		/* Create child thread */
4897c478bd9Sstevel@tonic-gate 		if (pthread_create(&cur_slot->sl_tid, NULL,
490*d288ba74SAnthony Scarpino 		    child_waitforslotevent,
491*d288ba74SAnthony Scarpino 		    (void *)cur_slot->sl_wfse_args) != 0) {
4927c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&cur_slot->sl_mutex);
4937c478bd9Sstevel@tonic-gate 			continue;
4947c478bd9Sstevel@tonic-gate 		}
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&cur_slot->sl_mutex);
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 		/*
4997c478bd9Sstevel@tonic-gate 		 * This counter is decremented every time a
5007c478bd9Sstevel@tonic-gate 		 * child_waitforslotevent() wakes up the listener.
5017c478bd9Sstevel@tonic-gate 		 */
5027c478bd9Sstevel@tonic-gate 		slottable->st_thr_count++;
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 		last_prov_id = prov_id;
5057c478bd9Sstevel@tonic-gate 	}
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	/* If no children are listening, kill the listener */
5087c478bd9Sstevel@tonic-gate 	if (slottable->st_thr_count == 0) {
5097c478bd9Sstevel@tonic-gate 		(void) pthread_cancel(slottable->st_tid);
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 		/* If there are no child threads, no event will occur */
5127c478bd9Sstevel@tonic-gate 		slottable->st_wfse_active = B_FALSE;
5137c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&slottable->st_mutex);
5147c478bd9Sstevel@tonic-gate 		return (CKR_NO_EVENT);
5157c478bd9Sstevel@tonic-gate 	}
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&slottable->st_mutex);
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 	/* Wait for listener thread to terminate */
5207c478bd9Sstevel@tonic-gate 	(void) pthread_join(slottable->st_tid, NULL);
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	/* Make sure C_Finalize has not been called */
5237c478bd9Sstevel@tonic-gate 	if (!pkcs11_initialized) {
5247c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&slottable->st_mutex);
5257c478bd9Sstevel@tonic-gate 		slottable->st_wfse_active = B_FALSE;
5267c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&slottable->st_mutex);
5277c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
5287c478bd9Sstevel@tonic-gate 	}
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	/* See if any events actually occurred */
5317c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&slottable->st_mutex);
5327c478bd9Sstevel@tonic-gate 	event_slot = slottable->st_event_slot;
5337c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&slottable->st_mutex);
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 	if (pkcs11_is_valid_slot(event_slot) == CKR_OK) {
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&slottable->
5387c478bd9Sstevel@tonic-gate 		    st_slots[event_slot]->sl_mutex);
5397c478bd9Sstevel@tonic-gate 		if (slottable->st_slots[event_slot]->
5407c478bd9Sstevel@tonic-gate 		    sl_wfse_state == WFSE_EVENT) {
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 			/* An event has occurred on this slot */
5437c478bd9Sstevel@tonic-gate 			slottable->st_slots[event_slot]->sl_wfse_state =
5447c478bd9Sstevel@tonic-gate 			    WFSE_CLEAR;
5457c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&slottable->
5467c478bd9Sstevel@tonic-gate 			    st_slots[event_slot]->sl_mutex);
5477c478bd9Sstevel@tonic-gate 			*pSlot = event_slot;
5487c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_lock(&slottable->st_mutex);
5497c478bd9Sstevel@tonic-gate 			slottable->st_blocking = B_FALSE;
5507c478bd9Sstevel@tonic-gate 			slottable->st_wfse_active = B_FALSE;
5517c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&slottable->st_mutex);
5527c478bd9Sstevel@tonic-gate 			return (CKR_OK);
5537c478bd9Sstevel@tonic-gate 		} else {
5547c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&slottable->
5557c478bd9Sstevel@tonic-gate 			    st_slots[event_slot]->sl_mutex);
5567c478bd9Sstevel@tonic-gate 		}
5577c478bd9Sstevel@tonic-gate 	}
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&slottable->st_mutex);
5607c478bd9Sstevel@tonic-gate 	slottable->st_blocking = B_FALSE;
5617c478bd9Sstevel@tonic-gate 	slottable->st_wfse_active = B_FALSE;
5627c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&slottable->st_mutex);
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	/* No provider reported any events, or no provider implemented this */
5657c478bd9Sstevel@tonic-gate 	return (CKR_NO_EVENT);
5667c478bd9Sstevel@tonic-gate }
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate /*
5697c478bd9Sstevel@tonic-gate  * C_GetMechanismList cannot just be a direct pass through to the
5707c478bd9Sstevel@tonic-gate  * underlying provider, because we allow the administrator to
5717c478bd9Sstevel@tonic-gate  * disable certain mechanisms from specific providers.  This affects
5727c478bd9Sstevel@tonic-gate  * both pulCount and pMechanismList.  Only when the fastpath with
5737c478bd9Sstevel@tonic-gate  * no policy is in effect can we pass through directly to the
5747c478bd9Sstevel@tonic-gate  * underlying provider.
5757c478bd9Sstevel@tonic-gate  *
5767c478bd9Sstevel@tonic-gate  * It is necessary, for policy filtering, to get the actual list
5777c478bd9Sstevel@tonic-gate  * of mechanisms from the underlying provider, even if the calling
5787c478bd9Sstevel@tonic-gate  * application is just requesting a count.  It is the only way to
5797c478bd9Sstevel@tonic-gate  * get an accurate count of the number of mechanisms actually available.
5807c478bd9Sstevel@tonic-gate  */
5817c478bd9Sstevel@tonic-gate CK_RV
C_GetMechanismList(CK_SLOT_ID slotID,CK_MECHANISM_TYPE_PTR pMechanismList,CK_ULONG_PTR pulCount)5827c478bd9Sstevel@tonic-gate C_GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList,
5837c478bd9Sstevel@tonic-gate     CK_ULONG_PTR pulCount)
5847c478bd9Sstevel@tonic-gate {
5857c478bd9Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
5867c478bd9Sstevel@tonic-gate 	CK_ULONG mech_count;
5877c478bd9Sstevel@tonic-gate 	CK_ULONG tmpmech_count;
5887c478bd9Sstevel@tonic-gate 	CK_MECHANISM_TYPE_PTR pmech_list, tmpmech_list;
5897c478bd9Sstevel@tonic-gate 	CK_SLOT_ID true_id;
5907c478bd9Sstevel@tonic-gate 	CK_SLOT_ID fw_st_id; /* id for accessing framework's slottable */
5917c478bd9Sstevel@tonic-gate 	CK_FUNCTION_LIST_PTR prov_funcs;
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 	CK_ULONG i;
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	if (!pkcs11_initialized) {
5967c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
5977c478bd9Sstevel@tonic-gate 	}
5987c478bd9Sstevel@tonic-gate 
599*d288ba74SAnthony Scarpino 	/* Check for a fastpath */
600*d288ba74SAnthony Scarpino 	if ((purefastpath || policyfastpath) && !metaslot_enabled)
601*d288ba74SAnthony Scarpino 		return (fast_funcs->C_GetMechanismList(slotID,
602*d288ba74SAnthony Scarpino 		    pMechanismList, pulCount));
603*d288ba74SAnthony Scarpino 
6047c478bd9Sstevel@tonic-gate 	if (slotID == METASLOT_FRAMEWORK_ID) {
6057c478bd9Sstevel@tonic-gate 		return (meta_GetMechanismList(METASLOT_SLOTID, pMechanismList,
6067c478bd9Sstevel@tonic-gate 		    pulCount));
6077c478bd9Sstevel@tonic-gate 	}
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	/* Check that slotID is valid */
6107c478bd9Sstevel@tonic-gate 	if (pkcs11_validate_and_convert_slotid(slotID, &fw_st_id) != CKR_OK) {
6117c478bd9Sstevel@tonic-gate 		return (CKR_SLOT_ID_INVALID);
6127c478bd9Sstevel@tonic-gate 	}
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 	if (policyfastpath) {
6157c478bd9Sstevel@tonic-gate 		true_id = fw_st_id;
6167c478bd9Sstevel@tonic-gate 		slotID = fast_slot;
6177c478bd9Sstevel@tonic-gate 		prov_funcs = fast_funcs;
6187c478bd9Sstevel@tonic-gate 	} else {
6197c478bd9Sstevel@tonic-gate 		true_id = TRUEID(fw_st_id);
6207c478bd9Sstevel@tonic-gate 		prov_funcs = FUNCLIST(fw_st_id);
6217c478bd9Sstevel@tonic-gate 	}
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	mech_count = 0;
6247c478bd9Sstevel@tonic-gate 	tmpmech_count = MECHLIST_SIZE;
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 	/*
6277c478bd9Sstevel@tonic-gate 	 * Allocate memory for a mechanism list.  We are assuming
6287c478bd9Sstevel@tonic-gate 	 * that most mechanism lists will be less than MECHLIST_SIZE.
6297c478bd9Sstevel@tonic-gate 	 * If that is not enough memory, we will try a second time
6307c478bd9Sstevel@tonic-gate 	 * with more memory allocated.
6317c478bd9Sstevel@tonic-gate 	 */
6327c478bd9Sstevel@tonic-gate 	pmech_list = malloc(tmpmech_count * sizeof (CK_MECHANISM_TYPE));
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	if (pmech_list == NULL) {
6357c478bd9Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
6367c478bd9Sstevel@tonic-gate 	}
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	/*
6397c478bd9Sstevel@tonic-gate 	 * Attempt to get the mechanism list.  PKCS11 supports
6407c478bd9Sstevel@tonic-gate 	 * removable media, so the mechanism list of a slot can vary
6417c478bd9Sstevel@tonic-gate 	 * over the life of the application.
6427c478bd9Sstevel@tonic-gate 	 */
6437c478bd9Sstevel@tonic-gate 	rv = prov_funcs->C_GetMechanismList(true_id,
6447c478bd9Sstevel@tonic-gate 	    pmech_list, &tmpmech_count);
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	if (rv == CKR_BUFFER_TOO_SMALL) {
6477c478bd9Sstevel@tonic-gate 		/* Need to use more space */
6487c478bd9Sstevel@tonic-gate 		tmpmech_list = pmech_list;
6497c478bd9Sstevel@tonic-gate 		pmech_list = realloc
6507c478bd9Sstevel@tonic-gate 		    (tmpmech_list, tmpmech_count * sizeof (CK_MECHANISM_TYPE));
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 		if (pmech_list == NULL) {
6537c478bd9Sstevel@tonic-gate 			free(tmpmech_list);
6547c478bd9Sstevel@tonic-gate 			return (CKR_HOST_MEMORY);
6557c478bd9Sstevel@tonic-gate 		}
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 		/* Try again to get mechanism list. */
6587c478bd9Sstevel@tonic-gate 		rv = prov_funcs->C_GetMechanismList(true_id,
6597c478bd9Sstevel@tonic-gate 		    pmech_list, &tmpmech_count);
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 	}
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	/*
6647c478bd9Sstevel@tonic-gate 	 * Present consistent face to calling application.
6657c478bd9Sstevel@tonic-gate 	 * If something strange has happened, or this function
6667c478bd9Sstevel@tonic-gate 	 * is not supported by this provider, return a count
6677c478bd9Sstevel@tonic-gate 	 * of zero mechanisms.
6687c478bd9Sstevel@tonic-gate 	 */
6697c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
6707c478bd9Sstevel@tonic-gate 		*pulCount = 0;
6717c478bd9Sstevel@tonic-gate 		free(pmech_list);
6727c478bd9Sstevel@tonic-gate 		return (CKR_OK);
6737c478bd9Sstevel@tonic-gate 	}
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	/*
6767c478bd9Sstevel@tonic-gate 	 * Process the mechanism list, removing any mechanisms
6777c478bd9Sstevel@tonic-gate 	 * that are disabled via the framework.  Even if the
6787c478bd9Sstevel@tonic-gate 	 * application is only asking for a count, we must
6797c478bd9Sstevel@tonic-gate 	 * process the actual mechanisms being offered by this slot.
6807c478bd9Sstevel@tonic-gate 	 * We could not just subtract our stored count of disabled
6817c478bd9Sstevel@tonic-gate 	 * mechanisms, since it is not guaranteed that those
6827c478bd9Sstevel@tonic-gate 	 * mechanisms are actually supported by the slot.
6837c478bd9Sstevel@tonic-gate 	 */
6847c478bd9Sstevel@tonic-gate 	for (i = 0; i < tmpmech_count; i++) {
6857c478bd9Sstevel@tonic-gate 		/* Filter out the disabled mechanisms */
6867c478bd9Sstevel@tonic-gate 		if (pkcs11_is_dismech(fw_st_id, pmech_list[i])) {
6877c478bd9Sstevel@tonic-gate 			continue;
6887c478bd9Sstevel@tonic-gate 		}
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 		/*
6917c478bd9Sstevel@tonic-gate 		 * Only set pMechanismList if enough memory
6927c478bd9Sstevel@tonic-gate 		 * is available.  If it was set to NULL
6937c478bd9Sstevel@tonic-gate 		 * originally, this loop will just be counting
6947c478bd9Sstevel@tonic-gate 		 * mechanims.
6957c478bd9Sstevel@tonic-gate 		 */
6967c478bd9Sstevel@tonic-gate 		if (pMechanismList && (*pulCount > mech_count)) {
6977c478bd9Sstevel@tonic-gate 			pMechanismList[mech_count] = pmech_list[i];
6987c478bd9Sstevel@tonic-gate 		}
6997c478bd9Sstevel@tonic-gate 		mech_count++;
7007c478bd9Sstevel@tonic-gate 	}
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	/*
7037c478bd9Sstevel@tonic-gate 	 * Catch the case where pMechanismList was not set to NULL,
7047c478bd9Sstevel@tonic-gate 	 * yet the buffer was not large enough.  If pMechanismList is
7057c478bd9Sstevel@tonic-gate 	 * set to NULL, this function will simply set pulCount and
7067c478bd9Sstevel@tonic-gate 	 * return CKR_OK.
7077c478bd9Sstevel@tonic-gate 	 */
7087c478bd9Sstevel@tonic-gate 	if ((*pulCount < mech_count) && (pMechanismList != NULL)) {
7097c478bd9Sstevel@tonic-gate 		*pulCount = mech_count;
7107c478bd9Sstevel@tonic-gate 		free(pmech_list);
7117c478bd9Sstevel@tonic-gate 		return (CKR_BUFFER_TOO_SMALL);
7127c478bd9Sstevel@tonic-gate 	}
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 	*pulCount = mech_count;
7157c478bd9Sstevel@tonic-gate 	free(pmech_list);
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 	return (CKR_OK);
7187c478bd9Sstevel@tonic-gate }
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate CK_RV
C_GetMechanismInfo(CK_SLOT_ID slotID,CK_MECHANISM_TYPE type,CK_MECHANISM_INFO_PTR pInfo)7227c478bd9Sstevel@tonic-gate C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type,
7237c478bd9Sstevel@tonic-gate     CK_MECHANISM_INFO_PTR pInfo)
7247c478bd9Sstevel@tonic-gate {
7257c478bd9Sstevel@tonic-gate 	CK_RV rv;
7267c478bd9Sstevel@tonic-gate 	CK_SLOT_ID true_id;
7277c478bd9Sstevel@tonic-gate 	CK_SLOT_ID fw_st_id; /* id for accessing framework's slottable */
7287c478bd9Sstevel@tonic-gate 	CK_FUNCTION_LIST_PTR prov_funcs;
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 	if (!pkcs11_initialized) {
7317c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
7327c478bd9Sstevel@tonic-gate 	}
7337c478bd9Sstevel@tonic-gate 
734*d288ba74SAnthony Scarpino 	/* Check for a fastpath */
735*d288ba74SAnthony Scarpino 	if ((purefastpath || policyfastpath) && !metaslot_enabled)
736*d288ba74SAnthony Scarpino 		return (fast_funcs->C_GetMechanismInfo(slotID, type, pInfo));
737*d288ba74SAnthony Scarpino 
7387c478bd9Sstevel@tonic-gate 	if (slotID == METASLOT_FRAMEWORK_ID) {
7397c478bd9Sstevel@tonic-gate 		/* just need to get metaslot information */
7407c478bd9Sstevel@tonic-gate 		return (meta_GetMechanismInfo(METASLOT_SLOTID, type, pInfo));
7417c478bd9Sstevel@tonic-gate 	}
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 	/* Check that slotID is valid */
7447c478bd9Sstevel@tonic-gate 	if (pkcs11_validate_and_convert_slotid(slotID, &fw_st_id) != CKR_OK) {
7457c478bd9Sstevel@tonic-gate 		return (CKR_SLOT_ID_INVALID);
7467c478bd9Sstevel@tonic-gate 	}
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	if (policyfastpath) {
7497c478bd9Sstevel@tonic-gate 		true_id = fw_st_id;
7507c478bd9Sstevel@tonic-gate 		slotID = fast_slot;
7517c478bd9Sstevel@tonic-gate 		prov_funcs = fast_funcs;
7527c478bd9Sstevel@tonic-gate 	} else {
7537c478bd9Sstevel@tonic-gate 		true_id = TRUEID(fw_st_id);
7547c478bd9Sstevel@tonic-gate 		prov_funcs = FUNCLIST(fw_st_id);
7557c478bd9Sstevel@tonic-gate 	}
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	/* Make sure this is not a disabled mechanism */
7587c478bd9Sstevel@tonic-gate 	if (pkcs11_is_dismech(fw_st_id, type)) {
7597c478bd9Sstevel@tonic-gate 		return (CKR_MECHANISM_INVALID);
7607c478bd9Sstevel@tonic-gate 	}
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 	rv = prov_funcs->C_GetMechanismInfo(true_id, type, pInfo);
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 	/* Present consistent interface to the application */
7657c478bd9Sstevel@tonic-gate 	if (rv == CKR_FUNCTION_NOT_SUPPORTED) {
7667c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
7677c478bd9Sstevel@tonic-gate 	}
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 	return (rv);
7707c478bd9Sstevel@tonic-gate }
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate CK_RV
C_InitToken(CK_SLOT_ID slotID,CK_UTF8CHAR_PTR pPin,CK_ULONG ulPinLen,CK_UTF8CHAR_PTR pLabel)7747c478bd9Sstevel@tonic-gate C_InitToken(CK_SLOT_ID slotID, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen,
7757c478bd9Sstevel@tonic-gate     CK_UTF8CHAR_PTR pLabel)
7767c478bd9Sstevel@tonic-gate {
7777c478bd9Sstevel@tonic-gate 	CK_RV rv;
7787c478bd9Sstevel@tonic-gate 	CK_SLOT_ID fw_st_id; /* id for accessing framework's slottable */
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 	if (!pkcs11_initialized) {
7817c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
7827c478bd9Sstevel@tonic-gate 	}
7837c478bd9Sstevel@tonic-gate 
784*d288ba74SAnthony Scarpino 	/* Check for a fastpath */
785*d288ba74SAnthony Scarpino 	if ((purefastpath || policyfastpath) && !metaslot_enabled)
786*d288ba74SAnthony Scarpino 		return (fast_funcs->C_InitToken(slotID, pPin, ulPinLen,
787*d288ba74SAnthony Scarpino 		    pLabel));
788*d288ba74SAnthony Scarpino 
7897c478bd9Sstevel@tonic-gate 	if (slotID == METASLOT_FRAMEWORK_ID) {
7907c478bd9Sstevel@tonic-gate 		/* just need to get metaslot information */
7917c478bd9Sstevel@tonic-gate 		return (meta_InitToken(METASLOT_SLOTID, pPin, ulPinLen,
7927c478bd9Sstevel@tonic-gate 		    pLabel));
7937c478bd9Sstevel@tonic-gate 	}
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 	/* Check that slotID is valid */
7967c478bd9Sstevel@tonic-gate 	if (pkcs11_validate_and_convert_slotid(slotID, &fw_st_id) != CKR_OK) {
7977c478bd9Sstevel@tonic-gate 		return (CKR_SLOT_ID_INVALID);
7987c478bd9Sstevel@tonic-gate 	}
7997c478bd9Sstevel@tonic-gate 
800*d288ba74SAnthony Scarpino 	rv = FUNCLIST(fw_st_id)->C_InitToken(TRUEID(fw_st_id), pPin, ulPinLen,
801*d288ba74SAnthony Scarpino 	    pLabel);
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 	/* Present consistent interface to the application */
8047c478bd9Sstevel@tonic-gate 	if (rv == CKR_FUNCTION_NOT_SUPPORTED) {
8057c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
8067c478bd9Sstevel@tonic-gate 	}
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	return (rv);
8097c478bd9Sstevel@tonic-gate }
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate CK_RV
C_InitPIN(CK_SESSION_HANDLE hSession,CK_UTF8CHAR_PTR pPin,CK_ULONG ulPinLen)8127c478bd9Sstevel@tonic-gate C_InitPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen)
8137c478bd9Sstevel@tonic-gate {
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 	CK_RV rv;
8167c478bd9Sstevel@tonic-gate 	pkcs11_session_t *sessp;
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 	/* Check for a fastpath */
8197c478bd9Sstevel@tonic-gate 	if (purefastpath || policyfastpath) {
8207c478bd9Sstevel@tonic-gate 		return (fast_funcs->C_InitPIN(hSession, pPin, ulPinLen));
8217c478bd9Sstevel@tonic-gate 	}
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 	if (!pkcs11_initialized) {
8247c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
8257c478bd9Sstevel@tonic-gate 	}
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	/* Obtain the session pointer */
8287c478bd9Sstevel@tonic-gate 	HANDLE2SESSION(hSession, sessp, rv);
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
8317c478bd9Sstevel@tonic-gate 		return (rv);
8327c478bd9Sstevel@tonic-gate 	}
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 	/* Initialize the PIN with the provider */
8357c478bd9Sstevel@tonic-gate 	rv = FUNCLIST(sessp->se_slotid)->C_InitPIN(sessp->se_handle,
8367c478bd9Sstevel@tonic-gate 	    pPin, ulPinLen);
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 	/* Present consistent interface to the application */
8397c478bd9Sstevel@tonic-gate 	if (rv == CKR_FUNCTION_NOT_SUPPORTED) {
8407c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
8417c478bd9Sstevel@tonic-gate 	}
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 	return (rv);
8447c478bd9Sstevel@tonic-gate }
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate CK_RV
C_SetPIN(CK_SESSION_HANDLE hSession,CK_UTF8CHAR_PTR pOldPin,CK_ULONG ulOldPinLen,CK_UTF8CHAR_PTR pNewPin,CK_ULONG ulNewPinLen)8477c478bd9Sstevel@tonic-gate C_SetPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pOldPin,
8487c478bd9Sstevel@tonic-gate 	CK_ULONG ulOldPinLen, CK_UTF8CHAR_PTR pNewPin,
8497c478bd9Sstevel@tonic-gate 	CK_ULONG ulNewPinLen)
8507c478bd9Sstevel@tonic-gate {
8517c478bd9Sstevel@tonic-gate 	CK_RV rv;
8527c478bd9Sstevel@tonic-gate 	pkcs11_session_t *sessp;
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 	/* Check for a fastpath */
8557c478bd9Sstevel@tonic-gate 	if (purefastpath || policyfastpath) {
8567c478bd9Sstevel@tonic-gate 		return (fast_funcs->C_SetPIN(hSession, pOldPin, ulOldPinLen,
857*d288ba74SAnthony Scarpino 		    pNewPin, ulNewPinLen));
8587c478bd9Sstevel@tonic-gate 	}
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	if (!pkcs11_initialized) {
8617c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
8627c478bd9Sstevel@tonic-gate 	}
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	/* Obtain the session pointer */
8657c478bd9Sstevel@tonic-gate 	HANDLE2SESSION(hSession, sessp, rv);
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
8687c478bd9Sstevel@tonic-gate 		return (rv);
8697c478bd9Sstevel@tonic-gate 	}
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 	/* Set the PIN with the provider */
8727c478bd9Sstevel@tonic-gate 	rv = FUNCLIST(sessp->se_slotid)->C_SetPIN(sessp->se_handle,
8737c478bd9Sstevel@tonic-gate 	    pOldPin, ulOldPinLen, pNewPin, ulNewPinLen);
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	/* Present consistent interface to the application */
8767c478bd9Sstevel@tonic-gate 	if (rv == CKR_FUNCTION_NOT_SUPPORTED) {
8777c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
8787c478bd9Sstevel@tonic-gate 	}
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 	return (rv);
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate }
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate /*
8857c478bd9Sstevel@tonic-gate  * listener_waitforslotevent is spawned by the main C_WaitForSlotEvent()
8867c478bd9Sstevel@tonic-gate  * to listen for events from any of the providers.  It also watches the
8877c478bd9Sstevel@tonic-gate  * count of threads, which may go to zero with no recorded events, if
8887c478bd9Sstevel@tonic-gate  * none of the underlying providers have actually implemented this
8897c478bd9Sstevel@tonic-gate  * function.
8907c478bd9Sstevel@tonic-gate  */
8917c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8927c478bd9Sstevel@tonic-gate static void *
listener_waitforslotevent(void * arg)8937c478bd9Sstevel@tonic-gate listener_waitforslotevent(void *arg) {
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	CK_SLOT_ID eventID;
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 	/* Mark slottable in state blocking */
8987c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&slottable->st_mutex);
8997c478bd9Sstevel@tonic-gate 	slottable->st_blocking = B_TRUE;
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 	/* alert calling thread that this thread has started */
9027c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&slottable->st_start_mutex);
9037c478bd9Sstevel@tonic-gate 	(void) pthread_cond_signal(&slottable->st_start_cond);
9047c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&slottable->st_start_mutex);
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 	/* wait for an event, or number of threads to reach zero */
9077c478bd9Sstevel@tonic-gate 	for (;;) {
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate 		/*
9107c478bd9Sstevel@tonic-gate 		 * Make sure we've really been signaled, and not waking
9117c478bd9Sstevel@tonic-gate 		 * for another reason.
9127c478bd9Sstevel@tonic-gate 		 */
9137c478bd9Sstevel@tonic-gate 		while (slottable->st_list_signaled != B_TRUE) {
9147c478bd9Sstevel@tonic-gate 			(void) pthread_cond_wait(&slottable->st_wait_cond,
9157c478bd9Sstevel@tonic-gate 			    &slottable->st_mutex);
9167c478bd9Sstevel@tonic-gate 		}
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 		slottable->st_list_signaled = B_FALSE;
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 		/* See why we were woken up */
9217c478bd9Sstevel@tonic-gate 		if (!pkcs11_initialized) {
9227c478bd9Sstevel@tonic-gate 			/* Another thread has called C_Finalize() */
9237c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&slottable->st_mutex);
9247c478bd9Sstevel@tonic-gate 			return (NULL);
9257c478bd9Sstevel@tonic-gate 		}
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 		/* A thread has finished, decrement counter */
9287c478bd9Sstevel@tonic-gate 		slottable->st_thr_count--;
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate 		eventID = slottable->st_event_slot;
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 		if (pkcs11_is_valid_slot(eventID) == CKR_OK) {
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_lock(&slottable->
9357c478bd9Sstevel@tonic-gate 			    st_slots[eventID]->sl_mutex);
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 			if (slottable->st_slots[eventID]->
9387c478bd9Sstevel@tonic-gate 			    sl_wfse_state == WFSE_EVENT) {
9397c478bd9Sstevel@tonic-gate 				(void) pthread_mutex_unlock(&slottable->
9407c478bd9Sstevel@tonic-gate 				    st_slots[eventID]->sl_mutex);
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 				/*
9437c478bd9Sstevel@tonic-gate 				 * st_event_slot is set to a valid value, event
9447c478bd9Sstevel@tonic-gate 				 * flag is set for that slot.  The flag will
9457c478bd9Sstevel@tonic-gate 				 * be cleared by main C_WaitForSlotEvent().
9467c478bd9Sstevel@tonic-gate 				 */
9477c478bd9Sstevel@tonic-gate 				(void) pthread_mutex_unlock(
9487c478bd9Sstevel@tonic-gate 					&slottable->st_mutex);
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 				pthread_exit(0);
9517c478bd9Sstevel@tonic-gate 			} else {
9527c478bd9Sstevel@tonic-gate 				(void) pthread_mutex_unlock(&slottable->
9537c478bd9Sstevel@tonic-gate 				    st_slots[eventID]->sl_mutex);
9547c478bd9Sstevel@tonic-gate 			}
9557c478bd9Sstevel@tonic-gate 		}
9567c478bd9Sstevel@tonic-gate 		if (slottable->st_thr_count == 0) {
9577c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&slottable->st_mutex);
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 			/* No more threads, no events found */
9607c478bd9Sstevel@tonic-gate 			pthread_exit(0);
9617c478bd9Sstevel@tonic-gate 		}
9627c478bd9Sstevel@tonic-gate 	}
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
9657c478bd9Sstevel@tonic-gate 	return (NULL);
9667c478bd9Sstevel@tonic-gate }
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate /*
9697c478bd9Sstevel@tonic-gate  * child_waitforslotevent is used as a child thread to contact
9707c478bd9Sstevel@tonic-gate  * underlying provider's C_WaitForSlotEvent().
9717c478bd9Sstevel@tonic-gate  */
9727c478bd9Sstevel@tonic-gate static void *
child_waitforslotevent(void * arg)9737c478bd9Sstevel@tonic-gate child_waitforslotevent(void *arg) {
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 	wfse_args_t *wfse = (wfse_args_t *)arg;
9767c478bd9Sstevel@tonic-gate 	CK_SLOT_ID slot;
9777c478bd9Sstevel@tonic-gate 	CK_RV rv;
9787c478bd9Sstevel@tonic-gate 	uint32_t cur_prov;
9797c478bd9Sstevel@tonic-gate 	CK_SLOT_ID i;
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate 	rv = FUNCLIST(wfse->slotid)->C_WaitForSlotEvent(wfse->flags, &slot,
9827c478bd9Sstevel@tonic-gate 	    wfse->pReserved);
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	/*
9857c478bd9Sstevel@tonic-gate 	 * Need to hold the mutex while processing the results, to
9867c478bd9Sstevel@tonic-gate 	 * keep things synchronized with the listener thread and
9877c478bd9Sstevel@tonic-gate 	 * the slottable.  Otherwise, due to the timing
9887c478bd9Sstevel@tonic-gate 	 * at which some underlying providers complete, the listener
9897c478bd9Sstevel@tonic-gate 	 * thread may not actually be blocking on st_wait_cond when
9907c478bd9Sstevel@tonic-gate 	 * this child signals.  Holding the lock a bit longer prevents
9917c478bd9Sstevel@tonic-gate 	 * this from happening.
9927c478bd9Sstevel@tonic-gate 	 */
9937c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&slottable->st_mutex);
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 	while (slottable->st_list_signaled == B_TRUE) {
9967c478bd9Sstevel@tonic-gate 		/*
9977c478bd9Sstevel@tonic-gate 		 * We've taken the mutex when the listener should have
9987c478bd9Sstevel@tonic-gate 		 * control. Release the mutex, thread scheduler should
9997c478bd9Sstevel@tonic-gate 		 * give control back to the listener.
10007c478bd9Sstevel@tonic-gate 		 */
10017c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&slottable->st_mutex);
10027c478bd9Sstevel@tonic-gate 		(void) sleep(1);
10037c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&slottable->st_mutex);
10047c478bd9Sstevel@tonic-gate 	}
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 	if (rv == CKR_OK) {
10077c478bd9Sstevel@tonic-gate 		/* we've had an event, find slot and store it */
10087c478bd9Sstevel@tonic-gate 		cur_prov = slottable->st_slots[wfse->slotid]->sl_prov_id;
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate 		/*
10117c478bd9Sstevel@tonic-gate 		 * It is safe to unset active status now, since call to
10127c478bd9Sstevel@tonic-gate 		 * underlying provider has already terminated, and we
10137c478bd9Sstevel@tonic-gate 		 * hold the slottable wide mutex (st_mutex).
10147c478bd9Sstevel@tonic-gate 		 */
10157c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&slottable->
10167c478bd9Sstevel@tonic-gate 		    st_slots[wfse->slotid]->sl_mutex);
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 		slottable->st_slots[wfse->slotid]->sl_wfse_state = WFSE_CLEAR;
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&slottable->
10217c478bd9Sstevel@tonic-gate 		    st_slots[wfse->slotid]->sl_mutex);
10227c478bd9Sstevel@tonic-gate 
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 		for (i = wfse->slotid; i <= slottable->st_last; i++) {
10257c478bd9Sstevel@tonic-gate 			if (cur_prov != slottable->st_slots[i]->sl_prov_id) {
10267c478bd9Sstevel@tonic-gate 				break;
10277c478bd9Sstevel@tonic-gate 			}
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 			if (slot == slottable->st_slots[i]->sl_id) {
10307c478bd9Sstevel@tonic-gate 				(void) pthread_mutex_lock(&slottable->
10317c478bd9Sstevel@tonic-gate 				    st_slots[i]->sl_mutex);
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 				slottable->st_slots[i]->
10347c478bd9Sstevel@tonic-gate 				    sl_wfse_state = WFSE_EVENT;
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 				(void) pthread_mutex_unlock(&slottable->
10377c478bd9Sstevel@tonic-gate 				    st_slots[i]->sl_mutex);
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 				slottable->st_event_slot = i;
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 				if (slottable->st_blocking) {
10427c478bd9Sstevel@tonic-gate 					slottable->st_list_signaled = B_TRUE;
10437c478bd9Sstevel@tonic-gate 					(void) pthread_cond_signal(&slottable->
10447c478bd9Sstevel@tonic-gate 					    st_wait_cond);
10457c478bd9Sstevel@tonic-gate 				}
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 				(void) pthread_mutex_unlock(
10487c478bd9Sstevel@tonic-gate 					&slottable->st_mutex);
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate 				pthread_exit(0);
10517c478bd9Sstevel@tonic-gate 			}
10527c478bd9Sstevel@tonic-gate 		}
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 	}
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&slottable->
10577c478bd9Sstevel@tonic-gate 	    st_slots[wfse->slotid]->sl_mutex);
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	/*
10607c478bd9Sstevel@tonic-gate 	 * If the provider told us that it does not support
10617c478bd9Sstevel@tonic-gate 	 * this function, we should mark it so we do not waste
10627c478bd9Sstevel@tonic-gate 	 * time later with it.  If an error returned, we'll clean
10637c478bd9Sstevel@tonic-gate 	 * up this thread now and possibly try it again later.
10647c478bd9Sstevel@tonic-gate 	 */
10657c478bd9Sstevel@tonic-gate 	if (rv == CKR_FUNCTION_NOT_SUPPORTED) {
10667c478bd9Sstevel@tonic-gate 		slottable->st_slots[wfse->slotid]->sl_no_wfse = B_TRUE;
10677c478bd9Sstevel@tonic-gate 	}
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 	/*
10707c478bd9Sstevel@tonic-gate 	 * It is safe to unset active status now, since call to
10717c478bd9Sstevel@tonic-gate 	 * underlying provider has already terminated, and we
10727c478bd9Sstevel@tonic-gate 	 * hold the slottable wide mutex (st_mutex).
10737c478bd9Sstevel@tonic-gate 	 */
10747c478bd9Sstevel@tonic-gate 	slottable->st_slots[wfse->slotid]->sl_wfse_state = WFSE_CLEAR;
10757c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&slottable->
10767c478bd9Sstevel@tonic-gate 	    st_slots[wfse->slotid]->sl_mutex);
10777c478bd9Sstevel@tonic-gate 
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 	if (slottable->st_blocking) {
10807c478bd9Sstevel@tonic-gate 		slottable->st_list_signaled = B_TRUE;
10817c478bd9Sstevel@tonic-gate 		(void) pthread_cond_signal(&slottable->st_wait_cond);
10827c478bd9Sstevel@tonic-gate 	}
10837c478bd9Sstevel@tonic-gate 
10847c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&slottable->st_mutex);
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate 	/* Manually exit the thread, since nobody will join to it */
10877c478bd9Sstevel@tonic-gate 	pthread_exit(0);
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
10907c478bd9Sstevel@tonic-gate 	return (NULL);
10917c478bd9Sstevel@tonic-gate }
1092