1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/dev/devslot.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,260 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "pkcs11.h" 1.9 + 1.10 +#ifndef DEVM_H 1.11 +#include "devm.h" 1.12 +#endif /* DEVM_H */ 1.13 + 1.14 +#ifndef CKHELPER_H 1.15 +#include "ckhelper.h" 1.16 +#endif /* CKHELPER_H */ 1.17 + 1.18 +#include "pk11pub.h" 1.19 + 1.20 +/* measured in seconds */ 1.21 +#define NSSSLOT_TOKEN_DELAY_TIME 1 1.22 + 1.23 +/* this should track global and per-transaction login information */ 1.24 + 1.25 +#define NSSSLOT_IS_FRIENDLY(slot) \ 1.26 + (slot->base.flags & NSSSLOT_FLAGS_FRIENDLY) 1.27 + 1.28 +/* measured as interval */ 1.29 +static PRIntervalTime s_token_delay_time = 0; 1.30 + 1.31 +/* The flags needed to open a read-only session. */ 1.32 +static const CK_FLAGS s_ck_readonly_flags = CKF_SERIAL_SESSION; 1.33 + 1.34 +NSS_IMPLEMENT PRStatus 1.35 +nssSlot_Destroy ( 1.36 + NSSSlot *slot 1.37 +) 1.38 +{ 1.39 + if (slot) { 1.40 + if (PR_ATOMIC_DECREMENT(&slot->base.refCount) == 0) { 1.41 + PZ_DestroyLock(slot->base.lock); 1.42 + return nssArena_Destroy(slot->base.arena); 1.43 + } 1.44 + } 1.45 + return PR_SUCCESS; 1.46 +} 1.47 + 1.48 +void 1.49 +nssSlot_EnterMonitor(NSSSlot *slot) 1.50 +{ 1.51 + if (slot->lock) { 1.52 + PZ_Lock(slot->lock); 1.53 + } 1.54 +} 1.55 + 1.56 +void 1.57 +nssSlot_ExitMonitor(NSSSlot *slot) 1.58 +{ 1.59 + if (slot->lock) { 1.60 + PZ_Unlock(slot->lock); 1.61 + } 1.62 +} 1.63 + 1.64 +NSS_IMPLEMENT void 1.65 +NSSSlot_Destroy ( 1.66 + NSSSlot *slot 1.67 +) 1.68 +{ 1.69 + (void)nssSlot_Destroy(slot); 1.70 +} 1.71 + 1.72 +NSS_IMPLEMENT NSSSlot * 1.73 +nssSlot_AddRef ( 1.74 + NSSSlot *slot 1.75 +) 1.76 +{ 1.77 + PR_ATOMIC_INCREMENT(&slot->base.refCount); 1.78 + return slot; 1.79 +} 1.80 + 1.81 +NSS_IMPLEMENT NSSUTF8 * 1.82 +nssSlot_GetName ( 1.83 + NSSSlot *slot 1.84 +) 1.85 +{ 1.86 + return slot->base.name; 1.87 +} 1.88 + 1.89 +NSS_IMPLEMENT NSSUTF8 * 1.90 +nssSlot_GetTokenName ( 1.91 + NSSSlot *slot 1.92 +) 1.93 +{ 1.94 + return nssToken_GetName(slot->token); 1.95 +} 1.96 + 1.97 +NSS_IMPLEMENT void 1.98 +nssSlot_ResetDelay ( 1.99 + NSSSlot *slot 1.100 +) 1.101 +{ 1.102 + slot->lastTokenPing = 0; 1.103 +} 1.104 + 1.105 +static PRBool 1.106 +within_token_delay_period(NSSSlot *slot) 1.107 +{ 1.108 + PRIntervalTime time, lastTime; 1.109 + /* Set the delay time for checking the token presence */ 1.110 + if (s_token_delay_time == 0) { 1.111 + s_token_delay_time = PR_SecondsToInterval(NSSSLOT_TOKEN_DELAY_TIME); 1.112 + } 1.113 + time = PR_IntervalNow(); 1.114 + lastTime = slot->lastTokenPing; 1.115 + if ((lastTime) && ((time - lastTime) < s_token_delay_time)) { 1.116 + return PR_TRUE; 1.117 + } 1.118 + slot->lastTokenPing = time; 1.119 + return PR_FALSE; 1.120 +} 1.121 + 1.122 +NSS_IMPLEMENT PRBool 1.123 +nssSlot_IsTokenPresent ( 1.124 + NSSSlot *slot 1.125 +) 1.126 +{ 1.127 + CK_RV ckrv; 1.128 + PRStatus nssrv; 1.129 + /* XXX */ 1.130 + nssSession *session; 1.131 + CK_SLOT_INFO slotInfo; 1.132 + void *epv; 1.133 + /* permanent slots are always present unless they're disabled */ 1.134 + if (nssSlot_IsPermanent(slot)) { 1.135 + return !PK11_IsDisabled(slot->pk11slot); 1.136 + } 1.137 + /* avoid repeated calls to check token status within set interval */ 1.138 + if (within_token_delay_period(slot)) { 1.139 + return ((slot->ckFlags & CKF_TOKEN_PRESENT) != 0); 1.140 + } 1.141 + 1.142 + /* First obtain the slot info */ 1.143 + epv = slot->epv; 1.144 + if (!epv) { 1.145 + return PR_FALSE; 1.146 + } 1.147 + nssSlot_EnterMonitor(slot); 1.148 + ckrv = CKAPI(epv)->C_GetSlotInfo(slot->slotID, &slotInfo); 1.149 + nssSlot_ExitMonitor(slot); 1.150 + if (ckrv != CKR_OK) { 1.151 + slot->token->base.name[0] = 0; /* XXX */ 1.152 + return PR_FALSE; 1.153 + } 1.154 + slot->ckFlags = slotInfo.flags; 1.155 + /* check for the presence of the token */ 1.156 + if ((slot->ckFlags & CKF_TOKEN_PRESENT) == 0) { 1.157 + if (!slot->token) { 1.158 + /* token was never present */ 1.159 + return PR_FALSE; 1.160 + } 1.161 + session = nssToken_GetDefaultSession(slot->token); 1.162 + if (session) { 1.163 + nssSession_EnterMonitor(session); 1.164 + /* token is not present */ 1.165 + if (session->handle != CK_INVALID_SESSION) { 1.166 + /* session is valid, close and invalidate it */ 1.167 + CKAPI(epv)->C_CloseSession(session->handle); 1.168 + session->handle = CK_INVALID_SESSION; 1.169 + } 1.170 + nssSession_ExitMonitor(session); 1.171 + } 1.172 + if (slot->token->base.name[0] != 0) { 1.173 + /* notify the high-level cache that the token is removed */ 1.174 + slot->token->base.name[0] = 0; /* XXX */ 1.175 + nssToken_NotifyCertsNotVisible(slot->token); 1.176 + } 1.177 + slot->token->base.name[0] = 0; /* XXX */ 1.178 + /* clear the token cache */ 1.179 + nssToken_Remove(slot->token); 1.180 + return PR_FALSE; 1.181 + } 1.182 + /* token is present, use the session info to determine if the card 1.183 + * has been removed and reinserted. 1.184 + */ 1.185 + session = nssToken_GetDefaultSession(slot->token); 1.186 + if (session) { 1.187 + PRBool isPresent = PR_FALSE; 1.188 + nssSession_EnterMonitor(session); 1.189 + if (session->handle != CK_INVALID_SESSION) { 1.190 + CK_SESSION_INFO sessionInfo; 1.191 + ckrv = CKAPI(epv)->C_GetSessionInfo(session->handle, &sessionInfo); 1.192 + if (ckrv != CKR_OK) { 1.193 + /* session is screwy, close and invalidate it */ 1.194 + CKAPI(epv)->C_CloseSession(session->handle); 1.195 + session->handle = CK_INVALID_SESSION; 1.196 + } 1.197 + } 1.198 + isPresent = session->handle != CK_INVALID_SESSION; 1.199 + nssSession_ExitMonitor(session); 1.200 + /* token not removed, finished */ 1.201 + if (isPresent) 1.202 + return PR_TRUE; 1.203 + } 1.204 + /* the token has been removed, and reinserted, or the slot contains 1.205 + * a token it doesn't recognize. invalidate all the old 1.206 + * information we had on this token, if we can't refresh, clear 1.207 + * the present flag */ 1.208 + nssToken_NotifyCertsNotVisible(slot->token); 1.209 + nssToken_Remove(slot->token); 1.210 + /* token has been removed, need to refresh with new session */ 1.211 + nssrv = nssSlot_Refresh(slot); 1.212 + if (nssrv != PR_SUCCESS) { 1.213 + slot->token->base.name[0] = 0; /* XXX */ 1.214 + slot->ckFlags &= ~CKF_TOKEN_PRESENT; 1.215 + return PR_FALSE; 1.216 + } 1.217 + return PR_TRUE; 1.218 +} 1.219 + 1.220 +NSS_IMPLEMENT void * 1.221 +nssSlot_GetCryptokiEPV ( 1.222 + NSSSlot *slot 1.223 +) 1.224 +{ 1.225 + return slot->epv; 1.226 +} 1.227 + 1.228 +NSS_IMPLEMENT NSSToken * 1.229 +nssSlot_GetToken ( 1.230 + NSSSlot *slot 1.231 +) 1.232 +{ 1.233 + if (nssSlot_IsTokenPresent(slot)) { 1.234 + return nssToken_AddRef(slot->token); 1.235 + } 1.236 + return (NSSToken *)NULL; 1.237 +} 1.238 + 1.239 +NSS_IMPLEMENT PRStatus 1.240 +nssSession_EnterMonitor ( 1.241 + nssSession *s 1.242 +) 1.243 +{ 1.244 + if (s->lock) PZ_Lock(s->lock); 1.245 + return PR_SUCCESS; 1.246 +} 1.247 + 1.248 +NSS_IMPLEMENT PRStatus 1.249 +nssSession_ExitMonitor ( 1.250 + nssSession *s 1.251 +) 1.252 +{ 1.253 + return (s->lock) ? PZ_Unlock(s->lock) : PR_SUCCESS; 1.254 +} 1.255 + 1.256 +NSS_EXTERN PRBool 1.257 +nssSession_IsReadWrite ( 1.258 + nssSession *s 1.259 +) 1.260 +{ 1.261 + return s->isRW; 1.262 +} 1.263 +