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
54a5b2e70Shaimay  * Common Development and Distribution License (the "License").
64a5b2e70Shaimay  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*94f411ebSwyllys  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * Functions for dealing with provider sessions
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <string.h>
317c478bd9Sstevel@tonic-gate #include <cryptoutil.h>
327c478bd9Sstevel@tonic-gate #include "metaGlobal.h"
337c478bd9Sstevel@tonic-gate #include "pkcs11Session.h"
347c478bd9Sstevel@tonic-gate #include "pkcs11Global.h"
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate /*
387c478bd9Sstevel@tonic-gate  * This is just a **WILD** guess for the maximum idle sessions to
397c478bd9Sstevel@tonic-gate  * keep for each slot.  This number should probably be adjusted
407c478bd9Sstevel@tonic-gate  * when there's more data from actual application use
417c478bd9Sstevel@tonic-gate  */
427c478bd9Sstevel@tonic-gate #define	MAX_IDLE_SESSIONS	100
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate /*
457c478bd9Sstevel@tonic-gate  * The following 5 variables are initialized at the time metaslot
467c478bd9Sstevel@tonic-gate  * is initialized.  They are not modified after they are initialized
477c478bd9Sstevel@tonic-gate  *
487c478bd9Sstevel@tonic-gate  * During initialization time, they are protected by the "initmutex"
497c478bd9Sstevel@tonic-gate  * defined in metaGeneral.c
507c478bd9Sstevel@tonic-gate  */
517c478bd9Sstevel@tonic-gate slot_data_t *slots;
527c478bd9Sstevel@tonic-gate CK_SLOT_ID metaslot_keystore_slotid;
537c478bd9Sstevel@tonic-gate static CK_ULONG num_slots;
547c478bd9Sstevel@tonic-gate static CK_ULONG objtok_slotnum;
554a5b2e70Shaimay static CK_ULONG softtoken_slotnum;
567c478bd9Sstevel@tonic-gate static boolean_t write_protected;
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /* protects the "metaslotLoggedIn" variable */
597c478bd9Sstevel@tonic-gate static pthread_mutex_t metaslotLoggedIn_mutex = PTHREAD_MUTEX_INITIALIZER;
607c478bd9Sstevel@tonic-gate static boolean_t metaslotLoggedIn;
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate /*
637c478bd9Sstevel@tonic-gate  * meta_slotManager_initialize
647c478bd9Sstevel@tonic-gate  *
657c478bd9Sstevel@tonic-gate  * Called from C_Initialize. Allocates and initializes the storage needed
667c478bd9Sstevel@tonic-gate  * by the slot manager.
677c478bd9Sstevel@tonic-gate  */
687c478bd9Sstevel@tonic-gate CK_RV
meta_slotManager_initialize()697c478bd9Sstevel@tonic-gate meta_slotManager_initialize() {
707c478bd9Sstevel@tonic-gate 	CK_ULONG slot_count = 0;
717c478bd9Sstevel@tonic-gate 	CK_RV rv;
727c478bd9Sstevel@tonic-gate 	CK_SLOT_ID i;
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate 	/* Initialize the static variables */
757c478bd9Sstevel@tonic-gate 	write_protected = B_FALSE;
767c478bd9Sstevel@tonic-gate 	metaslotLoggedIn = B_FALSE;
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate 	/*
797c478bd9Sstevel@tonic-gate 	 * Count the number of slots in the framework.
807c478bd9Sstevel@tonic-gate 	 * We start at ((slottable->st_first) + 1) instead of
817c478bd9Sstevel@tonic-gate 	 * slottable->st_first because when we are here, metaslot is
827c478bd9Sstevel@tonic-gate 	 * enabled, and st_first is always metaslot, which doesn't
837c478bd9Sstevel@tonic-gate 	 * need to be counted.
847c478bd9Sstevel@tonic-gate 	 */
857c478bd9Sstevel@tonic-gate 	for (i = (slottable->st_first) + 1; i <= slottable->st_last; i++) {
867c478bd9Sstevel@tonic-gate 		slot_count++;
877c478bd9Sstevel@tonic-gate 	}
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 	/*
907c478bd9Sstevel@tonic-gate 	 * This shouldn't happen, because there should at least
917c478bd9Sstevel@tonic-gate 	 * be 1 other slot besides metaslot.
927c478bd9Sstevel@tonic-gate 	 */
937c478bd9Sstevel@tonic-gate 	if (slot_count < 1) {
947c478bd9Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
957c478bd9Sstevel@tonic-gate 		goto clean_exit;
967c478bd9Sstevel@tonic-gate 	}
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	slots = calloc(slot_count, sizeof (slot_data_t));
997c478bd9Sstevel@tonic-gate 	if (slots == NULL) {
1007c478bd9Sstevel@tonic-gate 		rv = CKR_HOST_MEMORY;
1017c478bd9Sstevel@tonic-gate 		goto clean_exit;
1027c478bd9Sstevel@tonic-gate 	}
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	/*
1057c478bd9Sstevel@tonic-gate 	 * Store the slot IDs. Adjust for the fact that the first slot is
1067c478bd9Sstevel@tonic-gate 	 * actually us (metaslot).
1077c478bd9Sstevel@tonic-gate 	 */
1087c478bd9Sstevel@tonic-gate 	for (i = 0; i < slot_count; i++) {
1097c478bd9Sstevel@tonic-gate 		slots[i].fw_st_id = i + 1;
1107c478bd9Sstevel@tonic-gate 		(void) pthread_rwlock_init(
1117c478bd9Sstevel@tonic-gate 		    &(slots[i].tokenobject_list_lock), NULL);
1127c478bd9Sstevel@tonic-gate 	}
1137c478bd9Sstevel@tonic-gate 	num_slots = slot_count;
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 	return (CKR_OK);
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate clean_exit:
1187c478bd9Sstevel@tonic-gate 	if (slots) {
1197c478bd9Sstevel@tonic-gate 		free(slots);
1207c478bd9Sstevel@tonic-gate 		slots = NULL;
1217c478bd9Sstevel@tonic-gate 	}
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	num_slots = 0;
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	return (rv);
1267c478bd9Sstevel@tonic-gate }
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate /*
1307c478bd9Sstevel@tonic-gate  * meta_slotManager_finalize
1317c478bd9Sstevel@tonic-gate  *
1327c478bd9Sstevel@tonic-gate  * Called from C_Finalize. Deallocates any storage held by the slot manager.
1337c478bd9Sstevel@tonic-gate  */
1347c478bd9Sstevel@tonic-gate void
meta_slotManager_finalize()1357c478bd9Sstevel@tonic-gate meta_slotManager_finalize() {
1367c478bd9Sstevel@tonic-gate 	CK_ULONG slot;
1377c478bd9Sstevel@tonic-gate 
138*94f411ebSwyllys 	/* If no slots to free, return */
139*94f411ebSwyllys 	if (slots == NULL)
140*94f411ebSwyllys 		return;
1417c478bd9Sstevel@tonic-gate 	/*
1427c478bd9Sstevel@tonic-gate 	 * No need to lock pool, we assume all meta sessions are closed.
1437c478bd9Sstevel@tonic-gate 	 *
1447c478bd9Sstevel@tonic-gate 	 * Close all sessions in the idle and persist list.
1457c478bd9Sstevel@tonic-gate 	 * The active list is empty.  It doesn't need to be checked.
1467c478bd9Sstevel@tonic-gate 	 */
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	for (slot = 0; slot < num_slots; slot++) {
1497c478bd9Sstevel@tonic-gate 		slot_session_t *session, *next_session;
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 		/*
1527c478bd9Sstevel@tonic-gate 		 * The slotobjects associated with the session should have
1537c478bd9Sstevel@tonic-gate 		 * been closed when the metaobjects were closed. Thus, no
1547c478bd9Sstevel@tonic-gate 		 * need to do anything here.
1557c478bd9Sstevel@tonic-gate 		 */
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 		session = slots[slot].session_pool.idle_list_head;
1587c478bd9Sstevel@tonic-gate 		while (session) {
1597c478bd9Sstevel@tonic-gate 			next_session = session->next;
1607c478bd9Sstevel@tonic-gate 			(void) FUNCLIST(session->fw_st_id)->C_CloseSession(
1617c478bd9Sstevel@tonic-gate 			    session->hSession);
1627c478bd9Sstevel@tonic-gate 			(void) pthread_rwlock_destroy(
1637c478bd9Sstevel@tonic-gate 				&session->object_list_lock);
1647c478bd9Sstevel@tonic-gate 			free(session);
1657c478bd9Sstevel@tonic-gate 			session = next_session;
1667c478bd9Sstevel@tonic-gate 		}
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 		session = slots[slot].session_pool.persist_list_head;
1697c478bd9Sstevel@tonic-gate 		while (session) {
1707c478bd9Sstevel@tonic-gate 			next_session = session->next;
1717c478bd9Sstevel@tonic-gate 			(void) FUNCLIST(session->fw_st_id)->C_CloseSession(
1727c478bd9Sstevel@tonic-gate 			    session->hSession);
1737c478bd9Sstevel@tonic-gate 			(void) pthread_rwlock_destroy(
1747c478bd9Sstevel@tonic-gate 				&session->object_list_lock);
1757c478bd9Sstevel@tonic-gate 			free(session);
1767c478bd9Sstevel@tonic-gate 			session = next_session;
1777c478bd9Sstevel@tonic-gate 		}
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 		(void) pthread_rwlock_destroy(
1807c478bd9Sstevel@tonic-gate 			&slots[slot].tokenobject_list_lock);
1817c478bd9Sstevel@tonic-gate 	}
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	free(slots);
1847c478bd9Sstevel@tonic-gate 	slots = NULL;
185*94f411ebSwyllys 	num_slots = 0;
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate /*
1907c478bd9Sstevel@tonic-gate  * meta_slotManager_find_object_token()
1917c478bd9Sstevel@tonic-gate  *
1927c478bd9Sstevel@tonic-gate  * Called from meta_Initialize. Searches for the "object token," which is used
1937c478bd9Sstevel@tonic-gate  * for storing token objects and loging into.
1947c478bd9Sstevel@tonic-gate  *
1957c478bd9Sstevel@tonic-gate  * We do the search using the following algorithm.
1967c478bd9Sstevel@tonic-gate  *
1977c478bd9Sstevel@tonic-gate  * If either ${METASLOT_OBJECTSTORE_SLOT} or ${METASLOT_OBJECTSTORE_TOKEN}
1987c478bd9Sstevel@tonic-gate  * environment variable is defined, the value of the defined variable(s)
1997c478bd9Sstevel@tonic-gate  * will be used for the match.  All token and slot values defined system-wide
2007c478bd9Sstevel@tonic-gate  * will be ignored.
2017c478bd9Sstevel@tonic-gate  *
2027c478bd9Sstevel@tonic-gate  * If neither variables above are defined, the system-wide values defined
2037c478bd9Sstevel@tonic-gate  * in pkcs11.conf are used.
2047c478bd9Sstevel@tonic-gate  *
2057c478bd9Sstevel@tonic-gate  * If neither environment variables or system-wide values are defined,
2067c478bd9Sstevel@tonic-gate  * or if none of the existing slots/tokens match the defined
2077c478bd9Sstevel@tonic-gate  * values, the first slot after metaslot will be used as the default.
2087c478bd9Sstevel@tonic-gate  *
2097c478bd9Sstevel@tonic-gate  */
2107c478bd9Sstevel@tonic-gate void
meta_slotManager_find_object_token()2117c478bd9Sstevel@tonic-gate meta_slotManager_find_object_token() {
2127c478bd9Sstevel@tonic-gate 	CK_ULONG slot;
2137c478bd9Sstevel@tonic-gate 	boolean_t found = B_FALSE;
2147c478bd9Sstevel@tonic-gate 	CK_RV rv;
2157c478bd9Sstevel@tonic-gate 	unsigned int num_match_needed = 0;
2167c478bd9Sstevel@tonic-gate 	CK_SLOT_INFO slotinfo;
2177c478bd9Sstevel@tonic-gate 	CK_TOKEN_INFO tokeninfo;
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	if (metaslot_config.keystore_token_specified) {
2207c478bd9Sstevel@tonic-gate 		num_match_needed++;
2217c478bd9Sstevel@tonic-gate 	}
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	if (metaslot_config.keystore_slot_specified) {
2247c478bd9Sstevel@tonic-gate 		num_match_needed++;
2257c478bd9Sstevel@tonic-gate 	}
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	if (num_match_needed == 0) {
2287c478bd9Sstevel@tonic-gate 		goto skip_search;
2297c478bd9Sstevel@tonic-gate 	}
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 	for (slot = 0; slot < num_slots; slot++) {
2327c478bd9Sstevel@tonic-gate 		unsigned int num_matched = 0;
2337c478bd9Sstevel@tonic-gate 		boolean_t have_tokeninfo = B_FALSE;
2347c478bd9Sstevel@tonic-gate 		CK_SLOT_ID true_id, fw_st_id;
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 		fw_st_id = slots[slot].fw_st_id;
2377c478bd9Sstevel@tonic-gate 		true_id = TRUEID(fw_st_id);
2387c478bd9Sstevel@tonic-gate 
2394a5b2e70Shaimay 		(void) memset(&slotinfo, 0, sizeof (CK_SLOT_INFO));
2404a5b2e70Shaimay 		rv = FUNCLIST(fw_st_id)->C_GetSlotInfo(true_id,
2414a5b2e70Shaimay 		    &slotinfo);
2424a5b2e70Shaimay 		if (rv != CKR_OK)
2434a5b2e70Shaimay 			continue;
2444a5b2e70Shaimay 
2454a5b2e70Shaimay 		if (strncmp((char *)SOFT_SLOT_DESCRIPTION,
2464a5b2e70Shaimay 		    (char *)slotinfo.slotDescription,
2474a5b2e70Shaimay 		    SLOT_DESCRIPTION_SIZE) == 0) {
2484a5b2e70Shaimay 			softtoken_slotnum = slot;
2494a5b2e70Shaimay 		}
2504a5b2e70Shaimay 
2517c478bd9Sstevel@tonic-gate 		if (metaslot_config.keystore_slot_specified) {
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 			unsigned char *slot;
2547c478bd9Sstevel@tonic-gate 			size_t slot_str_len;
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 			rv = FUNCLIST(fw_st_id)->C_GetSlotInfo(true_id,
2577c478bd9Sstevel@tonic-gate 			    &slotinfo);
2587c478bd9Sstevel@tonic-gate 			if (rv != CKR_OK)
2597c478bd9Sstevel@tonic-gate 				continue;
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 			/*
2627c478bd9Sstevel@tonic-gate 			 * pad slot description from user/system configuration
2637c478bd9Sstevel@tonic-gate 			 * with spaces
2647c478bd9Sstevel@tonic-gate 			 */
2657c478bd9Sstevel@tonic-gate 			slot = metaslot_config.keystore_slot;
2667c478bd9Sstevel@tonic-gate 			slot_str_len = strlen((char *)slot);
2677c478bd9Sstevel@tonic-gate 			(void) memset(slot + slot_str_len, ' ',
2687c478bd9Sstevel@tonic-gate 			    SLOT_DESCRIPTION_SIZE - slot_str_len);
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 			/*
2717c478bd9Sstevel@tonic-gate 			 * The PKCS#11 strings are not null-terminated, so,
2727c478bd9Sstevel@tonic-gate 			 * we just compare SLOT_DESCRIPTION_SIZE bytes
2737c478bd9Sstevel@tonic-gate 			 */
2747c478bd9Sstevel@tonic-gate 			if (strncmp((char *)slot,
2757c478bd9Sstevel@tonic-gate 			    (char *)slotinfo.slotDescription,
2767c478bd9Sstevel@tonic-gate 			    SLOT_DESCRIPTION_SIZE) == 0) {
2777c478bd9Sstevel@tonic-gate 				num_matched++;
2787c478bd9Sstevel@tonic-gate 			}
2797c478bd9Sstevel@tonic-gate 		}
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 		if (metaslot_config.keystore_token_specified) {
2827c478bd9Sstevel@tonic-gate 			unsigned char *token;
2837c478bd9Sstevel@tonic-gate 			size_t token_str_len;
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 			rv = FUNCLIST(fw_st_id)->C_GetTokenInfo(true_id,
2867c478bd9Sstevel@tonic-gate 			    &tokeninfo);
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 			if (rv != CKR_OK) {
2897c478bd9Sstevel@tonic-gate 				continue;
2907c478bd9Sstevel@tonic-gate 			}
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 			have_tokeninfo = B_TRUE;
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 			/*
2957c478bd9Sstevel@tonic-gate 			 * pad slot description from user/system configuration
2967c478bd9Sstevel@tonic-gate 			 * with spaces
2977c478bd9Sstevel@tonic-gate 			 */
2987c478bd9Sstevel@tonic-gate 			token = metaslot_config.keystore_token;
2997c478bd9Sstevel@tonic-gate 			token_str_len = strlen((char *)token);
3007c478bd9Sstevel@tonic-gate 			(void) memset(token + token_str_len, ' ',
3017c478bd9Sstevel@tonic-gate 			    TOKEN_LABEL_SIZE - token_str_len);
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 			/*
3047c478bd9Sstevel@tonic-gate 			 * The PKCS#11 strings are not null-terminated.
3057c478bd9Sstevel@tonic-gate 			 * So, just compare TOKEN_LABEL_SIZE bytes
3067c478bd9Sstevel@tonic-gate 			 */
3077c478bd9Sstevel@tonic-gate 			if (strncmp((char *)token, (char *)tokeninfo.label,
3087c478bd9Sstevel@tonic-gate 			    TOKEN_LABEL_SIZE) == 0) {
3097c478bd9Sstevel@tonic-gate 				num_matched++;
3107c478bd9Sstevel@tonic-gate 			}
3117c478bd9Sstevel@tonic-gate 		}
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 		if (num_match_needed == num_matched) {
3147c478bd9Sstevel@tonic-gate 			/* match is found */
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 			if (!have_tokeninfo) {
3177c478bd9Sstevel@tonic-gate 				rv = FUNCLIST(fw_st_id)->C_GetTokenInfo(true_id,
3187c478bd9Sstevel@tonic-gate 				    &tokeninfo);
3197c478bd9Sstevel@tonic-gate 				if (rv != CKR_OK) {
3207c478bd9Sstevel@tonic-gate 					continue;
3217c478bd9Sstevel@tonic-gate 				}
3227c478bd9Sstevel@tonic-gate 			}
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 			if (tokeninfo.flags & CKF_WRITE_PROTECTED) {
3267c478bd9Sstevel@tonic-gate 				/*
3277c478bd9Sstevel@tonic-gate 				 * Currently this is the only time that
3287c478bd9Sstevel@tonic-gate 				 * the write_protected state is set, and
3297c478bd9Sstevel@tonic-gate 				 * it is never cleared. The token could
3307c478bd9Sstevel@tonic-gate 				 * clear (or set!) this flag later on.
3317c478bd9Sstevel@tonic-gate 				 * We might want to adjust the state
3327c478bd9Sstevel@tonic-gate 				 * of metaslot, but there's know way to know
3337c478bd9Sstevel@tonic-gate 				 * when a token changes this flag.
3347c478bd9Sstevel@tonic-gate 				 */
3357c478bd9Sstevel@tonic-gate 				write_protected = B_TRUE;
3367c478bd9Sstevel@tonic-gate 			}
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 			found = B_TRUE;
3397c478bd9Sstevel@tonic-gate 			break;
3407c478bd9Sstevel@tonic-gate 		}
3417c478bd9Sstevel@tonic-gate 	}
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate skip_search:
3447c478bd9Sstevel@tonic-gate 	if (found) {
3457c478bd9Sstevel@tonic-gate 		objtok_slotnum = slot;
3467c478bd9Sstevel@tonic-gate 	} else {
3477c478bd9Sstevel@tonic-gate 		/*
3487c478bd9Sstevel@tonic-gate 		 * if slot and/or token is not defined for the keystore,
3497c478bd9Sstevel@tonic-gate 		 * just use the first available slot as keystore
3507c478bd9Sstevel@tonic-gate 		 */
3517c478bd9Sstevel@tonic-gate 		objtok_slotnum = 0;
3527c478bd9Sstevel@tonic-gate 	}
3537c478bd9Sstevel@tonic-gate 	slots[objtok_slotnum].session_pool.keep_one_alive = B_TRUE;
3547c478bd9Sstevel@tonic-gate 	metaslot_keystore_slotid = slots[objtok_slotnum].fw_st_id;
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate CK_ULONG
get_keystore_slotnum()3597c478bd9Sstevel@tonic-gate get_keystore_slotnum()
3607c478bd9Sstevel@tonic-gate {
3617c478bd9Sstevel@tonic-gate 	return (objtok_slotnum);
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate 
3644a5b2e70Shaimay CK_ULONG
get_softtoken_slotnum()3654a5b2e70Shaimay get_softtoken_slotnum()
3664a5b2e70Shaimay {
3674a5b2e70Shaimay 	return (softtoken_slotnum);
3684a5b2e70Shaimay }
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate CK_SLOT_ID
meta_slotManager_get_framework_table_id(CK_ULONG slotnum)3717c478bd9Sstevel@tonic-gate meta_slotManager_get_framework_table_id(CK_ULONG slotnum)
3727c478bd9Sstevel@tonic-gate {
3737c478bd9Sstevel@tonic-gate 	/*
3747c478bd9Sstevel@tonic-gate 	 * This is only used internally, and so the slotnum should always
3757c478bd9Sstevel@tonic-gate 	 * be valid.
3767c478bd9Sstevel@tonic-gate 	 */
3777c478bd9Sstevel@tonic-gate 	return (slots[slotnum].fw_st_id);
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate CK_ULONG
meta_slotManager_get_slotcount()3817c478bd9Sstevel@tonic-gate meta_slotManager_get_slotcount()
3827c478bd9Sstevel@tonic-gate {
3837c478bd9Sstevel@tonic-gate 	return (num_slots);
3847c478bd9Sstevel@tonic-gate }
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate boolean_t
meta_slotManager_token_write_protected()3877c478bd9Sstevel@tonic-gate meta_slotManager_token_write_protected()
3887c478bd9Sstevel@tonic-gate {
3897c478bd9Sstevel@tonic-gate 	return (write_protected);
3907c478bd9Sstevel@tonic-gate }
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate /*
3937c478bd9Sstevel@tonic-gate  * Find a session in the given list that matches the specified flags.
3947c478bd9Sstevel@tonic-gate  * If such a session is found, it will be removed from the list, and
3957c478bd9Sstevel@tonic-gate  * returned to the caller.  If such a session is not found, will
3967c478bd9Sstevel@tonic-gate  * return NULL
3977c478bd9Sstevel@tonic-gate  */
3987c478bd9Sstevel@tonic-gate static slot_session_t *
get_session(slot_session_t ** session_list,CK_FLAGS flags)3997c478bd9Sstevel@tonic-gate get_session(slot_session_t **session_list, CK_FLAGS flags)
4007c478bd9Sstevel@tonic-gate {
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	slot_session_t *tmp_session;
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	tmp_session = *session_list;
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	while (tmp_session != NULL) {
4077c478bd9Sstevel@tonic-gate 		if (tmp_session->session_flags == flags) {
4087c478bd9Sstevel@tonic-gate 			break;
4097c478bd9Sstevel@tonic-gate 		} else {
4107c478bd9Sstevel@tonic-gate 			tmp_session = tmp_session->next;
4117c478bd9Sstevel@tonic-gate 		}
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	}
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	if (tmp_session == NULL) {
4167c478bd9Sstevel@tonic-gate 		/* no match */
4177c478bd9Sstevel@tonic-gate 		return (NULL);
4187c478bd9Sstevel@tonic-gate 	}
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	/* Remove from list */
4217c478bd9Sstevel@tonic-gate 	REMOVE_FROM_LIST(*session_list, tmp_session);
4227c478bd9Sstevel@tonic-gate 	return (tmp_session);
4237c478bd9Sstevel@tonic-gate }
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate /*
4267c478bd9Sstevel@tonic-gate  * meta_get_slot_session
4277c478bd9Sstevel@tonic-gate  *
4287c478bd9Sstevel@tonic-gate  * Call to get a session with a specific slot/token.
4297c478bd9Sstevel@tonic-gate  *
4307c478bd9Sstevel@tonic-gate  * NOTE - We assume the slot allows an unlimited number of sessions. We
4317c478bd9Sstevel@tonic-gate  * could look at what's reported in the token info, but that information is
4327c478bd9Sstevel@tonic-gate  * not always set. It's also unclear when we should (A) wait for one to become
4337c478bd9Sstevel@tonic-gate  * available, (B) skip the slot for now or (C) return a fatal error. The
4347c478bd9Sstevel@tonic-gate  * extra complexity is not worth it.
4357c478bd9Sstevel@tonic-gate  *
4367c478bd9Sstevel@tonic-gate  */
4377c478bd9Sstevel@tonic-gate CK_RV
meta_get_slot_session(CK_ULONG slotnum,slot_session_t ** session,CK_FLAGS flags)4387c478bd9Sstevel@tonic-gate meta_get_slot_session(CK_ULONG slotnum, slot_session_t **session,
4397c478bd9Sstevel@tonic-gate     CK_FLAGS flags) {
4407c478bd9Sstevel@tonic-gate 	session_pool_t *pool;
4417c478bd9Sstevel@tonic-gate 	slot_session_t *new_session, *tmp_session;
4427c478bd9Sstevel@tonic-gate 	CK_RV rv;
4437c478bd9Sstevel@tonic-gate 	CK_SLOT_ID fw_st_id, true_id;
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	if (slotnum >= num_slots) {
4467c478bd9Sstevel@tonic-gate 		return (CKR_SLOT_ID_INVALID);
4477c478bd9Sstevel@tonic-gate 	}
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	pool = &slots[slotnum].session_pool;
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	/*
4527c478bd9Sstevel@tonic-gate 	 * Try to reuse an existing session.
4537c478bd9Sstevel@tonic-gate 	 */
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&pool->list_lock);
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	if (pool->idle_list_head != NULL) {
4587c478bd9Sstevel@tonic-gate 		tmp_session = get_session(&(pool->idle_list_head), flags);
4597c478bd9Sstevel@tonic-gate 		if (tmp_session != NULL) {
4607c478bd9Sstevel@tonic-gate 			/* Add to active list */
4617c478bd9Sstevel@tonic-gate 			INSERT_INTO_LIST(pool->active_list_head, tmp_session);
4627c478bd9Sstevel@tonic-gate 			*session = tmp_session;
4637c478bd9Sstevel@tonic-gate 			pool->num_idle_sessions--;
4647c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&pool->list_lock);
4657c478bd9Sstevel@tonic-gate 			return (CKR_OK);
4667c478bd9Sstevel@tonic-gate 		}
4677c478bd9Sstevel@tonic-gate 	}
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	if (pool->persist_list_head != NULL) {
4707c478bd9Sstevel@tonic-gate 		tmp_session = get_session(&(pool->persist_list_head), flags);
4717c478bd9Sstevel@tonic-gate 		if (tmp_session != NULL) {
4727c478bd9Sstevel@tonic-gate 			/* Add to active list */
4737c478bd9Sstevel@tonic-gate 			INSERT_INTO_LIST(pool->active_list_head, tmp_session);
4747c478bd9Sstevel@tonic-gate 			*session = tmp_session;
4757c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&pool->list_lock);
4767c478bd9Sstevel@tonic-gate 			return (CKR_OK);
4777c478bd9Sstevel@tonic-gate 		}
4787c478bd9Sstevel@tonic-gate 	}
4797c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&pool->list_lock);
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	fw_st_id = slots[slotnum].fw_st_id;
4827c478bd9Sstevel@tonic-gate 	true_id = TRUEID(fw_st_id);
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	new_session = calloc(1, sizeof (slot_session_t));
4857c478bd9Sstevel@tonic-gate 	if (new_session == NULL) {
4867c478bd9Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
4877c478bd9Sstevel@tonic-gate 	}
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	/* initialize slotsession */
4907c478bd9Sstevel@tonic-gate 	new_session->slotnum = slotnum;
4917c478bd9Sstevel@tonic-gate 	new_session->fw_st_id = fw_st_id;
4927c478bd9Sstevel@tonic-gate 	new_session->object_list_head = NULL;
4937c478bd9Sstevel@tonic-gate 	new_session->session_flags = flags;
4947c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_init(&new_session->object_list_lock, NULL);
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	rv = FUNCLIST(fw_st_id)->C_OpenSession(true_id, flags, NULL, NULL,
4977c478bd9Sstevel@tonic-gate 	    &new_session->hSession);
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 	if (rv == CKR_TOKEN_WRITE_PROTECTED) {
5007c478bd9Sstevel@tonic-gate 		/* Retry with a RO session. */
5017c478bd9Sstevel@tonic-gate 		new_session->session_flags &= ~CKF_SERIAL_SESSION;
5027c478bd9Sstevel@tonic-gate 		rv = FUNCLIST(fw_st_id)->C_OpenSession(true_id,
5037c478bd9Sstevel@tonic-gate 		    new_session->session_flags, NULL, NULL,
5047c478bd9Sstevel@tonic-gate 		    &new_session->hSession);
5057c478bd9Sstevel@tonic-gate 	}
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
5087c478bd9Sstevel@tonic-gate 		free(new_session);
5097c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
5107c478bd9Sstevel@tonic-gate 	}
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	/* Insert session into active list */
5137c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&pool->list_lock);
5147c478bd9Sstevel@tonic-gate 	INSERT_INTO_LIST(pool->active_list_head, new_session);
5157c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&pool->list_lock);
5167c478bd9Sstevel@tonic-gate 	*session = new_session;
5177c478bd9Sstevel@tonic-gate 	return (CKR_OK);
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate /*
5227c478bd9Sstevel@tonic-gate  * meta_release_slot_session
5237c478bd9Sstevel@tonic-gate  *
5247c478bd9Sstevel@tonic-gate  * Call to release a session obtained via meta_get_slot_session()
5257c478bd9Sstevel@tonic-gate  */
5267c478bd9Sstevel@tonic-gate void
meta_release_slot_session(slot_session_t * session)5277c478bd9Sstevel@tonic-gate meta_release_slot_session(slot_session_t *session) {
5287c478bd9Sstevel@tonic-gate 	session_pool_t *pool;
5297c478bd9Sstevel@tonic-gate 	boolean_t must_retain, can_close = B_FALSE;
5307c478bd9Sstevel@tonic-gate 	boolean_t this_is_last_session = B_FALSE;
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	pool = &slots[session->slotnum].session_pool;
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	/* Note that the active_list must have >= 1 entry (this session) */
5357c478bd9Sstevel@tonic-gate 	if (pool->persist_list_head == NULL &&
5367c478bd9Sstevel@tonic-gate 	    pool->idle_list_head == NULL &&
5377c478bd9Sstevel@tonic-gate 	    pool->active_list_head->next == NULL)
5387c478bd9Sstevel@tonic-gate 		this_is_last_session = B_TRUE;
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	/*
5417c478bd9Sstevel@tonic-gate 	 * If the session has session objects, we need to retain it. Also
5427c478bd9Sstevel@tonic-gate 	 * retain it if it's the only session holding login state (or handles
5437c478bd9Sstevel@tonic-gate 	 * to public token objects)
5447c478bd9Sstevel@tonic-gate 	 */
5457c478bd9Sstevel@tonic-gate 	must_retain = session->object_list_head != NULL ||
5467c478bd9Sstevel@tonic-gate 	    (pool->keep_one_alive && this_is_last_session);
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	if ((!must_retain) && (pool->num_idle_sessions > MAX_IDLE_SESSIONS)) {
5497c478bd9Sstevel@tonic-gate 		can_close = B_TRUE;
5507c478bd9Sstevel@tonic-gate 	}
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&pool->list_lock);
5537c478bd9Sstevel@tonic-gate 	/* remove from active list */
5547c478bd9Sstevel@tonic-gate 	REMOVE_FROM_LIST(pool->active_list_head, session);
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	if (must_retain) {
5577c478bd9Sstevel@tonic-gate 		/* insert into persist list */
5587c478bd9Sstevel@tonic-gate 		INSERT_INTO_LIST(pool->persist_list_head, session);
5597c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&pool->list_lock);
5607c478bd9Sstevel@tonic-gate 		return;
5617c478bd9Sstevel@tonic-gate 	} else if (!can_close) {
5627c478bd9Sstevel@tonic-gate 		/* insert into idle list */
5637c478bd9Sstevel@tonic-gate 		INSERT_INTO_LIST(pool->idle_list_head, session);
5647c478bd9Sstevel@tonic-gate 		pool->num_idle_sessions++;
5657c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&pool->list_lock);
5667c478bd9Sstevel@tonic-gate 		return;
5677c478bd9Sstevel@tonic-gate 	}
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&pool->list_lock);
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	(void) FUNCLIST(session->fw_st_id)->C_CloseSession(session->hSession);
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_destroy(&session->object_list_lock);
5747c478bd9Sstevel@tonic-gate 	free(session);
5757c478bd9Sstevel@tonic-gate }
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate /*
5787c478bd9Sstevel@tonic-gate  * Returns whether metaslot has directly logged in
5797c478bd9Sstevel@tonic-gate  */
5807c478bd9Sstevel@tonic-gate boolean_t
metaslot_logged_in()5817c478bd9Sstevel@tonic-gate metaslot_logged_in()
5827c478bd9Sstevel@tonic-gate {
5837c478bd9Sstevel@tonic-gate 	return (metaslotLoggedIn);
5847c478bd9Sstevel@tonic-gate }
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate void
metaslot_set_logged_in_flag(boolean_t value)5877c478bd9Sstevel@tonic-gate metaslot_set_logged_in_flag(boolean_t value)
5887c478bd9Sstevel@tonic-gate {
5897c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&metaslotLoggedIn_mutex);
5907c478bd9Sstevel@tonic-gate 	metaslotLoggedIn = value;
5917c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&metaslotLoggedIn_mutex);
5927c478bd9Sstevel@tonic-gate }
593