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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 * Functions for dealing with provider sessions
33 #include <cryptoutil.h>
34 #include "metaGlobal.h"
35 #include "pkcs11Session.h"
36 #include "pkcs11Global.h"
40 * This is just a **WILD** guess for the maximum idle sessions to
41 * keep for each slot. This number should probably be adjusted
42 * when there's more data from actual application use
44 #define MAX_IDLE_SESSIONS 100
47 * The following 5 variables are initialized at the time metaslot
48 * is initialized. They are not modified after they are initialized
50 * During initialization time, they are protected by the "initmutex"
51 * defined in metaGeneral.c
54 CK_SLOT_ID metaslot_keystore_slotid
;
55 static CK_ULONG num_slots
;
56 static CK_ULONG objtok_slotnum
;
57 static CK_ULONG softtoken_slotnum
;
58 static boolean_t write_protected
;
60 /* protects the "metaslotLoggedIn" variable */
61 static pthread_mutex_t metaslotLoggedIn_mutex
= PTHREAD_MUTEX_INITIALIZER
;
62 static boolean_t metaslotLoggedIn
;
65 * meta_slotManager_initialize
67 * Called from C_Initialize. Allocates and initializes the storage needed
68 * by the slot manager.
71 meta_slotManager_initialize() {
72 CK_ULONG slot_count
= 0;
76 /* Initialize the static variables */
77 write_protected
= B_FALSE
;
78 metaslotLoggedIn
= B_FALSE
;
81 * Count the number of slots in the framework.
82 * We start at ((slottable->st_first) + 1) instead of
83 * slottable->st_first because when we are here, metaslot is
84 * enabled, and st_first is always metaslot, which doesn't
87 for (i
= (slottable
->st_first
) + 1; i
<= slottable
->st_last
; i
++) {
92 * This shouldn't happen, because there should at least
93 * be 1 other slot besides metaslot.
96 rv
= CKR_FUNCTION_FAILED
;
100 slots
= calloc(slot_count
, sizeof (slot_data_t
));
102 rv
= CKR_HOST_MEMORY
;
107 * Store the slot IDs. Adjust for the fact that the first slot is
108 * actually us (metaslot).
110 for (i
= 0; i
< slot_count
; i
++) {
111 slots
[i
].fw_st_id
= i
+ 1;
112 (void) pthread_rwlock_init(
113 &(slots
[i
].tokenobject_list_lock
), NULL
);
115 num_slots
= slot_count
;
132 * meta_slotManager_finalize
134 * Called from C_Finalize. Deallocates any storage held by the slot manager.
137 meta_slotManager_finalize() {
140 /* If no slots to free, return */
144 * No need to lock pool, we assume all meta sessions are closed.
146 * Close all sessions in the idle and persist list.
147 * The active list is empty. It doesn't need to be checked.
150 for (slot
= 0; slot
< num_slots
; slot
++) {
151 slot_session_t
*session
, *next_session
;
154 * The slotobjects associated with the session should have
155 * been closed when the metaobjects were closed. Thus, no
156 * need to do anything here.
159 session
= slots
[slot
].session_pool
.idle_list_head
;
161 next_session
= session
->next
;
162 (void) FUNCLIST(session
->fw_st_id
)->C_CloseSession(
164 (void) pthread_rwlock_destroy(
165 &session
->object_list_lock
);
167 session
= next_session
;
170 session
= slots
[slot
].session_pool
.persist_list_head
;
172 next_session
= session
->next
;
173 (void) FUNCLIST(session
->fw_st_id
)->C_CloseSession(
175 (void) pthread_rwlock_destroy(
176 &session
->object_list_lock
);
178 session
= next_session
;
181 (void) pthread_rwlock_destroy(
182 &slots
[slot
].tokenobject_list_lock
);
192 * meta_slotManager_find_object_token()
194 * Called from meta_Initialize. Searches for the "object token," which is used
195 * for storing token objects and loging into.
197 * We do the search using the following algorithm.
199 * If either ${METASLOT_OBJECTSTORE_SLOT} or ${METASLOT_OBJECTSTORE_TOKEN}
200 * environment variable is defined, the value of the defined variable(s)
201 * will be used for the match. All token and slot values defined system-wide
204 * If neither variables above are defined, the system-wide values defined
205 * in pkcs11.conf are used.
207 * If neither environment variables or system-wide values are defined,
208 * or if none of the existing slots/tokens match the defined
209 * values, the first slot after metaslot will be used as the default.
213 meta_slotManager_find_object_token() {
215 boolean_t found
= B_FALSE
;
217 unsigned int num_match_needed
= 0;
218 CK_SLOT_INFO slotinfo
;
219 CK_TOKEN_INFO tokeninfo
;
221 if (metaslot_config
.keystore_token_specified
) {
225 if (metaslot_config
.keystore_slot_specified
) {
229 if (num_match_needed
== 0) {
233 for (slot
= 0; slot
< num_slots
; slot
++) {
234 unsigned int num_matched
= 0;
235 boolean_t have_tokeninfo
= B_FALSE
;
236 CK_SLOT_ID true_id
, fw_st_id
;
238 fw_st_id
= slots
[slot
].fw_st_id
;
239 true_id
= TRUEID(fw_st_id
);
241 (void) memset(&slotinfo
, 0, sizeof (CK_SLOT_INFO
));
242 rv
= FUNCLIST(fw_st_id
)->C_GetSlotInfo(true_id
,
247 if (strncmp((char *)SOFT_SLOT_DESCRIPTION
,
248 (char *)slotinfo
.slotDescription
,
249 SLOT_DESCRIPTION_SIZE
) == 0) {
250 softtoken_slotnum
= slot
;
253 if (metaslot_config
.keystore_slot_specified
) {
258 rv
= FUNCLIST(fw_st_id
)->C_GetSlotInfo(true_id
,
264 * pad slot description from user/system configuration
267 slot
= metaslot_config
.keystore_slot
;
268 slot_str_len
= strlen((char *)slot
);
269 (void) memset(slot
+ slot_str_len
, ' ',
270 SLOT_DESCRIPTION_SIZE
- slot_str_len
);
273 * The PKCS#11 strings are not null-terminated, so,
274 * we just compare SLOT_DESCRIPTION_SIZE bytes
276 if (strncmp((char *)slot
,
277 (char *)slotinfo
.slotDescription
,
278 SLOT_DESCRIPTION_SIZE
) == 0) {
283 if (metaslot_config
.keystore_token_specified
) {
284 unsigned char *token
;
285 size_t token_str_len
;
287 rv
= FUNCLIST(fw_st_id
)->C_GetTokenInfo(true_id
,
294 have_tokeninfo
= B_TRUE
;
297 * pad slot description from user/system configuration
300 token
= metaslot_config
.keystore_token
;
301 token_str_len
= strlen((char *)token
);
302 (void) memset(token
+ token_str_len
, ' ',
303 TOKEN_LABEL_SIZE
- token_str_len
);
306 * The PKCS#11 strings are not null-terminated.
307 * So, just compare TOKEN_LABEL_SIZE bytes
309 if (strncmp((char *)token
, (char *)tokeninfo
.label
,
310 TOKEN_LABEL_SIZE
) == 0) {
315 if (num_match_needed
== num_matched
) {
318 if (!have_tokeninfo
) {
319 rv
= FUNCLIST(fw_st_id
)->C_GetTokenInfo(true_id
,
327 if (tokeninfo
.flags
& CKF_WRITE_PROTECTED
) {
329 * Currently this is the only time that
330 * the write_protected state is set, and
331 * it is never cleared. The token could
332 * clear (or set!) this flag later on.
333 * We might want to adjust the state
334 * of metaslot, but there's know way to know
335 * when a token changes this flag.
337 write_protected
= B_TRUE
;
347 objtok_slotnum
= slot
;
350 * if slot and/or token is not defined for the keystore,
351 * just use the first available slot as keystore
355 slots
[objtok_slotnum
].session_pool
.keep_one_alive
= B_TRUE
;
356 metaslot_keystore_slotid
= slots
[objtok_slotnum
].fw_st_id
;
361 get_keystore_slotnum()
363 return (objtok_slotnum
);
367 get_softtoken_slotnum()
369 return (softtoken_slotnum
);
373 meta_slotManager_get_framework_table_id(CK_ULONG slotnum
)
376 * This is only used internally, and so the slotnum should always
379 return (slots
[slotnum
].fw_st_id
);
383 meta_slotManager_get_slotcount()
389 meta_slotManager_token_write_protected()
391 return (write_protected
);
395 * Find a session in the given list that matches the specified flags.
396 * If such a session is found, it will be removed from the list, and
397 * returned to the caller. If such a session is not found, will
400 static slot_session_t
*
401 get_session(slot_session_t
**session_list
, CK_FLAGS flags
)
404 slot_session_t
*tmp_session
;
406 tmp_session
= *session_list
;
408 while (tmp_session
!= NULL
) {
409 if (tmp_session
->session_flags
== flags
) {
412 tmp_session
= tmp_session
->next
;
417 if (tmp_session
== NULL
) {
422 /* Remove from list */
423 REMOVE_FROM_LIST(*session_list
, tmp_session
);
424 return (tmp_session
);
428 * meta_get_slot_session
430 * Call to get a session with a specific slot/token.
432 * NOTE - We assume the slot allows an unlimited number of sessions. We
433 * could look at what's reported in the token info, but that information is
434 * not always set. It's also unclear when we should (A) wait for one to become
435 * available, (B) skip the slot for now or (C) return a fatal error. The
436 * extra complexity is not worth it.
440 meta_get_slot_session(CK_ULONG slotnum
, slot_session_t
**session
,
442 session_pool_t
*pool
;
443 slot_session_t
*new_session
, *tmp_session
;
445 CK_SLOT_ID fw_st_id
, true_id
;
447 if (slotnum
>= num_slots
) {
448 return (CKR_SLOT_ID_INVALID
);
451 pool
= &slots
[slotnum
].session_pool
;
454 * Try to reuse an existing session.
457 (void) pthread_mutex_lock(&pool
->list_lock
);
459 if (pool
->idle_list_head
!= NULL
) {
460 tmp_session
= get_session(&(pool
->idle_list_head
), flags
);
461 if (tmp_session
!= NULL
) {
462 /* Add to active list */
463 INSERT_INTO_LIST(pool
->active_list_head
, tmp_session
);
464 *session
= tmp_session
;
465 pool
->num_idle_sessions
--;
466 (void) pthread_mutex_unlock(&pool
->list_lock
);
471 if (pool
->persist_list_head
!= NULL
) {
472 tmp_session
= get_session(&(pool
->persist_list_head
), flags
);
473 if (tmp_session
!= NULL
) {
474 /* Add to active list */
475 INSERT_INTO_LIST(pool
->active_list_head
, tmp_session
);
476 *session
= tmp_session
;
477 (void) pthread_mutex_unlock(&pool
->list_lock
);
481 (void) pthread_mutex_unlock(&pool
->list_lock
);
483 fw_st_id
= slots
[slotnum
].fw_st_id
;
484 true_id
= TRUEID(fw_st_id
);
486 new_session
= calloc(1, sizeof (slot_session_t
));
487 if (new_session
== NULL
) {
488 return (CKR_HOST_MEMORY
);
491 /* initialize slotsession */
492 new_session
->slotnum
= slotnum
;
493 new_session
->fw_st_id
= fw_st_id
;
494 new_session
->object_list_head
= NULL
;
495 new_session
->session_flags
= flags
;
496 (void) pthread_rwlock_init(&new_session
->object_list_lock
, NULL
);
498 rv
= FUNCLIST(fw_st_id
)->C_OpenSession(true_id
, flags
, NULL
, NULL
,
499 &new_session
->hSession
);
501 if (rv
== CKR_TOKEN_WRITE_PROTECTED
) {
502 /* Retry with a RO session. */
503 new_session
->session_flags
&= ~CKF_SERIAL_SESSION
;
504 rv
= FUNCLIST(fw_st_id
)->C_OpenSession(true_id
,
505 new_session
->session_flags
, NULL
, NULL
,
506 &new_session
->hSession
);
511 return (CKR_FUNCTION_FAILED
);
514 /* Insert session into active list */
515 (void) pthread_mutex_lock(&pool
->list_lock
);
516 INSERT_INTO_LIST(pool
->active_list_head
, new_session
);
517 (void) pthread_mutex_unlock(&pool
->list_lock
);
518 *session
= new_session
;
524 * meta_release_slot_session
526 * Call to release a session obtained via meta_get_slot_session()
529 meta_release_slot_session(slot_session_t
*session
) {
530 session_pool_t
*pool
;
531 boolean_t must_retain
, can_close
= B_FALSE
;
532 boolean_t this_is_last_session
= B_FALSE
;
534 pool
= &slots
[session
->slotnum
].session_pool
;
536 /* Note that the active_list must have >= 1 entry (this session) */
537 if (pool
->persist_list_head
== NULL
&&
538 pool
->idle_list_head
== NULL
&&
539 pool
->active_list_head
->next
== NULL
)
540 this_is_last_session
= B_TRUE
;
543 * If the session has session objects, we need to retain it. Also
544 * retain it if it's the only session holding login state (or handles
545 * to public token objects)
547 must_retain
= session
->object_list_head
!= NULL
||
548 (pool
->keep_one_alive
&& this_is_last_session
);
550 if ((!must_retain
) && (pool
->num_idle_sessions
> MAX_IDLE_SESSIONS
)) {
554 (void) pthread_mutex_lock(&pool
->list_lock
);
555 /* remove from active list */
556 REMOVE_FROM_LIST(pool
->active_list_head
, session
);
559 /* insert into persist list */
560 INSERT_INTO_LIST(pool
->persist_list_head
, session
);
561 (void) pthread_mutex_unlock(&pool
->list_lock
);
563 } else if (!can_close
) {
564 /* insert into idle list */
565 INSERT_INTO_LIST(pool
->idle_list_head
, session
);
566 pool
->num_idle_sessions
++;
567 (void) pthread_mutex_unlock(&pool
->list_lock
);
571 (void) pthread_mutex_unlock(&pool
->list_lock
);
573 (void) FUNCLIST(session
->fw_st_id
)->C_CloseSession(session
->hSession
);
575 (void) pthread_rwlock_destroy(&session
->object_list_lock
);
580 * Returns whether metaslot has directly logged in
585 return (metaslotLoggedIn
);
589 metaslot_set_logged_in_flag(boolean_t value
)
591 (void) pthread_mutex_lock(&metaslotLoggedIn_mutex
);
592 metaslotLoggedIn
= value
;
593 (void) pthread_mutex_unlock(&metaslotLoggedIn_mutex
);