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 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 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 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 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 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 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 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 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