Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <stdio.h>
     27 #include <stdlib.h>
     28 #include <pthread.h>
     29 #include <time.h>
     30 #include <security/cryptoki.h>
     31 #include "pkcs11Global.h"
     32 #include "pkcs11Conf.h"
     33 #include "pkcs11Slot.h"
     34 #include "metaGlobal.h"
     35 
     36 static void *listener_waitforslotevent(void *arg);
     37 static void *child_waitforslotevent(void *arg);
     38 
     39 /*
     40  * C_GetSlotList is implemented entirely within this framework,
     41  * using the slottable that was created during the call to
     42  * C_Initialize in pkcs11_slot_mapping().  The plugged in providers
     43  * are only queried when tokenPresent is set.
     44  *
     45  * If metaslot is enabled, the slot that provides keystore support
     46  * needs to be hidden.  Therefore, even when fastpath is enabled,
     47  * we can't go through fastpath because the slot needs to be
     48  * hidden.
     49  */
     50 CK_RV
     51 C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList,
     52     CK_ULONG_PTR pulCount)
     53 {
     54 
     55 	CK_RV rv;
     56 	CK_RV prov_rv;
     57 	CK_SLOT_ID true_id;
     58 	CK_SLOT_INFO_PTR pinfo;
     59 	CK_SLOT_ID count = 0, i;
     60 	CK_SLOT_ID slot_id; /* slot ID for returning to the application */
     61 
     62 	/* Check for a fastpath */
     63 	if ((purefastpath || policyfastpath) && (!metaslot_enabled)) {
     64 		return (fast_funcs->C_GetSlotList(tokenPresent, pSlotList,
     65 		    pulCount));
     66 	}
     67 
     68 	if (!pkcs11_initialized) {
     69 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
     70 	}
     71 
     72 	if (pulCount == NULL) {
     73 		return (CKR_ARGUMENTS_BAD);
     74 	}
     75 
     76 	if (tokenPresent) {
     77 		/* Need to allocate memory for pinfo */
     78 		pinfo = malloc(sizeof (CK_SLOT_INFO));
     79 		if (pinfo == NULL) {
     80 			return (CKR_HOST_MEMORY);
     81 		}
     82 	}
     83 
     84 	/*
     85 	 * Count the number of valid slots for returning to the application.
     86 	 * If metaslot is enabled, the slot providing keystore support for
     87 	 * metaslot is skipped.  Therefore, we can't simply sequentially
     88 	 * assign "i" as the slot id to be returned to the application.
     89 	 * The variable "slot_id" is used for keeping track of the
     90 	 * next slot id to be assigned.
     91 	 */
     92 	slot_id = slottable->st_first;
     93 	for (i = slottable->st_first; i <= slottable->st_last; i++) {
     94 		if ((pkcs11_is_valid_slot(i) == CKR_OK) &&
     95 		    ((!metaslot_enabled) || (i != metaslot_keystore_slotid))) {
     96 
     97 			/* Check if token present is required */
     98 			if (tokenPresent) {
     99 				/* Check with provider */
    100 				true_id = TRUEID(i);
    101 				prov_rv = FUNCLIST(i)->
    102 				    C_GetSlotInfo(true_id, pinfo);
    103 				if ((prov_rv != CKR_OK) ||
    104 				    !(pinfo->flags & CKF_TOKEN_PRESENT)) {
    105 					continue;
    106 				}
    107 			}
    108 			/* Fill in the given buffer if it is sufficient */
    109 			if (pSlotList && (*pulCount > count)) {
    110 				pSlotList[count] = slot_id;
    111 				slot_id++;
    112 			}
    113 			count++;
    114 		}
    115 	}
    116 
    117 	/* pSlotList set to NULL means caller only wants count */
    118 	if ((*pulCount < count) && (pSlotList != NULL)) {
    119 		rv = CKR_BUFFER_TOO_SMALL;
    120 	} else {
    121 		rv = CKR_OK;
    122 	}
    123 
    124 	*pulCount = count;
    125 
    126 	if (tokenPresent) {
    127 		free(pinfo);
    128 	}
    129 
    130 	return (rv);
    131 }
    132 
    133 CK_RV
    134 C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo)
    135 {
    136 
    137 	CK_RV rv;
    138 	CK_SLOT_ID fw_st_id; /* id for accessing framework's slottable */
    139 
    140 	if (!pkcs11_initialized) {
    141 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
    142 	}
    143 
    144 	/* Check for a fastpath */
    145 	if ((purefastpath || policyfastpath) && !metaslot_enabled)
    146 		return (fast_funcs->C_GetSlotInfo(slotID, pInfo));
    147 
    148 	if (slotID == METASLOT_FRAMEWORK_ID) {
    149 		/* just need to get metaslot information */
    150 		return (meta_GetSlotInfo(METASLOT_SLOTID, pInfo));
    151 	}
    152 
    153 	/* Check that slotID is valid */
    154 	if (pkcs11_validate_and_convert_slotid(slotID, &fw_st_id) != CKR_OK) {
    155 		return (CKR_SLOT_ID_INVALID);
    156 	}
    157 
    158 	rv = FUNCLIST(fw_st_id)->C_GetSlotInfo(TRUEID(fw_st_id), pInfo);
    159 
    160 	/* Present consistent interface to the application */
    161 	if (rv == CKR_FUNCTION_NOT_SUPPORTED) {
    162 		return (CKR_FUNCTION_FAILED);
    163 	}
    164 
    165 	return (rv);
    166 }
    167 
    168 CK_RV
    169 C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo)
    170 {
    171 	CK_RV rv;
    172 	CK_SLOT_ID fw_st_id; /* id for accessing framework's slottable */
    173 
    174 	if (!pkcs11_initialized) {
    175 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
    176 	}
    177 
    178 	/* Check for a fastpath */
    179 	if ((purefastpath || policyfastpath) && !metaslot_enabled)
    180 		return (fast_funcs->C_GetTokenInfo(slotID, pInfo));
    181 
    182 	if (slotID == METASLOT_FRAMEWORK_ID) {
    183 		/* just need to get metaslot information */
    184 		return (meta_GetTokenInfo(METASLOT_SLOTID, pInfo));
    185 	}
    186 
    187 	/* Check that slotID is valid */
    188 	if (pkcs11_validate_and_convert_slotid(slotID, &fw_st_id) != CKR_OK) {
    189 		return (CKR_SLOT_ID_INVALID);
    190 	}
    191 
    192 	rv = FUNCLIST(fw_st_id)->C_GetTokenInfo(TRUEID(fw_st_id), pInfo);
    193 
    194 	/* Present consistent interface to the application */
    195 	if (rv == CKR_FUNCTION_NOT_SUPPORTED) {
    196 		return (CKR_FUNCTION_FAILED);
    197 	}
    198 
    199 	return (rv);
    200 }
    201 
    202 /*
    203  * C_WaitForSlotEvent cannot be a direct pass through to the underlying
    204  * provider (except in the case of fastpath), due to the complex nature
    205  * of this function.  The calling application is asking to be alerted
    206  * when an event has occurred on any of the slots in the framework, so
    207  * we need to check with all underlying providers and ask for events
    208  * on any of their slots.  If this is called in blocking mode, we will
    209  * need to start threads to wait for slot events for each provider
    210  * plugged into the framework.
    211  */
    212 CK_RV
    213 C_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved)
    214 {
    215 	CK_SLOT_ID i, j;
    216 	uint32_t prov_id;
    217 	int32_t last_prov_id = -1;
    218 	CK_RV rv = CKR_OK;
    219 	CK_SLOT_ID event_slot;
    220 	pkcs11_slot_t *cur_slot;
    221 
    222 	/* Check for a fastpath */
    223 	if (purefastpath || policyfastpath) {
    224 		return (fast_funcs->C_WaitForSlotEvent(flags, pSlot,
    225 		    pReserved));
    226 	}
    227 
    228 	if (!pkcs11_initialized) {
    229 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
    230 	}
    231 
    232 	if (pReserved != NULL) {
    233 		return (CKR_ARGUMENTS_BAD);
    234 	}
    235 
    236 	/*
    237 	 * Check to see if we're already blocking on another threads
    238 	 * call to this function.  If so, behaviour is undefined so
    239 	 * we should return to application.
    240 	 */
    241 	(void) pthread_mutex_lock(&slottable->st_mutex);
    242 	if ((slottable->st_blocking) || (slottable->st_wfse_active)) {
    243 		(void) pthread_mutex_unlock(&slottable->st_mutex);
    244 		return (CKR_FUNCTION_FAILED);
    245 	} else {
    246 		slottable->st_wfse_active = B_TRUE;
    247 		(void) pthread_mutex_unlock(&slottable->st_mutex);
    248 	}
    249 
    250 	/*
    251 	 * Check first to see if any events have been recorded
    252 	 * already on any of the slots, regardless of blocking or
    253 	 * thread status.
    254 	 */
    255 	for (i = slottable->st_first; i <= slottable->st_last; i++) {
    256 
    257 		cur_slot = slottable->st_slots[i];
    258 
    259 		if (cur_slot->sl_wfse_state == WFSE_EVENT) {
    260 
    261 			/* found one, clear event and notify application */
    262 
    263 			(void) pthread_mutex_lock(&cur_slot->sl_mutex);
    264 			cur_slot->sl_wfse_state = WFSE_CLEAR;
    265 			(void) pthread_mutex_unlock(&cur_slot->sl_mutex);
    266 			*pSlot = i;
    267 
    268 			/*
    269 			 * This event has been captured, clear the function's
    270 			 * active status.  Other threads may now enter this
    271 			 * function.
    272 			 */
    273 			(void) pthread_mutex_lock(&slottable->st_mutex);
    274 			slottable->st_wfse_active = B_FALSE;
    275 			(void) pthread_mutex_unlock(&slottable->st_mutex);
    276 			return (CKR_OK);
    277 		}
    278 	}
    279 
    280 	/*
    281 	 * We could not find any existing event, so let's see
    282 	 * if we can block and start threads to watch for events.
    283 	 */
    284 	if (flags & CKF_DONT_BLOCK) {
    285 		/*
    286 		 * Application does not want us to block so check with
    287 		 * underlying providers to see if any events have occurred.
    288 		 * Not every provider will have implemented this function,
    289 		 * so error codes or CKR_NO_EVENT can be ignored.
    290 		 */
    291 
    292 		for (i = slottable->st_first; i <= slottable->st_last; i++) {
    293 			prov_id = slottable->st_slots[i]->sl_prov_id;
    294 			cur_slot = slottable->st_slots[i];
    295 
    296 			/*
    297 			 * Only do process once per provider.
    298 			 */
    299 			if (prov_id == last_prov_id) {
    300 				continue;
    301 			}
    302 
    303 			/*
    304 			 * Check to make sure a child thread is not already
    305 			 * running, due to another of the application's
    306 			 * thread calling this function.
    307 			 */
    308 			(void) pthread_mutex_lock(&cur_slot->sl_mutex);
    309 			if (cur_slot->sl_wfse_state == WFSE_ACTIVE) {
    310 				(void) pthread_mutex_unlock(
    311 				    &cur_slot->sl_mutex);
    312 				continue;
    313 			}
    314 
    315 			cur_slot->sl_wfse_state = WFSE_ACTIVE;
    316 
    317 
    318 			/*
    319 			 * Release the hold on the slot's mutex while we
    320 			 * are waiting for this function to complete.
    321 			 */
    322 			(void) pthread_mutex_unlock(&cur_slot->sl_mutex);
    323 
    324 			rv = FUNCLIST(i)->C_WaitForSlotEvent(flags,
    325 			    pSlot, pReserved);
    326 
    327 			(void) pthread_mutex_lock(&cur_slot->sl_mutex);
    328 
    329 			cur_slot->sl_wfse_state = WFSE_CLEAR;
    330 
    331 			(void) pthread_mutex_unlock(&cur_slot->sl_mutex);
    332 
    333 			/* See if we've found a slot with an event */
    334 			if ((rv == CKR_OK) && (pSlot != NULL)) {
    335 				/*
    336 				 * Try to map the returned slotid to a slot
    337 				 * allocated by the framework.  All slots from
    338 				 * one provider are adjacent in the framework's
    339 				 * slottable, so search for a mapping while
    340 				 * the prov_id field is the same.
    341 				 */
    342 				j = i;
    343 				while (prov_id ==
    344 				    slottable->st_slots[j]->sl_prov_id) {
    345 
    346 					/* Find the slot, remap pSlot */
    347 					if (*pSlot == TRUEID(j)) {
    348 						*pSlot = j;
    349 						(void) pthread_mutex_lock(
    350 						    &slottable->st_mutex);
    351 						slottable->st_wfse_active =
    352 						    B_FALSE;
    353 						(void) pthread_mutex_unlock(
    354 						    &slottable->st_mutex);
    355 						return (CKR_OK);
    356 					}
    357 					j++;
    358 				}
    359 
    360 			}
    361 
    362 			/*
    363 			 * If we reach this part of the loop, this
    364 			 * provider either had no events, did not support
    365 			 * this function, or set pSlot to a value we
    366 			 * could not find in the slots associated with
    367 			 * this provider. Continue checking with remaining
    368 			 * providers.
    369 			 */
    370 			last_prov_id = prov_id;
    371 		}
    372 
    373 		/* No provider had any events */
    374 		(void) pthread_mutex_lock(&slottable->st_mutex);
    375 		slottable->st_wfse_active = B_FALSE;
    376 		(void) pthread_mutex_unlock(&slottable->st_mutex);
    377 		return (CKR_NO_EVENT);
    378 
    379 	} else if (!(flags & CKF_DONT_BLOCK) && (pkcs11_cant_create_threads)) {
    380 		/*
    381 		 * Application has asked us to block, but forbidden
    382 		 * us from creating threads.  This is too risky to perform
    383 		 * with underlying providers (we may block indefinitely),
    384 		 * so will return an error in this case.
    385 		 */
    386 		(void) pthread_mutex_lock(&slottable->st_mutex);
    387 		slottable->st_wfse_active = B_FALSE;
    388 		(void) pthread_mutex_unlock(&slottable->st_mutex);
    389 		return (CKR_FUNCTION_FAILED);
    390 	}
    391 
    392 	/*
    393 	 * Grab the st_start_mutex now, which will prevent the listener
    394 	 * thread from signaling on st_start_cond before we're ready to
    395 	 * wait for it.
    396 	 */
    397 	(void) pthread_mutex_lock(&slottable->st_start_mutex);
    398 
    399 	/*
    400 	 * Application allows us to create threads and has
    401 	 * asked us to block.  Create listener thread to wait for
    402 	 * child threads to return.
    403 	 */
    404 	(void) pthread_mutex_lock(&slottable->st_mutex);
    405 	if (pthread_create(&slottable->st_tid, NULL,
    406 	    listener_waitforslotevent, NULL) != 0) {
    407 		slottable->st_wfse_active = B_FALSE;
    408 		(void) pthread_mutex_unlock(&slottable->st_mutex);
    409 		(void) pthread_mutex_unlock(&slottable->st_start_mutex);
    410 		return (CKR_FUNCTION_FAILED);
    411 	}
    412 
    413 	(void) pthread_mutex_unlock(&slottable->st_mutex);
    414 
    415 	/*
    416 	 * Wait for the listening thread to get started before
    417 	 * we spawn child threads.
    418 	 */
    419 	(void) pthread_cond_wait(&slottable->st_start_cond,
    420 	    &slottable->st_start_mutex);
    421 	(void) pthread_mutex_unlock(&slottable->st_start_mutex);
    422 
    423 	/*
    424 	 * Need to hold the mutex on the entire slottable for the
    425 	 * entire setup of the child threads.  Otherwise, the first
    426 	 * child thread may complete before a later child thread is
    427 	 * fully started, resulting in an inaccurate value of
    428 	 * st_thr_count and a potential race condition.
    429 	 */
    430 	(void) pthread_mutex_lock(&slottable->st_mutex);
    431 
    432 	/*
    433 	 * Create child threads to check with the plugged in providers
    434 	 * to check for events.  Keep a count of the current open threads,
    435 	 * so the listener thread knows when there are no more children
    436 	 * to listen for.  Also, make sure a thread is not already active
    437 	 * for that provider.
    438 	 */
    439 	for (i = slottable->st_first; i <= slottable->st_last; i++) {
    440 		prov_id = slottable->st_slots[i]->sl_prov_id;
    441 		cur_slot = slottable->st_slots[i];
    442 
    443 		/*
    444 		 * Only do process once per provider.
    445 		 */
    446 		if (prov_id == last_prov_id) {
    447 			continue;
    448 		}
    449 
    450 		/*
    451 		 * Check to make sure a child thread is not already running,
    452 		 * due to another of the application's threads calling
    453 		 * this function. Also, check that the provider has actually
    454 		 * implemented this function.
    455 		 */
    456 		(void) pthread_mutex_lock(&cur_slot->sl_mutex);
    457 		if ((cur_slot->sl_wfse_state == WFSE_ACTIVE) ||
    458 		    (cur_slot->sl_no_wfse)) {
    459 			(void) pthread_mutex_unlock(&cur_slot->sl_mutex);
    460 			last_prov_id = prov_id;
    461 			continue;
    462 		}
    463 
    464 		/* Set slot to active */
    465 		cur_slot->sl_wfse_state = WFSE_ACTIVE;
    466 
    467 		/*
    468 		 * set up variable to pass arguments to child threads.
    469 		 * Only need to set up once, as values will remain the
    470 		 * same for each successive call.
    471 		 */
    472 		if (cur_slot->sl_wfse_args == NULL) {
    473 			cur_slot->sl_wfse_args = malloc(sizeof (wfse_args_t));
    474 
    475 			if (cur_slot->sl_wfse_args == NULL) {
    476 				(void) pthread_mutex_unlock(
    477 				    &cur_slot->sl_mutex);
    478 				slottable->st_wfse_active = B_FALSE;
    479 				(void) pthread_mutex_unlock(
    480 				    &slottable->st_mutex);
    481 				return (CKR_HOST_MEMORY);
    482 			}
    483 			cur_slot->sl_wfse_args->flags = flags;
    484 			cur_slot->sl_wfse_args->pReserved = pReserved;
    485 			cur_slot->sl_wfse_args->slotid = i;
    486 		}
    487 
    488 		/* Create child thread */
    489 		if (pthread_create(&cur_slot->sl_tid, NULL,
    490 		    child_waitforslotevent,
    491 		    (void *)cur_slot->sl_wfse_args) != 0) {
    492 			(void) pthread_mutex_unlock(&cur_slot->sl_mutex);
    493 			continue;
    494 		}
    495 
    496 		(void) pthread_mutex_unlock(&cur_slot->sl_mutex);
    497 
    498 		/*
    499 		 * This counter is decremented every time a
    500 		 * child_waitforslotevent() wakes up the listener.
    501 		 */
    502 		slottable->st_thr_count++;
    503 
    504 		last_prov_id = prov_id;
    505 	}
    506 
    507 	/* If no children are listening, kill the listener */
    508 	if (slottable->st_thr_count == 0) {
    509 		(void) pthread_cancel(slottable->st_tid);
    510 
    511 		/* If there are no child threads, no event will occur */
    512 		slottable->st_wfse_active = B_FALSE;
    513 		(void) pthread_mutex_unlock(&slottable->st_mutex);
    514 		return (CKR_NO_EVENT);
    515 	}
    516 
    517 	(void) pthread_mutex_unlock(&slottable->st_mutex);
    518 
    519 	/* Wait for listener thread to terminate */
    520 	(void) pthread_join(slottable->st_tid, NULL);
    521 
    522 	/* Make sure C_Finalize has not been called */
    523 	if (!pkcs11_initialized) {
    524 		(void) pthread_mutex_lock(&slottable->st_mutex);
    525 		slottable->st_wfse_active = B_FALSE;
    526 		(void) pthread_mutex_unlock(&slottable->st_mutex);
    527 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
    528 	}
    529 
    530 	/* See if any events actually occurred */
    531 	(void) pthread_mutex_lock(&slottable->st_mutex);
    532 	event_slot = slottable->st_event_slot;
    533 	(void) pthread_mutex_unlock(&slottable->st_mutex);
    534 
    535 	if (pkcs11_is_valid_slot(event_slot) == CKR_OK) {
    536 
    537 		(void) pthread_mutex_lock(&slottable->
    538 		    st_slots[event_slot]->sl_mutex);
    539 		if (slottable->st_slots[event_slot]->
    540 		    sl_wfse_state == WFSE_EVENT) {
    541 
    542 			/* An event has occurred on this slot */
    543 			slottable->st_slots[event_slot]->sl_wfse_state =
    544 			    WFSE_CLEAR;
    545 			(void) pthread_mutex_unlock(&slottable->
    546 			    st_slots[event_slot]->sl_mutex);
    547 			*pSlot = event_slot;
    548 			(void) pthread_mutex_lock(&slottable->st_mutex);
    549 			slottable->st_blocking = B_FALSE;
    550 			slottable->st_wfse_active = B_FALSE;
    551 			(void) pthread_mutex_unlock(&slottable->st_mutex);
    552 			return (CKR_OK);
    553 		} else {
    554 			(void) pthread_mutex_unlock(&slottable->
    555 			    st_slots[event_slot]->sl_mutex);
    556 		}
    557 	}
    558 
    559 	(void) pthread_mutex_lock(&slottable->st_mutex);
    560 	slottable->st_blocking = B_FALSE;
    561 	slottable->st_wfse_active = B_FALSE;
    562 	(void) pthread_mutex_unlock(&slottable->st_mutex);
    563 
    564 	/* No provider reported any events, or no provider implemented this */
    565 	return (CKR_NO_EVENT);
    566 }
    567 
    568 /*
    569  * C_GetMechanismList cannot just be a direct pass through to the
    570  * underlying provider, because we allow the administrator to
    571  * disable certain mechanisms from specific providers.  This affects
    572  * both pulCount and pMechanismList.  Only when the fastpath with
    573  * no policy is in effect can we pass through directly to the
    574  * underlying provider.
    575  *
    576  * It is necessary, for policy filtering, to get the actual list
    577  * of mechanisms from the underlying provider, even if the calling
    578  * application is just requesting a count.  It is the only way to
    579  * get an accurate count of the number of mechanisms actually available.
    580  */
    581 CK_RV
    582 C_GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList,
    583     CK_ULONG_PTR pulCount)
    584 {
    585 	CK_RV rv = CKR_OK;
    586 	CK_ULONG mech_count;
    587 	CK_ULONG tmpmech_count;
    588 	CK_MECHANISM_TYPE_PTR pmech_list, tmpmech_list;
    589 	CK_SLOT_ID true_id;
    590 	CK_SLOT_ID fw_st_id; /* id for accessing framework's slottable */
    591 	CK_FUNCTION_LIST_PTR prov_funcs;
    592 
    593 	CK_ULONG i;
    594 
    595 	if (!pkcs11_initialized) {
    596 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
    597 	}
    598 
    599 	/* Check for a fastpath */
    600 	if ((purefastpath || policyfastpath) && !metaslot_enabled)
    601 		return (fast_funcs->C_GetMechanismList(slotID,
    602 		    pMechanismList, pulCount));
    603 
    604 	if (slotID == METASLOT_FRAMEWORK_ID) {
    605 		return (meta_GetMechanismList(METASLOT_SLOTID, pMechanismList,
    606 		    pulCount));
    607 	}
    608 
    609 	/* Check that slotID is valid */
    610 	if (pkcs11_validate_and_convert_slotid(slotID, &fw_st_id) != CKR_OK) {
    611 		return (CKR_SLOT_ID_INVALID);
    612 	}
    613 
    614 	if (policyfastpath) {
    615 		true_id = fw_st_id;
    616 		slotID = fast_slot;
    617 		prov_funcs = fast_funcs;
    618 	} else {
    619 		true_id = TRUEID(fw_st_id);
    620 		prov_funcs = FUNCLIST(fw_st_id);
    621 	}
    622 
    623 	mech_count = 0;
    624 	tmpmech_count = MECHLIST_SIZE;
    625 
    626 	/*
    627 	 * Allocate memory for a mechanism list.  We are assuming
    628 	 * that most mechanism lists will be less than MECHLIST_SIZE.
    629 	 * If that is not enough memory, we will try a second time
    630 	 * with more memory allocated.
    631 	 */
    632 	pmech_list = malloc(tmpmech_count * sizeof (CK_MECHANISM_TYPE));
    633 
    634 	if (pmech_list == NULL) {
    635 		return (CKR_HOST_MEMORY);
    636 	}
    637 
    638 	/*
    639 	 * Attempt to get the mechanism list.  PKCS11 supports
    640 	 * removable media, so the mechanism list of a slot can vary
    641 	 * over the life of the application.
    642 	 */
    643 	rv = prov_funcs->C_GetMechanismList(true_id,
    644 	    pmech_list, &tmpmech_count);
    645 
    646 	if (rv == CKR_BUFFER_TOO_SMALL) {
    647 		/* Need to use more space */
    648 		tmpmech_list = pmech_list;
    649 		pmech_list = realloc
    650 		    (tmpmech_list, tmpmech_count * sizeof (CK_MECHANISM_TYPE));
    651 
    652 		if (pmech_list == NULL) {
    653 			free(tmpmech_list);
    654 			return (CKR_HOST_MEMORY);
    655 		}
    656 
    657 		/* Try again to get mechanism list. */
    658 		rv = prov_funcs->C_GetMechanismList(true_id,
    659 		    pmech_list, &tmpmech_count);
    660 
    661 	}
    662 
    663 	/*
    664 	 * Present consistent face to calling application.
    665 	 * If something strange has happened, or this function
    666 	 * is not supported by this provider, return a count
    667 	 * of zero mechanisms.
    668 	 */
    669 	if (rv != CKR_OK) {
    670 		*pulCount = 0;
    671 		free(pmech_list);
    672 		return (CKR_OK);
    673 	}
    674 
    675 	/*
    676 	 * Process the mechanism list, removing any mechanisms
    677 	 * that are disabled via the framework.  Even if the
    678 	 * application is only asking for a count, we must
    679 	 * process the actual mechanisms being offered by this slot.
    680 	 * We could not just subtract our stored count of disabled
    681 	 * mechanisms, since it is not guaranteed that those
    682 	 * mechanisms are actually supported by the slot.
    683 	 */
    684 	for (i = 0; i < tmpmech_count; i++) {
    685 		/* Filter out the disabled mechanisms */
    686 		if (pkcs11_is_dismech(fw_st_id, pmech_list[i])) {
    687 			continue;
    688 		}
    689 
    690 		/*
    691 		 * Only set pMechanismList if enough memory
    692 		 * is available.  If it was set to NULL
    693 		 * originally, this loop will just be counting
    694 		 * mechanims.
    695 		 */
    696 		if (pMechanismList && (*pulCount > mech_count)) {
    697 			pMechanismList[mech_count] = pmech_list[i];
    698 		}
    699 		mech_count++;
    700 	}
    701 
    702 	/*
    703 	 * Catch the case where pMechanismList was not set to NULL,
    704 	 * yet the buffer was not large enough.  If pMechanismList is
    705 	 * set to NULL, this function will simply set pulCount and
    706 	 * return CKR_OK.
    707 	 */
    708 	if ((*pulCount < mech_count) && (pMechanismList != NULL)) {
    709 		*pulCount = mech_count;
    710 		free(pmech_list);
    711 		return (CKR_BUFFER_TOO_SMALL);
    712 	}
    713 
    714 	*pulCount = mech_count;
    715 	free(pmech_list);
    716 
    717 	return (CKR_OK);
    718 }
    719 
    720 
    721 CK_RV
    722 C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type,
    723     CK_MECHANISM_INFO_PTR pInfo)
    724 {
    725 	CK_RV rv;
    726 	CK_SLOT_ID true_id;
    727 	CK_SLOT_ID fw_st_id; /* id for accessing framework's slottable */
    728 	CK_FUNCTION_LIST_PTR prov_funcs;
    729 
    730 	if (!pkcs11_initialized) {
    731 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
    732 	}
    733 
    734 	/* Check for a fastpath */
    735 	if ((purefastpath || policyfastpath) && !metaslot_enabled)
    736 		return (fast_funcs->C_GetMechanismInfo(slotID, type, pInfo));
    737 
    738 	if (slotID == METASLOT_FRAMEWORK_ID) {
    739 		/* just need to get metaslot information */
    740 		return (meta_GetMechanismInfo(METASLOT_SLOTID, type, pInfo));
    741 	}
    742 
    743 	/* Check that slotID is valid */
    744 	if (pkcs11_validate_and_convert_slotid(slotID, &fw_st_id) != CKR_OK) {
    745 		return (CKR_SLOT_ID_INVALID);
    746 	}
    747 
    748 	if (policyfastpath) {
    749 		true_id = fw_st_id;
    750 		slotID = fast_slot;
    751 		prov_funcs = fast_funcs;
    752 	} else {
    753 		true_id = TRUEID(fw_st_id);
    754 		prov_funcs = FUNCLIST(fw_st_id);
    755 	}
    756 
    757 	/* Make sure this is not a disabled mechanism */
    758 	if (pkcs11_is_dismech(fw_st_id, type)) {
    759 		return (CKR_MECHANISM_INVALID);
    760 	}
    761 
    762 	rv = prov_funcs->C_GetMechanismInfo(true_id, type, pInfo);
    763 
    764 	/* Present consistent interface to the application */
    765 	if (rv == CKR_FUNCTION_NOT_SUPPORTED) {
    766 		return (CKR_FUNCTION_FAILED);
    767 	}
    768 
    769 	return (rv);
    770 }
    771 
    772 
    773 CK_RV
    774 C_InitToken(CK_SLOT_ID slotID, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen,
    775     CK_UTF8CHAR_PTR pLabel)
    776 {
    777 	CK_RV rv;
    778 	CK_SLOT_ID fw_st_id; /* id for accessing framework's slottable */
    779 
    780 	if (!pkcs11_initialized) {
    781 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
    782 	}
    783 
    784 	/* Check for a fastpath */
    785 	if ((purefastpath || policyfastpath) && !metaslot_enabled)
    786 		return (fast_funcs->C_InitToken(slotID, pPin, ulPinLen,
    787 		    pLabel));
    788 
    789 	if (slotID == METASLOT_FRAMEWORK_ID) {
    790 		/* just need to get metaslot information */
    791 		return (meta_InitToken(METASLOT_SLOTID, pPin, ulPinLen,
    792 		    pLabel));
    793 	}
    794 
    795 	/* Check that slotID is valid */
    796 	if (pkcs11_validate_and_convert_slotid(slotID, &fw_st_id) != CKR_OK) {
    797 		return (CKR_SLOT_ID_INVALID);
    798 	}
    799 
    800 	rv = FUNCLIST(fw_st_id)->C_InitToken(TRUEID(fw_st_id), pPin, ulPinLen,
    801 	    pLabel);
    802 
    803 	/* Present consistent interface to the application */
    804 	if (rv == CKR_FUNCTION_NOT_SUPPORTED) {
    805 		return (CKR_FUNCTION_FAILED);
    806 	}
    807 
    808 	return (rv);
    809 }
    810 
    811 CK_RV
    812 C_InitPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen)
    813 {
    814 
    815 	CK_RV rv;
    816 	pkcs11_session_t *sessp;
    817 
    818 	/* Check for a fastpath */
    819 	if (purefastpath || policyfastpath) {
    820 		return (fast_funcs->C_InitPIN(hSession, pPin, ulPinLen));
    821 	}
    822 
    823 	if (!pkcs11_initialized) {
    824 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
    825 	}
    826 
    827 	/* Obtain the session pointer */
    828 	HANDLE2SESSION(hSession, sessp, rv);
    829 
    830 	if (rv != CKR_OK) {
    831 		return (rv);
    832 	}
    833 
    834 	/* Initialize the PIN with the provider */
    835 	rv = FUNCLIST(sessp->se_slotid)->C_InitPIN(sessp->se_handle,
    836 	    pPin, ulPinLen);
    837 
    838 	/* Present consistent interface to the application */
    839 	if (rv == CKR_FUNCTION_NOT_SUPPORTED) {
    840 		return (CKR_FUNCTION_FAILED);
    841 	}
    842 
    843 	return (rv);
    844 }
    845 
    846 CK_RV
    847 C_SetPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pOldPin,
    848 	CK_ULONG ulOldPinLen, CK_UTF8CHAR_PTR pNewPin,
    849 	CK_ULONG ulNewPinLen)
    850 {
    851 	CK_RV rv;
    852 	pkcs11_session_t *sessp;
    853 
    854 	/* Check for a fastpath */
    855 	if (purefastpath || policyfastpath) {
    856 		return (fast_funcs->C_SetPIN(hSession, pOldPin, ulOldPinLen,
    857 		    pNewPin, ulNewPinLen));
    858 	}
    859 
    860 	if (!pkcs11_initialized) {
    861 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
    862 	}
    863 
    864 	/* Obtain the session pointer */
    865 	HANDLE2SESSION(hSession, sessp, rv);
    866 
    867 	if (rv != CKR_OK) {
    868 		return (rv);
    869 	}
    870 
    871 	/* Set the PIN with the provider */
    872 	rv = FUNCLIST(sessp->se_slotid)->C_SetPIN(sessp->se_handle,
    873 	    pOldPin, ulOldPinLen, pNewPin, ulNewPinLen);
    874 
    875 	/* Present consistent interface to the application */
    876 	if (rv == CKR_FUNCTION_NOT_SUPPORTED) {
    877 		return (CKR_FUNCTION_FAILED);
    878 	}
    879 
    880 	return (rv);
    881 
    882 }
    883 
    884 /*
    885  * listener_waitforslotevent is spawned by the main C_WaitForSlotEvent()
    886  * to listen for events from any of the providers.  It also watches the
    887  * count of threads, which may go to zero with no recorded events, if
    888  * none of the underlying providers have actually implemented this
    889  * function.
    890  */
    891 /*ARGSUSED*/
    892 static void *
    893 listener_waitforslotevent(void *arg) {
    894 
    895 	CK_SLOT_ID eventID;
    896 
    897 	/* Mark slottable in state blocking */
    898 	(void) pthread_mutex_lock(&slottable->st_mutex);
    899 	slottable->st_blocking = B_TRUE;
    900 
    901 	/* alert calling thread that this thread has started */
    902 	(void) pthread_mutex_lock(&slottable->st_start_mutex);
    903 	(void) pthread_cond_signal(&slottable->st_start_cond);
    904 	(void) pthread_mutex_unlock(&slottable->st_start_mutex);
    905 
    906 	/* wait for an event, or number of threads to reach zero */
    907 	for (;;) {
    908 
    909 		/*
    910 		 * Make sure we've really been signaled, and not waking
    911 		 * for another reason.
    912 		 */
    913 		while (slottable->st_list_signaled != B_TRUE) {
    914 			(void) pthread_cond_wait(&slottable->st_wait_cond,
    915 			    &slottable->st_mutex);
    916 		}
    917 
    918 		slottable->st_list_signaled = B_FALSE;
    919 
    920 		/* See why we were woken up */
    921 		if (!pkcs11_initialized) {
    922 			/* Another thread has called C_Finalize() */
    923 			(void) pthread_mutex_unlock(&slottable->st_mutex);
    924 			return (NULL);
    925 		}
    926 
    927 		/* A thread has finished, decrement counter */
    928 		slottable->st_thr_count--;
    929 
    930 		eventID = slottable->st_event_slot;
    931 
    932 		if (pkcs11_is_valid_slot(eventID) == CKR_OK) {
    933 
    934 			(void) pthread_mutex_lock(&slottable->
    935 			    st_slots[eventID]->sl_mutex);
    936 
    937 			if (slottable->st_slots[eventID]->
    938 			    sl_wfse_state == WFSE_EVENT) {
    939 				(void) pthread_mutex_unlock(&slottable->
    940 				    st_slots[eventID]->sl_mutex);
    941 
    942 				/*
    943 				 * st_event_slot is set to a valid value, event
    944 				 * flag is set for that slot.  The flag will
    945 				 * be cleared by main C_WaitForSlotEvent().
    946 				 */
    947 				(void) pthread_mutex_unlock(
    948 					&slottable->st_mutex);
    949 
    950 				pthread_exit(0);
    951 			} else {
    952 				(void) pthread_mutex_unlock(&slottable->
    953 				    st_slots[eventID]->sl_mutex);
    954 			}
    955 		}
    956 		if (slottable->st_thr_count == 0) {
    957 			(void) pthread_mutex_unlock(&slottable->st_mutex);
    958 
    959 			/* No more threads, no events found */
    960 			pthread_exit(0);
    961 		}
    962 	}
    963 
    964 	/*NOTREACHED*/
    965 	return (NULL);
    966 }
    967 
    968 /*
    969  * child_waitforslotevent is used as a child thread to contact
    970  * underlying provider's C_WaitForSlotEvent().
    971  */
    972 static void *
    973 child_waitforslotevent(void *arg) {
    974 
    975 	wfse_args_t *wfse = (wfse_args_t *)arg;
    976 	CK_SLOT_ID slot;
    977 	CK_RV rv;
    978 	uint32_t cur_prov;
    979 	CK_SLOT_ID i;
    980 
    981 	rv = FUNCLIST(wfse->slotid)->C_WaitForSlotEvent(wfse->flags, &slot,
    982 	    wfse->pReserved);
    983 
    984 	/*
    985 	 * Need to hold the mutex while processing the results, to
    986 	 * keep things synchronized with the listener thread and
    987 	 * the slottable.  Otherwise, due to the timing
    988 	 * at which some underlying providers complete, the listener
    989 	 * thread may not actually be blocking on st_wait_cond when
    990 	 * this child signals.  Holding the lock a bit longer prevents
    991 	 * this from happening.
    992 	 */
    993 	(void) pthread_mutex_lock(&slottable->st_mutex);
    994 
    995 	while (slottable->st_list_signaled == B_TRUE) {
    996 		/*
    997 		 * We've taken the mutex when the listener should have
    998 		 * control. Release the mutex, thread scheduler should
    999 		 * give control back to the listener.
   1000 		 */
   1001 		(void) pthread_mutex_unlock(&slottable->st_mutex);
   1002 		(void) sleep(1);
   1003 		(void) pthread_mutex_lock(&slottable->st_mutex);
   1004 	}
   1005 
   1006 	if (rv == CKR_OK) {
   1007 		/* we've had an event, find slot and store it */
   1008 		cur_prov = slottable->st_slots[wfse->slotid]->sl_prov_id;
   1009 
   1010 		/*
   1011 		 * It is safe to unset active status now, since call to
   1012 		 * underlying provider has already terminated, and we
   1013 		 * hold the slottable wide mutex (st_mutex).
   1014 		 */
   1015 		(void) pthread_mutex_lock(&slottable->
   1016 		    st_slots[wfse->slotid]->sl_mutex);
   1017 
   1018 		slottable->st_slots[wfse->slotid]->sl_wfse_state = WFSE_CLEAR;
   1019 
   1020 		(void) pthread_mutex_unlock(&slottable->
   1021 		    st_slots[wfse->slotid]->sl_mutex);
   1022 
   1023 
   1024 		for (i = wfse->slotid; i <= slottable->st_last; i++) {
   1025 			if (cur_prov != slottable->st_slots[i]->sl_prov_id) {
   1026 				break;
   1027 			}
   1028 
   1029 			if (slot == slottable->st_slots[i]->sl_id) {
   1030 				(void) pthread_mutex_lock(&slottable->
   1031 				    st_slots[i]->sl_mutex);
   1032 
   1033 				slottable->st_slots[i]->
   1034 				    sl_wfse_state = WFSE_EVENT;
   1035 
   1036 				(void) pthread_mutex_unlock(&slottable->
   1037 				    st_slots[i]->sl_mutex);
   1038 
   1039 				slottable->st_event_slot = i;
   1040 
   1041 				if (slottable->st_blocking) {
   1042 					slottable->st_list_signaled = B_TRUE;
   1043 					(void) pthread_cond_signal(&slottable->
   1044 					    st_wait_cond);
   1045 				}
   1046 
   1047 				(void) pthread_mutex_unlock(
   1048 					&slottable->st_mutex);
   1049 
   1050 				pthread_exit(0);
   1051 			}
   1052 		}
   1053 
   1054 	}
   1055 
   1056 	(void) pthread_mutex_lock(&slottable->
   1057 	    st_slots[wfse->slotid]->sl_mutex);
   1058 
   1059 	/*
   1060 	 * If the provider told us that it does not support
   1061 	 * this function, we should mark it so we do not waste
   1062 	 * time later with it.  If an error returned, we'll clean
   1063 	 * up this thread now and possibly try it again later.
   1064 	 */
   1065 	if (rv == CKR_FUNCTION_NOT_SUPPORTED) {
   1066 		slottable->st_slots[wfse->slotid]->sl_no_wfse = B_TRUE;
   1067 	}
   1068 
   1069 	/*
   1070 	 * It is safe to unset active status now, since call to
   1071 	 * underlying provider has already terminated, and we
   1072 	 * hold the slottable wide mutex (st_mutex).
   1073 	 */
   1074 	slottable->st_slots[wfse->slotid]->sl_wfse_state = WFSE_CLEAR;
   1075 	(void) pthread_mutex_unlock(&slottable->
   1076 	    st_slots[wfse->slotid]->sl_mutex);
   1077 
   1078 
   1079 	if (slottable->st_blocking) {
   1080 		slottable->st_list_signaled = B_TRUE;
   1081 		(void) pthread_cond_signal(&slottable->st_wait_cond);
   1082 	}
   1083 
   1084 	(void) pthread_mutex_unlock(&slottable->st_mutex);
   1085 
   1086 	/* Manually exit the thread, since nobody will join to it */
   1087 	pthread_exit(0);
   1088 
   1089 	/*NOTREACHED*/
   1090 	return (NULL);
   1091 }
   1092