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

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

mercurial