10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54072Skrishna  * Common Development and Distribution License (the "License").
64072Skrishna  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*9661SZdenek.Kotala@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <pthread.h>
270Sstevel@tonic-gate #include <syslog.h>
280Sstevel@tonic-gate #include <stdlib.h>
290Sstevel@tonic-gate #include <string.h>
300Sstevel@tonic-gate #include <errno.h>
310Sstevel@tonic-gate #include <sys/crypto/ioctl.h>
320Sstevel@tonic-gate #include <security/cryptoki.h>
330Sstevel@tonic-gate #include "kernelGlobal.h"
340Sstevel@tonic-gate #include "kernelSession.h"
350Sstevel@tonic-gate #include "kernelSlot.h"
364072Skrishna #include "kernelEmulate.h"
370Sstevel@tonic-gate 
38214Smcpowers static pthread_mutex_t delete_sessions_mutex = PTHREAD_MUTEX_INITIALIZER;
39214Smcpowers 
400Sstevel@tonic-gate /*
410Sstevel@tonic-gate  * Delete all the sessions. First, obtain the slot lock.
420Sstevel@tonic-gate  * Then start to delete one session at a time.  The boolean wrapper_only
430Sstevel@tonic-gate  * argument indicates that whether the caller only wants to clean up the
440Sstevel@tonic-gate  * session wrappers and the object wrappers in the library.
450Sstevel@tonic-gate  * - When this function is called by C_CloseAllSessions or indirectly by
460Sstevel@tonic-gate  *   C_Finalize, wrapper_only is FALSE.
470Sstevel@tonic-gate  * - When this function is called by cleanup_child, wrapper_only is TRUE.
480Sstevel@tonic-gate  */
49214Smcpowers void
kernel_delete_all_sessions(CK_SLOT_ID slotID,boolean_t wrapper_only)500Sstevel@tonic-gate kernel_delete_all_sessions(CK_SLOT_ID slotID, boolean_t wrapper_only)
510Sstevel@tonic-gate {
520Sstevel@tonic-gate 	kernel_session_t *session_p;
530Sstevel@tonic-gate 	kernel_slot_t *pslot;
540Sstevel@tonic-gate 
55214Smcpowers 	(void) pthread_mutex_lock(&delete_sessions_mutex);
56214Smcpowers 
570Sstevel@tonic-gate 	pslot = slot_table[slotID];
580Sstevel@tonic-gate 
590Sstevel@tonic-gate 	/*
600Sstevel@tonic-gate 	 * Delete all the sessions in the slot's session list.
610Sstevel@tonic-gate 	 * The routine kernel_delete_session() updates the linked list.
620Sstevel@tonic-gate 	 * So, we do not need to maintain the list here.
630Sstevel@tonic-gate 	 */
64214Smcpowers 	for (;;) {
65214Smcpowers 		(void) pthread_mutex_lock(&pslot->sl_mutex);
66214Smcpowers 		if (pslot->sl_sess_list == NULL)
67214Smcpowers 			break;
680Sstevel@tonic-gate 
69214Smcpowers 		session_p = pslot->sl_sess_list;
70214Smcpowers 		/*
71214Smcpowers 		 * Set SESSION_IS_CLOSING flag so any access to this
72214Smcpowers 		 * session will be rejected.
73214Smcpowers 		 */
74214Smcpowers 		(void) pthread_mutex_lock(&session_p->session_mutex);
75214Smcpowers 		if (session_p->ses_close_sync & SESSION_IS_CLOSING) {
76214Smcpowers 			(void) pthread_mutex_unlock(&session_p->session_mutex);
77214Smcpowers 			continue;
780Sstevel@tonic-gate 		}
79214Smcpowers 		session_p->ses_close_sync |= SESSION_IS_CLOSING;
80214Smcpowers 		(void) pthread_mutex_unlock(&session_p->session_mutex);
810Sstevel@tonic-gate 
82214Smcpowers 		(void) pthread_mutex_unlock(&pslot->sl_mutex);
83214Smcpowers 		kernel_delete_session(slotID, session_p, B_FALSE, wrapper_only);
840Sstevel@tonic-gate 	}
850Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&pslot->sl_mutex);
86214Smcpowers 	(void) pthread_mutex_unlock(&delete_sessions_mutex);
870Sstevel@tonic-gate }
880Sstevel@tonic-gate 
890Sstevel@tonic-gate /*
900Sstevel@tonic-gate  * Create a new session struct, and add it to the slot's session list.
910Sstevel@tonic-gate  *
920Sstevel@tonic-gate  * This function is called by C_OpenSession(), which hold the slot lock.
930Sstevel@tonic-gate  */
940Sstevel@tonic-gate CK_RV
kernel_add_session(CK_SLOT_ID slotID,CK_FLAGS flags,CK_VOID_PTR pApplication,CK_NOTIFY notify,CK_ULONG * sessionhandle_p)950Sstevel@tonic-gate kernel_add_session(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication,
960Sstevel@tonic-gate 	CK_NOTIFY notify, CK_ULONG *sessionhandle_p)
970Sstevel@tonic-gate {
980Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
990Sstevel@tonic-gate 	kernel_session_t *new_sp = NULL;
1000Sstevel@tonic-gate 	crypto_open_session_t open_session;
1010Sstevel@tonic-gate 	kernel_slot_t	*pslot;
1020Sstevel@tonic-gate 	int r;
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 	/* Allocate a new session struct */
1050Sstevel@tonic-gate 	new_sp = calloc(1, sizeof (kernel_session_t));
1060Sstevel@tonic-gate 	if (new_sp == NULL) {
1070Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
1080Sstevel@tonic-gate 	}
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 	new_sp->magic_marker = KERNELTOKEN_SESSION_MAGIC;
1110Sstevel@tonic-gate 	new_sp->pApplication = pApplication;
1120Sstevel@tonic-gate 	new_sp->Notify = notify;
1130Sstevel@tonic-gate 	new_sp->flags = flags;
1140Sstevel@tonic-gate 	new_sp->ses_RO = (flags & CKF_RW_SESSION) ? B_FALSE : B_TRUE;
1150Sstevel@tonic-gate 	new_sp->ses_slotid = slotID;
1160Sstevel@tonic-gate 	new_sp->object_list = NULL;
1170Sstevel@tonic-gate 	new_sp->ses_refcnt = 0;
1180Sstevel@tonic-gate 	new_sp->ses_close_sync = 0;
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	/* Initialize the lock for the newly created session */
1210Sstevel@tonic-gate 	if (pthread_mutex_init(&new_sp->session_mutex, NULL) != 0) {
1220Sstevel@tonic-gate 		free(new_sp);
1230Sstevel@tonic-gate 		return (CKR_CANT_LOCK);
1240Sstevel@tonic-gate 	}
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	pslot = slot_table[slotID];
1270Sstevel@tonic-gate 	open_session.os_provider_id = pslot->sl_provider_id;
1280Sstevel@tonic-gate 	open_session.os_flags = flags;
1290Sstevel@tonic-gate 	while ((r = ioctl(kernel_fd, CRYPTO_OPEN_SESSION, &open_session)) < 0) {
1300Sstevel@tonic-gate 		if (errno != EINTR)
1310Sstevel@tonic-gate 			break;
1320Sstevel@tonic-gate 	}
1330Sstevel@tonic-gate 	if (r < 0) {
1340Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
1350Sstevel@tonic-gate 	} else {
1360Sstevel@tonic-gate 		rv = crypto2pkcs11_error_number(open_session.os_return_value);
1370Sstevel@tonic-gate 	}
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 	if (rv != CKR_OK) {
1400Sstevel@tonic-gate 		(void) pthread_mutex_destroy(&new_sp->session_mutex);
1410Sstevel@tonic-gate 		free(new_sp);
1420Sstevel@tonic-gate 		return (rv);
1430Sstevel@tonic-gate 	}
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 	new_sp->k_session = open_session.os_session;
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	(void) pthread_mutex_init(&new_sp->ses_free_mutex, NULL);
1480Sstevel@tonic-gate 	(void) pthread_cond_init(&new_sp->ses_free_cond, NULL);
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 	/* Insert the new session in front of the slot's session list */
1510Sstevel@tonic-gate 	if (pslot->sl_sess_list == NULL) {
1520Sstevel@tonic-gate 		pslot->sl_sess_list = new_sp;
1530Sstevel@tonic-gate 		new_sp->prev = NULL;
1540Sstevel@tonic-gate 		new_sp->next = NULL;
1550Sstevel@tonic-gate 	} else {
1560Sstevel@tonic-gate 		pslot->sl_sess_list->prev = new_sp;
1570Sstevel@tonic-gate 		new_sp->next = pslot->sl_sess_list;
1580Sstevel@tonic-gate 		new_sp->prev = NULL;
1590Sstevel@tonic-gate 		pslot->sl_sess_list = new_sp;
1600Sstevel@tonic-gate 	}
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 	/* Type casting the address of a session struct to a session handle */
1630Sstevel@tonic-gate 	*sessionhandle_p =  (CK_ULONG)new_sp;
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	return (CKR_OK);
1660Sstevel@tonic-gate }
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate /*
1690Sstevel@tonic-gate  * Delete a session:
1700Sstevel@tonic-gate  * - Remove the session from the slot's session list.
1710Sstevel@tonic-gate  * - Release all the objects created by the session.
1720Sstevel@tonic-gate  *
1730Sstevel@tonic-gate  * The boolean argument slot_lock_held is used to indicate that whether
1740Sstevel@tonic-gate  * the caller of this function holds the slot lock or not.
1750Sstevel@tonic-gate  * - When called by kernel_delete_all_sessions(), which is called by
1760Sstevel@tonic-gate  *   C_Finalize() or C_CloseAllSessions() -- slot_lock_held = TRUE.
1770Sstevel@tonic-gate  * - When called by C_CloseSession() -- slot_lock_held = FALSE.
1780Sstevel@tonic-gate  */
179214Smcpowers void
kernel_delete_session(CK_SLOT_ID slotID,kernel_session_t * session_p,boolean_t slot_lock_held,boolean_t wrapper_only)1800Sstevel@tonic-gate kernel_delete_session(CK_SLOT_ID slotID, kernel_session_t *session_p,
1810Sstevel@tonic-gate     boolean_t slot_lock_held, boolean_t wrapper_only)
1820Sstevel@tonic-gate {
1830Sstevel@tonic-gate 	crypto_session_id_t k_session;
1840Sstevel@tonic-gate 	crypto_close_session_t close_session;
1850Sstevel@tonic-gate 	kernel_slot_t	*pslot;
1860Sstevel@tonic-gate 	kernel_object_t *objp;
1870Sstevel@tonic-gate 	kernel_object_t *objp1;
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	/*
1900Sstevel@tonic-gate 	 * Check to see if the caller holds the lock on the global
1910Sstevel@tonic-gate 	 * session list. If not, we need to acquire that lock in
1920Sstevel@tonic-gate 	 * order to proceed.
1930Sstevel@tonic-gate 	 */
1940Sstevel@tonic-gate 	pslot = slot_table[slotID];
1950Sstevel@tonic-gate 	if (!slot_lock_held) {
1960Sstevel@tonic-gate 		/* Acquire the slot lock */
1970Sstevel@tonic-gate 		(void) pthread_mutex_lock(&pslot->sl_mutex);
1980Sstevel@tonic-gate 	}
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	/*
2010Sstevel@tonic-gate 	 * Remove the session from the slot's session list first.
2020Sstevel@tonic-gate 	 */
2030Sstevel@tonic-gate 	if (pslot->sl_sess_list == session_p) {
2040Sstevel@tonic-gate 		/* Session is the first one in the list */
2050Sstevel@tonic-gate 		if (session_p->next) {
2060Sstevel@tonic-gate 			pslot->sl_sess_list = session_p->next;
2070Sstevel@tonic-gate 			session_p->next->prev = NULL;
2080Sstevel@tonic-gate 		} else {
2090Sstevel@tonic-gate 			/* Session is the only one in the list */
2100Sstevel@tonic-gate 			pslot->sl_sess_list = NULL;
2110Sstevel@tonic-gate 		}
2120Sstevel@tonic-gate 	} else {
2130Sstevel@tonic-gate 		/* Session is not the first one in the list */
2140Sstevel@tonic-gate 		if (session_p->next) {
2150Sstevel@tonic-gate 			/* Session is in the middle of the list */
2160Sstevel@tonic-gate 			session_p->prev->next = session_p->next;
2170Sstevel@tonic-gate 			session_p->next->prev = session_p->prev;
2180Sstevel@tonic-gate 		} else {
2190Sstevel@tonic-gate 			/* Session is the last one in the list */
2200Sstevel@tonic-gate 			session_p->prev->next = NULL;
2210Sstevel@tonic-gate 		}
2220Sstevel@tonic-gate 	}
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	if (!slot_lock_held) {
2250Sstevel@tonic-gate 		/*
2260Sstevel@tonic-gate 		 * If the slot lock is obtained by
2270Sstevel@tonic-gate 		 * this function, then release that lock after
2280Sstevel@tonic-gate 		 * removing the session from session linked list.
2290Sstevel@tonic-gate 		 * We want the releasing of the objects of the
2300Sstevel@tonic-gate 		 * session, and freeing of the session itself to
2310Sstevel@tonic-gate 		 * be done without holding the slot's session list
2320Sstevel@tonic-gate 		 * lock.
2330Sstevel@tonic-gate 		 */
2340Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&pslot->sl_mutex);
2350Sstevel@tonic-gate 	}
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 	/* Acquire the individual session lock */
2380Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 	/*
2410Sstevel@tonic-gate 	 * Make sure another thread hasn't freed the session.
2420Sstevel@tonic-gate 	 */
2430Sstevel@tonic-gate 	if (session_p->magic_marker != KERNELTOKEN_SESSION_MAGIC) {
2440Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&session_p->session_mutex);
245214Smcpowers 		return;
2460Sstevel@tonic-gate 	}
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	/*
2490Sstevel@tonic-gate 	 * The deletion of a session must be blocked when the session reference
2500Sstevel@tonic-gate 	 * count is not zero. This means that if the thread that is attempting
2510Sstevel@tonic-gate 	 * to close the session must wait until the prior operations on this
2520Sstevel@tonic-gate 	 * session are finished.
2536824Srupertk 	 *
2546824Srupertk 	 * Unless we are being forced to shut everything down, this only
2556824Srupertk 	 * happens if the library's _fini() is running not if someone
2566824Srupertk 	 * explicitly called C_Finalize().
2570Sstevel@tonic-gate 	 */
2580Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->ses_free_mutex);
2590Sstevel@tonic-gate 
2606824Srupertk 	if (wrapper_only) {
2616824Srupertk 		session_p->ses_refcnt = 0;
2626824Srupertk 	}
2636824Srupertk 
2640Sstevel@tonic-gate 	while (session_p->ses_refcnt != 0) {
2650Sstevel@tonic-gate 		/*
2660Sstevel@tonic-gate 		 * We set the SESSION_REFCNT_WAITING flag before we put
2670Sstevel@tonic-gate 		 * this closing thread in a wait state, so other non-closing
2680Sstevel@tonic-gate 		 * operation thread will wake it up only when
2690Sstevel@tonic-gate 		 * the session reference count becomes zero and this flag
2700Sstevel@tonic-gate 		 * is set.
2710Sstevel@tonic-gate 		 */
2720Sstevel@tonic-gate 		session_p->ses_close_sync |= SESSION_REFCNT_WAITING;
2730Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&session_p->session_mutex);
2740Sstevel@tonic-gate 		(void) pthread_cond_wait(&session_p->ses_free_cond,
2750Sstevel@tonic-gate 		    &session_p->ses_free_mutex);
2760Sstevel@tonic-gate 		(void) pthread_mutex_lock(&session_p->session_mutex);
2770Sstevel@tonic-gate 	}
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	session_p->ses_close_sync &= ~SESSION_REFCNT_WAITING;
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	/* Mark session as no longer valid. */
2820Sstevel@tonic-gate 	session_p->magic_marker = 0;
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->ses_free_mutex);
2850Sstevel@tonic-gate 	(void) pthread_mutex_destroy(&session_p->ses_free_mutex);
2860Sstevel@tonic-gate 	(void) pthread_cond_destroy(&session_p->ses_free_cond);
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	/*
289214Smcpowers 	 * Remove all the objects created in this session, waiting
290214Smcpowers 	 * until each object's refcnt is 0.
2910Sstevel@tonic-gate 	 */
2920Sstevel@tonic-gate 	kernel_delete_all_objects_in_session(session_p, wrapper_only);
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	/* In case application did not call Final */
2954072Skrishna 	if (session_p->digest.context != NULL) {
2964072Skrishna 		digest_buf_t *bufp = session_p->digest.context;
2974072Skrishna 
2984072Skrishna 		if (bufp->buf != NULL) {
2994072Skrishna 			free_soft_ctx(get_sp(&session_p->digest), OP_DIGEST);
3004072Skrishna 			bzero(bufp->buf, bufp->indata_len);
3014072Skrishna 			free(bufp->buf);
3024072Skrishna 		}
3034072Skrishna 		free(bufp);
3044072Skrishna 	}
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	if (session_p->encrypt.context != NULL)
3070Sstevel@tonic-gate 		free(session_p->encrypt.context);
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	if (session_p->decrypt.context != NULL)
3100Sstevel@tonic-gate 		free(session_p->decrypt.context);
3110Sstevel@tonic-gate 
3124072Skrishna 	if (session_p->sign.context != NULL) {
3134072Skrishna 		digest_buf_t *bufp = session_p->sign.context;
3144072Skrishna 
3154072Skrishna 		if (bufp->buf != NULL) {
3164072Skrishna 			free_soft_ctx(get_sp(&session_p->sign), OP_SIGN);
3174072Skrishna 			bzero(bufp->buf, bufp->indata_len);
3184072Skrishna 			free(bufp->buf);
3194072Skrishna 		}
3204072Skrishna 		free(bufp);
3214072Skrishna 	}
3220Sstevel@tonic-gate 
3234072Skrishna 	if (session_p->verify.context != NULL) {
3244072Skrishna 		digest_buf_t *bufp = session_p->verify.context;
3254072Skrishna 
3264072Skrishna 		if (bufp->buf != NULL) {
3274072Skrishna 			free_soft_ctx(get_sp(&session_p->verify), OP_VERIFY);
3284072Skrishna 			bzero(bufp->buf, bufp->indata_len);
3294072Skrishna 			free(bufp->buf);
3304072Skrishna 		}
3314072Skrishna 		free(bufp);
3324072Skrishna 	}
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	k_session = session_p->k_session;
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	/* Reset SESSION_IS_CLOSING flag. */
3370Sstevel@tonic-gate 	session_p->ses_close_sync &= ~SESSION_IS_CLOSING;
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
3400Sstevel@tonic-gate 	/* Destroy the individual session lock */
3410Sstevel@tonic-gate 	(void) pthread_mutex_destroy(&session_p->session_mutex);
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	if (!wrapper_only) {
3440Sstevel@tonic-gate 		close_session.cs_session = k_session;
345214Smcpowers 		while (ioctl(kernel_fd, CRYPTO_CLOSE_SESSION,
346214Smcpowers 		    &close_session) < 0) {
3470Sstevel@tonic-gate 			if (errno != EINTR)
3480Sstevel@tonic-gate 				break;
3490Sstevel@tonic-gate 		}
350214Smcpowers 		/*
351214Smcpowers 		 * Ignore ioctl return codes. If the library tells the kernel
352214Smcpowers 		 * to close a session and the kernel says "I don't know what
353214Smcpowers 		 * session you're talking about", there's not much that can be
354214Smcpowers 		 * done.  All sessions in the kernel will be closed when the
355214Smcpowers 		 * application exits and closes /dev/crypto.
356214Smcpowers 		 */
3570Sstevel@tonic-gate 	}
358214Smcpowers 	kernel_session_delay_free(session_p);
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	/*
3610Sstevel@tonic-gate 	 * If there is no more session remained in this slot, reset the slot's
3620Sstevel@tonic-gate 	 * session state to CKU_PUBLIC.  Also, clean up all the token object
3630Sstevel@tonic-gate 	 * wrappers in the library for this slot.
3640Sstevel@tonic-gate 	 */
365214Smcpowers 	/* Acquire the slot lock if lock is not held */
366214Smcpowers 	if (!slot_lock_held) {
367214Smcpowers 		(void) pthread_mutex_lock(&pslot->sl_mutex);
368214Smcpowers 	}
3690Sstevel@tonic-gate 
370214Smcpowers 	if (pslot->sl_sess_list == NULL) {
371214Smcpowers 		/* Reset the session auth state. */
3720Sstevel@tonic-gate 		pslot->sl_state = CKU_PUBLIC;
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 		/* Clean up token object wrappers. */
3750Sstevel@tonic-gate 		objp = pslot->sl_tobj_list;
3760Sstevel@tonic-gate 		while (objp) {
3770Sstevel@tonic-gate 			objp1 = objp->next;
3780Sstevel@tonic-gate 			(void) pthread_mutex_destroy(&objp->object_mutex);
379214Smcpowers 			(void) kernel_object_delay_free(objp);
3800Sstevel@tonic-gate 			objp = objp1;
3810Sstevel@tonic-gate 		}
3820Sstevel@tonic-gate 		pslot->sl_tobj_list = NULL;
3830Sstevel@tonic-gate 	}
3840Sstevel@tonic-gate 
385214Smcpowers 	/* Release the slot lock if lock is not held */
386214Smcpowers 	if (!slot_lock_held) {
387214Smcpowers 		(void) pthread_mutex_unlock(&pslot->sl_mutex);
388214Smcpowers 	}
3890Sstevel@tonic-gate }
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate /*
3920Sstevel@tonic-gate  * This function is used to type cast a session handle to a pointer to
3930Sstevel@tonic-gate  * the session struct. Also, it does the following things:
3940Sstevel@tonic-gate  * 1) Check to see if the session struct is tagged with a session
3950Sstevel@tonic-gate  *    magic number. This is to detect when an application passes
3960Sstevel@tonic-gate  *    a bogus session pointer.
3976050Skrishna  * 2) Acquire the locks on the designated session.
3980Sstevel@tonic-gate  * 3) Check to see if the session is in the closing state that another
3990Sstevel@tonic-gate  *    thread is performing.
4000Sstevel@tonic-gate  * 4) Increment the session reference count by one. This is to prevent
4010Sstevel@tonic-gate  *    this session from being closed by other thread.
4026050Skrishna  * 5) Release the locks on the designated session.
4030Sstevel@tonic-gate  */
4040Sstevel@tonic-gate CK_RV
handle2session(CK_SESSION_HANDLE hSession,kernel_session_t ** session_p)4050Sstevel@tonic-gate handle2session(CK_SESSION_HANDLE hSession, kernel_session_t **session_p)
4060Sstevel@tonic-gate {
4070Sstevel@tonic-gate 	kernel_session_t *sp = (kernel_session_t *)(hSession);
4080Sstevel@tonic-gate 	CK_RV rv;
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 	if ((sp == NULL) ||
4110Sstevel@tonic-gate 	    (sp->magic_marker != KERNELTOKEN_SESSION_MAGIC)) {
4120Sstevel@tonic-gate 		return (CKR_SESSION_HANDLE_INVALID);
4130Sstevel@tonic-gate 	} else {
4140Sstevel@tonic-gate 		(void) pthread_mutex_lock(&sp->session_mutex);
4150Sstevel@tonic-gate 		if (sp->ses_close_sync & SESSION_IS_CLOSING) {
4160Sstevel@tonic-gate 			rv = CKR_SESSION_CLOSED;
4170Sstevel@tonic-gate 		} else {
4180Sstevel@tonic-gate 			/* Increment session ref count. */
4190Sstevel@tonic-gate 			sp->ses_refcnt++;
4200Sstevel@tonic-gate 			rv = CKR_OK;
4210Sstevel@tonic-gate 		}
4220Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&sp->session_mutex);
4230Sstevel@tonic-gate 	}
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	if (rv == CKR_OK)
4260Sstevel@tonic-gate 		*session_p = sp;
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 	return (rv);
4290Sstevel@tonic-gate }
430214Smcpowers 
431214Smcpowers /*
432214Smcpowers  * This function adds the to-be-freed session to a linked list.
433214Smcpowers  * When the number of sessions queued in the linked list reaches the
434214Smcpowers  * maximum threshold MAX_SES_TO_BE_FREED, it will free the first
435214Smcpowers  * session (FIFO) in the list.
436214Smcpowers  */
437214Smcpowers void
kernel_session_delay_free(kernel_session_t * sp)438214Smcpowers kernel_session_delay_free(kernel_session_t *sp)
439214Smcpowers {
440214Smcpowers 	kernel_session_t *tmp;
441214Smcpowers 
442214Smcpowers 	(void) pthread_mutex_lock(&ses_delay_freed.ses_to_be_free_mutex);
443214Smcpowers 
444214Smcpowers 	/* Add the newly deleted session at the end of the list */
445214Smcpowers 	sp->next = NULL;
446214Smcpowers 	if (ses_delay_freed.first == NULL) {
447214Smcpowers 		ses_delay_freed.last = sp;
448214Smcpowers 		ses_delay_freed.first = sp;
449214Smcpowers 	} else {
450214Smcpowers 		ses_delay_freed.last->next = sp;
451214Smcpowers 		ses_delay_freed.last = sp;
452214Smcpowers 	}
453214Smcpowers 
454214Smcpowers 	if (++ses_delay_freed.count >= MAX_SES_TO_BE_FREED) {
455214Smcpowers 		/*
456214Smcpowers 		 * Free the first session in the list only if
457214Smcpowers 		 * the total count reaches maximum threshold.
458214Smcpowers 		 */
459214Smcpowers 		ses_delay_freed.count--;
460214Smcpowers 		tmp = ses_delay_freed.first->next;
461214Smcpowers 		free(ses_delay_freed.first);
462214Smcpowers 		ses_delay_freed.first = tmp;
463214Smcpowers 	}
464214Smcpowers 	(void) pthread_mutex_unlock(&ses_delay_freed.ses_to_be_free_mutex);
465214Smcpowers }
4666824Srupertk 
4676824Srupertk /*
4686824Srupertk  * Acquire all slots' mutexes and all their sessions' mutexes.
4696824Srupertk  * Order:
4706824Srupertk  * 1. delete_sessions_mutex
4716824Srupertk  * for each slot:
4726824Srupertk  *  2. pslot->sl_mutex
4736824Srupertk  *  for each session:
4746824Srupertk  *   3. session_p->session_mutex
4756824Srupertk  *   4. session_p->ses_free_mutex
4766824Srupertk  */
4776824Srupertk void
kernel_acquire_all_slots_mutexes()4786824Srupertk kernel_acquire_all_slots_mutexes()
4796824Srupertk {
4806824Srupertk 	int slotID;
4816824Srupertk 	kernel_slot_t *pslot;
4826824Srupertk 	kernel_session_t *session_p;
4836824Srupertk 
4846824Srupertk 	(void) pthread_mutex_lock(&delete_sessions_mutex);
485*9661SZdenek.Kotala@Sun.COM 
4866824Srupertk 	for (slotID = 0; slotID < slot_count; slotID++) {
4876824Srupertk 		pslot = slot_table[slotID];
4886824Srupertk 		(void) pthread_mutex_lock(&pslot->sl_mutex);
4896824Srupertk 
4906824Srupertk 		/* Iterate through sessions acquiring all mutexes */
4916824Srupertk 		session_p = pslot->sl_sess_list;
4926824Srupertk 		while (session_p) {
493*9661SZdenek.Kotala@Sun.COM 			struct object *objp;
494*9661SZdenek.Kotala@Sun.COM 
4956824Srupertk 			(void) pthread_mutex_lock(&session_p->session_mutex);
496*9661SZdenek.Kotala@Sun.COM 			(void) pthread_mutex_lock(&session_p->ses_free_mutex);
497*9661SZdenek.Kotala@Sun.COM 
498*9661SZdenek.Kotala@Sun.COM 			objp = session_p->object_list;
499*9661SZdenek.Kotala@Sun.COM 			while (objp) {
500*9661SZdenek.Kotala@Sun.COM 				(void) pthread_mutex_lock(&objp->object_mutex);
501*9661SZdenek.Kotala@Sun.COM 				objp = objp->next;
502*9661SZdenek.Kotala@Sun.COM 			}
503*9661SZdenek.Kotala@Sun.COM 
5046824Srupertk 			session_p = session_p->next;
5056824Srupertk 		}
5066824Srupertk 	}
5076824Srupertk }
5086824Srupertk 
5096824Srupertk /* Release in opposite order to kernel_acquire_all_slots_mutexes(). */
5106824Srupertk void
kernel_release_all_slots_mutexes()5116824Srupertk kernel_release_all_slots_mutexes()
5126824Srupertk {
5136824Srupertk 	int slotID;
5146824Srupertk 	kernel_slot_t *pslot;
5156824Srupertk 	kernel_session_t *session_p;
5166824Srupertk 
5176824Srupertk 	for (slotID = 0; slotID < slot_count; slotID++) {
5186824Srupertk 		pslot = slot_table[slotID];
5196824Srupertk 
5206824Srupertk 		/* Iterate through sessions releasing all mutexes */
5216824Srupertk 		session_p = pslot->sl_sess_list;
5226824Srupertk 		while (session_p) {
523*9661SZdenek.Kotala@Sun.COM 			struct object *objp;
524*9661SZdenek.Kotala@Sun.COM 
525*9661SZdenek.Kotala@Sun.COM 			objp = session_p->object_list;
526*9661SZdenek.Kotala@Sun.COM 			while (objp) {
527*9661SZdenek.Kotala@Sun.COM 				(void) pthread_mutex_unlock(
528*9661SZdenek.Kotala@Sun.COM 				    &objp->object_mutex);
529*9661SZdenek.Kotala@Sun.COM 				objp = objp->next;
530*9661SZdenek.Kotala@Sun.COM 			}
531*9661SZdenek.Kotala@Sun.COM 
532*9661SZdenek.Kotala@Sun.COM 			(void) pthread_mutex_unlock(&session_p->ses_free_mutex);
5336824Srupertk 			(void) pthread_mutex_unlock(&session_p->session_mutex);
5346824Srupertk 			session_p = session_p->next;
5356824Srupertk 		}
5366824Srupertk 
5376824Srupertk 		(void) pthread_mutex_unlock(&pslot->sl_mutex);
5386824Srupertk 	}
5396824Srupertk 
5406824Srupertk 	(void) pthread_mutex_unlock(&delete_sessions_mutex);
5416824Srupertk }
542