michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "pkcs11.h" michael@0: michael@0: #ifndef DEVM_H michael@0: #include "devm.h" michael@0: #endif /* DEVM_H */ michael@0: michael@0: #ifndef CKHELPER_H michael@0: #include "ckhelper.h" michael@0: #endif /* CKHELPER_H */ michael@0: michael@0: #include "pk11pub.h" michael@0: michael@0: /* measured in seconds */ michael@0: #define NSSSLOT_TOKEN_DELAY_TIME 1 michael@0: michael@0: /* this should track global and per-transaction login information */ michael@0: michael@0: #define NSSSLOT_IS_FRIENDLY(slot) \ michael@0: (slot->base.flags & NSSSLOT_FLAGS_FRIENDLY) michael@0: michael@0: /* measured as interval */ michael@0: static PRIntervalTime s_token_delay_time = 0; michael@0: michael@0: /* The flags needed to open a read-only session. */ michael@0: static const CK_FLAGS s_ck_readonly_flags = CKF_SERIAL_SESSION; michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: nssSlot_Destroy ( michael@0: NSSSlot *slot michael@0: ) michael@0: { michael@0: if (slot) { michael@0: if (PR_ATOMIC_DECREMENT(&slot->base.refCount) == 0) { michael@0: PZ_DestroyLock(slot->base.lock); michael@0: return nssArena_Destroy(slot->base.arena); michael@0: } michael@0: } michael@0: return PR_SUCCESS; michael@0: } michael@0: michael@0: void michael@0: nssSlot_EnterMonitor(NSSSlot *slot) michael@0: { michael@0: if (slot->lock) { michael@0: PZ_Lock(slot->lock); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nssSlot_ExitMonitor(NSSSlot *slot) michael@0: { michael@0: if (slot->lock) { michael@0: PZ_Unlock(slot->lock); michael@0: } michael@0: } michael@0: michael@0: NSS_IMPLEMENT void michael@0: NSSSlot_Destroy ( michael@0: NSSSlot *slot michael@0: ) michael@0: { michael@0: (void)nssSlot_Destroy(slot); michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSSlot * michael@0: nssSlot_AddRef ( michael@0: NSSSlot *slot michael@0: ) michael@0: { michael@0: PR_ATOMIC_INCREMENT(&slot->base.refCount); michael@0: return slot; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSUTF8 * michael@0: nssSlot_GetName ( michael@0: NSSSlot *slot michael@0: ) michael@0: { michael@0: return slot->base.name; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSUTF8 * michael@0: nssSlot_GetTokenName ( michael@0: NSSSlot *slot michael@0: ) michael@0: { michael@0: return nssToken_GetName(slot->token); michael@0: } michael@0: michael@0: NSS_IMPLEMENT void michael@0: nssSlot_ResetDelay ( michael@0: NSSSlot *slot michael@0: ) michael@0: { michael@0: slot->lastTokenPing = 0; michael@0: } michael@0: michael@0: static PRBool michael@0: within_token_delay_period(NSSSlot *slot) michael@0: { michael@0: PRIntervalTime time, lastTime; michael@0: /* Set the delay time for checking the token presence */ michael@0: if (s_token_delay_time == 0) { michael@0: s_token_delay_time = PR_SecondsToInterval(NSSSLOT_TOKEN_DELAY_TIME); michael@0: } michael@0: time = PR_IntervalNow(); michael@0: lastTime = slot->lastTokenPing; michael@0: if ((lastTime) && ((time - lastTime) < s_token_delay_time)) { michael@0: return PR_TRUE; michael@0: } michael@0: slot->lastTokenPing = time; michael@0: return PR_FALSE; michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRBool michael@0: nssSlot_IsTokenPresent ( michael@0: NSSSlot *slot michael@0: ) michael@0: { michael@0: CK_RV ckrv; michael@0: PRStatus nssrv; michael@0: /* XXX */ michael@0: nssSession *session; michael@0: CK_SLOT_INFO slotInfo; michael@0: void *epv; michael@0: /* permanent slots are always present unless they're disabled */ michael@0: if (nssSlot_IsPermanent(slot)) { michael@0: return !PK11_IsDisabled(slot->pk11slot); michael@0: } michael@0: /* avoid repeated calls to check token status within set interval */ michael@0: if (within_token_delay_period(slot)) { michael@0: return ((slot->ckFlags & CKF_TOKEN_PRESENT) != 0); michael@0: } michael@0: michael@0: /* First obtain the slot info */ michael@0: epv = slot->epv; michael@0: if (!epv) { michael@0: return PR_FALSE; michael@0: } michael@0: nssSlot_EnterMonitor(slot); michael@0: ckrv = CKAPI(epv)->C_GetSlotInfo(slot->slotID, &slotInfo); michael@0: nssSlot_ExitMonitor(slot); michael@0: if (ckrv != CKR_OK) { michael@0: slot->token->base.name[0] = 0; /* XXX */ michael@0: return PR_FALSE; michael@0: } michael@0: slot->ckFlags = slotInfo.flags; michael@0: /* check for the presence of the token */ michael@0: if ((slot->ckFlags & CKF_TOKEN_PRESENT) == 0) { michael@0: if (!slot->token) { michael@0: /* token was never present */ michael@0: return PR_FALSE; michael@0: } michael@0: session = nssToken_GetDefaultSession(slot->token); michael@0: if (session) { michael@0: nssSession_EnterMonitor(session); michael@0: /* token is not present */ michael@0: if (session->handle != CK_INVALID_SESSION) { michael@0: /* session is valid, close and invalidate it */ michael@0: CKAPI(epv)->C_CloseSession(session->handle); michael@0: session->handle = CK_INVALID_SESSION; michael@0: } michael@0: nssSession_ExitMonitor(session); michael@0: } michael@0: if (slot->token->base.name[0] != 0) { michael@0: /* notify the high-level cache that the token is removed */ michael@0: slot->token->base.name[0] = 0; /* XXX */ michael@0: nssToken_NotifyCertsNotVisible(slot->token); michael@0: } michael@0: slot->token->base.name[0] = 0; /* XXX */ michael@0: /* clear the token cache */ michael@0: nssToken_Remove(slot->token); michael@0: return PR_FALSE; michael@0: } michael@0: /* token is present, use the session info to determine if the card michael@0: * has been removed and reinserted. michael@0: */ michael@0: session = nssToken_GetDefaultSession(slot->token); michael@0: if (session) { michael@0: PRBool isPresent = PR_FALSE; michael@0: nssSession_EnterMonitor(session); michael@0: if (session->handle != CK_INVALID_SESSION) { michael@0: CK_SESSION_INFO sessionInfo; michael@0: ckrv = CKAPI(epv)->C_GetSessionInfo(session->handle, &sessionInfo); michael@0: if (ckrv != CKR_OK) { michael@0: /* session is screwy, close and invalidate it */ michael@0: CKAPI(epv)->C_CloseSession(session->handle); michael@0: session->handle = CK_INVALID_SESSION; michael@0: } michael@0: } michael@0: isPresent = session->handle != CK_INVALID_SESSION; michael@0: nssSession_ExitMonitor(session); michael@0: /* token not removed, finished */ michael@0: if (isPresent) michael@0: return PR_TRUE; michael@0: } michael@0: /* the token has been removed, and reinserted, or the slot contains michael@0: * a token it doesn't recognize. invalidate all the old michael@0: * information we had on this token, if we can't refresh, clear michael@0: * the present flag */ michael@0: nssToken_NotifyCertsNotVisible(slot->token); michael@0: nssToken_Remove(slot->token); michael@0: /* token has been removed, need to refresh with new session */ michael@0: nssrv = nssSlot_Refresh(slot); michael@0: if (nssrv != PR_SUCCESS) { michael@0: slot->token->base.name[0] = 0; /* XXX */ michael@0: slot->ckFlags &= ~CKF_TOKEN_PRESENT; michael@0: return PR_FALSE; michael@0: } michael@0: return PR_TRUE; michael@0: } michael@0: michael@0: NSS_IMPLEMENT void * michael@0: nssSlot_GetCryptokiEPV ( michael@0: NSSSlot *slot michael@0: ) michael@0: { michael@0: return slot->epv; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSToken * michael@0: nssSlot_GetToken ( michael@0: NSSSlot *slot michael@0: ) michael@0: { michael@0: if (nssSlot_IsTokenPresent(slot)) { michael@0: return nssToken_AddRef(slot->token); michael@0: } michael@0: return (NSSToken *)NULL; michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: nssSession_EnterMonitor ( michael@0: nssSession *s michael@0: ) michael@0: { michael@0: if (s->lock) PZ_Lock(s->lock); michael@0: return PR_SUCCESS; michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: nssSession_ExitMonitor ( michael@0: nssSession *s michael@0: ) michael@0: { michael@0: return (s->lock) ? PZ_Unlock(s->lock) : PR_SUCCESS; michael@0: } michael@0: michael@0: NSS_EXTERN PRBool michael@0: nssSession_IsReadWrite ( michael@0: nssSession *s michael@0: ) michael@0: { michael@0: return s->isRW; michael@0: } michael@0: