xref: /illumos-gate/usr/src/lib/pkcs11/libpkcs11/common/pkcs11SlotToken.c (revision 9b9d39d2a32ff806d2431dbcc50968ef1e6d46b2)
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