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 2008 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 write-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 tmp_session->magic_marker != METASLOT_SESSION_MAGIC) { 119 return (CKR_SESSION_HANDLE_INVALID); 120 } 121 122 /* 123 * sessions can only be used by a single thread at a time. 124 * So, we need to get a write-lock. 125 */ 126 (void) pthread_rwlock_wrlock(&tmp_session->session_lock); 127 128 /* Make sure this session is not in the process of being deleted */ 129 (void) pthread_mutex_lock(&tmp_session->isClosingSession_lock); 130 if (tmp_session->isClosingSession) { 131 (void) pthread_mutex_unlock( 132 &tmp_session->isClosingSession_lock); 133 (void) pthread_rwlock_unlock(&tmp_session->session_lock); 134 return (CKR_SESSION_HANDLE_INVALID); 135 } 136 (void) pthread_mutex_unlock(&tmp_session->isClosingSession_lock); 137 138 *session = tmp_session; 139 return (CKR_OK); 140 } 141 142 143 /* 144 * meta_session_alloc 145 */ 146 CK_RV 147 meta_session_alloc(meta_session_t **session) 148 { 149 meta_session_t *new_session; 150 151 /* Allocate memory for the session. */ 152 new_session = calloc(1, sizeof (meta_session_t)); 153 if (new_session == NULL) 154 return (CKR_HOST_MEMORY); 155 156 (new_session->mech_support_info).supporting_slots 157 = malloc(meta_slotManager_get_slotcount() * sizeof (mechinfo_t *)); 158 if ((new_session->mech_support_info).supporting_slots == NULL) { 159 free(new_session); 160 return (CKR_HOST_MEMORY); 161 } 162 (new_session->mech_support_info).num_supporting_slots = 0; 163 164 new_session->magic_marker = METASLOT_SESSION_MAGIC; 165 (void) pthread_rwlock_init(&new_session->session_lock, NULL); 166 (void) pthread_mutex_init(&new_session->isClosingSession_lock, NULL); 167 (void) pthread_rwlock_init(&new_session->object_list_lock, NULL); 168 169 *session = new_session; 170 return (CKR_OK); 171 } 172 173 174 /* 175 * meta_session_activate 176 * 177 * Create and add a session to the list of active meta sessions. 178 */ 179 CK_RV 180 meta_session_activate(meta_session_t *session) 181 { 182 CK_RV rv = CKR_OK; 183 184 /* Add session to the list of sessions. */ 185 (void) pthread_rwlock_wrlock(&meta_sessionlist_lock); 186 INSERT_INTO_LIST(meta_sessionlist_head, session); 187 (void) pthread_rwlock_unlock(&meta_sessionlist_lock); 188 189 return (rv); 190 } 191 192 /* 193 * meta_session_deactivate 194 * 195 * 196 */ 197 CK_RV 198 meta_session_deactivate(meta_session_t *session, 199 boolean_t have_sessionlist_lock) 200 { 201 boolean_t isLastSession = B_FALSE; 202 meta_object_t *object; 203 204 /* Safely resolve attempts of concurrent-close */ 205 (void) pthread_mutex_lock(&session->isClosingSession_lock); 206 if (session->isClosingSession) { 207 /* Lost a delete race. */ 208 (void) pthread_mutex_unlock(&session->isClosingSession_lock); 209 REFRELEASE(session); 210 return (CKR_SESSION_HANDLE_INVALID); 211 } 212 session->isClosingSession = B_TRUE; 213 session->magic_marker = METASLOT_SESSION_BADMAGIC; 214 (void) pthread_mutex_unlock(&session->isClosingSession_lock); 215 216 /* 217 * Remove session from the session list. Once removed, it will not 218 * be possible for another thread to begin using the session. 219 */ 220 (void) pthread_rwlock_wrlock(&meta_sessionclose_lock); 221 if (!have_sessionlist_lock) { 222 (void) pthread_rwlock_wrlock(&meta_sessionlist_lock); 223 } 224 225 REMOVE_FROM_LIST(meta_sessionlist_head, session); 226 if (meta_sessionlist_head == NULL) { 227 isLastSession = B_TRUE; 228 } 229 if (!have_sessionlist_lock) { 230 (void) pthread_rwlock_unlock(&meta_sessionlist_lock); 231 } 232 (void) pthread_rwlock_unlock(&meta_sessionclose_lock); 233 234 (void) pthread_rwlock_unlock(&session->session_lock); 235 236 /* Cleanup any in-progress operations. */ 237 if (session->op1.type != 0) { 238 meta_operation_cleanup(session, session->op1.type, FALSE); 239 } 240 241 if (session->op1.session != NULL) { 242 meta_release_slot_session(session->op1.session); 243 session->op1.session = NULL; 244 } 245 246 /* Remove all the session metaobjects created in this session. */ 247 /* Basically, emulate C_DestroyObject, including safety h2s */ 248 while ((object = session->object_list_head) != NULL) { 249 CK_RV rv; 250 251 rv = meta_handle2object((CK_OBJECT_HANDLE)object, &object); 252 if (rv != CKR_OK) { 253 /* Can only happen if someone else just closed it. */ 254 continue; 255 } 256 257 rv = meta_object_deactivate(object, B_FALSE, B_TRUE); 258 if (rv != CKR_OK) { 259 continue; 260 } 261 262 rv = meta_object_dealloc(object, B_FALSE); 263 if (rv != CKR_OK) { 264 continue; 265 } 266 267 } 268 269 if ((isLastSession) && (metaslot_logged_in())) { 270 slot_session_t *slotsessp; 271 CK_RV rv; 272 273 rv = meta_get_slot_session(get_keystore_slotnum(), &slotsessp, 274 session->session_flags); 275 if (rv != CKR_OK) 276 return (rv); 277 rv = FUNCLIST(slotsessp->fw_st_id)->C_Logout( 278 slotsessp->hSession); 279 280 meta_release_slot_session(slotsessp); 281 282 /* if C_Logout fails, just ignore the error */ 283 metaslot_set_logged_in_flag(B_FALSE); 284 285 if (rv != CKR_OK) 286 return (rv); 287 288 /* need to deactivate all the PRIVATE token objects */ 289 rv = meta_token_object_deactivate(PRIVATE_TOKEN); 290 if (rv != CKR_OK) { 291 return (rv); 292 } 293 } 294 295 return (CKR_OK); 296 } 297 298 299 /* 300 * meta_session_dealloc 301 * 302 * Release the resources held by a metasession. If the session has been 303 * activated, it must be deactivated first. 304 */ 305 void 306 meta_session_dealloc(meta_session_t *session) 307 { 308 if ((session->find_objs_info).matched_objs) { 309 free((session->find_objs_info).matched_objs); 310 } 311 312 free((session->mech_support_info).supporting_slots); 313 314 /* 315 * If there were active operations, cleanup the slot session so that 316 * it can be reused (otherwise provider might complain that an 317 * operation is active). 318 */ 319 if (session->op1.type != 0) 320 meta_operation_cleanup(session, session->op1.type, FALSE); 321 322 /* Final object cleanup. */ 323 (void) pthread_rwlock_destroy(&session->session_lock); 324 (void) pthread_mutex_destroy(&session->isClosingSession_lock); 325 (void) pthread_rwlock_destroy(&session->object_list_lock); 326 327 meta_session_delay_free(session); 328 } 329 330 /* 331 * This function adds the to-be-freed meta session to a linked list. 332 * When the number of sessions queued in the linked list reaches the 333 * maximum threshold MAX_SESSION_TO_BE_FREED, it will free the first 334 * session (FIFO) in the list. 335 */ 336 void 337 meta_session_delay_free(meta_session_t *sp) 338 { 339 meta_session_t *tmp; 340 341 (void) pthread_mutex_lock(&ses_delay_freed.ses_to_be_free_mutex); 342 343 /* Add the newly deleted session at the end of the list */ 344 sp->next = NULL; 345 if (ses_delay_freed.first == NULL) { 346 ses_delay_freed.last = sp; 347 ses_delay_freed.first = sp; 348 } else { 349 ses_delay_freed.last->next = sp; 350 ses_delay_freed.last = sp; 351 } 352 353 if (++ses_delay_freed.count >= MAX_SESSION_TO_BE_FREED) { 354 /* 355 * Free the first session in the list only if 356 * the total count reaches maximum threshold. 357 */ 358 ses_delay_freed.count--; 359 tmp = ses_delay_freed.first->next; 360 free(ses_delay_freed.first); 361 ses_delay_freed.first = tmp; 362 } 363 (void) pthread_mutex_unlock(&ses_delay_freed.ses_to_be_free_mutex); 364 } 365