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