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