17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5d288ba74SAnthony Scarpino  * Common Development and Distribution License (the "License").
6d288ba74SAnthony Scarpino  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21*699ea13aSValerie Bubb Fenwick 
227c478bd9Sstevel@tonic-gate /*
23*699ea13aSValerie Bubb Fenwick  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <dlfcn.h>
277c478bd9Sstevel@tonic-gate #include <stdlib.h>
287c478bd9Sstevel@tonic-gate #include <pthread.h>
297c478bd9Sstevel@tonic-gate #include <strings.h>
307c478bd9Sstevel@tonic-gate #include <security/cryptoki.h>
317c478bd9Sstevel@tonic-gate #include "pkcs11Global.h"
327c478bd9Sstevel@tonic-gate #include "pkcs11Slot.h"
337c478bd9Sstevel@tonic-gate #include "metaGlobal.h"
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate pkcs11_slottable_t *slottable = NULL;
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate /*
387c478bd9Sstevel@tonic-gate  * pkcs11_slottable_initialize initizializes the global slottable.
397c478bd9Sstevel@tonic-gate  * This slottable will contain information about the plugged in
407c478bd9Sstevel@tonic-gate  * slots, including their mapped slotID.  This function should only
417c478bd9Sstevel@tonic-gate  * be called by C_Intialize.
427c478bd9Sstevel@tonic-gate  */
437c478bd9Sstevel@tonic-gate CK_RV
pkcs11_slottable_initialize()447c478bd9Sstevel@tonic-gate pkcs11_slottable_initialize() {
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate 	pkcs11_slottable_t *stmp = malloc(sizeof (pkcs11_slottable_t));
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate 	if (stmp == NULL)
507c478bd9Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate 	stmp->st_first = 1;
537c478bd9Sstevel@tonic-gate 	stmp->st_cur_size = 0;
547c478bd9Sstevel@tonic-gate 	stmp->st_last = 0;
557c478bd9Sstevel@tonic-gate 	stmp->st_slots = NULL;
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate 	if (pthread_mutex_init(&stmp->st_mutex, NULL) != 0) {
587c478bd9Sstevel@tonic-gate 		free(stmp);
597c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
607c478bd9Sstevel@tonic-gate 	}
617c478bd9Sstevel@tonic-gate 	/* Set up for possible threads later */
627c478bd9Sstevel@tonic-gate 	stmp->st_event_slot = 0;
637c478bd9Sstevel@tonic-gate 	stmp->st_thr_count = 0;
647c478bd9Sstevel@tonic-gate 	stmp->st_wfse_active = B_FALSE;
657c478bd9Sstevel@tonic-gate 	stmp->st_blocking = B_FALSE;
667c478bd9Sstevel@tonic-gate 	stmp->st_list_signaled = B_FALSE;
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate 	(void) pthread_cond_init(&stmp->st_wait_cond, NULL);
697c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_init(&stmp->st_start_mutex, NULL);
707c478bd9Sstevel@tonic-gate 	(void) pthread_cond_init(&stmp->st_start_cond, NULL);
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 	slottable = stmp;
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate 	return (CKR_OK);
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate }
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate  * pkcs11_slottable_increase should only be called from C_Initialize().
807c478bd9Sstevel@tonic-gate  * It is called after the first call to C_GetSlotList() and is used to
817c478bd9Sstevel@tonic-gate  * increase the size of the slottable, as needed, to contain the next
827c478bd9Sstevel@tonic-gate  * set of slots that C_Initialize() is currently mapping into the framework.
837c478bd9Sstevel@tonic-gate  */
847c478bd9Sstevel@tonic-gate CK_RV
pkcs11_slottable_increase(ulong_t increment)857c478bd9Sstevel@tonic-gate pkcs11_slottable_increase(ulong_t increment) {
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	pkcs11_slot_t **tmpslots;
887c478bd9Sstevel@tonic-gate 	ulong_t newsize;
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&slottable->st_mutex);
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate 	/* Add 1 to cover space for the metaslot */
937c478bd9Sstevel@tonic-gate 	newsize = slottable->st_last + increment + 1;
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	/* Check to see if we already have enough space */
967c478bd9Sstevel@tonic-gate 	if (slottable->st_cur_size >= newsize) {
977c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&slottable->st_mutex);
987c478bd9Sstevel@tonic-gate 		return (CKR_OK);
997c478bd9Sstevel@tonic-gate 	}
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	tmpslots = realloc
1027c478bd9Sstevel@tonic-gate 	    (slottable->st_slots, newsize * sizeof (pkcs11_slot_t *));
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	if (tmpslots == NULL) {
1057c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&slottable->st_mutex);
1067c478bd9Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
1077c478bd9Sstevel@tonic-gate 	}
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate 	slottable->st_slots = tmpslots;
1107c478bd9Sstevel@tonic-gate 	slottable->st_cur_size = newsize;
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&slottable->st_mutex);
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 	return (CKR_OK);
1157c478bd9Sstevel@tonic-gate }
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate /*
1187c478bd9Sstevel@tonic-gate  * pkcs11_slot_allocate should only be called from C_Initialize().
1197c478bd9Sstevel@tonic-gate  * We won't know if the metaslot will be used until after all of
1207c478bd9Sstevel@tonic-gate  * the other slots have been allocated.
1217c478bd9Sstevel@tonic-gate  */
1227c478bd9Sstevel@tonic-gate CK_RV
pkcs11_slot_allocate(CK_SLOT_ID * pslot_id)1237c478bd9Sstevel@tonic-gate pkcs11_slot_allocate(CK_SLOT_ID *pslot_id) {
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	pkcs11_slot_t *tmpslot;
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	tmpslot = malloc(sizeof (pkcs11_slot_t));
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	if (tmpslot == NULL)
1307c478bd9Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	bzero(tmpslot, sizeof (pkcs11_slot_t));
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	tmpslot->sl_wfse_state = WFSE_CLEAR;
1357c478bd9Sstevel@tonic-gate 	tmpslot->sl_enabledpol = B_FALSE;
1367c478bd9Sstevel@tonic-gate 	tmpslot->sl_no_wfse = B_FALSE;
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	/* Initialize this slot's mutex */
1397c478bd9Sstevel@tonic-gate 	if (pthread_mutex_init(&tmpslot->sl_mutex, NULL) != 0) {
1407c478bd9Sstevel@tonic-gate 		free(tmpslot);
1417c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
1427c478bd9Sstevel@tonic-gate 	}
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&slottable->st_mutex);
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	slottable->st_last++;
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	*pslot_id = slottable->st_last;
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	slottable->st_slots[*pslot_id] = tmpslot;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&slottable->st_mutex);
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	return (CKR_OK);
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate /*
1597c478bd9Sstevel@tonic-gate  * pkcs11_slottable_delete should only be called by C_Finalize(),
1607c478bd9Sstevel@tonic-gate  * or by C_Initialize() in error conditions.
1617c478bd9Sstevel@tonic-gate  */
1627c478bd9Sstevel@tonic-gate CK_RV
pkcs11_slottable_delete()1637c478bd9Sstevel@tonic-gate pkcs11_slottable_delete() {
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	ulong_t i;
1667c478bd9Sstevel@tonic-gate 	uint32_t prov_id;
1677c478bd9Sstevel@tonic-gate 	int32_t last_prov_id = -1;
1687c478bd9Sstevel@tonic-gate 	pkcs11_slot_t *cur_slot;
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&slottable->st_mutex);
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	for (i = slottable->st_first; i <= slottable->st_last; i++) {
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 		if (slottable->st_slots[i] != NULL) {
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 			cur_slot = slottable->st_slots[i];
1777c478bd9Sstevel@tonic-gate 			prov_id = cur_slot->sl_prov_id;
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_lock(&cur_slot->sl_mutex);
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 			/*
1827c478bd9Sstevel@tonic-gate 			 * For the first slot from this provider, do
1837c478bd9Sstevel@tonic-gate 			 * extra cleanup.
1847c478bd9Sstevel@tonic-gate 			 */
1857c478bd9Sstevel@tonic-gate 			if (prov_id != last_prov_id) {
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 				if (cur_slot->sl_wfse_state == WFSE_ACTIVE) {
1887c478bd9Sstevel@tonic-gate 					(void) pthread_cancel
1897c478bd9Sstevel@tonic-gate 					    (cur_slot->sl_tid);
1907c478bd9Sstevel@tonic-gate 				}
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 				/*
1937c478bd9Sstevel@tonic-gate 				 * Only call C_Finalize of plug-in if we
1947c478bd9Sstevel@tonic-gate 				 * get here from an explicit C_Finalize
1957c478bd9Sstevel@tonic-gate 				 * call from an application.  Otherwise,
1967c478bd9Sstevel@tonic-gate 				 * there is a risk that the application may
1977c478bd9Sstevel@tonic-gate 				 * have directly dlopened this provider and
1987c478bd9Sstevel@tonic-gate 				 * we could interrupt their work.  Plug-ins
1997c478bd9Sstevel@tonic-gate 				 * should have their own _fini function to
2007c478bd9Sstevel@tonic-gate 				 * clean up when they are no longer referenced.
2017c478bd9Sstevel@tonic-gate 				 */
2027c478bd9Sstevel@tonic-gate 				if ((cur_slot->sl_func_list != NULL) &&
2037c478bd9Sstevel@tonic-gate 				    (!fini_called)) {
2047c478bd9Sstevel@tonic-gate 					(void) cur_slot->
2057c478bd9Sstevel@tonic-gate 					    sl_func_list->C_Finalize(NULL);
2067c478bd9Sstevel@tonic-gate 				}
207*699ea13aSValerie Bubb Fenwick 
208*699ea13aSValerie Bubb Fenwick 				/* metaslot won't have a sl_dldesc! */
209*699ea13aSValerie Bubb Fenwick 				if (cur_slot->sl_dldesc != NULL) {
210*699ea13aSValerie Bubb Fenwick 					(void) dlclose(cur_slot->sl_dldesc);
211*699ea13aSValerie Bubb Fenwick 				}
2127c478bd9Sstevel@tonic-gate 
213d288ba74SAnthony Scarpino 				/*
214d288ba74SAnthony Scarpino 				 * Each provider maintains one disabled
215d288ba74SAnthony Scarpino 				 * mechanism list for each of its slots to use.
216d288ba74SAnthony Scarpino 				 */
217d288ba74SAnthony Scarpino 				if (cur_slot->sl_pol_mechs != NULL)
218d288ba74SAnthony Scarpino 					free(cur_slot->sl_pol_mechs);
2197c478bd9Sstevel@tonic-gate 			}
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 			if (cur_slot->sl_wfse_args != NULL) {
2227c478bd9Sstevel@tonic-gate 				free(cur_slot->sl_wfse_args);
2237c478bd9Sstevel@tonic-gate 			}
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&cur_slot->sl_mutex);
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 			/*
2287c478bd9Sstevel@tonic-gate 			 * Cleanup the session list.  This must
2297c478bd9Sstevel@tonic-gate 			 * happen after the mutext is unlocked
2307c478bd9Sstevel@tonic-gate 			 * because session_delete tries to lock it
2317c478bd9Sstevel@tonic-gate 			 * again.
2327c478bd9Sstevel@tonic-gate 			 */
2337c478bd9Sstevel@tonic-gate 			pkcs11_sessionlist_delete(cur_slot);
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_destroy(&cur_slot->sl_mutex);
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 			free(cur_slot);
2387c478bd9Sstevel@tonic-gate 			cur_slot = NULL;
2397c478bd9Sstevel@tonic-gate 			last_prov_id = prov_id;
2407c478bd9Sstevel@tonic-gate 		}
2417c478bd9Sstevel@tonic-gate 	}
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	(void) pthread_cond_destroy(&slottable->st_wait_cond);
2447c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_destroy(&slottable->st_start_mutex);
2457c478bd9Sstevel@tonic-gate 	(void) pthread_cond_destroy(&slottable->st_start_cond);
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	free(slottable->st_slots);
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&slottable->st_mutex);
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_destroy(&slottable->st_mutex);
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	free(slottable);
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	slottable = NULL;
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	return (CKR_OK);
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate }
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate /*
2627c478bd9Sstevel@tonic-gate  * pkcs11_is_valid_slot verifies that the slot ID passed to the
2637c478bd9Sstevel@tonic-gate  * framework is valid.
2647c478bd9Sstevel@tonic-gate  */
2657c478bd9Sstevel@tonic-gate CK_RV
pkcs11_is_valid_slot(CK_SLOT_ID slot_id)2667c478bd9Sstevel@tonic-gate pkcs11_is_valid_slot(CK_SLOT_ID slot_id) {
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	if ((slot_id < slottable->st_first) ||
2697c478bd9Sstevel@tonic-gate 	    (slot_id > slottable->st_last)) {
2707c478bd9Sstevel@tonic-gate 		return (CKR_SLOT_ID_INVALID);
2717c478bd9Sstevel@tonic-gate 	} else if (slottable->st_slots[slot_id] != NULL) {
2727c478bd9Sstevel@tonic-gate 		return (CKR_OK);
2737c478bd9Sstevel@tonic-gate 	} else {
2747c478bd9Sstevel@tonic-gate 		return (CKR_SLOT_ID_INVALID);
2757c478bd9Sstevel@tonic-gate 	}
2767c478bd9Sstevel@tonic-gate }
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate /*
2807c478bd9Sstevel@tonic-gate  * pkcs11_validate_and_convert_slotid verifies whether the slot ID
2817c478bd9Sstevel@tonic-gate  * passed to the framework is valid, and convert it to the
2827c478bd9Sstevel@tonic-gate  * true slot ID maintained in the framework data structures
2837c478bd9Sstevel@tonic-gate  * accordingly.
2847c478bd9Sstevel@tonic-gate  *
2857c478bd9Sstevel@tonic-gate  * This is necessary because when metaslot is enabled, the slot
2867c478bd9Sstevel@tonic-gate  * providing persistent object storage is "hidden".
2877c478bd9Sstevel@tonic-gate  *
2887c478bd9Sstevel@tonic-gate  * The real ID is returned in the "real_slot_id" argument regardless conversion
2897c478bd9Sstevel@tonic-gate  * is done or not.
2907c478bd9Sstevel@tonic-gate  */
2917c478bd9Sstevel@tonic-gate CK_RV
pkcs11_validate_and_convert_slotid(CK_SLOT_ID slot_id,CK_SLOT_ID * real_slot_id)2927c478bd9Sstevel@tonic-gate pkcs11_validate_and_convert_slotid(CK_SLOT_ID slot_id,
2937c478bd9Sstevel@tonic-gate     CK_SLOT_ID *real_slot_id) {
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	if (!metaslot_enabled) {
2967c478bd9Sstevel@tonic-gate 		*real_slot_id = slot_id;
2977c478bd9Sstevel@tonic-gate 	} else {
2987c478bd9Sstevel@tonic-gate 		/* need to do conversion */
2997c478bd9Sstevel@tonic-gate 		if (slot_id >= metaslot_keystore_slotid) {
3007c478bd9Sstevel@tonic-gate 			*real_slot_id = slot_id + 1;
3017c478bd9Sstevel@tonic-gate 		} else {
3027c478bd9Sstevel@tonic-gate 			*real_slot_id = slot_id;
3037c478bd9Sstevel@tonic-gate 		}
3047c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate 	return (pkcs11_is_valid_slot(*real_slot_id));
3067c478bd9Sstevel@tonic-gate }
307