1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 4841 haimay * Common Development and Distribution License (the "License"). 6 4841 haimay * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 7136 wyllys * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel #pragma ident "%Z%%M% %I% %E% SMI" 27 0 stevel 28 0 stevel /* 29 0 stevel * Functions for dealing with provider sessions 30 0 stevel */ 31 0 stevel 32 0 stevel #include <string.h> 33 0 stevel #include <cryptoutil.h> 34 0 stevel #include "metaGlobal.h" 35 0 stevel #include "pkcs11Session.h" 36 0 stevel #include "pkcs11Global.h" 37 0 stevel 38 0 stevel 39 0 stevel /* 40 0 stevel * This is just a **WILD** guess for the maximum idle sessions to 41 0 stevel * keep for each slot. This number should probably be adjusted 42 0 stevel * when there's more data from actual application use 43 0 stevel */ 44 0 stevel #define MAX_IDLE_SESSIONS 100 45 0 stevel 46 0 stevel /* 47 0 stevel * The following 5 variables are initialized at the time metaslot 48 0 stevel * is initialized. They are not modified after they are initialized 49 0 stevel * 50 0 stevel * During initialization time, they are protected by the "initmutex" 51 0 stevel * defined in metaGeneral.c 52 0 stevel */ 53 0 stevel slot_data_t *slots; 54 0 stevel CK_SLOT_ID metaslot_keystore_slotid; 55 0 stevel static CK_ULONG num_slots; 56 0 stevel static CK_ULONG objtok_slotnum; 57 4841 haimay static CK_ULONG softtoken_slotnum; 58 0 stevel static boolean_t write_protected; 59 0 stevel 60 0 stevel /* protects the "metaslotLoggedIn" variable */ 61 0 stevel static pthread_mutex_t metaslotLoggedIn_mutex = PTHREAD_MUTEX_INITIALIZER; 62 0 stevel static boolean_t metaslotLoggedIn; 63 0 stevel 64 0 stevel /* 65 0 stevel * meta_slotManager_initialize 66 0 stevel * 67 0 stevel * Called from C_Initialize. Allocates and initializes the storage needed 68 0 stevel * by the slot manager. 69 0 stevel */ 70 0 stevel CK_RV 71 0 stevel meta_slotManager_initialize() { 72 0 stevel CK_ULONG slot_count = 0; 73 0 stevel CK_RV rv; 74 0 stevel CK_SLOT_ID i; 75 0 stevel 76 0 stevel /* Initialize the static variables */ 77 0 stevel write_protected = B_FALSE; 78 0 stevel metaslotLoggedIn = B_FALSE; 79 0 stevel 80 0 stevel /* 81 0 stevel * Count the number of slots in the framework. 82 0 stevel * We start at ((slottable->st_first) + 1) instead of 83 0 stevel * slottable->st_first because when we are here, metaslot is 84 0 stevel * enabled, and st_first is always metaslot, which doesn't 85 0 stevel * need to be counted. 86 0 stevel */ 87 0 stevel for (i = (slottable->st_first) + 1; i <= slottable->st_last; i++) { 88 0 stevel slot_count++; 89 0 stevel } 90 0 stevel 91 0 stevel /* 92 0 stevel * This shouldn't happen, because there should at least 93 0 stevel * be 1 other slot besides metaslot. 94 0 stevel */ 95 0 stevel if (slot_count < 1) { 96 0 stevel rv = CKR_FUNCTION_FAILED; 97 0 stevel goto clean_exit; 98 0 stevel } 99 0 stevel 100 0 stevel slots = calloc(slot_count, sizeof (slot_data_t)); 101 0 stevel if (slots == NULL) { 102 0 stevel rv = CKR_HOST_MEMORY; 103 0 stevel goto clean_exit; 104 0 stevel } 105 0 stevel 106 0 stevel /* 107 0 stevel * Store the slot IDs. Adjust for the fact that the first slot is 108 0 stevel * actually us (metaslot). 109 0 stevel */ 110 0 stevel for (i = 0; i < slot_count; i++) { 111 0 stevel slots[i].fw_st_id = i + 1; 112 0 stevel (void) pthread_rwlock_init( 113 0 stevel &(slots[i].tokenobject_list_lock), NULL); 114 0 stevel } 115 0 stevel num_slots = slot_count; 116 0 stevel 117 0 stevel return (CKR_OK); 118 0 stevel 119 0 stevel clean_exit: 120 0 stevel if (slots) { 121 0 stevel free(slots); 122 0 stevel slots = NULL; 123 0 stevel } 124 0 stevel 125 0 stevel num_slots = 0; 126 0 stevel 127 0 stevel return (rv); 128 0 stevel } 129 0 stevel 130 0 stevel 131 0 stevel /* 132 0 stevel * meta_slotManager_finalize 133 0 stevel * 134 0 stevel * Called from C_Finalize. Deallocates any storage held by the slot manager. 135 0 stevel */ 136 0 stevel void 137 0 stevel meta_slotManager_finalize() { 138 0 stevel CK_ULONG slot; 139 0 stevel 140 7136 wyllys /* If no slots to free, return */ 141 7136 wyllys if (slots == NULL) 142 7136 wyllys return; 143 0 stevel /* 144 0 stevel * No need to lock pool, we assume all meta sessions are closed. 145 0 stevel * 146 0 stevel * Close all sessions in the idle and persist list. 147 0 stevel * The active list is empty. It doesn't need to be checked. 148 0 stevel */ 149 0 stevel 150 0 stevel for (slot = 0; slot < num_slots; slot++) { 151 0 stevel slot_session_t *session, *next_session; 152 0 stevel 153 0 stevel /* 154 0 stevel * The slotobjects associated with the session should have 155 0 stevel * been closed when the metaobjects were closed. Thus, no 156 0 stevel * need to do anything here. 157 0 stevel */ 158 0 stevel 159 0 stevel session = slots[slot].session_pool.idle_list_head; 160 0 stevel while (session) { 161 0 stevel next_session = session->next; 162 0 stevel (void) FUNCLIST(session->fw_st_id)->C_CloseSession( 163 0 stevel session->hSession); 164 0 stevel (void) pthread_rwlock_destroy( 165 0 stevel &session->object_list_lock); 166 0 stevel free(session); 167 0 stevel session = next_session; 168 0 stevel } 169 0 stevel 170 0 stevel session = slots[slot].session_pool.persist_list_head; 171 0 stevel while (session) { 172 0 stevel next_session = session->next; 173 0 stevel (void) FUNCLIST(session->fw_st_id)->C_CloseSession( 174 0 stevel session->hSession); 175 0 stevel (void) pthread_rwlock_destroy( 176 0 stevel &session->object_list_lock); 177 0 stevel free(session); 178 0 stevel session = next_session; 179 0 stevel } 180 0 stevel 181 0 stevel (void) pthread_rwlock_destroy( 182 0 stevel &slots[slot].tokenobject_list_lock); 183 0 stevel } 184 0 stevel 185 0 stevel free(slots); 186 0 stevel slots = NULL; 187 7136 wyllys num_slots = 0; 188 0 stevel } 189 0 stevel 190 0 stevel 191 0 stevel /* 192 0 stevel * meta_slotManager_find_object_token() 193 0 stevel * 194 0 stevel * Called from meta_Initialize. Searches for the "object token," which is used 195 0 stevel * for storing token objects and loging into. 196 0 stevel * 197 0 stevel * We do the search using the following algorithm. 198 0 stevel * 199 0 stevel * If either ${METASLOT_OBJECTSTORE_SLOT} or ${METASLOT_OBJECTSTORE_TOKEN} 200 0 stevel * environment variable is defined, the value of the defined variable(s) 201 0 stevel * will be used for the match. All token and slot values defined system-wide 202 0 stevel * will be ignored. 203 0 stevel * 204 0 stevel * If neither variables above are defined, the system-wide values defined 205 0 stevel * in pkcs11.conf are used. 206 0 stevel * 207 0 stevel * If neither environment variables or system-wide values are defined, 208 0 stevel * or if none of the existing slots/tokens match the defined 209 0 stevel * values, the first slot after metaslot will be used as the default. 210 0 stevel * 211 0 stevel */ 212 0 stevel void 213 0 stevel meta_slotManager_find_object_token() { 214 0 stevel CK_ULONG slot; 215 0 stevel boolean_t found = B_FALSE; 216 0 stevel CK_RV rv; 217 0 stevel unsigned int num_match_needed = 0; 218 0 stevel CK_SLOT_INFO slotinfo; 219 0 stevel CK_TOKEN_INFO tokeninfo; 220 0 stevel 221 0 stevel if (metaslot_config.keystore_token_specified) { 222 0 stevel num_match_needed++; 223 0 stevel } 224 0 stevel 225 0 stevel if (metaslot_config.keystore_slot_specified) { 226 0 stevel num_match_needed++; 227 0 stevel } 228 0 stevel 229 0 stevel if (num_match_needed == 0) { 230 0 stevel goto skip_search; 231 0 stevel } 232 0 stevel 233 0 stevel for (slot = 0; slot < num_slots; slot++) { 234 0 stevel unsigned int num_matched = 0; 235 0 stevel boolean_t have_tokeninfo = B_FALSE; 236 0 stevel CK_SLOT_ID true_id, fw_st_id; 237 0 stevel 238 0 stevel fw_st_id = slots[slot].fw_st_id; 239 0 stevel true_id = TRUEID(fw_st_id); 240 4841 haimay 241 4841 haimay (void) memset(&slotinfo, 0, sizeof (CK_SLOT_INFO)); 242 4841 haimay rv = FUNCLIST(fw_st_id)->C_GetSlotInfo(true_id, 243 4841 haimay &slotinfo); 244 4841 haimay if (rv != CKR_OK) 245 4841 haimay continue; 246 4841 haimay 247 4841 haimay if (strncmp((char *)SOFT_SLOT_DESCRIPTION, 248 4841 haimay (char *)slotinfo.slotDescription, 249 4841 haimay SLOT_DESCRIPTION_SIZE) == 0) { 250 4841 haimay softtoken_slotnum = slot; 251 4841 haimay } 252 0 stevel 253 0 stevel if (metaslot_config.keystore_slot_specified) { 254 0 stevel 255 0 stevel unsigned char *slot; 256 0 stevel size_t slot_str_len; 257 0 stevel 258 0 stevel rv = FUNCLIST(fw_st_id)->C_GetSlotInfo(true_id, 259 0 stevel &slotinfo); 260 0 stevel if (rv != CKR_OK) 261 0 stevel continue; 262 0 stevel 263 0 stevel /* 264 0 stevel * pad slot description from user/system configuration 265 0 stevel * with spaces 266 0 stevel */ 267 0 stevel slot = metaslot_config.keystore_slot; 268 0 stevel slot_str_len = strlen((char *)slot); 269 0 stevel (void) memset(slot + slot_str_len, ' ', 270 0 stevel SLOT_DESCRIPTION_SIZE - slot_str_len); 271 0 stevel 272 0 stevel /* 273 0 stevel * The PKCS#11 strings are not null-terminated, so, 274 0 stevel * we just compare SLOT_DESCRIPTION_SIZE bytes 275 0 stevel */ 276 0 stevel if (strncmp((char *)slot, 277 0 stevel (char *)slotinfo.slotDescription, 278 0 stevel SLOT_DESCRIPTION_SIZE) == 0) { 279 0 stevel num_matched++; 280 0 stevel } 281 0 stevel } 282 0 stevel 283 0 stevel if (metaslot_config.keystore_token_specified) { 284 0 stevel unsigned char *token; 285 0 stevel size_t token_str_len; 286 0 stevel 287 0 stevel rv = FUNCLIST(fw_st_id)->C_GetTokenInfo(true_id, 288 0 stevel &tokeninfo); 289 0 stevel 290 0 stevel if (rv != CKR_OK) { 291 0 stevel continue; 292 0 stevel } 293 0 stevel 294 0 stevel have_tokeninfo = B_TRUE; 295 0 stevel 296 0 stevel /* 297 0 stevel * pad slot description from user/system configuration 298 0 stevel * with spaces 299 0 stevel */ 300 0 stevel token = metaslot_config.keystore_token; 301 0 stevel token_str_len = strlen((char *)token); 302 0 stevel (void) memset(token + token_str_len, ' ', 303 0 stevel TOKEN_LABEL_SIZE - token_str_len); 304 0 stevel 305 0 stevel /* 306 0 stevel * The PKCS#11 strings are not null-terminated. 307 0 stevel * So, just compare TOKEN_LABEL_SIZE bytes 308 0 stevel */ 309 0 stevel if (strncmp((char *)token, (char *)tokeninfo.label, 310 0 stevel TOKEN_LABEL_SIZE) == 0) { 311 0 stevel num_matched++; 312 0 stevel } 313 0 stevel } 314 0 stevel 315 0 stevel if (num_match_needed == num_matched) { 316 0 stevel /* match is found */ 317 0 stevel 318 0 stevel if (!have_tokeninfo) { 319 0 stevel rv = FUNCLIST(fw_st_id)->C_GetTokenInfo(true_id, 320 0 stevel &tokeninfo); 321 0 stevel if (rv != CKR_OK) { 322 0 stevel continue; 323 0 stevel } 324 0 stevel } 325 0 stevel 326 0 stevel 327 0 stevel if (tokeninfo.flags & CKF_WRITE_PROTECTED) { 328 0 stevel /* 329 0 stevel * Currently this is the only time that 330 0 stevel * the write_protected state is set, and 331 0 stevel * it is never cleared. The token could 332 0 stevel * clear (or set!) this flag later on. 333 0 stevel * We might want to adjust the state 334 0 stevel * of metaslot, but there's know way to know 335 0 stevel * when a token changes this flag. 336 0 stevel */ 337 0 stevel write_protected = B_TRUE; 338 0 stevel } 339 0 stevel 340 0 stevel found = B_TRUE; 341 0 stevel break; 342 0 stevel } 343 0 stevel } 344 0 stevel 345 0 stevel skip_search: 346 0 stevel if (found) { 347 0 stevel objtok_slotnum = slot; 348 0 stevel } else { 349 0 stevel /* 350 0 stevel * if slot and/or token is not defined for the keystore, 351 0 stevel * just use the first available slot as keystore 352 0 stevel */ 353 0 stevel objtok_slotnum = 0; 354 0 stevel } 355 0 stevel slots[objtok_slotnum].session_pool.keep_one_alive = B_TRUE; 356 0 stevel metaslot_keystore_slotid = slots[objtok_slotnum].fw_st_id; 357 0 stevel } 358 0 stevel 359 0 stevel 360 0 stevel CK_ULONG 361 0 stevel get_keystore_slotnum() 362 0 stevel { 363 0 stevel return (objtok_slotnum); 364 0 stevel } 365 0 stevel 366 4841 haimay CK_ULONG 367 4841 haimay get_softtoken_slotnum() 368 4841 haimay { 369 4841 haimay return (softtoken_slotnum); 370 4841 haimay } 371 0 stevel 372 0 stevel CK_SLOT_ID 373 0 stevel meta_slotManager_get_framework_table_id(CK_ULONG slotnum) 374 0 stevel { 375 0 stevel /* 376 0 stevel * This is only used internally, and so the slotnum should always 377 0 stevel * be valid. 378 0 stevel */ 379 0 stevel return (slots[slotnum].fw_st_id); 380 0 stevel } 381 0 stevel 382 0 stevel CK_ULONG 383 0 stevel meta_slotManager_get_slotcount() 384 0 stevel { 385 0 stevel return (num_slots); 386 0 stevel } 387 0 stevel 388 0 stevel boolean_t 389 0 stevel meta_slotManager_token_write_protected() 390 0 stevel { 391 0 stevel return (write_protected); 392 0 stevel } 393 0 stevel 394 0 stevel /* 395 0 stevel * Find a session in the given list that matches the specified flags. 396 0 stevel * If such a session is found, it will be removed from the list, and 397 0 stevel * returned to the caller. If such a session is not found, will 398 0 stevel * return NULL 399 0 stevel */ 400 0 stevel static slot_session_t * 401 0 stevel get_session(slot_session_t **session_list, CK_FLAGS flags) 402 0 stevel { 403 0 stevel 404 0 stevel slot_session_t *tmp_session; 405 0 stevel 406 0 stevel tmp_session = *session_list; 407 0 stevel 408 0 stevel while (tmp_session != NULL) { 409 0 stevel if (tmp_session->session_flags == flags) { 410 0 stevel break; 411 0 stevel } else { 412 0 stevel tmp_session = tmp_session->next; 413 0 stevel } 414 0 stevel 415 0 stevel } 416 0 stevel 417 0 stevel if (tmp_session == NULL) { 418 0 stevel /* no match */ 419 0 stevel return (NULL); 420 0 stevel } 421 0 stevel 422 0 stevel /* Remove from list */ 423 0 stevel REMOVE_FROM_LIST(*session_list, tmp_session); 424 0 stevel return (tmp_session); 425 0 stevel } 426 0 stevel 427 0 stevel /* 428 0 stevel * meta_get_slot_session 429 0 stevel * 430 0 stevel * Call to get a session with a specific slot/token. 431 0 stevel * 432 0 stevel * NOTE - We assume the slot allows an unlimited number of sessions. We 433 0 stevel * could look at what's reported in the token info, but that information is 434 0 stevel * not always set. It's also unclear when we should (A) wait for one to become 435 0 stevel * available, (B) skip the slot for now or (C) return a fatal error. The 436 0 stevel * extra complexity is not worth it. 437 0 stevel * 438 0 stevel */ 439 0 stevel CK_RV 440 0 stevel meta_get_slot_session(CK_ULONG slotnum, slot_session_t **session, 441 0 stevel CK_FLAGS flags) { 442 0 stevel session_pool_t *pool; 443 0 stevel slot_session_t *new_session, *tmp_session; 444 0 stevel CK_RV rv; 445 0 stevel CK_SLOT_ID fw_st_id, true_id; 446 0 stevel 447 0 stevel if (slotnum >= num_slots) { 448 0 stevel return (CKR_SLOT_ID_INVALID); 449 0 stevel } 450 0 stevel 451 0 stevel pool = &slots[slotnum].session_pool; 452 0 stevel 453 0 stevel /* 454 0 stevel * Try to reuse an existing session. 455 0 stevel */ 456 0 stevel 457 0 stevel (void) pthread_mutex_lock(&pool->list_lock); 458 0 stevel 459 0 stevel if (pool->idle_list_head != NULL) { 460 0 stevel tmp_session = get_session(&(pool->idle_list_head), flags); 461 0 stevel if (tmp_session != NULL) { 462 0 stevel /* Add to active list */ 463 0 stevel INSERT_INTO_LIST(pool->active_list_head, tmp_session); 464 0 stevel *session = tmp_session; 465 0 stevel pool->num_idle_sessions--; 466 0 stevel (void) pthread_mutex_unlock(&pool->list_lock); 467 0 stevel return (CKR_OK); 468 0 stevel } 469 0 stevel } 470 0 stevel 471 0 stevel if (pool->persist_list_head != NULL) { 472 0 stevel tmp_session = get_session(&(pool->persist_list_head), flags); 473 0 stevel if (tmp_session != NULL) { 474 0 stevel /* Add to active list */ 475 0 stevel INSERT_INTO_LIST(pool->active_list_head, tmp_session); 476 0 stevel *session = tmp_session; 477 0 stevel (void) pthread_mutex_unlock(&pool->list_lock); 478 0 stevel return (CKR_OK); 479 0 stevel } 480 0 stevel } 481 0 stevel (void) pthread_mutex_unlock(&pool->list_lock); 482 0 stevel 483 0 stevel fw_st_id = slots[slotnum].fw_st_id; 484 0 stevel true_id = TRUEID(fw_st_id); 485 0 stevel 486 0 stevel new_session = calloc(1, sizeof (slot_session_t)); 487 0 stevel if (new_session == NULL) { 488 0 stevel return (CKR_HOST_MEMORY); 489 0 stevel } 490 0 stevel 491 0 stevel /* initialize slotsession */ 492 0 stevel new_session->slotnum = slotnum; 493 0 stevel new_session->fw_st_id = fw_st_id; 494 0 stevel new_session->object_list_head = NULL; 495 0 stevel new_session->session_flags = flags; 496 0 stevel (void) pthread_rwlock_init(&new_session->object_list_lock, NULL); 497 0 stevel 498 0 stevel rv = FUNCLIST(fw_st_id)->C_OpenSession(true_id, flags, NULL, NULL, 499 0 stevel &new_session->hSession); 500 0 stevel 501 0 stevel if (rv == CKR_TOKEN_WRITE_PROTECTED) { 502 0 stevel /* Retry with a RO session. */ 503 0 stevel new_session->session_flags &= ~CKF_SERIAL_SESSION; 504 0 stevel rv = FUNCLIST(fw_st_id)->C_OpenSession(true_id, 505 0 stevel new_session->session_flags, NULL, NULL, 506 0 stevel &new_session->hSession); 507 0 stevel } 508 0 stevel 509 0 stevel if (rv != CKR_OK) { 510 0 stevel free(new_session); 511 0 stevel return (CKR_FUNCTION_FAILED); 512 0 stevel } 513 0 stevel 514 0 stevel /* Insert session into active list */ 515 0 stevel (void) pthread_mutex_lock(&pool->list_lock); 516 0 stevel INSERT_INTO_LIST(pool->active_list_head, new_session); 517 0 stevel (void) pthread_mutex_unlock(&pool->list_lock); 518 0 stevel *session = new_session; 519 0 stevel return (CKR_OK); 520 0 stevel } 521 0 stevel 522 0 stevel 523 0 stevel /* 524 0 stevel * meta_release_slot_session 525 0 stevel * 526 0 stevel * Call to release a session obtained via meta_get_slot_session() 527 0 stevel */ 528 0 stevel void 529 0 stevel meta_release_slot_session(slot_session_t *session) { 530 0 stevel session_pool_t *pool; 531 0 stevel boolean_t must_retain, can_close = B_FALSE; 532 0 stevel boolean_t this_is_last_session = B_FALSE; 533 0 stevel 534 0 stevel pool = &slots[session->slotnum].session_pool; 535 0 stevel 536 0 stevel /* Note that the active_list must have >= 1 entry (this session) */ 537 0 stevel if (pool->persist_list_head == NULL && 538 0 stevel pool->idle_list_head == NULL && 539 0 stevel pool->active_list_head->next == NULL) 540 0 stevel this_is_last_session = B_TRUE; 541 0 stevel 542 0 stevel /* 543 0 stevel * If the session has session objects, we need to retain it. Also 544 0 stevel * retain it if it's the only session holding login state (or handles 545 0 stevel * to public token objects) 546 0 stevel */ 547 0 stevel must_retain = session->object_list_head != NULL || 548 0 stevel (pool->keep_one_alive && this_is_last_session); 549 0 stevel 550 0 stevel if ((!must_retain) && (pool->num_idle_sessions > MAX_IDLE_SESSIONS)) { 551 0 stevel can_close = B_TRUE; 552 0 stevel } 553 0 stevel 554 0 stevel (void) pthread_mutex_lock(&pool->list_lock); 555 0 stevel /* remove from active list */ 556 0 stevel REMOVE_FROM_LIST(pool->active_list_head, session); 557 0 stevel 558 0 stevel if (must_retain) { 559 0 stevel /* insert into persist list */ 560 0 stevel INSERT_INTO_LIST(pool->persist_list_head, session); 561 0 stevel (void) pthread_mutex_unlock(&pool->list_lock); 562 0 stevel return; 563 0 stevel } else if (!can_close) { 564 0 stevel /* insert into idle list */ 565 0 stevel INSERT_INTO_LIST(pool->idle_list_head, session); 566 0 stevel pool->num_idle_sessions++; 567 0 stevel (void) pthread_mutex_unlock(&pool->list_lock); 568 0 stevel return; 569 0 stevel } 570 0 stevel 571 0 stevel (void) pthread_mutex_unlock(&pool->list_lock); 572 0 stevel 573 0 stevel (void) FUNCLIST(session->fw_st_id)->C_CloseSession(session->hSession); 574 0 stevel 575 0 stevel (void) pthread_rwlock_destroy(&session->object_list_lock); 576 0 stevel free(session); 577 0 stevel } 578 0 stevel 579 0 stevel /* 580 0 stevel * Returns whether metaslot has directly logged in 581 0 stevel */ 582 0 stevel boolean_t 583 0 stevel metaslot_logged_in() 584 0 stevel { 585 0 stevel return (metaslotLoggedIn); 586 0 stevel } 587 0 stevel 588 0 stevel void 589 0 stevel metaslot_set_logged_in_flag(boolean_t value) 590 0 stevel { 591 0 stevel (void) pthread_mutex_lock(&metaslotLoggedIn_mutex); 592 0 stevel metaslotLoggedIn = value; 593 0 stevel (void) pthread_mutex_unlock(&metaslotLoggedIn_mutex); 594 0 stevel } 595