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 <pthread.h> 30 #include <syslog.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <errno.h> 34 #include <sys/crypto/ioctl.h> 35 #include <security/cryptoki.h> 36 #include "kernelGlobal.h" 37 #include "kernelSession.h" 38 #include "kernelSlot.h" 39 40 /* 41 * Delete all the sessions. First, obtain the slot lock. 42 * Then start to delete one session at a time. The boolean wrapper_only 43 * argument indicates that whether the caller only wants to clean up the 44 * session wrappers and the object wrappers in the library. 45 * - When this function is called by C_CloseAllSessions or indirectly by 46 * C_Finalize, wrapper_only is FALSE. 47 * - When this function is called by cleanup_child, wrapper_only is TRUE. 48 */ 49 CK_RV 50 kernel_delete_all_sessions(CK_SLOT_ID slotID, boolean_t wrapper_only) 51 { 52 CK_RV rv = CKR_OK; 53 CK_RV rv1; 54 kernel_session_t *session_p; 55 kernel_session_t *session_p1; 56 kernel_slot_t *pslot; 57 58 /* Acquire the slot lock */ 59 pslot = slot_table[slotID]; 60 (void) pthread_mutex_lock(&pslot->sl_mutex); 61 62 /* 63 * Delete all the sessions in the slot's session list. 64 * The routine kernel_delete_session() updates the linked list. 65 * So, we do not need to maintain the list here. 66 */ 67 session_p = pslot->sl_sess_list; 68 while (session_p) { 69 session_p1 = session_p->next; 70 /* 71 * Delete a session by calling kernel_delete_session() 72 * with a session pointer and a boolean arguments. 73 * Boolean value TRUE is used to indicate that the 74 * caller holds the slot lock. 75 */ 76 rv1 = kernel_delete_session(slotID, session_p, B_TRUE, 77 wrapper_only); 78 79 /* Record the very first error code */ 80 if (rv == CKR_OK) { 81 rv = rv1; 82 } 83 84 session_p = session_p1; 85 } 86 87 /* Release the slot lock */ 88 (void) pthread_mutex_unlock(&pslot->sl_mutex); 89 90 return (rv); 91 } 92 93 94 /* 95 * Create a new session struct, and add it to the slot's session list. 96 * 97 * This function is called by C_OpenSession(), which hold the slot lock. 98 */ 99 CK_RV 100 kernel_add_session(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, 101 CK_NOTIFY notify, CK_ULONG *sessionhandle_p) 102 { 103 CK_RV rv = CKR_OK; 104 kernel_session_t *new_sp = NULL; 105 crypto_open_session_t open_session; 106 kernel_slot_t *pslot; 107 int r; 108 109 /* Allocate a new session struct */ 110 new_sp = calloc(1, sizeof (kernel_session_t)); 111 if (new_sp == NULL) { 112 return (CKR_HOST_MEMORY); 113 } 114 115 new_sp->magic_marker = KERNELTOKEN_SESSION_MAGIC; 116 new_sp->pApplication = pApplication; 117 new_sp->Notify = notify; 118 new_sp->flags = flags; 119 new_sp->ses_RO = (flags & CKF_RW_SESSION) ? B_FALSE : B_TRUE; 120 new_sp->ses_slotid = slotID; 121 new_sp->object_list = NULL; 122 new_sp->ses_refcnt = 0; 123 new_sp->ses_close_sync = 0; 124 125 /* Initialize the lock for the newly created session */ 126 if (pthread_mutex_init(&new_sp->session_mutex, NULL) != 0) { 127 free(new_sp); 128 return (CKR_CANT_LOCK); 129 } 130 131 pslot = slot_table[slotID]; 132 open_session.os_provider_id = pslot->sl_provider_id; 133 open_session.os_flags = flags; 134 while ((r = ioctl(kernel_fd, CRYPTO_OPEN_SESSION, &open_session)) < 0) { 135 if (errno != EINTR) 136 break; 137 } 138 if (r < 0) { 139 rv = CKR_FUNCTION_FAILED; 140 } else { 141 rv = crypto2pkcs11_error_number(open_session.os_return_value); 142 } 143 144 if (rv != CKR_OK) { 145 (void) pthread_mutex_destroy(&new_sp->session_mutex); 146 free(new_sp); 147 return (rv); 148 } 149 150 new_sp->k_session = open_session.os_session; 151 152 (void) pthread_mutex_init(&new_sp->ses_free_mutex, NULL); 153 (void) pthread_cond_init(&new_sp->ses_free_cond, NULL); 154 155 /* Insert the new session in front of the slot's session list */ 156 if (pslot->sl_sess_list == NULL) { 157 pslot->sl_sess_list = new_sp; 158 new_sp->prev = NULL; 159 new_sp->next = NULL; 160 } else { 161 pslot->sl_sess_list->prev = new_sp; 162 new_sp->next = pslot->sl_sess_list; 163 new_sp->prev = NULL; 164 pslot->sl_sess_list = new_sp; 165 } 166 167 /* Type casting the address of a session struct to a session handle */ 168 *sessionhandle_p = (CK_ULONG)new_sp; 169 170 return (CKR_OK); 171 } 172 173 174 /* 175 * Delete a session: 176 * - Remove the session from the slot's session list. 177 * - Release all the objects created by the session. 178 * 179 * The boolean argument slot_lock_held is used to indicate that whether 180 * the caller of this function holds the slot lock or not. 181 * - When called by kernel_delete_all_sessions(), which is called by 182 * C_Finalize() or C_CloseAllSessions() -- slot_lock_held = TRUE. 183 * - When called by C_CloseSession() -- slot_lock_held = FALSE. 184 */ 185 CK_RV 186 kernel_delete_session(CK_SLOT_ID slotID, kernel_session_t *session_p, 187 boolean_t slot_lock_held, boolean_t wrapper_only) 188 { 189 CK_RV rv; 190 crypto_session_id_t k_session; 191 crypto_close_session_t close_session; 192 kernel_slot_t *pslot; 193 kernel_object_t *objp; 194 kernel_object_t *objp1; 195 int r; 196 197 /* 198 * Check to see if the caller holds the lock on the global 199 * session list. If not, we need to acquire that lock in 200 * order to proceed. 201 */ 202 pslot = slot_table[slotID]; 203 if (!slot_lock_held) { 204 /* Acquire the slot lock */ 205 (void) pthread_mutex_lock(&pslot->sl_mutex); 206 } 207 208 /* 209 * Remove the session from the slot's session list first. 210 */ 211 if (pslot->sl_sess_list == session_p) { 212 /* Session is the first one in the list */ 213 if (session_p->next) { 214 pslot->sl_sess_list = session_p->next; 215 session_p->next->prev = NULL; 216 } else { 217 /* Session is the only one in the list */ 218 pslot->sl_sess_list = NULL; 219 } 220 } else { 221 /* Session is not the first one in the list */ 222 if (session_p->next) { 223 /* Session is in the middle of the list */ 224 session_p->prev->next = session_p->next; 225 session_p->next->prev = session_p->prev; 226 } else { 227 /* Session is the last one in the list */ 228 session_p->prev->next = NULL; 229 } 230 } 231 232 233 if (!slot_lock_held) { 234 /* 235 * If the slot lock is obtained by 236 * this function, then release that lock after 237 * removing the session from session linked list. 238 * We want the releasing of the objects of the 239 * session, and freeing of the session itself to 240 * be done without holding the slot's session list 241 * lock. 242 */ 243 (void) pthread_mutex_unlock(&pslot->sl_mutex); 244 } 245 246 /* Acquire the individual session lock */ 247 (void) pthread_mutex_lock(&session_p->session_mutex); 248 249 /* 250 * Make sure another thread hasn't freed the session. 251 */ 252 if (session_p->magic_marker != KERNELTOKEN_SESSION_MAGIC) { 253 (void) pthread_mutex_unlock(&session_p->session_mutex); 254 return (CKR_OK); 255 } 256 257 /* 258 * The deletion of a session must be blocked when the session reference 259 * count is not zero. This means that if the thread that is attempting 260 * to close the session must wait until the prior operations on this 261 * session are finished. 262 */ 263 (void) pthread_mutex_lock(&session_p->ses_free_mutex); 264 265 while (session_p->ses_refcnt != 0) { 266 /* 267 * We set the SESSION_REFCNT_WAITING flag before we put 268 * this closing thread in a wait state, so other non-closing 269 * operation thread will wake it up only when 270 * the session reference count becomes zero and this flag 271 * is set. 272 */ 273 session_p->ses_close_sync |= SESSION_REFCNT_WAITING; 274 (void) pthread_mutex_unlock(&session_p->session_mutex); 275 (void) pthread_cond_wait(&session_p->ses_free_cond, 276 &session_p->ses_free_mutex); 277 (void) pthread_mutex_lock(&session_p->session_mutex); 278 } 279 280 session_p->ses_close_sync &= ~SESSION_REFCNT_WAITING; 281 282 /* Mark session as no longer valid. */ 283 session_p->magic_marker = 0; 284 285 (void) pthread_mutex_unlock(&session_p->ses_free_mutex); 286 (void) pthread_mutex_destroy(&session_p->ses_free_mutex); 287 (void) pthread_cond_destroy(&session_p->ses_free_cond); 288 289 /* 290 * Remove all the objects created in this session. 291 */ 292 kernel_delete_all_objects_in_session(session_p, wrapper_only); 293 294 /* In case application did not call Final */ 295 if (session_p->digest.context != NULL) 296 free(session_p->digest.context); 297 298 if (session_p->encrypt.context != NULL) 299 free(session_p->encrypt.context); 300 301 if (session_p->decrypt.context != NULL) 302 free(session_p->decrypt.context); 303 304 if (session_p->sign.context != NULL) 305 free(session_p->sign.context); 306 307 if (session_p->verify.context != NULL) 308 free(session_p->verify.context); 309 310 k_session = session_p->k_session; 311 312 /* Reset SESSION_IS_CLOSING flag. */ 313 session_p->ses_close_sync &= ~SESSION_IS_CLOSING; 314 315 (void) pthread_mutex_unlock(&session_p->session_mutex); 316 /* Destroy the individual session lock */ 317 (void) pthread_mutex_destroy(&session_p->session_mutex); 318 319 if (!wrapper_only) { 320 close_session.cs_session = k_session; 321 while ((r = ioctl(kernel_fd, CRYPTO_CLOSE_SESSION, 322 &close_session)) < 0) { 323 if (errno != EINTR) 324 break; 325 } 326 if (r < 0) { 327 rv = CKR_FUNCTION_FAILED; 328 } else { 329 rv = crypto2pkcs11_error_number( 330 close_session.cs_return_value); 331 } 332 } 333 334 /* 335 * Ignore ioctl return codes. If the library tells the kernel to 336 * close a session and the kernel says "I don't know what session 337 * you're talking about", there's not much that can be done. All 338 * sessions in the kernel will be closed when the application exits 339 * and closes /dev/crypto. 340 */ 341 rv = CKR_OK; 342 free(session_p); 343 344 /* 345 * If there is no more session remained in this slot, reset the slot's 346 * session state to CKU_PUBLIC. Also, clean up all the token object 347 * wrappers in the library for this slot. 348 */ 349 if (pslot->sl_sess_list == NULL) { 350 351 /* Acquire the slot lock if lock is not held */ 352 if (!slot_lock_held) { 353 (void) pthread_mutex_lock(&pslot->sl_mutex); 354 } 355 356 /* Reset the session auth. state. */ 357 pslot->sl_state = CKU_PUBLIC; 358 359 /* Clean up token object wrappers. */ 360 objp = pslot->sl_tobj_list; 361 while (objp) { 362 objp1 = objp->next; 363 (void) pthread_mutex_destroy(&objp->object_mutex); 364 (void) free(objp); 365 objp = objp1; 366 } 367 pslot->sl_tobj_list = NULL; 368 369 /* Release the slot lock if lock is not held */ 370 if (!slot_lock_held) { 371 (void) pthread_mutex_unlock(&pslot->sl_mutex); 372 } 373 } 374 375 return (rv); 376 } 377 378 379 /* 380 * This function is used to type cast a session handle to a pointer to 381 * the session struct. Also, it does the following things: 382 * 1) Check to see if the session struct is tagged with a session 383 * magic number. This is to detect when an application passes 384 * a bogus session pointer. 385 * 2) Acquire the locks on the designated session and the slot which owns 386 * this session. 387 * 3) Check to see if the session is in the closing state that another 388 * thread is performing. 389 * 4) Increment the session reference count by one. This is to prevent 390 * this session from being closed by other thread. 391 * 5) Release the locks on the designated session and on the slot. 392 */ 393 CK_RV 394 handle2session(CK_SESSION_HANDLE hSession, kernel_session_t **session_p) 395 { 396 kernel_session_t *sp = (kernel_session_t *)(hSession); 397 CK_RV rv; 398 kernel_slot_t *pslot; 399 400 if ((sp == NULL) || 401 (sp->magic_marker != KERNELTOKEN_SESSION_MAGIC)) { 402 return (CKR_SESSION_HANDLE_INVALID); 403 } else { 404 pslot = slot_table[sp->ses_slotid]; 405 (void) pthread_mutex_lock(&pslot->sl_mutex); 406 (void) pthread_mutex_lock(&sp->session_mutex); 407 if (sp->ses_close_sync & SESSION_IS_CLOSING) { 408 rv = CKR_SESSION_CLOSED; 409 } else { 410 /* Increment session ref count. */ 411 sp->ses_refcnt++; 412 rv = CKR_OK; 413 } 414 (void) pthread_mutex_unlock(&sp->session_mutex); 415 (void) pthread_mutex_unlock(&pslot->sl_mutex); 416 } 417 418 if (rv == CKR_OK) 419 *session_p = sp; 420 421 return (rv); 422 } 423