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.
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.
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]
21 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
29 #include <security/cryptoki.h>
30 #include "kmsGlobal.h"
31 #include "kmsSession.h"
33 #include "kmsKeystoreUtil.h"
35 static pthread_mutex_t delete_sessions_mutex
= PTHREAD_MUTEX_INITIALIZER
;
36 CK_ULONG kms_session_cnt
= 0;
37 CK_ULONG kms_session_rw_cnt
= 0;
40 * Delete all the sessions. First, obtain the slot lock.
41 * Then start to delete one session at a time. The boolean wrapper_only
42 * argument indicates that whether the caller only wants to clean up the
43 * session wrappers and the object wrappers in the library.
44 * - When this function is called by C_CloseAllSessions or indirectly by
45 * C_Finalize, wrapper_only is FALSE.
46 * - When this function is called by cleanup_child, wrapper_only is TRUE.
49 kms_delete_all_sessions(boolean_t wrapper_only
)
51 kms_session_t
*session_p
;
54 (void) pthread_mutex_lock(&delete_sessions_mutex
);
56 pslot
= get_slotinfo();
59 * Delete all the sessions in the slot's session list.
60 * The routine kms_delete_session() updates the linked list.
61 * So, we do not need to maintain the list here.
64 (void) pthread_mutex_lock(&pslot
->sl_mutex
);
65 if (pslot
->sl_sess_list
== NULL
)
68 session_p
= pslot
->sl_sess_list
;
70 * Set SESSION_IS_CLOSING flag so any access to this
71 * session will be rejected.
73 (void) pthread_mutex_lock(&session_p
->session_mutex
);
74 if (session_p
->ses_close_sync
& SESSION_IS_CLOSING
) {
75 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
78 session_p
->ses_close_sync
|= SESSION_IS_CLOSING
;
79 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
81 (void) pthread_mutex_unlock(&pslot
->sl_mutex
);
82 kms_delete_session(session_p
, B_FALSE
, wrapper_only
);
84 (void) pthread_mutex_unlock(&pslot
->sl_mutex
);
85 (void) pthread_mutex_unlock(&delete_sessions_mutex
);
89 labelcmp(const void *a
, const void *b
)
91 objlabel_t
*obja
= (objlabel_t
*)a
;
92 objlabel_t
*objb
= (objlabel_t
*)b
;
95 if (obja
== NULL
|| obja
->label
== NULL
)
97 if (objb
== NULL
|| objb
->label
== NULL
)
100 n
= strcmp((char *)obja
->label
, (char *)objb
->label
);
109 * Create a new session struct, and add it to the slot's session list.
111 * This function is called by C_OpenSession(), which hold the slot lock.
114 kms_add_session(CK_SLOT_ID slotID
, CK_FLAGS flags
, CK_VOID_PTR pApplication
,
115 CK_NOTIFY notify
, CK_ULONG
*sessionhandle_p
)
117 kms_session_t
*new_sp
= NULL
;
121 /* Allocate a new session struct */
122 new_sp
= calloc(1, sizeof (kms_session_t
));
123 if (new_sp
== NULL
) {
124 return (CKR_HOST_MEMORY
);
127 new_sp
->magic_marker
= KMSTOKEN_SESSION_MAGIC
;
128 new_sp
->pApplication
= pApplication
;
129 new_sp
->Notify
= notify
;
130 new_sp
->flags
= flags
;
131 new_sp
->ses_RO
= (flags
& CKF_RW_SESSION
) ? B_FALSE
: B_TRUE
;
132 new_sp
->ses_slotid
= slotID
;
133 new_sp
->object_list
= NULL
;
134 new_sp
->ses_refcnt
= 0;
135 new_sp
->ses_close_sync
= 0;
137 avl_create(&new_sp
->objlabel_tree
, labelcmp
, sizeof (objlabel_t
),
138 KMSOFFSETOF(objlabel_t
, nodep
));
140 rv
= kms_reload_labels(new_sp
);
146 /* Initialize the lock for the newly created session */
147 if (pthread_mutex_init(&new_sp
->session_mutex
, NULL
) != 0) {
149 return (CKR_CANT_LOCK
);
152 pslot
= get_slotinfo();
154 (void) pthread_mutex_init(&new_sp
->ses_free_mutex
, NULL
);
155 (void) pthread_cond_init(&new_sp
->ses_free_cond
, NULL
);
157 /* Insert the new session in front of the slot's session list */
158 if (pslot
->sl_sess_list
== NULL
) {
159 pslot
->sl_sess_list
= new_sp
;
163 pslot
->sl_sess_list
->prev
= new_sp
;
164 new_sp
->next
= pslot
->sl_sess_list
;
166 pslot
->sl_sess_list
= new_sp
;
169 /* Type casting the address of a session struct to a session handle */
170 *sessionhandle_p
= (CK_ULONG
)new_sp
;
176 * - Remove the session from the slot's session list.
177 * - Release all the objects created by the session.
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 kms_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.
186 kms_delete_session(kms_session_t
*session_p
,
187 boolean_t slot_lock_held
, boolean_t wrapper_only
)
194 * Check to see if the caller holds the lock on the global
195 * session list. If not, we need to acquire that lock in
198 pslot
= get_slotinfo();
199 if (!slot_lock_held
) {
200 /* Acquire the slot lock */
201 (void) pthread_mutex_lock(&pslot
->sl_mutex
);
205 * Remove the session from the slot's session list first.
207 if (pslot
->sl_sess_list
== session_p
) {
208 /* Session is the first one in the list */
209 if (session_p
->next
) {
210 pslot
->sl_sess_list
= session_p
->next
;
211 session_p
->next
->prev
= NULL
;
213 /* Session is the only one in the list */
214 pslot
->sl_sess_list
= NULL
;
217 /* Session is not the first one in the list */
218 if (session_p
->next
) {
219 /* Session is in the middle of the list */
220 session_p
->prev
->next
= session_p
->next
;
221 session_p
->next
->prev
= session_p
->prev
;
223 /* Session is the last one in the list */
224 session_p
->prev
->next
= NULL
;
228 if (!slot_lock_held
) {
230 * If the slot lock is obtained by
231 * this function, then release that lock after
232 * removing the session from session linked list.
233 * We want the releasing of the objects of the
234 * session, and freeing of the session itself to
235 * be done without holding the slot's session list
238 (void) pthread_mutex_unlock(&pslot
->sl_mutex
);
241 /* Acquire the individual session lock */
242 (void) pthread_mutex_lock(&session_p
->session_mutex
);
245 * Make sure another thread hasn't freed the session.
247 if (session_p
->magic_marker
!= KMSTOKEN_SESSION_MAGIC
) {
248 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
253 * The deletion of a session must be blocked when the session reference
254 * count is not zero. This means that if the thread that is attempting
255 * to close the session must wait until the prior operations on this
256 * session are finished.
258 * Unless we are being forced to shut everything down, this only
259 * happens if the library's _fini() is running not if someone
260 * explicitly called C_Finalize().
262 (void) pthread_mutex_lock(&session_p
->ses_free_mutex
);
265 session_p
->ses_refcnt
= 0;
268 while (session_p
->ses_refcnt
!= 0) {
270 * We set the SESSION_REFCNT_WAITING flag before we put
271 * this closing thread in a wait state, so other non-closing
272 * operation thread will wake it up only when
273 * the session reference count becomes zero and this flag
276 session_p
->ses_close_sync
|= SESSION_REFCNT_WAITING
;
277 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
278 (void) pthread_cond_wait(&session_p
->ses_free_cond
,
279 &session_p
->ses_free_mutex
);
280 (void) pthread_mutex_lock(&session_p
->session_mutex
);
283 session_p
->ses_close_sync
&= ~SESSION_REFCNT_WAITING
;
285 /* Mark session as no longer valid. */
286 session_p
->magic_marker
= 0;
288 (void) pthread_mutex_unlock(&session_p
->ses_free_mutex
);
289 (void) pthread_mutex_destroy(&session_p
->ses_free_mutex
);
290 (void) pthread_cond_destroy(&session_p
->ses_free_cond
);
293 * Remove all the objects created in this session, waiting
294 * until each object's refcnt is 0.
296 kms_delete_all_objects_in_session(session_p
, wrapper_only
);
298 /* Close the KMS agent profile. */
299 KMS_UnloadProfile(&session_p
->kmsProfile
);
301 /* Reset SESSION_IS_CLOSING flag. */
302 session_p
->ses_close_sync
&= ~SESSION_IS_CLOSING
;
304 kms_clear_label_list(&session_p
->objlabel_tree
);
305 avl_destroy(&session_p
->objlabel_tree
);
307 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
308 /* Destroy the individual session lock */
309 (void) pthread_mutex_destroy(&session_p
->session_mutex
);
311 kms_session_delay_free(session_p
);
314 * If there is no more session remained in this slot, reset the slot's
315 * session state to CKU_PUBLIC. Also, clean up all the token object
316 * wrappers in the library for this slot.
318 /* Acquire the slot lock if lock is not held */
319 if (!slot_lock_held
) {
320 (void) pthread_mutex_lock(&pslot
->sl_mutex
);
323 if (pslot
->sl_sess_list
== NULL
) {
324 /* Reset the session auth state. */
325 pslot
->sl_state
= CKU_PUBLIC
;
327 /* Clean up token object wrappers. */
328 objp
= pslot
->sl_tobj_list
;
331 (void) pthread_mutex_destroy(&objp
->object_mutex
);
332 (void) kms_cleanup_object(objp
);
336 pslot
->sl_tobj_list
= NULL
;
339 /* Release the slot lock if lock is not held */
340 if (!slot_lock_held
) {
341 (void) pthread_mutex_unlock(&pslot
->sl_mutex
);
346 * This function is used to type cast a session handle to a pointer to
347 * the session struct. Also, it does the following things:
348 * 1) Check to see if the session struct is tagged with a session
349 * magic number. This is to detect when an application passes
350 * a bogus session pointer.
351 * 2) Acquire the locks on the designated session.
352 * 3) Check to see if the session is in the closing state that another
353 * thread is performing.
354 * 4) Increment the session reference count by one. This is to prevent
355 * this session from being closed by other thread.
356 * 5) Release the locks on the designated session.
359 handle2session(CK_SESSION_HANDLE hSession
, kms_session_t
**session_p
)
361 kms_session_t
*sp
= (kms_session_t
*)(hSession
);
365 (sp
->magic_marker
!= KMSTOKEN_SESSION_MAGIC
)) {
366 return (CKR_SESSION_HANDLE_INVALID
);
368 (void) pthread_mutex_lock(&sp
->session_mutex
);
369 if (sp
->ses_close_sync
& SESSION_IS_CLOSING
) {
370 rv
= CKR_SESSION_CLOSED
;
372 /* Increment session ref count. */
376 (void) pthread_mutex_unlock(&sp
->session_mutex
);
386 * This function adds the to-be-freed session to a linked list.
387 * When the number of sessions queued in the linked list reaches the
388 * maximum threshold MAX_SES_TO_BE_FREED, it will free the first
389 * session (FIFO) in the list.
392 kms_session_delay_free(kms_session_t
*sp
)
396 (void) pthread_mutex_lock(&ses_delay_freed
.ses_to_be_free_mutex
);
398 /* Add the newly deleted session at the end of the list */
400 if (ses_delay_freed
.first
== NULL
) {
401 ses_delay_freed
.last
= sp
;
402 ses_delay_freed
.first
= sp
;
404 ses_delay_freed
.last
->next
= sp
;
405 ses_delay_freed
.last
= sp
;
408 if (++ses_delay_freed
.count
>= MAX_SES_TO_BE_FREED
) {
410 * Free the first session in the list only if
411 * the total count reaches maximum threshold.
413 ses_delay_freed
.count
--;
414 tmp
= ses_delay_freed
.first
->next
;
415 free(ses_delay_freed
.first
);
416 ses_delay_freed
.first
= tmp
;
418 (void) pthread_mutex_unlock(&ses_delay_freed
.ses_to_be_free_mutex
);
422 * Acquire all slots' mutexes and all their sessions' mutexes.
424 * 1. delete_sessions_mutex
428 * 3. session_p->session_mutex
429 * 4. session_p->ses_free_mutex
432 kms_acquire_all_slots_mutexes()
435 kms_session_t
*session_p
;
437 (void) pthread_mutex_lock(&delete_sessions_mutex
);
439 pslot
= get_slotinfo();
440 (void) pthread_mutex_lock(&pslot
->sl_mutex
);
442 /* Iterate through sessions acquiring all mutexes */
443 session_p
= pslot
->sl_sess_list
;
447 (void) pthread_mutex_lock(&session_p
->session_mutex
);
448 (void) pthread_mutex_lock(&session_p
->ses_free_mutex
);
450 objp
= session_p
->object_list
;
452 (void) pthread_mutex_lock(&objp
->object_mutex
);
456 session_p
= session_p
->next
;
460 /* Release in opposite order to kms_acquire_all_slots_mutexes(). */
462 kms_release_all_slots_mutexes()
465 kms_session_t
*session_p
;
467 pslot
= get_slotinfo();
469 /* Iterate through sessions releasing all mutexes */
470 session_p
= pslot
->sl_sess_list
;
474 objp
= session_p
->object_list
;
476 (void) pthread_mutex_unlock(&objp
->object_mutex
);
480 (void) pthread_mutex_unlock(&session_p
->ses_free_mutex
);
481 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
482 session_p
= session_p
->next
;
486 * acquired in "acquire_all_slots_mutexes" which only
487 * happens just prior to a fork.
489 (void) pthread_mutex_unlock(&pslot
->sl_mutex
);
490 (void) pthread_mutex_unlock(&delete_sessions_mutex
);