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