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