security/nss/lib/dev/devslot.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #include "pkcs11.h"
michael@0 6
michael@0 7 #ifndef DEVM_H
michael@0 8 #include "devm.h"
michael@0 9 #endif /* DEVM_H */
michael@0 10
michael@0 11 #ifndef CKHELPER_H
michael@0 12 #include "ckhelper.h"
michael@0 13 #endif /* CKHELPER_H */
michael@0 14
michael@0 15 #include "pk11pub.h"
michael@0 16
michael@0 17 /* measured in seconds */
michael@0 18 #define NSSSLOT_TOKEN_DELAY_TIME 1
michael@0 19
michael@0 20 /* this should track global and per-transaction login information */
michael@0 21
michael@0 22 #define NSSSLOT_IS_FRIENDLY(slot) \
michael@0 23 (slot->base.flags & NSSSLOT_FLAGS_FRIENDLY)
michael@0 24
michael@0 25 /* measured as interval */
michael@0 26 static PRIntervalTime s_token_delay_time = 0;
michael@0 27
michael@0 28 /* The flags needed to open a read-only session. */
michael@0 29 static const CK_FLAGS s_ck_readonly_flags = CKF_SERIAL_SESSION;
michael@0 30
michael@0 31 NSS_IMPLEMENT PRStatus
michael@0 32 nssSlot_Destroy (
michael@0 33 NSSSlot *slot
michael@0 34 )
michael@0 35 {
michael@0 36 if (slot) {
michael@0 37 if (PR_ATOMIC_DECREMENT(&slot->base.refCount) == 0) {
michael@0 38 PZ_DestroyLock(slot->base.lock);
michael@0 39 return nssArena_Destroy(slot->base.arena);
michael@0 40 }
michael@0 41 }
michael@0 42 return PR_SUCCESS;
michael@0 43 }
michael@0 44
michael@0 45 void
michael@0 46 nssSlot_EnterMonitor(NSSSlot *slot)
michael@0 47 {
michael@0 48 if (slot->lock) {
michael@0 49 PZ_Lock(slot->lock);
michael@0 50 }
michael@0 51 }
michael@0 52
michael@0 53 void
michael@0 54 nssSlot_ExitMonitor(NSSSlot *slot)
michael@0 55 {
michael@0 56 if (slot->lock) {
michael@0 57 PZ_Unlock(slot->lock);
michael@0 58 }
michael@0 59 }
michael@0 60
michael@0 61 NSS_IMPLEMENT void
michael@0 62 NSSSlot_Destroy (
michael@0 63 NSSSlot *slot
michael@0 64 )
michael@0 65 {
michael@0 66 (void)nssSlot_Destroy(slot);
michael@0 67 }
michael@0 68
michael@0 69 NSS_IMPLEMENT NSSSlot *
michael@0 70 nssSlot_AddRef (
michael@0 71 NSSSlot *slot
michael@0 72 )
michael@0 73 {
michael@0 74 PR_ATOMIC_INCREMENT(&slot->base.refCount);
michael@0 75 return slot;
michael@0 76 }
michael@0 77
michael@0 78 NSS_IMPLEMENT NSSUTF8 *
michael@0 79 nssSlot_GetName (
michael@0 80 NSSSlot *slot
michael@0 81 )
michael@0 82 {
michael@0 83 return slot->base.name;
michael@0 84 }
michael@0 85
michael@0 86 NSS_IMPLEMENT NSSUTF8 *
michael@0 87 nssSlot_GetTokenName (
michael@0 88 NSSSlot *slot
michael@0 89 )
michael@0 90 {
michael@0 91 return nssToken_GetName(slot->token);
michael@0 92 }
michael@0 93
michael@0 94 NSS_IMPLEMENT void
michael@0 95 nssSlot_ResetDelay (
michael@0 96 NSSSlot *slot
michael@0 97 )
michael@0 98 {
michael@0 99 slot->lastTokenPing = 0;
michael@0 100 }
michael@0 101
michael@0 102 static PRBool
michael@0 103 within_token_delay_period(NSSSlot *slot)
michael@0 104 {
michael@0 105 PRIntervalTime time, lastTime;
michael@0 106 /* Set the delay time for checking the token presence */
michael@0 107 if (s_token_delay_time == 0) {
michael@0 108 s_token_delay_time = PR_SecondsToInterval(NSSSLOT_TOKEN_DELAY_TIME);
michael@0 109 }
michael@0 110 time = PR_IntervalNow();
michael@0 111 lastTime = slot->lastTokenPing;
michael@0 112 if ((lastTime) && ((time - lastTime) < s_token_delay_time)) {
michael@0 113 return PR_TRUE;
michael@0 114 }
michael@0 115 slot->lastTokenPing = time;
michael@0 116 return PR_FALSE;
michael@0 117 }
michael@0 118
michael@0 119 NSS_IMPLEMENT PRBool
michael@0 120 nssSlot_IsTokenPresent (
michael@0 121 NSSSlot *slot
michael@0 122 )
michael@0 123 {
michael@0 124 CK_RV ckrv;
michael@0 125 PRStatus nssrv;
michael@0 126 /* XXX */
michael@0 127 nssSession *session;
michael@0 128 CK_SLOT_INFO slotInfo;
michael@0 129 void *epv;
michael@0 130 /* permanent slots are always present unless they're disabled */
michael@0 131 if (nssSlot_IsPermanent(slot)) {
michael@0 132 return !PK11_IsDisabled(slot->pk11slot);
michael@0 133 }
michael@0 134 /* avoid repeated calls to check token status within set interval */
michael@0 135 if (within_token_delay_period(slot)) {
michael@0 136 return ((slot->ckFlags & CKF_TOKEN_PRESENT) != 0);
michael@0 137 }
michael@0 138
michael@0 139 /* First obtain the slot info */
michael@0 140 epv = slot->epv;
michael@0 141 if (!epv) {
michael@0 142 return PR_FALSE;
michael@0 143 }
michael@0 144 nssSlot_EnterMonitor(slot);
michael@0 145 ckrv = CKAPI(epv)->C_GetSlotInfo(slot->slotID, &slotInfo);
michael@0 146 nssSlot_ExitMonitor(slot);
michael@0 147 if (ckrv != CKR_OK) {
michael@0 148 slot->token->base.name[0] = 0; /* XXX */
michael@0 149 return PR_FALSE;
michael@0 150 }
michael@0 151 slot->ckFlags = slotInfo.flags;
michael@0 152 /* check for the presence of the token */
michael@0 153 if ((slot->ckFlags & CKF_TOKEN_PRESENT) == 0) {
michael@0 154 if (!slot->token) {
michael@0 155 /* token was never present */
michael@0 156 return PR_FALSE;
michael@0 157 }
michael@0 158 session = nssToken_GetDefaultSession(slot->token);
michael@0 159 if (session) {
michael@0 160 nssSession_EnterMonitor(session);
michael@0 161 /* token is not present */
michael@0 162 if (session->handle != CK_INVALID_SESSION) {
michael@0 163 /* session is valid, close and invalidate it */
michael@0 164 CKAPI(epv)->C_CloseSession(session->handle);
michael@0 165 session->handle = CK_INVALID_SESSION;
michael@0 166 }
michael@0 167 nssSession_ExitMonitor(session);
michael@0 168 }
michael@0 169 if (slot->token->base.name[0] != 0) {
michael@0 170 /* notify the high-level cache that the token is removed */
michael@0 171 slot->token->base.name[0] = 0; /* XXX */
michael@0 172 nssToken_NotifyCertsNotVisible(slot->token);
michael@0 173 }
michael@0 174 slot->token->base.name[0] = 0; /* XXX */
michael@0 175 /* clear the token cache */
michael@0 176 nssToken_Remove(slot->token);
michael@0 177 return PR_FALSE;
michael@0 178 }
michael@0 179 /* token is present, use the session info to determine if the card
michael@0 180 * has been removed and reinserted.
michael@0 181 */
michael@0 182 session = nssToken_GetDefaultSession(slot->token);
michael@0 183 if (session) {
michael@0 184 PRBool isPresent = PR_FALSE;
michael@0 185 nssSession_EnterMonitor(session);
michael@0 186 if (session->handle != CK_INVALID_SESSION) {
michael@0 187 CK_SESSION_INFO sessionInfo;
michael@0 188 ckrv = CKAPI(epv)->C_GetSessionInfo(session->handle, &sessionInfo);
michael@0 189 if (ckrv != CKR_OK) {
michael@0 190 /* session is screwy, close and invalidate it */
michael@0 191 CKAPI(epv)->C_CloseSession(session->handle);
michael@0 192 session->handle = CK_INVALID_SESSION;
michael@0 193 }
michael@0 194 }
michael@0 195 isPresent = session->handle != CK_INVALID_SESSION;
michael@0 196 nssSession_ExitMonitor(session);
michael@0 197 /* token not removed, finished */
michael@0 198 if (isPresent)
michael@0 199 return PR_TRUE;
michael@0 200 }
michael@0 201 /* the token has been removed, and reinserted, or the slot contains
michael@0 202 * a token it doesn't recognize. invalidate all the old
michael@0 203 * information we had on this token, if we can't refresh, clear
michael@0 204 * the present flag */
michael@0 205 nssToken_NotifyCertsNotVisible(slot->token);
michael@0 206 nssToken_Remove(slot->token);
michael@0 207 /* token has been removed, need to refresh with new session */
michael@0 208 nssrv = nssSlot_Refresh(slot);
michael@0 209 if (nssrv != PR_SUCCESS) {
michael@0 210 slot->token->base.name[0] = 0; /* XXX */
michael@0 211 slot->ckFlags &= ~CKF_TOKEN_PRESENT;
michael@0 212 return PR_FALSE;
michael@0 213 }
michael@0 214 return PR_TRUE;
michael@0 215 }
michael@0 216
michael@0 217 NSS_IMPLEMENT void *
michael@0 218 nssSlot_GetCryptokiEPV (
michael@0 219 NSSSlot *slot
michael@0 220 )
michael@0 221 {
michael@0 222 return slot->epv;
michael@0 223 }
michael@0 224
michael@0 225 NSS_IMPLEMENT NSSToken *
michael@0 226 nssSlot_GetToken (
michael@0 227 NSSSlot *slot
michael@0 228 )
michael@0 229 {
michael@0 230 if (nssSlot_IsTokenPresent(slot)) {
michael@0 231 return nssToken_AddRef(slot->token);
michael@0 232 }
michael@0 233 return (NSSToken *)NULL;
michael@0 234 }
michael@0 235
michael@0 236 NSS_IMPLEMENT PRStatus
michael@0 237 nssSession_EnterMonitor (
michael@0 238 nssSession *s
michael@0 239 )
michael@0 240 {
michael@0 241 if (s->lock) PZ_Lock(s->lock);
michael@0 242 return PR_SUCCESS;
michael@0 243 }
michael@0 244
michael@0 245 NSS_IMPLEMENT PRStatus
michael@0 246 nssSession_ExitMonitor (
michael@0 247 nssSession *s
michael@0 248 )
michael@0 249 {
michael@0 250 return (s->lock) ? PZ_Unlock(s->lock) : PR_SUCCESS;
michael@0 251 }
michael@0 252
michael@0 253 NSS_EXTERN PRBool
michael@0 254 nssSession_IsReadWrite (
michael@0 255 nssSession *s
michael@0 256 )
michael@0 257 {
michael@0 258 return s->isRW;
michael@0 259 }
michael@0 260

mercurial