xref: /titanic_52/usr/src/lib/pkcs11/libpkcs11/common/metaSessionManager.c (revision 8e4728571e959f3afb368407b22125278412c9d4)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <stdlib.h>
29 #include <string.h>
30 #include "metaGlobal.h"
31 
32 /*
33  * The list and the list lock are global for two external uses:
34  * 1) C_CloseAllSessions need to close the head (repeatedly,
35  *    until no more sessions exist).
36  * 2) meta_object_find_by_handle needs to walk all sessions,
37  *    searching each session object list for matching objects.
38  */
39 pthread_rwlock_t meta_sessionlist_lock;
40 meta_session_t *meta_sessionlist_head;
41 
42 /*
43  * The following 2 variables are used for tracking the number of
44  * sessions and number of rw sessios that are currently open
45  *
46  * They are being manipulated in the metaSession.c file, and being
47  * referenced in the metaSlotToken.c file
48  */
49 CK_ULONG num_meta_sessions;
50 CK_ULONG num_rw_meta_sessions;
51 
52 
53 
54 static pthread_rwlock_t meta_sessionclose_lock;
55 
56 
57 /*
58  * meta_sessionManager_initialize
59  *
60  * Called from meta_Initialize.  Initializes all the variables used
61  * by the session manager.
62  */
63 CK_RV
64 meta_sessionManager_initialize()
65 {
66 
67 	if (pthread_rwlock_init(&meta_sessionlist_lock, NULL) != 0) {
68 		return (CKR_FUNCTION_FAILED);
69 	}
70 
71 	if (pthread_rwlock_init(&meta_sessionclose_lock, NULL) != 0) {
72 		(void) pthread_rwlock_destroy(&meta_sessionlist_lock);
73 		return (CKR_FUNCTION_FAILED);
74 	}
75 
76 	meta_sessionlist_head = NULL;
77 	num_meta_sessions = 0;
78 	num_rw_meta_sessions = 0;
79 
80 	return (CKR_OK);
81 }
82 
83 /*
84  * meta_sessionManager_finalize
85  *
86  * Close all sessions, and destroy all the locks
87  */
88 void
89 meta_sessionManager_finalize()
90 {
91 	/*
92 	 * Close any remaining metasessions, can just simply call
93 	 * meta_CloseAllSessions.  The METASLOT_SLOTID argument is
94 	 * not used, but need to be passed in.
95 	 */
96 	(void) meta_CloseAllSessions(METASLOT_SLOTID);
97 
98 	(void) pthread_rwlock_destroy(&meta_sessionclose_lock);
99 
100 	(void) pthread_rwlock_destroy(&meta_sessionlist_lock);
101 }
102 
103 /*
104  * meta_handle2session
105  *
106  * Convert a CK_SESSION_HANDLE to the corresponding metasession. If
107  * successful, a reader-lock on the session will be held to indicate
108  * that it's in use. Call REFRELEASE() when finished.
109  *
110  */
111 CK_RV
112 meta_handle2session(CK_SESSION_HANDLE hSession, meta_session_t **session)
113 {
114 	meta_session_t *tmp_session = (meta_session_t *)(hSession);
115 
116 	/* Check for bad args (eg CK_INVALID_HANDLE, which is 0/NULL). */
117 	if (tmp_session == NULL) {
118 		*session = NULL;
119 		return (CKR_SESSION_HANDLE_INVALID);
120 	}
121 
122 
123 	/* Lock to ensure the magic-check + read-lock is atomic. */
124 	(void) pthread_rwlock_rdlock(&meta_sessionclose_lock);
125 
126 	if (tmp_session->magic_marker != METASLOT_SESSION_MAGIC) {
127 		(void) pthread_rwlock_unlock(&meta_sessionclose_lock);
128 		*session = NULL;
129 		return (CKR_SESSION_HANDLE_INVALID);
130 	}
131 	(void) pthread_rwlock_unlock(&meta_sessionclose_lock);
132 
133 	/*
134 	 * sessions can only be used by a single thread at a time.
135 	 * So, we need to get a write-lock.
136 	 */
137 	(void) pthread_rwlock_wrlock(&tmp_session->session_lock);
138 
139 	/* Make sure this session is not in the process of being deleted */
140 	(void) pthread_mutex_lock(&tmp_session->isClosingSession_lock);
141 	if (tmp_session->isClosingSession) {
142 		(void) pthread_mutex_unlock(
143 		    &tmp_session->isClosingSession_lock);
144 		(void) pthread_rwlock_unlock(&tmp_session->session_lock);
145 		return (CKR_SESSION_HANDLE_INVALID);
146 	}
147 	(void) pthread_mutex_unlock(&tmp_session->isClosingSession_lock);
148 
149 	*session = tmp_session;
150 	return (CKR_OK);
151 }
152 
153 
154 /*
155  * meta_session_alloc
156  */
157 CK_RV
158 meta_session_alloc(meta_session_t **session)
159 {
160 	meta_session_t *new_session;
161 
162 	/* Allocate memory for the session. */
163 	new_session = calloc(1, sizeof (meta_session_t));
164 	if (new_session == NULL)
165 		return (CKR_HOST_MEMORY);
166 
167 	(new_session->mech_support_info).supporting_slots
168 	    = malloc(meta_slotManager_get_slotcount() * sizeof (mechinfo_t *));
169 	if ((new_session->mech_support_info).supporting_slots == NULL) {
170 		free(new_session);
171 		return (CKR_HOST_MEMORY);
172 	}
173 	(new_session->mech_support_info).num_supporting_slots = 0;
174 
175 	new_session->magic_marker = METASLOT_SESSION_MAGIC;
176 	(void) pthread_rwlock_init(&new_session->session_lock, NULL);
177 	(void) pthread_mutex_init(&new_session->isClosingSession_lock, NULL);
178 	(void) pthread_rwlock_init(&new_session->object_list_lock, NULL);
179 
180 	*session = new_session;
181 	return (CKR_OK);
182 }
183 
184 
185 /*
186  * meta_session_activate
187  *
188  * Create and add a session to the list of active meta sessions.
189  */
190 CK_RV
191 meta_session_activate(meta_session_t *session)
192 {
193 	CK_RV rv = CKR_OK;
194 
195 	/* Add session to the list of sessions. */
196 	(void) pthread_rwlock_wrlock(&meta_sessionlist_lock);
197 	INSERT_INTO_LIST(meta_sessionlist_head, session);
198 	(void) pthread_rwlock_unlock(&meta_sessionlist_lock);
199 
200 	return (rv);
201 }
202 
203 /*
204  * meta_session_deactivate
205  *
206  *
207  */
208 CK_RV
209 meta_session_deactivate(meta_session_t *session,
210     boolean_t have_sessionlist_lock)
211 {
212 	boolean_t isLastSession = B_FALSE;
213 	meta_object_t *object;
214 
215 	/* Safely resolve attempts of concurrent-close */
216 	(void) pthread_mutex_lock(&session->isClosingSession_lock);
217 	if (session->isClosingSession) {
218 		/* Lost a delete race. */
219 		(void) pthread_mutex_unlock(&session->isClosingSession_lock);
220 		REFRELEASE(session);
221 		return (CKR_SESSION_HANDLE_INVALID);
222 	}
223 	session->isClosingSession = B_TRUE;
224 	(void) pthread_mutex_unlock(&session->isClosingSession_lock);
225 
226 	/*
227 	 * Remove session from the session list. Once removed, it will not
228 	 * be possible for another thread to begin using the session.
229 	 */
230 	(void) pthread_rwlock_wrlock(&meta_sessionclose_lock);
231 	if (!have_sessionlist_lock) {
232 		(void) pthread_rwlock_wrlock(&meta_sessionlist_lock);
233 	}
234 
235 	session->magic_marker = METASLOT_SESSION_BADMAGIC;
236 	REMOVE_FROM_LIST(meta_sessionlist_head, session);
237 	if (meta_sessionlist_head == NULL) {
238 		isLastSession = B_TRUE;
239 	}
240 	if (!have_sessionlist_lock) {
241 		(void) pthread_rwlock_unlock(&meta_sessionlist_lock);
242 	}
243 	(void) pthread_rwlock_unlock(&meta_sessionclose_lock);
244 
245 	(void) pthread_rwlock_unlock(&session->session_lock);
246 
247 	/* Cleanup any in-progress operations. */
248 	if (session->op1.type != 0) {
249 		meta_operation_cleanup(session, session->op1.type, FALSE);
250 	}
251 
252 	if (session->op1.session != NULL) {
253 		meta_release_slot_session(session->op1.session);
254 		session->op1.session = NULL;
255 	}
256 
257 	/* Remove all the session metaobjects created in this session. */
258 	/* Basically, emulate C_DestroyObject, including safety h2s */
259 	while ((object = session->object_list_head) != NULL) {
260 		CK_RV rv;
261 
262 		rv = meta_handle2object((CK_OBJECT_HANDLE)object, &object);
263 		if (rv != CKR_OK) {
264 			/* Can only happen if someone else just closed it. */
265 			continue;
266 		}
267 
268 		rv = meta_object_deactivate(object, B_FALSE, B_TRUE);
269 		if (rv != CKR_OK) {
270 			continue;
271 		}
272 
273 		rv = meta_object_dealloc(object, B_FALSE);
274 		if (rv != CKR_OK) {
275 			continue;
276 		}
277 
278 	}
279 
280 	if ((isLastSession) && (metaslot_logged_in())) {
281 		slot_session_t *slotsessp;
282 		CK_RV rv;
283 
284 		rv = meta_get_slot_session(get_keystore_slotnum(), &slotsessp,
285 		    session->session_flags);
286 		if (rv != CKR_OK)
287 			return (rv);
288 		rv = FUNCLIST(slotsessp->fw_st_id)->C_Logout(
289 		    slotsessp->hSession);
290 
291 		meta_release_slot_session(slotsessp);
292 
293 		/* if C_Logout fails, just ignore the error */
294 		metaslot_set_logged_in_flag(B_FALSE);
295 
296 		if (rv != CKR_OK)
297 			return (rv);
298 
299 		/* need to deactivate all the PRIVATE token objects */
300 		rv = meta_token_object_deactivate(PRIVATE_TOKEN);
301 		if (rv != CKR_OK) {
302 			return (rv);
303 		}
304 	}
305 
306 	return (CKR_OK);
307 }
308 
309 
310 /*
311  * meta_session_dealloc
312  *
313  * Release the resources held by a metasession. If the session has been
314  * activated, it must be deactivated first.
315  */
316 void
317 meta_session_dealloc(meta_session_t *session)
318 {
319 	if ((session->find_objs_info).matched_objs) {
320 		free((session->find_objs_info).matched_objs);
321 	}
322 
323 	free((session->mech_support_info).supporting_slots);
324 
325 	/*
326 	 * If there were active operations, cleanup the slot session so that
327 	 * it can be reused (otherwise provider might complain that an
328 	 * operation is active).
329 	 */
330 	if (session->op1.type != 0)
331 		meta_operation_cleanup(session, session->op1.type, FALSE);
332 
333 	/* Final object cleanup. */
334 	(void) pthread_rwlock_destroy(&session->session_lock);
335 	(void) pthread_mutex_destroy(&session->isClosingSession_lock);
336 	(void) pthread_rwlock_destroy(&session->object_list_lock);
337 
338 	meta_session_delay_free(session);
339 }
340 
341 /*
342  * This function adds the to-be-freed meta session to a linked list.
343  * When the number of sessions queued in the linked list reaches the
344  * maximum threshold MAX_SESSION_TO_BE_FREED, it will free the first
345  * session (FIFO) in the list.
346  */
347 void
348 meta_session_delay_free(meta_session_t *sp)
349 {
350 	meta_session_t *tmp;
351 
352 	(void) pthread_mutex_lock(&ses_delay_freed.ses_to_be_free_mutex);
353 
354 	/* Add the newly deleted session at the end of the list */
355 	sp->next = NULL;
356 	if (ses_delay_freed.first == NULL) {
357 		ses_delay_freed.last = sp;
358 		ses_delay_freed.first = sp;
359 	} else {
360 		ses_delay_freed.last->next = sp;
361 		ses_delay_freed.last = sp;
362 	}
363 
364 	if (++ses_delay_freed.count >= MAX_SESSION_TO_BE_FREED) {
365 		/*
366 		 * Free the first session in the list only if
367 		 * the total count reaches maximum threshold.
368 		 */
369 		ses_delay_freed.count--;
370 		tmp = ses_delay_freed.first->next;
371 		free(ses_delay_freed.first);
372 		ses_delay_freed.first = tmp;
373 	}
374 	(void) pthread_mutex_unlock(&ses_delay_freed.ses_to_be_free_mutex);
375 }
376