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