xref: /onnv-gate/usr/src/lib/pkcs11/pkcs11_kms/common/kmsSessionUtil.c (revision 12720:3db6e0082404)
1*12720SWyllys.Ingersoll@Sun.COM /*
2*12720SWyllys.Ingersoll@Sun.COM  * CDDL HEADER START
3*12720SWyllys.Ingersoll@Sun.COM  *
4*12720SWyllys.Ingersoll@Sun.COM  * The contents of this file are subject to the terms of the
5*12720SWyllys.Ingersoll@Sun.COM  * Common Development and Distribution License (the "License").
6*12720SWyllys.Ingersoll@Sun.COM  * You may not use this file except in compliance with the License.
7*12720SWyllys.Ingersoll@Sun.COM  *
8*12720SWyllys.Ingersoll@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*12720SWyllys.Ingersoll@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*12720SWyllys.Ingersoll@Sun.COM  * See the License for the specific language governing permissions
11*12720SWyllys.Ingersoll@Sun.COM  * and limitations under the License.
12*12720SWyllys.Ingersoll@Sun.COM  *
13*12720SWyllys.Ingersoll@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*12720SWyllys.Ingersoll@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*12720SWyllys.Ingersoll@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*12720SWyllys.Ingersoll@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*12720SWyllys.Ingersoll@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*12720SWyllys.Ingersoll@Sun.COM  *
19*12720SWyllys.Ingersoll@Sun.COM  * CDDL HEADER END
20*12720SWyllys.Ingersoll@Sun.COM  *
21*12720SWyllys.Ingersoll@Sun.COM  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
22*12720SWyllys.Ingersoll@Sun.COM  */
23*12720SWyllys.Ingersoll@Sun.COM 
24*12720SWyllys.Ingersoll@Sun.COM #include <pthread.h>
25*12720SWyllys.Ingersoll@Sun.COM #include <syslog.h>
26*12720SWyllys.Ingersoll@Sun.COM #include <stdlib.h>
27*12720SWyllys.Ingersoll@Sun.COM #include <string.h>
28*12720SWyllys.Ingersoll@Sun.COM #include <errno.h>
29*12720SWyllys.Ingersoll@Sun.COM #include <security/cryptoki.h>
30*12720SWyllys.Ingersoll@Sun.COM #include "kmsGlobal.h"
31*12720SWyllys.Ingersoll@Sun.COM #include "kmsSession.h"
32*12720SWyllys.Ingersoll@Sun.COM #include "kmsSlot.h"
33*12720SWyllys.Ingersoll@Sun.COM #include "kmsKeystoreUtil.h"
34*12720SWyllys.Ingersoll@Sun.COM 
35*12720SWyllys.Ingersoll@Sun.COM static pthread_mutex_t delete_sessions_mutex = PTHREAD_MUTEX_INITIALIZER;
36*12720SWyllys.Ingersoll@Sun.COM CK_ULONG kms_session_cnt = 0;
37*12720SWyllys.Ingersoll@Sun.COM CK_ULONG kms_session_rw_cnt = 0;
38*12720SWyllys.Ingersoll@Sun.COM 
39*12720SWyllys.Ingersoll@Sun.COM /*
40*12720SWyllys.Ingersoll@Sun.COM  * Delete all the sessions. First, obtain the slot lock.
41*12720SWyllys.Ingersoll@Sun.COM  * Then start to delete one session at a time.  The boolean wrapper_only
42*12720SWyllys.Ingersoll@Sun.COM  * argument indicates that whether the caller only wants to clean up the
43*12720SWyllys.Ingersoll@Sun.COM  * session wrappers and the object wrappers in the library.
44*12720SWyllys.Ingersoll@Sun.COM  * - When this function is called by C_CloseAllSessions or indirectly by
45*12720SWyllys.Ingersoll@Sun.COM  *   C_Finalize, wrapper_only is FALSE.
46*12720SWyllys.Ingersoll@Sun.COM  * - When this function is called by cleanup_child, wrapper_only is TRUE.
47*12720SWyllys.Ingersoll@Sun.COM  */
48*12720SWyllys.Ingersoll@Sun.COM void
kms_delete_all_sessions(boolean_t wrapper_only)49*12720SWyllys.Ingersoll@Sun.COM kms_delete_all_sessions(boolean_t wrapper_only)
50*12720SWyllys.Ingersoll@Sun.COM {
51*12720SWyllys.Ingersoll@Sun.COM 	kms_session_t *session_p;
52*12720SWyllys.Ingersoll@Sun.COM 	kms_slot_t *pslot;
53*12720SWyllys.Ingersoll@Sun.COM 
54*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_lock(&delete_sessions_mutex);
55*12720SWyllys.Ingersoll@Sun.COM 
56*12720SWyllys.Ingersoll@Sun.COM 	pslot = get_slotinfo();
57*12720SWyllys.Ingersoll@Sun.COM 
58*12720SWyllys.Ingersoll@Sun.COM 	/*
59*12720SWyllys.Ingersoll@Sun.COM 	 * Delete all the sessions in the slot's session list.
60*12720SWyllys.Ingersoll@Sun.COM 	 * The routine kms_delete_session() updates the linked list.
61*12720SWyllys.Ingersoll@Sun.COM 	 * So, we do not need to maintain the list here.
62*12720SWyllys.Ingersoll@Sun.COM 	 */
63*12720SWyllys.Ingersoll@Sun.COM 	for (;;) {
64*12720SWyllys.Ingersoll@Sun.COM 		(void) pthread_mutex_lock(&pslot->sl_mutex);
65*12720SWyllys.Ingersoll@Sun.COM 		if (pslot->sl_sess_list == NULL)
66*12720SWyllys.Ingersoll@Sun.COM 			break;
67*12720SWyllys.Ingersoll@Sun.COM 
68*12720SWyllys.Ingersoll@Sun.COM 		session_p = pslot->sl_sess_list;
69*12720SWyllys.Ingersoll@Sun.COM 		/*
70*12720SWyllys.Ingersoll@Sun.COM 		 * Set SESSION_IS_CLOSING flag so any access to this
71*12720SWyllys.Ingersoll@Sun.COM 		 * session will be rejected.
72*12720SWyllys.Ingersoll@Sun.COM 		 */
73*12720SWyllys.Ingersoll@Sun.COM 		(void) pthread_mutex_lock(&session_p->session_mutex);
74*12720SWyllys.Ingersoll@Sun.COM 		if (session_p->ses_close_sync & SESSION_IS_CLOSING) {
75*12720SWyllys.Ingersoll@Sun.COM 			(void) pthread_mutex_unlock(&session_p->session_mutex);
76*12720SWyllys.Ingersoll@Sun.COM 			continue;
77*12720SWyllys.Ingersoll@Sun.COM 		}
78*12720SWyllys.Ingersoll@Sun.COM 		session_p->ses_close_sync |= SESSION_IS_CLOSING;
79*12720SWyllys.Ingersoll@Sun.COM 		(void) pthread_mutex_unlock(&session_p->session_mutex);
80*12720SWyllys.Ingersoll@Sun.COM 
81*12720SWyllys.Ingersoll@Sun.COM 		(void) pthread_mutex_unlock(&pslot->sl_mutex);
82*12720SWyllys.Ingersoll@Sun.COM 		kms_delete_session(session_p, B_FALSE, wrapper_only);
83*12720SWyllys.Ingersoll@Sun.COM 	}
84*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_unlock(&pslot->sl_mutex);
85*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_unlock(&delete_sessions_mutex);
86*12720SWyllys.Ingersoll@Sun.COM }
87*12720SWyllys.Ingersoll@Sun.COM 
88*12720SWyllys.Ingersoll@Sun.COM static int
labelcmp(const void * a,const void * b)89*12720SWyllys.Ingersoll@Sun.COM labelcmp(const void *a, const void *b)
90*12720SWyllys.Ingersoll@Sun.COM {
91*12720SWyllys.Ingersoll@Sun.COM 	objlabel_t *obja = (objlabel_t *)a;
92*12720SWyllys.Ingersoll@Sun.COM 	objlabel_t *objb = (objlabel_t *)b;
93*12720SWyllys.Ingersoll@Sun.COM 	int n;
94*12720SWyllys.Ingersoll@Sun.COM 
95*12720SWyllys.Ingersoll@Sun.COM 	if (obja == NULL || obja->label == NULL)
96*12720SWyllys.Ingersoll@Sun.COM 		return (-1);
97*12720SWyllys.Ingersoll@Sun.COM 	if (objb == NULL || objb->label == NULL)
98*12720SWyllys.Ingersoll@Sun.COM 		return (1);
99*12720SWyllys.Ingersoll@Sun.COM 
100*12720SWyllys.Ingersoll@Sun.COM 	n = strcmp((char *)obja->label, (char *)objb->label);
101*12720SWyllys.Ingersoll@Sun.COM 	if (n == 0)
102*12720SWyllys.Ingersoll@Sun.COM 		return (0);
103*12720SWyllys.Ingersoll@Sun.COM 	else if (n < 0)
104*12720SWyllys.Ingersoll@Sun.COM 		return (-1);
105*12720SWyllys.Ingersoll@Sun.COM 	return (1);
106*12720SWyllys.Ingersoll@Sun.COM }
107*12720SWyllys.Ingersoll@Sun.COM 
108*12720SWyllys.Ingersoll@Sun.COM /*
109*12720SWyllys.Ingersoll@Sun.COM  * Create a new session struct, and add it to the slot's session list.
110*12720SWyllys.Ingersoll@Sun.COM  *
111*12720SWyllys.Ingersoll@Sun.COM  * This function is called by C_OpenSession(), which hold the slot lock.
112*12720SWyllys.Ingersoll@Sun.COM  */
113*12720SWyllys.Ingersoll@Sun.COM CK_RV
kms_add_session(CK_SLOT_ID slotID,CK_FLAGS flags,CK_VOID_PTR pApplication,CK_NOTIFY notify,CK_ULONG * sessionhandle_p)114*12720SWyllys.Ingersoll@Sun.COM kms_add_session(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication,
115*12720SWyllys.Ingersoll@Sun.COM 	CK_NOTIFY notify, CK_ULONG *sessionhandle_p)
116*12720SWyllys.Ingersoll@Sun.COM {
117*12720SWyllys.Ingersoll@Sun.COM 	kms_session_t *new_sp = NULL;
118*12720SWyllys.Ingersoll@Sun.COM 	kms_slot_t	*pslot;
119*12720SWyllys.Ingersoll@Sun.COM 	CK_RV rv;
120*12720SWyllys.Ingersoll@Sun.COM 
121*12720SWyllys.Ingersoll@Sun.COM 	/* Allocate a new session struct */
122*12720SWyllys.Ingersoll@Sun.COM 	new_sp = calloc(1, sizeof (kms_session_t));
123*12720SWyllys.Ingersoll@Sun.COM 	if (new_sp == NULL) {
124*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_HOST_MEMORY);
125*12720SWyllys.Ingersoll@Sun.COM 	}
126*12720SWyllys.Ingersoll@Sun.COM 
127*12720SWyllys.Ingersoll@Sun.COM 	new_sp->magic_marker = KMSTOKEN_SESSION_MAGIC;
128*12720SWyllys.Ingersoll@Sun.COM 	new_sp->pApplication = pApplication;
129*12720SWyllys.Ingersoll@Sun.COM 	new_sp->Notify = notify;
130*12720SWyllys.Ingersoll@Sun.COM 	new_sp->flags = flags;
131*12720SWyllys.Ingersoll@Sun.COM 	new_sp->ses_RO = (flags & CKF_RW_SESSION) ? B_FALSE : B_TRUE;
132*12720SWyllys.Ingersoll@Sun.COM 	new_sp->ses_slotid = slotID;
133*12720SWyllys.Ingersoll@Sun.COM 	new_sp->object_list = NULL;
134*12720SWyllys.Ingersoll@Sun.COM 	new_sp->ses_refcnt = 0;
135*12720SWyllys.Ingersoll@Sun.COM 	new_sp->ses_close_sync = 0;
136*12720SWyllys.Ingersoll@Sun.COM 
137*12720SWyllys.Ingersoll@Sun.COM 	avl_create(&new_sp->objlabel_tree, labelcmp, sizeof (objlabel_t),
138*12720SWyllys.Ingersoll@Sun.COM 	    KMSOFFSETOF(objlabel_t, nodep));
139*12720SWyllys.Ingersoll@Sun.COM 
140*12720SWyllys.Ingersoll@Sun.COM 	rv = kms_reload_labels(new_sp);
141*12720SWyllys.Ingersoll@Sun.COM 	if (rv != CKR_OK) {
142*12720SWyllys.Ingersoll@Sun.COM 		free(new_sp);
143*12720SWyllys.Ingersoll@Sun.COM 		return (rv);
144*12720SWyllys.Ingersoll@Sun.COM 	}
145*12720SWyllys.Ingersoll@Sun.COM 
146*12720SWyllys.Ingersoll@Sun.COM 	/* Initialize the lock for the newly created session */
147*12720SWyllys.Ingersoll@Sun.COM 	if (pthread_mutex_init(&new_sp->session_mutex, NULL) != 0) {
148*12720SWyllys.Ingersoll@Sun.COM 		free(new_sp);
149*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_CANT_LOCK);
150*12720SWyllys.Ingersoll@Sun.COM 	}
151*12720SWyllys.Ingersoll@Sun.COM 
152*12720SWyllys.Ingersoll@Sun.COM 	pslot = get_slotinfo();
153*12720SWyllys.Ingersoll@Sun.COM 
154*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_init(&new_sp->ses_free_mutex, NULL);
155*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_cond_init(&new_sp->ses_free_cond, NULL);
156*12720SWyllys.Ingersoll@Sun.COM 
157*12720SWyllys.Ingersoll@Sun.COM 	/* Insert the new session in front of the slot's session list */
158*12720SWyllys.Ingersoll@Sun.COM 	if (pslot->sl_sess_list == NULL) {
159*12720SWyllys.Ingersoll@Sun.COM 		pslot->sl_sess_list = new_sp;
160*12720SWyllys.Ingersoll@Sun.COM 		new_sp->prev = NULL;
161*12720SWyllys.Ingersoll@Sun.COM 		new_sp->next = NULL;
162*12720SWyllys.Ingersoll@Sun.COM 	} else {
163*12720SWyllys.Ingersoll@Sun.COM 		pslot->sl_sess_list->prev = new_sp;
164*12720SWyllys.Ingersoll@Sun.COM 		new_sp->next = pslot->sl_sess_list;
165*12720SWyllys.Ingersoll@Sun.COM 		new_sp->prev = NULL;
166*12720SWyllys.Ingersoll@Sun.COM 		pslot->sl_sess_list = new_sp;
167*12720SWyllys.Ingersoll@Sun.COM 	}
168*12720SWyllys.Ingersoll@Sun.COM 
169*12720SWyllys.Ingersoll@Sun.COM 	/* Type casting the address of a session struct to a session handle */
170*12720SWyllys.Ingersoll@Sun.COM 	*sessionhandle_p =  (CK_ULONG)new_sp;
171*12720SWyllys.Ingersoll@Sun.COM 	return (CKR_OK);
172*12720SWyllys.Ingersoll@Sun.COM }
173*12720SWyllys.Ingersoll@Sun.COM 
174*12720SWyllys.Ingersoll@Sun.COM /*
175*12720SWyllys.Ingersoll@Sun.COM  * Delete a session:
176*12720SWyllys.Ingersoll@Sun.COM  * - Remove the session from the slot's session list.
177*12720SWyllys.Ingersoll@Sun.COM  * - Release all the objects created by the session.
178*12720SWyllys.Ingersoll@Sun.COM  *
179*12720SWyllys.Ingersoll@Sun.COM  * The boolean argument slot_lock_held is used to indicate that whether
180*12720SWyllys.Ingersoll@Sun.COM  * the caller of this function holds the slot lock or not.
181*12720SWyllys.Ingersoll@Sun.COM  * - When called by kms_delete_all_sessions(), which is called by
182*12720SWyllys.Ingersoll@Sun.COM  *   C_Finalize() or C_CloseAllSessions() -- slot_lock_held = TRUE.
183*12720SWyllys.Ingersoll@Sun.COM  * - When called by C_CloseSession() -- slot_lock_held = FALSE.
184*12720SWyllys.Ingersoll@Sun.COM  */
185*12720SWyllys.Ingersoll@Sun.COM void
kms_delete_session(kms_session_t * session_p,boolean_t slot_lock_held,boolean_t wrapper_only)186*12720SWyllys.Ingersoll@Sun.COM kms_delete_session(kms_session_t *session_p,
187*12720SWyllys.Ingersoll@Sun.COM     boolean_t slot_lock_held, boolean_t wrapper_only)
188*12720SWyllys.Ingersoll@Sun.COM {
189*12720SWyllys.Ingersoll@Sun.COM 	kms_slot_t	*pslot;
190*12720SWyllys.Ingersoll@Sun.COM 	kms_object_t *objp;
191*12720SWyllys.Ingersoll@Sun.COM 	kms_object_t *objp1;
192*12720SWyllys.Ingersoll@Sun.COM 
193*12720SWyllys.Ingersoll@Sun.COM 	/*
194*12720SWyllys.Ingersoll@Sun.COM 	 * Check to see if the caller holds the lock on the global
195*12720SWyllys.Ingersoll@Sun.COM 	 * session list. If not, we need to acquire that lock in
196*12720SWyllys.Ingersoll@Sun.COM 	 * order to proceed.
197*12720SWyllys.Ingersoll@Sun.COM 	 */
198*12720SWyllys.Ingersoll@Sun.COM 	pslot = get_slotinfo();
199*12720SWyllys.Ingersoll@Sun.COM 	if (!slot_lock_held) {
200*12720SWyllys.Ingersoll@Sun.COM 		/* Acquire the slot lock */
201*12720SWyllys.Ingersoll@Sun.COM 		(void) pthread_mutex_lock(&pslot->sl_mutex);
202*12720SWyllys.Ingersoll@Sun.COM 	}
203*12720SWyllys.Ingersoll@Sun.COM 
204*12720SWyllys.Ingersoll@Sun.COM 	/*
205*12720SWyllys.Ingersoll@Sun.COM 	 * Remove the session from the slot's session list first.
206*12720SWyllys.Ingersoll@Sun.COM 	 */
207*12720SWyllys.Ingersoll@Sun.COM 	if (pslot->sl_sess_list == session_p) {
208*12720SWyllys.Ingersoll@Sun.COM 		/* Session is the first one in the list */
209*12720SWyllys.Ingersoll@Sun.COM 		if (session_p->next) {
210*12720SWyllys.Ingersoll@Sun.COM 			pslot->sl_sess_list = session_p->next;
211*12720SWyllys.Ingersoll@Sun.COM 			session_p->next->prev = NULL;
212*12720SWyllys.Ingersoll@Sun.COM 		} else {
213*12720SWyllys.Ingersoll@Sun.COM 			/* Session is the only one in the list */
214*12720SWyllys.Ingersoll@Sun.COM 			pslot->sl_sess_list = NULL;
215*12720SWyllys.Ingersoll@Sun.COM 		}
216*12720SWyllys.Ingersoll@Sun.COM 	} else {
217*12720SWyllys.Ingersoll@Sun.COM 		/* Session is not the first one in the list */
218*12720SWyllys.Ingersoll@Sun.COM 		if (session_p->next) {
219*12720SWyllys.Ingersoll@Sun.COM 			/* Session is in the middle of the list */
220*12720SWyllys.Ingersoll@Sun.COM 			session_p->prev->next = session_p->next;
221*12720SWyllys.Ingersoll@Sun.COM 			session_p->next->prev = session_p->prev;
222*12720SWyllys.Ingersoll@Sun.COM 		} else {
223*12720SWyllys.Ingersoll@Sun.COM 			/* Session is the last one in the list */
224*12720SWyllys.Ingersoll@Sun.COM 			session_p->prev->next = NULL;
225*12720SWyllys.Ingersoll@Sun.COM 		}
226*12720SWyllys.Ingersoll@Sun.COM 	}
227*12720SWyllys.Ingersoll@Sun.COM 
228*12720SWyllys.Ingersoll@Sun.COM 	if (!slot_lock_held) {
229*12720SWyllys.Ingersoll@Sun.COM 		/*
230*12720SWyllys.Ingersoll@Sun.COM 		 * If the slot lock is obtained by
231*12720SWyllys.Ingersoll@Sun.COM 		 * this function, then release that lock after
232*12720SWyllys.Ingersoll@Sun.COM 		 * removing the session from session linked list.
233*12720SWyllys.Ingersoll@Sun.COM 		 * We want the releasing of the objects of the
234*12720SWyllys.Ingersoll@Sun.COM 		 * session, and freeing of the session itself to
235*12720SWyllys.Ingersoll@Sun.COM 		 * be done without holding the slot's session list
236*12720SWyllys.Ingersoll@Sun.COM 		 * lock.
237*12720SWyllys.Ingersoll@Sun.COM 		 */
238*12720SWyllys.Ingersoll@Sun.COM 		(void) pthread_mutex_unlock(&pslot->sl_mutex);
239*12720SWyllys.Ingersoll@Sun.COM 	}
240*12720SWyllys.Ingersoll@Sun.COM 
241*12720SWyllys.Ingersoll@Sun.COM 	/* Acquire the individual session lock */
242*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_lock(&session_p->session_mutex);
243*12720SWyllys.Ingersoll@Sun.COM 
244*12720SWyllys.Ingersoll@Sun.COM 	/*
245*12720SWyllys.Ingersoll@Sun.COM 	 * Make sure another thread hasn't freed the session.
246*12720SWyllys.Ingersoll@Sun.COM 	 */
247*12720SWyllys.Ingersoll@Sun.COM 	if (session_p->magic_marker != KMSTOKEN_SESSION_MAGIC) {
248*12720SWyllys.Ingersoll@Sun.COM 		(void) pthread_mutex_unlock(&session_p->session_mutex);
249*12720SWyllys.Ingersoll@Sun.COM 		return;
250*12720SWyllys.Ingersoll@Sun.COM 	}
251*12720SWyllys.Ingersoll@Sun.COM 
252*12720SWyllys.Ingersoll@Sun.COM 	/*
253*12720SWyllys.Ingersoll@Sun.COM 	 * The deletion of a session must be blocked when the session reference
254*12720SWyllys.Ingersoll@Sun.COM 	 * count is not zero. This means that if the thread that is attempting
255*12720SWyllys.Ingersoll@Sun.COM 	 * to close the session must wait until the prior operations on this
256*12720SWyllys.Ingersoll@Sun.COM 	 * session are finished.
257*12720SWyllys.Ingersoll@Sun.COM 	 *
258*12720SWyllys.Ingersoll@Sun.COM 	 * Unless we are being forced to shut everything down, this only
259*12720SWyllys.Ingersoll@Sun.COM 	 * happens if the library's _fini() is running not if someone
260*12720SWyllys.Ingersoll@Sun.COM 	 * explicitly called C_Finalize().
261*12720SWyllys.Ingersoll@Sun.COM 	 */
262*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_lock(&session_p->ses_free_mutex);
263*12720SWyllys.Ingersoll@Sun.COM 
264*12720SWyllys.Ingersoll@Sun.COM 	if (wrapper_only) {
265*12720SWyllys.Ingersoll@Sun.COM 		session_p->ses_refcnt = 0;
266*12720SWyllys.Ingersoll@Sun.COM 	}
267*12720SWyllys.Ingersoll@Sun.COM 
268*12720SWyllys.Ingersoll@Sun.COM 	while (session_p->ses_refcnt != 0) {
269*12720SWyllys.Ingersoll@Sun.COM 		/*
270*12720SWyllys.Ingersoll@Sun.COM 		 * We set the SESSION_REFCNT_WAITING flag before we put
271*12720SWyllys.Ingersoll@Sun.COM 		 * this closing thread in a wait state, so other non-closing
272*12720SWyllys.Ingersoll@Sun.COM 		 * operation thread will wake it up only when
273*12720SWyllys.Ingersoll@Sun.COM 		 * the session reference count becomes zero and this flag
274*12720SWyllys.Ingersoll@Sun.COM 		 * is set.
275*12720SWyllys.Ingersoll@Sun.COM 		 */
276*12720SWyllys.Ingersoll@Sun.COM 		session_p->ses_close_sync |= SESSION_REFCNT_WAITING;
277*12720SWyllys.Ingersoll@Sun.COM 		(void) pthread_mutex_unlock(&session_p->session_mutex);
278*12720SWyllys.Ingersoll@Sun.COM 		(void) pthread_cond_wait(&session_p->ses_free_cond,
279*12720SWyllys.Ingersoll@Sun.COM 		    &session_p->ses_free_mutex);
280*12720SWyllys.Ingersoll@Sun.COM 		(void) pthread_mutex_lock(&session_p->session_mutex);
281*12720SWyllys.Ingersoll@Sun.COM 	}
282*12720SWyllys.Ingersoll@Sun.COM 
283*12720SWyllys.Ingersoll@Sun.COM 	session_p->ses_close_sync &= ~SESSION_REFCNT_WAITING;
284*12720SWyllys.Ingersoll@Sun.COM 
285*12720SWyllys.Ingersoll@Sun.COM 	/* Mark session as no longer valid. */
286*12720SWyllys.Ingersoll@Sun.COM 	session_p->magic_marker = 0;
287*12720SWyllys.Ingersoll@Sun.COM 
288*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_unlock(&session_p->ses_free_mutex);
289*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_destroy(&session_p->ses_free_mutex);
290*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_cond_destroy(&session_p->ses_free_cond);
291*12720SWyllys.Ingersoll@Sun.COM 
292*12720SWyllys.Ingersoll@Sun.COM 	/*
293*12720SWyllys.Ingersoll@Sun.COM 	 * Remove all the objects created in this session, waiting
294*12720SWyllys.Ingersoll@Sun.COM 	 * until each object's refcnt is 0.
295*12720SWyllys.Ingersoll@Sun.COM 	 */
296*12720SWyllys.Ingersoll@Sun.COM 	kms_delete_all_objects_in_session(session_p, wrapper_only);
297*12720SWyllys.Ingersoll@Sun.COM 
298*12720SWyllys.Ingersoll@Sun.COM 	/* Close the KMS agent profile. */
299*12720SWyllys.Ingersoll@Sun.COM 	KMS_UnloadProfile(&session_p->kmsProfile);
300*12720SWyllys.Ingersoll@Sun.COM 
301*12720SWyllys.Ingersoll@Sun.COM 	/* Reset SESSION_IS_CLOSING flag. */
302*12720SWyllys.Ingersoll@Sun.COM 	session_p->ses_close_sync &= ~SESSION_IS_CLOSING;
303*12720SWyllys.Ingersoll@Sun.COM 
304*12720SWyllys.Ingersoll@Sun.COM 	kms_clear_label_list(&session_p->objlabel_tree);
305*12720SWyllys.Ingersoll@Sun.COM 	avl_destroy(&session_p->objlabel_tree);
306*12720SWyllys.Ingersoll@Sun.COM 
307*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_unlock(&session_p->session_mutex);
308*12720SWyllys.Ingersoll@Sun.COM 	/* Destroy the individual session lock */
309*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_destroy(&session_p->session_mutex);
310*12720SWyllys.Ingersoll@Sun.COM 
311*12720SWyllys.Ingersoll@Sun.COM 	kms_session_delay_free(session_p);
312*12720SWyllys.Ingersoll@Sun.COM 
313*12720SWyllys.Ingersoll@Sun.COM 	/*
314*12720SWyllys.Ingersoll@Sun.COM 	 * If there is no more session remained in this slot, reset the slot's
315*12720SWyllys.Ingersoll@Sun.COM 	 * session state to CKU_PUBLIC.  Also, clean up all the token object
316*12720SWyllys.Ingersoll@Sun.COM 	 * wrappers in the library for this slot.
317*12720SWyllys.Ingersoll@Sun.COM 	 */
318*12720SWyllys.Ingersoll@Sun.COM 	/* Acquire the slot lock if lock is not held */
319*12720SWyllys.Ingersoll@Sun.COM 	if (!slot_lock_held) {
320*12720SWyllys.Ingersoll@Sun.COM 		(void) pthread_mutex_lock(&pslot->sl_mutex);
321*12720SWyllys.Ingersoll@Sun.COM 	}
322*12720SWyllys.Ingersoll@Sun.COM 
323*12720SWyllys.Ingersoll@Sun.COM 	if (pslot->sl_sess_list == NULL) {
324*12720SWyllys.Ingersoll@Sun.COM 		/* Reset the session auth state. */
325*12720SWyllys.Ingersoll@Sun.COM 		pslot->sl_state = CKU_PUBLIC;
326*12720SWyllys.Ingersoll@Sun.COM 
327*12720SWyllys.Ingersoll@Sun.COM 		/* Clean up token object wrappers. */
328*12720SWyllys.Ingersoll@Sun.COM 		objp = pslot->sl_tobj_list;
329*12720SWyllys.Ingersoll@Sun.COM 		while (objp) {
330*12720SWyllys.Ingersoll@Sun.COM 			objp1 = objp->next;
331*12720SWyllys.Ingersoll@Sun.COM 			(void) pthread_mutex_destroy(&objp->object_mutex);
332*12720SWyllys.Ingersoll@Sun.COM 			(void) kms_cleanup_object(objp);
333*12720SWyllys.Ingersoll@Sun.COM 			free(objp);
334*12720SWyllys.Ingersoll@Sun.COM 			objp = objp1;
335*12720SWyllys.Ingersoll@Sun.COM 		}
336*12720SWyllys.Ingersoll@Sun.COM 		pslot->sl_tobj_list = NULL;
337*12720SWyllys.Ingersoll@Sun.COM 	}
338*12720SWyllys.Ingersoll@Sun.COM 
339*12720SWyllys.Ingersoll@Sun.COM 	/* Release the slot lock if lock is not held */
340*12720SWyllys.Ingersoll@Sun.COM 	if (!slot_lock_held) {
341*12720SWyllys.Ingersoll@Sun.COM 		(void) pthread_mutex_unlock(&pslot->sl_mutex);
342*12720SWyllys.Ingersoll@Sun.COM 	}
343*12720SWyllys.Ingersoll@Sun.COM }
344*12720SWyllys.Ingersoll@Sun.COM 
345*12720SWyllys.Ingersoll@Sun.COM /*
346*12720SWyllys.Ingersoll@Sun.COM  * This function is used to type cast a session handle to a pointer to
347*12720SWyllys.Ingersoll@Sun.COM  * the session struct. Also, it does the following things:
348*12720SWyllys.Ingersoll@Sun.COM  * 1) Check to see if the session struct is tagged with a session
349*12720SWyllys.Ingersoll@Sun.COM  *    magic number. This is to detect when an application passes
350*12720SWyllys.Ingersoll@Sun.COM  *    a bogus session pointer.
351*12720SWyllys.Ingersoll@Sun.COM  * 2) Acquire the locks on the designated session.
352*12720SWyllys.Ingersoll@Sun.COM  * 3) Check to see if the session is in the closing state that another
353*12720SWyllys.Ingersoll@Sun.COM  *    thread is performing.
354*12720SWyllys.Ingersoll@Sun.COM  * 4) Increment the session reference count by one. This is to prevent
355*12720SWyllys.Ingersoll@Sun.COM  *    this session from being closed by other thread.
356*12720SWyllys.Ingersoll@Sun.COM  * 5) Release the locks on the designated session.
357*12720SWyllys.Ingersoll@Sun.COM  */
358*12720SWyllys.Ingersoll@Sun.COM CK_RV
handle2session(CK_SESSION_HANDLE hSession,kms_session_t ** session_p)359*12720SWyllys.Ingersoll@Sun.COM handle2session(CK_SESSION_HANDLE hSession, kms_session_t **session_p)
360*12720SWyllys.Ingersoll@Sun.COM {
361*12720SWyllys.Ingersoll@Sun.COM 	kms_session_t *sp = (kms_session_t *)(hSession);
362*12720SWyllys.Ingersoll@Sun.COM 	CK_RV rv;
363*12720SWyllys.Ingersoll@Sun.COM 
364*12720SWyllys.Ingersoll@Sun.COM 	if ((sp == NULL) ||
365*12720SWyllys.Ingersoll@Sun.COM 	    (sp->magic_marker != KMSTOKEN_SESSION_MAGIC)) {
366*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_SESSION_HANDLE_INVALID);
367*12720SWyllys.Ingersoll@Sun.COM 	} else {
368*12720SWyllys.Ingersoll@Sun.COM 		(void) pthread_mutex_lock(&sp->session_mutex);
369*12720SWyllys.Ingersoll@Sun.COM 		if (sp->ses_close_sync & SESSION_IS_CLOSING) {
370*12720SWyllys.Ingersoll@Sun.COM 			rv = CKR_SESSION_CLOSED;
371*12720SWyllys.Ingersoll@Sun.COM 		} else {
372*12720SWyllys.Ingersoll@Sun.COM 			/* Increment session ref count. */
373*12720SWyllys.Ingersoll@Sun.COM 			sp->ses_refcnt++;
374*12720SWyllys.Ingersoll@Sun.COM 			rv = CKR_OK;
375*12720SWyllys.Ingersoll@Sun.COM 		}
376*12720SWyllys.Ingersoll@Sun.COM 		(void) pthread_mutex_unlock(&sp->session_mutex);
377*12720SWyllys.Ingersoll@Sun.COM 	}
378*12720SWyllys.Ingersoll@Sun.COM 
379*12720SWyllys.Ingersoll@Sun.COM 	if (rv == CKR_OK)
380*12720SWyllys.Ingersoll@Sun.COM 		*session_p = sp;
381*12720SWyllys.Ingersoll@Sun.COM 
382*12720SWyllys.Ingersoll@Sun.COM 	return (rv);
383*12720SWyllys.Ingersoll@Sun.COM }
384*12720SWyllys.Ingersoll@Sun.COM 
385*12720SWyllys.Ingersoll@Sun.COM /*
386*12720SWyllys.Ingersoll@Sun.COM  * This function adds the to-be-freed session to a linked list.
387*12720SWyllys.Ingersoll@Sun.COM  * When the number of sessions queued in the linked list reaches the
388*12720SWyllys.Ingersoll@Sun.COM  * maximum threshold MAX_SES_TO_BE_FREED, it will free the first
389*12720SWyllys.Ingersoll@Sun.COM  * session (FIFO) in the list.
390*12720SWyllys.Ingersoll@Sun.COM  */
391*12720SWyllys.Ingersoll@Sun.COM void
kms_session_delay_free(kms_session_t * sp)392*12720SWyllys.Ingersoll@Sun.COM kms_session_delay_free(kms_session_t *sp)
393*12720SWyllys.Ingersoll@Sun.COM {
394*12720SWyllys.Ingersoll@Sun.COM 	kms_session_t *tmp;
395*12720SWyllys.Ingersoll@Sun.COM 
396*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_lock(&ses_delay_freed.ses_to_be_free_mutex);
397*12720SWyllys.Ingersoll@Sun.COM 
398*12720SWyllys.Ingersoll@Sun.COM 	/* Add the newly deleted session at the end of the list */
399*12720SWyllys.Ingersoll@Sun.COM 	sp->next = NULL;
400*12720SWyllys.Ingersoll@Sun.COM 	if (ses_delay_freed.first == NULL) {
401*12720SWyllys.Ingersoll@Sun.COM 		ses_delay_freed.last = sp;
402*12720SWyllys.Ingersoll@Sun.COM 		ses_delay_freed.first = sp;
403*12720SWyllys.Ingersoll@Sun.COM 	} else {
404*12720SWyllys.Ingersoll@Sun.COM 		ses_delay_freed.last->next = sp;
405*12720SWyllys.Ingersoll@Sun.COM 		ses_delay_freed.last = sp;
406*12720SWyllys.Ingersoll@Sun.COM 	}
407*12720SWyllys.Ingersoll@Sun.COM 
408*12720SWyllys.Ingersoll@Sun.COM 	if (++ses_delay_freed.count >= MAX_SES_TO_BE_FREED) {
409*12720SWyllys.Ingersoll@Sun.COM 		/*
410*12720SWyllys.Ingersoll@Sun.COM 		 * Free the first session in the list only if
411*12720SWyllys.Ingersoll@Sun.COM 		 * the total count reaches maximum threshold.
412*12720SWyllys.Ingersoll@Sun.COM 		 */
413*12720SWyllys.Ingersoll@Sun.COM 		ses_delay_freed.count--;
414*12720SWyllys.Ingersoll@Sun.COM 		tmp = ses_delay_freed.first->next;
415*12720SWyllys.Ingersoll@Sun.COM 		free(ses_delay_freed.first);
416*12720SWyllys.Ingersoll@Sun.COM 		ses_delay_freed.first = tmp;
417*12720SWyllys.Ingersoll@Sun.COM 	}
418*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_unlock(&ses_delay_freed.ses_to_be_free_mutex);
419*12720SWyllys.Ingersoll@Sun.COM }
420*12720SWyllys.Ingersoll@Sun.COM 
421*12720SWyllys.Ingersoll@Sun.COM /*
422*12720SWyllys.Ingersoll@Sun.COM  * Acquire all slots' mutexes and all their sessions' mutexes.
423*12720SWyllys.Ingersoll@Sun.COM  * Order:
424*12720SWyllys.Ingersoll@Sun.COM  * 1. delete_sessions_mutex
425*12720SWyllys.Ingersoll@Sun.COM  * for each slot:
426*12720SWyllys.Ingersoll@Sun.COM  *  2. pslot->sl_mutex
427*12720SWyllys.Ingersoll@Sun.COM  *  for each session:
428*12720SWyllys.Ingersoll@Sun.COM  *   3. session_p->session_mutex
429*12720SWyllys.Ingersoll@Sun.COM  *   4. session_p->ses_free_mutex
430*12720SWyllys.Ingersoll@Sun.COM  */
431*12720SWyllys.Ingersoll@Sun.COM void
kms_acquire_all_slots_mutexes()432*12720SWyllys.Ingersoll@Sun.COM kms_acquire_all_slots_mutexes()
433*12720SWyllys.Ingersoll@Sun.COM {
434*12720SWyllys.Ingersoll@Sun.COM 	kms_slot_t *pslot;
435*12720SWyllys.Ingersoll@Sun.COM 	kms_session_t *session_p;
436*12720SWyllys.Ingersoll@Sun.COM 
437*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_lock(&delete_sessions_mutex);
438*12720SWyllys.Ingersoll@Sun.COM 
439*12720SWyllys.Ingersoll@Sun.COM 	pslot = get_slotinfo();
440*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_lock(&pslot->sl_mutex);
441*12720SWyllys.Ingersoll@Sun.COM 
442*12720SWyllys.Ingersoll@Sun.COM 	/* Iterate through sessions acquiring all mutexes */
443*12720SWyllys.Ingersoll@Sun.COM 	session_p = pslot->sl_sess_list;
444*12720SWyllys.Ingersoll@Sun.COM 	while (session_p) {
445*12720SWyllys.Ingersoll@Sun.COM 		struct object *objp;
446*12720SWyllys.Ingersoll@Sun.COM 
447*12720SWyllys.Ingersoll@Sun.COM 		(void) pthread_mutex_lock(&session_p->session_mutex);
448*12720SWyllys.Ingersoll@Sun.COM 		(void) pthread_mutex_lock(&session_p->ses_free_mutex);
449*12720SWyllys.Ingersoll@Sun.COM 
450*12720SWyllys.Ingersoll@Sun.COM 		objp = session_p->object_list;
451*12720SWyllys.Ingersoll@Sun.COM 		while (objp) {
452*12720SWyllys.Ingersoll@Sun.COM 			(void) pthread_mutex_lock(&objp->object_mutex);
453*12720SWyllys.Ingersoll@Sun.COM 			objp = objp->next;
454*12720SWyllys.Ingersoll@Sun.COM 		}
455*12720SWyllys.Ingersoll@Sun.COM 
456*12720SWyllys.Ingersoll@Sun.COM 		session_p = session_p->next;
457*12720SWyllys.Ingersoll@Sun.COM 	}
458*12720SWyllys.Ingersoll@Sun.COM }
459*12720SWyllys.Ingersoll@Sun.COM 
460*12720SWyllys.Ingersoll@Sun.COM /* Release in opposite order to kms_acquire_all_slots_mutexes(). */
461*12720SWyllys.Ingersoll@Sun.COM void
kms_release_all_slots_mutexes()462*12720SWyllys.Ingersoll@Sun.COM kms_release_all_slots_mutexes()
463*12720SWyllys.Ingersoll@Sun.COM {
464*12720SWyllys.Ingersoll@Sun.COM 	kms_slot_t *pslot;
465*12720SWyllys.Ingersoll@Sun.COM 	kms_session_t *session_p;
466*12720SWyllys.Ingersoll@Sun.COM 
467*12720SWyllys.Ingersoll@Sun.COM 	pslot = get_slotinfo();
468*12720SWyllys.Ingersoll@Sun.COM 
469*12720SWyllys.Ingersoll@Sun.COM 	/* Iterate through sessions releasing all mutexes */
470*12720SWyllys.Ingersoll@Sun.COM 	session_p = pslot->sl_sess_list;
471*12720SWyllys.Ingersoll@Sun.COM 	while (session_p) {
472*12720SWyllys.Ingersoll@Sun.COM 		struct object *objp;
473*12720SWyllys.Ingersoll@Sun.COM 
474*12720SWyllys.Ingersoll@Sun.COM 		objp = session_p->object_list;
475*12720SWyllys.Ingersoll@Sun.COM 		while (objp) {
476*12720SWyllys.Ingersoll@Sun.COM 			(void) pthread_mutex_unlock(&objp->object_mutex);
477*12720SWyllys.Ingersoll@Sun.COM 			objp = objp->next;
478*12720SWyllys.Ingersoll@Sun.COM 		}
479*12720SWyllys.Ingersoll@Sun.COM 
480*12720SWyllys.Ingersoll@Sun.COM 		(void) pthread_mutex_unlock(&session_p->ses_free_mutex);
481*12720SWyllys.Ingersoll@Sun.COM 		(void) pthread_mutex_unlock(&session_p->session_mutex);
482*12720SWyllys.Ingersoll@Sun.COM 		session_p = session_p->next;
483*12720SWyllys.Ingersoll@Sun.COM 	}
484*12720SWyllys.Ingersoll@Sun.COM 
485*12720SWyllys.Ingersoll@Sun.COM 	/*
486*12720SWyllys.Ingersoll@Sun.COM 	 * acquired in "acquire_all_slots_mutexes" which only
487*12720SWyllys.Ingersoll@Sun.COM 	 * happens just prior to a fork.
488*12720SWyllys.Ingersoll@Sun.COM 	 */
489*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_unlock(&pslot->sl_mutex);
490*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_unlock(&delete_sessions_mutex);
491*12720SWyllys.Ingersoll@Sun.COM }
492