xref: /titanic_52/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelSessionUtil.c (revision 1f49a79a97c031bfe0722e2e812dd0e192355be5)
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
5ba5f469cSkrishna  * Common Development and Distribution License (the "License").
6ba5f469cSkrishna  * 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*1f49a79aSZdenek Kotala  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <pthread.h>
277c478bd9Sstevel@tonic-gate #include <syslog.h>
287c478bd9Sstevel@tonic-gate #include <stdlib.h>
297c478bd9Sstevel@tonic-gate #include <string.h>
307c478bd9Sstevel@tonic-gate #include <errno.h>
317c478bd9Sstevel@tonic-gate #include <sys/crypto/ioctl.h>
327c478bd9Sstevel@tonic-gate #include <security/cryptoki.h>
337c478bd9Sstevel@tonic-gate #include "kernelGlobal.h"
347c478bd9Sstevel@tonic-gate #include "kernelSession.h"
357c478bd9Sstevel@tonic-gate #include "kernelSlot.h"
36ba5f469cSkrishna #include "kernelEmulate.h"
377c478bd9Sstevel@tonic-gate 
3801223cbaSmcpowers static pthread_mutex_t delete_sessions_mutex = PTHREAD_MUTEX_INITIALIZER;
3901223cbaSmcpowers 
407c478bd9Sstevel@tonic-gate /*
417c478bd9Sstevel@tonic-gate  * Delete all the sessions. First, obtain the slot lock.
427c478bd9Sstevel@tonic-gate  * Then start to delete one session at a time.  The boolean wrapper_only
437c478bd9Sstevel@tonic-gate  * argument indicates that whether the caller only wants to clean up the
447c478bd9Sstevel@tonic-gate  * session wrappers and the object wrappers in the library.
457c478bd9Sstevel@tonic-gate  * - When this function is called by C_CloseAllSessions or indirectly by
467c478bd9Sstevel@tonic-gate  *   C_Finalize, wrapper_only is FALSE.
477c478bd9Sstevel@tonic-gate  * - When this function is called by cleanup_child, wrapper_only is TRUE.
487c478bd9Sstevel@tonic-gate  */
4901223cbaSmcpowers void
507c478bd9Sstevel@tonic-gate kernel_delete_all_sessions(CK_SLOT_ID slotID, boolean_t wrapper_only)
517c478bd9Sstevel@tonic-gate {
527c478bd9Sstevel@tonic-gate 	kernel_session_t *session_p;
537c478bd9Sstevel@tonic-gate 	kernel_slot_t *pslot;
547c478bd9Sstevel@tonic-gate 
5501223cbaSmcpowers 	(void) pthread_mutex_lock(&delete_sessions_mutex);
5601223cbaSmcpowers 
577c478bd9Sstevel@tonic-gate 	pslot = slot_table[slotID];
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate 	/*
607c478bd9Sstevel@tonic-gate 	 * Delete all the sessions in the slot's session list.
617c478bd9Sstevel@tonic-gate 	 * The routine kernel_delete_session() updates the linked list.
627c478bd9Sstevel@tonic-gate 	 * So, we do not need to maintain the list here.
637c478bd9Sstevel@tonic-gate 	 */
6401223cbaSmcpowers 	for (;;) {
6501223cbaSmcpowers 		(void) pthread_mutex_lock(&pslot->sl_mutex);
6601223cbaSmcpowers 		if (pslot->sl_sess_list == NULL)
6701223cbaSmcpowers 			break;
6801223cbaSmcpowers 
697c478bd9Sstevel@tonic-gate 		session_p = pslot->sl_sess_list;
707c478bd9Sstevel@tonic-gate 		/*
7101223cbaSmcpowers 		 * Set SESSION_IS_CLOSING flag so any access to this
7201223cbaSmcpowers 		 * session will be rejected.
737c478bd9Sstevel@tonic-gate 		 */
7401223cbaSmcpowers 		(void) pthread_mutex_lock(&session_p->session_mutex);
7501223cbaSmcpowers 		if (session_p->ses_close_sync & SESSION_IS_CLOSING) {
7601223cbaSmcpowers 			(void) pthread_mutex_unlock(&session_p->session_mutex);
7701223cbaSmcpowers 			continue;
787c478bd9Sstevel@tonic-gate 		}
7901223cbaSmcpowers 		session_p->ses_close_sync |= SESSION_IS_CLOSING;
8001223cbaSmcpowers 		(void) pthread_mutex_unlock(&session_p->session_mutex);
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&pslot->sl_mutex);
8301223cbaSmcpowers 		kernel_delete_session(slotID, session_p, B_FALSE, wrapper_only);
847c478bd9Sstevel@tonic-gate 	}
8501223cbaSmcpowers 	(void) pthread_mutex_unlock(&pslot->sl_mutex);
8601223cbaSmcpowers 	(void) pthread_mutex_unlock(&delete_sessions_mutex);
8701223cbaSmcpowers }
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate /*
907c478bd9Sstevel@tonic-gate  * Create a new session struct, and add it to the slot's session list.
917c478bd9Sstevel@tonic-gate  *
927c478bd9Sstevel@tonic-gate  * This function is called by C_OpenSession(), which hold the slot lock.
937c478bd9Sstevel@tonic-gate  */
947c478bd9Sstevel@tonic-gate CK_RV
957c478bd9Sstevel@tonic-gate kernel_add_session(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication,
967c478bd9Sstevel@tonic-gate 	CK_NOTIFY notify, CK_ULONG *sessionhandle_p)
977c478bd9Sstevel@tonic-gate {
987c478bd9Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
997c478bd9Sstevel@tonic-gate 	kernel_session_t *new_sp = NULL;
1007c478bd9Sstevel@tonic-gate 	crypto_open_session_t open_session;
1017c478bd9Sstevel@tonic-gate 	kernel_slot_t	*pslot;
1027c478bd9Sstevel@tonic-gate 	int r;
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	/* Allocate a new session struct */
1057c478bd9Sstevel@tonic-gate 	new_sp = calloc(1, sizeof (kernel_session_t));
1067c478bd9Sstevel@tonic-gate 	if (new_sp == NULL) {
1077c478bd9Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
1087c478bd9Sstevel@tonic-gate 	}
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	new_sp->magic_marker = KERNELTOKEN_SESSION_MAGIC;
1117c478bd9Sstevel@tonic-gate 	new_sp->pApplication = pApplication;
1127c478bd9Sstevel@tonic-gate 	new_sp->Notify = notify;
1137c478bd9Sstevel@tonic-gate 	new_sp->flags = flags;
1147c478bd9Sstevel@tonic-gate 	new_sp->ses_RO = (flags & CKF_RW_SESSION) ? B_FALSE : B_TRUE;
1157c478bd9Sstevel@tonic-gate 	new_sp->ses_slotid = slotID;
1167c478bd9Sstevel@tonic-gate 	new_sp->object_list = NULL;
1177c478bd9Sstevel@tonic-gate 	new_sp->ses_refcnt = 0;
1187c478bd9Sstevel@tonic-gate 	new_sp->ses_close_sync = 0;
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	/* Initialize the lock for the newly created session */
1217c478bd9Sstevel@tonic-gate 	if (pthread_mutex_init(&new_sp->session_mutex, NULL) != 0) {
1227c478bd9Sstevel@tonic-gate 		free(new_sp);
1237c478bd9Sstevel@tonic-gate 		return (CKR_CANT_LOCK);
1247c478bd9Sstevel@tonic-gate 	}
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	pslot = slot_table[slotID];
1277c478bd9Sstevel@tonic-gate 	open_session.os_provider_id = pslot->sl_provider_id;
1287c478bd9Sstevel@tonic-gate 	open_session.os_flags = flags;
1297c478bd9Sstevel@tonic-gate 	while ((r = ioctl(kernel_fd, CRYPTO_OPEN_SESSION, &open_session)) < 0) {
1307c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
1317c478bd9Sstevel@tonic-gate 			break;
1327c478bd9Sstevel@tonic-gate 	}
1337c478bd9Sstevel@tonic-gate 	if (r < 0) {
1347c478bd9Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
1357c478bd9Sstevel@tonic-gate 	} else {
1367c478bd9Sstevel@tonic-gate 		rv = crypto2pkcs11_error_number(open_session.os_return_value);
1377c478bd9Sstevel@tonic-gate 	}
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
1407c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_destroy(&new_sp->session_mutex);
1417c478bd9Sstevel@tonic-gate 		free(new_sp);
1427c478bd9Sstevel@tonic-gate 		return (rv);
1437c478bd9Sstevel@tonic-gate 	}
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	new_sp->k_session = open_session.os_session;
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_init(&new_sp->ses_free_mutex, NULL);
1487c478bd9Sstevel@tonic-gate 	(void) pthread_cond_init(&new_sp->ses_free_cond, NULL);
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	/* Insert the new session in front of the slot's session list */
1517c478bd9Sstevel@tonic-gate 	if (pslot->sl_sess_list == NULL) {
1527c478bd9Sstevel@tonic-gate 		pslot->sl_sess_list = new_sp;
1537c478bd9Sstevel@tonic-gate 		new_sp->prev = NULL;
1547c478bd9Sstevel@tonic-gate 		new_sp->next = NULL;
1557c478bd9Sstevel@tonic-gate 	} else {
1567c478bd9Sstevel@tonic-gate 		pslot->sl_sess_list->prev = new_sp;
1577c478bd9Sstevel@tonic-gate 		new_sp->next = pslot->sl_sess_list;
1587c478bd9Sstevel@tonic-gate 		new_sp->prev = NULL;
1597c478bd9Sstevel@tonic-gate 		pslot->sl_sess_list = new_sp;
1607c478bd9Sstevel@tonic-gate 	}
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	/* Type casting the address of a session struct to a session handle */
1637c478bd9Sstevel@tonic-gate 	*sessionhandle_p =  (CK_ULONG)new_sp;
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	return (CKR_OK);
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate /*
1697c478bd9Sstevel@tonic-gate  * Delete a session:
1707c478bd9Sstevel@tonic-gate  * - Remove the session from the slot's session list.
1717c478bd9Sstevel@tonic-gate  * - Release all the objects created by the session.
1727c478bd9Sstevel@tonic-gate  *
1737c478bd9Sstevel@tonic-gate  * The boolean argument slot_lock_held is used to indicate that whether
1747c478bd9Sstevel@tonic-gate  * the caller of this function holds the slot lock or not.
1757c478bd9Sstevel@tonic-gate  * - When called by kernel_delete_all_sessions(), which is called by
1767c478bd9Sstevel@tonic-gate  *   C_Finalize() or C_CloseAllSessions() -- slot_lock_held = TRUE.
1777c478bd9Sstevel@tonic-gate  * - When called by C_CloseSession() -- slot_lock_held = FALSE.
1787c478bd9Sstevel@tonic-gate  */
17901223cbaSmcpowers void
1807c478bd9Sstevel@tonic-gate kernel_delete_session(CK_SLOT_ID slotID, kernel_session_t *session_p,
1817c478bd9Sstevel@tonic-gate     boolean_t slot_lock_held, boolean_t wrapper_only)
1827c478bd9Sstevel@tonic-gate {
1837c478bd9Sstevel@tonic-gate 	crypto_session_id_t k_session;
1847c478bd9Sstevel@tonic-gate 	crypto_close_session_t close_session;
1857c478bd9Sstevel@tonic-gate 	kernel_slot_t	*pslot;
1867c478bd9Sstevel@tonic-gate 	kernel_object_t *objp;
1877c478bd9Sstevel@tonic-gate 	kernel_object_t *objp1;
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	/*
1907c478bd9Sstevel@tonic-gate 	 * Check to see if the caller holds the lock on the global
1917c478bd9Sstevel@tonic-gate 	 * session list. If not, we need to acquire that lock in
1927c478bd9Sstevel@tonic-gate 	 * order to proceed.
1937c478bd9Sstevel@tonic-gate 	 */
1947c478bd9Sstevel@tonic-gate 	pslot = slot_table[slotID];
1957c478bd9Sstevel@tonic-gate 	if (!slot_lock_held) {
1967c478bd9Sstevel@tonic-gate 		/* Acquire the slot lock */
1977c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&pslot->sl_mutex);
1987c478bd9Sstevel@tonic-gate 	}
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	/*
2017c478bd9Sstevel@tonic-gate 	 * Remove the session from the slot's session list first.
2027c478bd9Sstevel@tonic-gate 	 */
2037c478bd9Sstevel@tonic-gate 	if (pslot->sl_sess_list == session_p) {
2047c478bd9Sstevel@tonic-gate 		/* Session is the first one in the list */
2057c478bd9Sstevel@tonic-gate 		if (session_p->next) {
2067c478bd9Sstevel@tonic-gate 			pslot->sl_sess_list = session_p->next;
2077c478bd9Sstevel@tonic-gate 			session_p->next->prev = NULL;
2087c478bd9Sstevel@tonic-gate 		} else {
2097c478bd9Sstevel@tonic-gate 			/* Session is the only one in the list */
2107c478bd9Sstevel@tonic-gate 			pslot->sl_sess_list = NULL;
2117c478bd9Sstevel@tonic-gate 		}
2127c478bd9Sstevel@tonic-gate 	} else {
2137c478bd9Sstevel@tonic-gate 		/* Session is not the first one in the list */
2147c478bd9Sstevel@tonic-gate 		if (session_p->next) {
2157c478bd9Sstevel@tonic-gate 			/* Session is in the middle of the list */
2167c478bd9Sstevel@tonic-gate 			session_p->prev->next = session_p->next;
2177c478bd9Sstevel@tonic-gate 			session_p->next->prev = session_p->prev;
2187c478bd9Sstevel@tonic-gate 		} else {
2197c478bd9Sstevel@tonic-gate 			/* Session is the last one in the list */
2207c478bd9Sstevel@tonic-gate 			session_p->prev->next = NULL;
2217c478bd9Sstevel@tonic-gate 		}
2227c478bd9Sstevel@tonic-gate 	}
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	if (!slot_lock_held) {
2257c478bd9Sstevel@tonic-gate 		/*
2267c478bd9Sstevel@tonic-gate 		 * If the slot lock is obtained by
2277c478bd9Sstevel@tonic-gate 		 * this function, then release that lock after
2287c478bd9Sstevel@tonic-gate 		 * removing the session from session linked list.
2297c478bd9Sstevel@tonic-gate 		 * We want the releasing of the objects of the
2307c478bd9Sstevel@tonic-gate 		 * session, and freeing of the session itself to
2317c478bd9Sstevel@tonic-gate 		 * be done without holding the slot's session list
2327c478bd9Sstevel@tonic-gate 		 * lock.
2337c478bd9Sstevel@tonic-gate 		 */
2347c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&pslot->sl_mutex);
2357c478bd9Sstevel@tonic-gate 	}
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	/* Acquire the individual session lock */
2387c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	/*
2417c478bd9Sstevel@tonic-gate 	 * Make sure another thread hasn't freed the session.
2427c478bd9Sstevel@tonic-gate 	 */
2437c478bd9Sstevel@tonic-gate 	if (session_p->magic_marker != KERNELTOKEN_SESSION_MAGIC) {
2447c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&session_p->session_mutex);
24501223cbaSmcpowers 		return;
2467c478bd9Sstevel@tonic-gate 	}
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	/*
2497c478bd9Sstevel@tonic-gate 	 * The deletion of a session must be blocked when the session reference
2507c478bd9Sstevel@tonic-gate 	 * count is not zero. This means that if the thread that is attempting
2517c478bd9Sstevel@tonic-gate 	 * to close the session must wait until the prior operations on this
2527c478bd9Sstevel@tonic-gate 	 * session are finished.
2534daf2311Srupertk 	 *
2544daf2311Srupertk 	 * Unless we are being forced to shut everything down, this only
2554daf2311Srupertk 	 * happens if the library's _fini() is running not if someone
2564daf2311Srupertk 	 * explicitly called C_Finalize().
2577c478bd9Sstevel@tonic-gate 	 */
2587c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->ses_free_mutex);
2597c478bd9Sstevel@tonic-gate 
2604daf2311Srupertk 	if (wrapper_only) {
2614daf2311Srupertk 		session_p->ses_refcnt = 0;
2624daf2311Srupertk 	}
2634daf2311Srupertk 
2647c478bd9Sstevel@tonic-gate 	while (session_p->ses_refcnt != 0) {
2657c478bd9Sstevel@tonic-gate 		/*
2667c478bd9Sstevel@tonic-gate 		 * We set the SESSION_REFCNT_WAITING flag before we put
2677c478bd9Sstevel@tonic-gate 		 * this closing thread in a wait state, so other non-closing
2687c478bd9Sstevel@tonic-gate 		 * operation thread will wake it up only when
2697c478bd9Sstevel@tonic-gate 		 * the session reference count becomes zero and this flag
2707c478bd9Sstevel@tonic-gate 		 * is set.
2717c478bd9Sstevel@tonic-gate 		 */
2727c478bd9Sstevel@tonic-gate 		session_p->ses_close_sync |= SESSION_REFCNT_WAITING;
2737c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&session_p->session_mutex);
2747c478bd9Sstevel@tonic-gate 		(void) pthread_cond_wait(&session_p->ses_free_cond,
2757c478bd9Sstevel@tonic-gate 		    &session_p->ses_free_mutex);
2767c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&session_p->session_mutex);
2777c478bd9Sstevel@tonic-gate 	}
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	session_p->ses_close_sync &= ~SESSION_REFCNT_WAITING;
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	/* Mark session as no longer valid. */
2827c478bd9Sstevel@tonic-gate 	session_p->magic_marker = 0;
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->ses_free_mutex);
2857c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_destroy(&session_p->ses_free_mutex);
2867c478bd9Sstevel@tonic-gate 	(void) pthread_cond_destroy(&session_p->ses_free_cond);
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	/*
28901223cbaSmcpowers 	 * Remove all the objects created in this session, waiting
29001223cbaSmcpowers 	 * until each object's refcnt is 0.
2917c478bd9Sstevel@tonic-gate 	 */
2927c478bd9Sstevel@tonic-gate 	kernel_delete_all_objects_in_session(session_p, wrapper_only);
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	/* In case application did not call Final */
295ba5f469cSkrishna 	if (session_p->digest.context != NULL) {
296ba5f469cSkrishna 		digest_buf_t *bufp = session_p->digest.context;
297ba5f469cSkrishna 
298ba5f469cSkrishna 		if (bufp->buf != NULL) {
299ba5f469cSkrishna 			free_soft_ctx(get_sp(&session_p->digest), OP_DIGEST);
300ba5f469cSkrishna 			bzero(bufp->buf, bufp->indata_len);
301ba5f469cSkrishna 			free(bufp->buf);
302ba5f469cSkrishna 		}
303ba5f469cSkrishna 		free(bufp);
304ba5f469cSkrishna 	}
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	if (session_p->encrypt.context != NULL)
3077c478bd9Sstevel@tonic-gate 		free(session_p->encrypt.context);
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	if (session_p->decrypt.context != NULL)
3107c478bd9Sstevel@tonic-gate 		free(session_p->decrypt.context);
3117c478bd9Sstevel@tonic-gate 
312ba5f469cSkrishna 	if (session_p->sign.context != NULL) {
313ba5f469cSkrishna 		digest_buf_t *bufp = session_p->sign.context;
3147c478bd9Sstevel@tonic-gate 
315ba5f469cSkrishna 		if (bufp->buf != NULL) {
316ba5f469cSkrishna 			free_soft_ctx(get_sp(&session_p->sign), OP_SIGN);
317ba5f469cSkrishna 			bzero(bufp->buf, bufp->indata_len);
318ba5f469cSkrishna 			free(bufp->buf);
319ba5f469cSkrishna 		}
320ba5f469cSkrishna 		free(bufp);
321ba5f469cSkrishna 	}
322ba5f469cSkrishna 
323ba5f469cSkrishna 	if (session_p->verify.context != NULL) {
324ba5f469cSkrishna 		digest_buf_t *bufp = session_p->verify.context;
325ba5f469cSkrishna 
326ba5f469cSkrishna 		if (bufp->buf != NULL) {
327ba5f469cSkrishna 			free_soft_ctx(get_sp(&session_p->verify), OP_VERIFY);
328ba5f469cSkrishna 			bzero(bufp->buf, bufp->indata_len);
329ba5f469cSkrishna 			free(bufp->buf);
330ba5f469cSkrishna 		}
331ba5f469cSkrishna 		free(bufp);
332ba5f469cSkrishna 	}
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	k_session = session_p->k_session;
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	/* Reset SESSION_IS_CLOSING flag. */
3377c478bd9Sstevel@tonic-gate 	session_p->ses_close_sync &= ~SESSION_IS_CLOSING;
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
3407c478bd9Sstevel@tonic-gate 	/* Destroy the individual session lock */
3417c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_destroy(&session_p->session_mutex);
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	if (!wrapper_only) {
3447c478bd9Sstevel@tonic-gate 		close_session.cs_session = k_session;
34501223cbaSmcpowers 		while (ioctl(kernel_fd, CRYPTO_CLOSE_SESSION,
34601223cbaSmcpowers 		    &close_session) < 0) {
3477c478bd9Sstevel@tonic-gate 			if (errno != EINTR)
3487c478bd9Sstevel@tonic-gate 				break;
3497c478bd9Sstevel@tonic-gate 		}
3507c478bd9Sstevel@tonic-gate 		/*
35101223cbaSmcpowers 		 * Ignore ioctl return codes. If the library tells the kernel
35201223cbaSmcpowers 		 * to close a session and the kernel says "I don't know what
35301223cbaSmcpowers 		 * session you're talking about", there's not much that can be
35401223cbaSmcpowers 		 * done.  All sessions in the kernel will be closed when the
35501223cbaSmcpowers 		 * application exits and closes /dev/crypto.
3567c478bd9Sstevel@tonic-gate 		 */
35701223cbaSmcpowers 	}
35801223cbaSmcpowers 	kernel_session_delay_free(session_p);
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	/*
3617c478bd9Sstevel@tonic-gate 	 * If there is no more session remained in this slot, reset the slot's
3627c478bd9Sstevel@tonic-gate 	 * session state to CKU_PUBLIC.  Also, clean up all the token object
3637c478bd9Sstevel@tonic-gate 	 * wrappers in the library for this slot.
3647c478bd9Sstevel@tonic-gate 	 */
3657c478bd9Sstevel@tonic-gate 	/* Acquire the slot lock if lock is not held */
3667c478bd9Sstevel@tonic-gate 	if (!slot_lock_held) {
3677c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&pslot->sl_mutex);
3687c478bd9Sstevel@tonic-gate 	}
3697c478bd9Sstevel@tonic-gate 
37001223cbaSmcpowers 	if (pslot->sl_sess_list == NULL) {
37101223cbaSmcpowers 		/* Reset the session auth state. */
3727c478bd9Sstevel@tonic-gate 		pslot->sl_state = CKU_PUBLIC;
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 		/* Clean up token object wrappers. */
3757c478bd9Sstevel@tonic-gate 		objp = pslot->sl_tobj_list;
3767c478bd9Sstevel@tonic-gate 		while (objp) {
3777c478bd9Sstevel@tonic-gate 			objp1 = objp->next;
3787c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_destroy(&objp->object_mutex);
37901223cbaSmcpowers 			(void) kernel_object_delay_free(objp);
3807c478bd9Sstevel@tonic-gate 			objp = objp1;
3817c478bd9Sstevel@tonic-gate 		}
3827c478bd9Sstevel@tonic-gate 		pslot->sl_tobj_list = NULL;
38301223cbaSmcpowers 	}
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	/* Release the slot lock if lock is not held */
3867c478bd9Sstevel@tonic-gate 	if (!slot_lock_held) {
3877c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&pslot->sl_mutex);
3887c478bd9Sstevel@tonic-gate 	}
3897c478bd9Sstevel@tonic-gate }
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate /*
3927c478bd9Sstevel@tonic-gate  * This function is used to type cast a session handle to a pointer to
3937c478bd9Sstevel@tonic-gate  * the session struct. Also, it does the following things:
3947c478bd9Sstevel@tonic-gate  * 1) Check to see if the session struct is tagged with a session
3957c478bd9Sstevel@tonic-gate  *    magic number. This is to detect when an application passes
3967c478bd9Sstevel@tonic-gate  *    a bogus session pointer.
397f243d98aSkrishna  * 2) Acquire the locks on the designated session.
3987c478bd9Sstevel@tonic-gate  * 3) Check to see if the session is in the closing state that another
3997c478bd9Sstevel@tonic-gate  *    thread is performing.
4007c478bd9Sstevel@tonic-gate  * 4) Increment the session reference count by one. This is to prevent
4017c478bd9Sstevel@tonic-gate  *    this session from being closed by other thread.
402f243d98aSkrishna  * 5) Release the locks on the designated session.
4037c478bd9Sstevel@tonic-gate  */
4047c478bd9Sstevel@tonic-gate CK_RV
4057c478bd9Sstevel@tonic-gate handle2session(CK_SESSION_HANDLE hSession, kernel_session_t **session_p)
4067c478bd9Sstevel@tonic-gate {
4077c478bd9Sstevel@tonic-gate 	kernel_session_t *sp = (kernel_session_t *)(hSession);
4087c478bd9Sstevel@tonic-gate 	CK_RV rv;
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	if ((sp == NULL) ||
4117c478bd9Sstevel@tonic-gate 	    (sp->magic_marker != KERNELTOKEN_SESSION_MAGIC)) {
4127c478bd9Sstevel@tonic-gate 		return (CKR_SESSION_HANDLE_INVALID);
4137c478bd9Sstevel@tonic-gate 	} else {
4147c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&sp->session_mutex);
4157c478bd9Sstevel@tonic-gate 		if (sp->ses_close_sync & SESSION_IS_CLOSING) {
4167c478bd9Sstevel@tonic-gate 			rv = CKR_SESSION_CLOSED;
4177c478bd9Sstevel@tonic-gate 		} else {
4187c478bd9Sstevel@tonic-gate 			/* Increment session ref count. */
4197c478bd9Sstevel@tonic-gate 			sp->ses_refcnt++;
4207c478bd9Sstevel@tonic-gate 			rv = CKR_OK;
4217c478bd9Sstevel@tonic-gate 		}
4227c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&sp->session_mutex);
4237c478bd9Sstevel@tonic-gate 	}
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	if (rv == CKR_OK)
4267c478bd9Sstevel@tonic-gate 		*session_p = sp;
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	return (rv);
4297c478bd9Sstevel@tonic-gate }
43001223cbaSmcpowers 
43101223cbaSmcpowers /*
43201223cbaSmcpowers  * This function adds the to-be-freed session to a linked list.
43301223cbaSmcpowers  * When the number of sessions queued in the linked list reaches the
43401223cbaSmcpowers  * maximum threshold MAX_SES_TO_BE_FREED, it will free the first
43501223cbaSmcpowers  * session (FIFO) in the list.
43601223cbaSmcpowers  */
43701223cbaSmcpowers void
43801223cbaSmcpowers kernel_session_delay_free(kernel_session_t *sp)
43901223cbaSmcpowers {
44001223cbaSmcpowers 	kernel_session_t *tmp;
44101223cbaSmcpowers 
44201223cbaSmcpowers 	(void) pthread_mutex_lock(&ses_delay_freed.ses_to_be_free_mutex);
44301223cbaSmcpowers 
44401223cbaSmcpowers 	/* Add the newly deleted session at the end of the list */
44501223cbaSmcpowers 	sp->next = NULL;
44601223cbaSmcpowers 	if (ses_delay_freed.first == NULL) {
44701223cbaSmcpowers 		ses_delay_freed.last = sp;
44801223cbaSmcpowers 		ses_delay_freed.first = sp;
44901223cbaSmcpowers 	} else {
45001223cbaSmcpowers 		ses_delay_freed.last->next = sp;
45101223cbaSmcpowers 		ses_delay_freed.last = sp;
45201223cbaSmcpowers 	}
45301223cbaSmcpowers 
45401223cbaSmcpowers 	if (++ses_delay_freed.count >= MAX_SES_TO_BE_FREED) {
45501223cbaSmcpowers 		/*
45601223cbaSmcpowers 		 * Free the first session in the list only if
45701223cbaSmcpowers 		 * the total count reaches maximum threshold.
45801223cbaSmcpowers 		 */
45901223cbaSmcpowers 		ses_delay_freed.count--;
46001223cbaSmcpowers 		tmp = ses_delay_freed.first->next;
46101223cbaSmcpowers 		free(ses_delay_freed.first);
46201223cbaSmcpowers 		ses_delay_freed.first = tmp;
46301223cbaSmcpowers 	}
46401223cbaSmcpowers 	(void) pthread_mutex_unlock(&ses_delay_freed.ses_to_be_free_mutex);
46501223cbaSmcpowers }
4664daf2311Srupertk 
4674daf2311Srupertk /*
4684daf2311Srupertk  * Acquire all slots' mutexes and all their sessions' mutexes.
4694daf2311Srupertk  * Order:
4704daf2311Srupertk  * 1. delete_sessions_mutex
4714daf2311Srupertk  * for each slot:
4724daf2311Srupertk  *  2. pslot->sl_mutex
4734daf2311Srupertk  *  for each session:
4744daf2311Srupertk  *   3. session_p->session_mutex
4754daf2311Srupertk  *   4. session_p->ses_free_mutex
4764daf2311Srupertk  */
4774daf2311Srupertk void
4784daf2311Srupertk kernel_acquire_all_slots_mutexes()
4794daf2311Srupertk {
4804daf2311Srupertk 	int slotID;
4814daf2311Srupertk 	kernel_slot_t *pslot;
4824daf2311Srupertk 	kernel_session_t *session_p;
4834daf2311Srupertk 
4844daf2311Srupertk 	(void) pthread_mutex_lock(&delete_sessions_mutex);
485*1f49a79aSZdenek Kotala 
4864daf2311Srupertk 	for (slotID = 0; slotID < slot_count; slotID++) {
4874daf2311Srupertk 		pslot = slot_table[slotID];
4884daf2311Srupertk 		(void) pthread_mutex_lock(&pslot->sl_mutex);
4894daf2311Srupertk 
4904daf2311Srupertk 		/* Iterate through sessions acquiring all mutexes */
4914daf2311Srupertk 		session_p = pslot->sl_sess_list;
4924daf2311Srupertk 		while (session_p) {
493*1f49a79aSZdenek Kotala 			struct object *objp;
494*1f49a79aSZdenek Kotala 
4954daf2311Srupertk 			(void) pthread_mutex_lock(&session_p->session_mutex);
496*1f49a79aSZdenek Kotala 			(void) pthread_mutex_lock(&session_p->ses_free_mutex);
497*1f49a79aSZdenek Kotala 
498*1f49a79aSZdenek Kotala 			objp = session_p->object_list;
499*1f49a79aSZdenek Kotala 			while (objp) {
500*1f49a79aSZdenek Kotala 				(void) pthread_mutex_lock(&objp->object_mutex);
501*1f49a79aSZdenek Kotala 				objp = objp->next;
502*1f49a79aSZdenek Kotala 			}
503*1f49a79aSZdenek Kotala 
5044daf2311Srupertk 			session_p = session_p->next;
5054daf2311Srupertk 		}
5064daf2311Srupertk 	}
5074daf2311Srupertk }
5084daf2311Srupertk 
5094daf2311Srupertk /* Release in opposite order to kernel_acquire_all_slots_mutexes(). */
5104daf2311Srupertk void
5114daf2311Srupertk kernel_release_all_slots_mutexes()
5124daf2311Srupertk {
5134daf2311Srupertk 	int slotID;
5144daf2311Srupertk 	kernel_slot_t *pslot;
5154daf2311Srupertk 	kernel_session_t *session_p;
5164daf2311Srupertk 
5174daf2311Srupertk 	for (slotID = 0; slotID < slot_count; slotID++) {
5184daf2311Srupertk 		pslot = slot_table[slotID];
5194daf2311Srupertk 
5204daf2311Srupertk 		/* Iterate through sessions releasing all mutexes */
5214daf2311Srupertk 		session_p = pslot->sl_sess_list;
5224daf2311Srupertk 		while (session_p) {
523*1f49a79aSZdenek Kotala 			struct object *objp;
524*1f49a79aSZdenek Kotala 
525*1f49a79aSZdenek Kotala 			objp = session_p->object_list;
526*1f49a79aSZdenek Kotala 			while (objp) {
527*1f49a79aSZdenek Kotala 				(void) pthread_mutex_unlock(
528*1f49a79aSZdenek Kotala 				    &objp->object_mutex);
529*1f49a79aSZdenek Kotala 				objp = objp->next;
530*1f49a79aSZdenek Kotala 			}
531*1f49a79aSZdenek Kotala 
532*1f49a79aSZdenek Kotala 			(void) pthread_mutex_unlock(&session_p->ses_free_mutex);
5334daf2311Srupertk 			(void) pthread_mutex_unlock(&session_p->session_mutex);
5344daf2311Srupertk 			session_p = session_p->next;
5354daf2311Srupertk 		}
5364daf2311Srupertk 
5374daf2311Srupertk 		(void) pthread_mutex_unlock(&pslot->sl_mutex);
5384daf2311Srupertk 	}
5394daf2311Srupertk 
5404daf2311Srupertk 	(void) pthread_mutex_unlock(&delete_sessions_mutex);
5414daf2311Srupertk }
542