Back to index

lightning-sunbird  0.9+nobinonly
devslot.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #ifdef DEBUG
00038 static const char CVS_ID[] = "@(#) $RCSfile: devslot.c,v $ $Revision: 1.22 $ $Date: 2005/09/14 01:35:02 $";
00039 #endif /* DEBUG */
00040 
00041 #ifndef NSSCKEPV_H
00042 #include "nssckepv.h"
00043 #endif /* NSSCKEPV_H */
00044 
00045 #ifndef DEVM_H
00046 #include "devm.h"
00047 #endif /* DEVM_H */
00048 
00049 #ifndef CKHELPER_H
00050 #include "ckhelper.h"
00051 #endif /* CKHELPER_H */
00052 
00053 /* measured in seconds */
00054 #define NSSSLOT_TOKEN_DELAY_TIME 1
00055 
00056 /* this should track global and per-transaction login information */
00057 
00058 #ifdef PURE_STAN_CODE
00059 typedef enum {
00060   nssSlotAskPasswordTimes_FirstTime = 0,
00061   nssSlotAskPasswordTimes_EveryTime = 1,
00062   nssSlotAskPasswordTimes_Timeout = 2
00063 } 
00064 nssSlotAskPasswordTimes;
00065 
00066 struct nssSlotAuthInfoStr
00067 {
00068   PRTime lastLogin;
00069   nssSlotAskPasswordTimes askTimes;
00070   PRIntervalTime askPasswordTimeout;
00071 };
00072 
00073 struct NSSSlotStr
00074 {
00075   struct nssDeviceBaseStr base;
00076   NSSModule *module; /* Parent */
00077   NSSToken *token;  /* Peer */
00078   CK_SLOT_ID slotID;
00079   CK_FLAGS ckFlags; /* from CK_SLOT_INFO.flags */
00080   struct nssSlotAuthInfoStr authInfo;
00081   PRIntervalTime lastTokenPing;
00082   PZLock *lock;
00083 #ifdef NSS_3_4_CODE
00084   PK11SlotInfo *pk11slot;
00085 #endif
00086 };
00087 #endif /* PURE_STAN_CODE */
00088 
00089 #define NSSSLOT_IS_FRIENDLY(slot) \
00090   (slot->base.flags & NSSSLOT_FLAGS_FRIENDLY)
00091 
00092 /* measured as interval */
00093 static PRIntervalTime s_token_delay_time = 0;
00094 
00095 /* The flags needed to open a read-only session. */
00096 static const CK_FLAGS s_ck_readonly_flags = CKF_SERIAL_SESSION;
00097 
00098 #ifdef PURE_STAN_BUILD
00099 /* In pk11slot.c, this was a no-op.  So it is here also. */
00100 static CK_RV PR_CALLBACK
00101 nss_ck_slot_notify (
00102   CK_SESSION_HANDLE session,
00103   CK_NOTIFICATION event,
00104   CK_VOID_PTR pData
00105 )
00106 {
00107     return CKR_OK;
00108 }
00109 
00110 NSS_IMPLEMENT NSSSlot *
00111 nssSlot_Create (
00112   CK_SLOT_ID slotID,
00113   NSSModule *parent
00114 )
00115 {
00116     NSSArena *arena = NULL;
00117     NSSSlot *rvSlot;
00118     NSSToken *token = NULL;
00119     NSSUTF8 *slotName = NULL;
00120     PRUint32 length;
00121     CK_SLOT_INFO slotInfo;
00122     CK_RV ckrv;
00123     void *epv;
00124     arena = NSSArena_Create();
00125     if(!arena) {
00126        return (NSSSlot *)NULL;
00127     }
00128     rvSlot = nss_ZNEW(arena, NSSSlot);
00129     if (!rvSlot) {
00130        goto loser;
00131     }
00132     /* Get slot information */
00133     epv = nssModule_GetCryptokiEPV(parent);
00134     ckrv = CKAPI(epv)->C_GetSlotInfo(slotID, &slotInfo);
00135     if (ckrv != CKR_OK) {
00136        /* set an error here, eh? */
00137        goto loser;
00138     }
00139     /* Grab the slot description from the PKCS#11 fixed-length buffer */
00140     length = nssPKCS11String_Length(slotInfo.slotDescription, 
00141                                     sizeof(slotInfo.slotDescription));
00142     if (length > 0) {
00143        slotName = nssUTF8_Create(arena, nssStringType_UTF8String, 
00144                                  (void *)slotInfo.slotDescription, length);
00145        if (!slotName) {
00146            goto loser;
00147        }
00148     }
00149     rvSlot->base.arena = arena;
00150     rvSlot->base.refCount = 1;
00151     rvSlot->base.name = slotName;
00152     rvSlot->base.lock = PZ_NewLock(nssNSSILockOther); /* XXX */
00153     if (!rvSlot->base.lock) {
00154        goto loser;
00155     }
00156     if (!nssModule_IsThreadSafe(parent)) {
00157        rvSlot->lock = nssModule_GetLock(parent);
00158     }
00159     rvSlot->module = parent; /* refs go from module to slots */
00160     rvSlot->slotID = slotID;
00161     rvSlot->ckFlags = slotInfo.flags;
00162     /* Initialize the token if present. */
00163     if (slotInfo.flags & CKF_TOKEN_PRESENT) {
00164        token = nssToken_Create(slotID, rvSlot);
00165        if (!token) {
00166            goto loser;
00167        }
00168     }
00169     rvSlot->token = token;
00170     return rvSlot;
00171 loser:
00172     nssArena_Destroy(arena);
00173     /* everything was created in the arena, nothing to see here, move along */
00174     return (NSSSlot *)NULL;
00175 }
00176 #endif /* PURE_STAN_BUILD */
00177 
00178 NSS_IMPLEMENT PRStatus
00179 nssSlot_Destroy (
00180   NSSSlot *slot
00181 )
00182 {
00183     if (slot) {
00184        if (PR_AtomicDecrement(&slot->base.refCount) == 0) {
00185            PZ_DestroyLock(slot->base.lock);
00186 #ifdef PURE_STAN_BUILD
00187            nssToken_Destroy(slot->token);
00188            nssModule_DestroyFromSlot(slot->module, slot);
00189 #endif
00190            return nssArena_Destroy(slot->base.arena);
00191        }
00192     }
00193     return PR_SUCCESS;
00194 }
00195 
00196 void
00197 nssSlot_EnterMonitor(NSSSlot *slot)
00198 {
00199     if (slot->lock) {
00200        PZ_Lock(slot->lock);
00201     }
00202 }
00203 
00204 void
00205 nssSlot_ExitMonitor(NSSSlot *slot)
00206 {
00207     if (slot->lock) {
00208        PZ_Unlock(slot->lock);
00209     }
00210 }
00211 
00212 NSS_IMPLEMENT void
00213 NSSSlot_Destroy (
00214   NSSSlot *slot
00215 )
00216 {
00217     (void)nssSlot_Destroy(slot);
00218 }
00219 
00220 NSS_IMPLEMENT NSSSlot *
00221 nssSlot_AddRef (
00222   NSSSlot *slot
00223 )
00224 {
00225     PR_AtomicIncrement(&slot->base.refCount);
00226     return slot;
00227 }
00228 
00229 NSS_IMPLEMENT NSSUTF8 *
00230 nssSlot_GetName (
00231   NSSSlot *slot
00232 )
00233 {
00234     return slot->base.name;
00235 }
00236 
00237 NSS_IMPLEMENT NSSUTF8 *
00238 nssSlot_GetTokenName (
00239   NSSSlot *slot
00240 )
00241 {
00242     return nssToken_GetName(slot->token);
00243 }
00244 
00245 NSS_IMPLEMENT void
00246 nssSlot_ResetDelay (
00247   NSSSlot *slot
00248 )
00249 {
00250     slot->lastTokenPing = 0;
00251 }
00252 
00253 static PRBool
00254 within_token_delay_period(NSSSlot *slot)
00255 {
00256     PRIntervalTime time, lastTime;
00257     /* Set the delay time for checking the token presence */
00258     if (s_token_delay_time == 0) {
00259        s_token_delay_time = PR_SecondsToInterval(NSSSLOT_TOKEN_DELAY_TIME);
00260     }
00261     time = PR_IntervalNow();
00262     lastTime = slot->lastTokenPing;
00263     if ((lastTime) && ((time - lastTime) < s_token_delay_time)) {
00264        return PR_TRUE;
00265     }
00266     slot->lastTokenPing = time;
00267     return PR_FALSE;
00268 }
00269 
00270 NSS_IMPLEMENT PRBool
00271 nssSlot_IsTokenPresent (
00272   NSSSlot *slot
00273 )
00274 {
00275     CK_RV ckrv;
00276     PRStatus nssrv;
00277     /* XXX */
00278     nssSession *session;
00279     CK_SLOT_INFO slotInfo;
00280     void *epv;
00281     /* permanent slots are always present */
00282     if (nssSlot_IsPermanent(slot)) {
00283        return PR_TRUE;
00284     }
00285     /* avoid repeated calls to check token status within set interval */
00286     if (within_token_delay_period(slot)) {
00287        return (PRBool)((slot->ckFlags & CKF_TOKEN_PRESENT) != 0);
00288     }
00289 
00290     /* First obtain the slot info */
00291 #ifdef PURE_STAN_BUILD
00292     epv = nssModule_GetCryptokiEPV(slot->module);
00293 #else
00294     epv = slot->epv;
00295 #endif
00296     if (!epv) {
00297        return PR_FALSE;
00298     }
00299     nssSlot_EnterMonitor(slot);
00300     ckrv = CKAPI(epv)->C_GetSlotInfo(slot->slotID, &slotInfo);
00301     nssSlot_ExitMonitor(slot);
00302     if (ckrv != CKR_OK) {
00303        slot->token->base.name[0] = 0; /* XXX */
00304        return PR_FALSE;
00305     }
00306     slot->ckFlags = slotInfo.flags;
00307     /* check for the presence of the token */
00308     if ((slot->ckFlags & CKF_TOKEN_PRESENT) == 0) {
00309        if (!slot->token) {
00310            /* token was ne'er present */
00311            return PR_FALSE;
00312        }
00313        session = nssToken_GetDefaultSession(slot->token);
00314        nssSession_EnterMonitor(session);
00315        /* token is not present */
00316        if (session->handle != CK_INVALID_SESSION) {
00317            /* session is valid, close and invalidate it */
00318            CKAPI(epv)->C_CloseSession(session->handle);
00319            session->handle = CK_INVALID_SESSION;
00320        }
00321        nssSession_ExitMonitor(session);
00322 #ifdef NSS_3_4_CODE
00323        if (slot->token->base.name[0] != 0) {
00324            /* notify the high-level cache that the token is removed */
00325            slot->token->base.name[0] = 0; /* XXX */
00326            nssToken_NotifyCertsNotVisible(slot->token);
00327        }
00328 #endif
00329        slot->token->base.name[0] = 0; /* XXX */
00330        /* clear the token cache */
00331        nssToken_Remove(slot->token);
00332        return PR_FALSE;
00333 #ifdef PURE_STAN_CODE
00334     } else if (!slot->token) {
00335        /* token was not present at boot time, is now */
00336        slot->token = nssToken_Create(slot->slotID, slot);
00337        return (slot->token != NULL);
00338 #endif
00339     }
00340     /* token is present, use the session info to determine if the card
00341      * has been removed and reinserted.
00342      */
00343     session = nssToken_GetDefaultSession(slot->token);
00344     nssSession_EnterMonitor(session);
00345     if (session->handle != CK_INVALID_SESSION) {
00346        CK_SESSION_INFO sessionInfo;
00347        ckrv = CKAPI(epv)->C_GetSessionInfo(session->handle, &sessionInfo);
00348        if (ckrv != CKR_OK) {
00349            /* session is screwy, close and invalidate it */
00350            CKAPI(epv)->C_CloseSession(session->handle);
00351            session->handle = CK_INVALID_SESSION;
00352        }
00353     }
00354     nssSession_ExitMonitor(session);
00355     /* token not removed, finished */
00356     if (session->handle != CK_INVALID_SESSION) {
00357        return PR_TRUE;
00358     } else {
00359        /* the token has been removed, and reinserted, or the slot contains
00360         * a token it doesn't recognize. invalidate all the old
00361         * information we had on this token, if we can't refresh, clear
00362         * the present flag */
00363 #ifdef NSS_3_4_CODE
00364        nssToken_NotifyCertsNotVisible(slot->token);
00365 #endif /* NSS_3_4_CODE */
00366        nssToken_Remove(slot->token);
00367        /* token has been removed, need to refresh with new session */
00368        nssrv = nssSlot_Refresh(slot);
00369        if (nssrv != PR_SUCCESS) {
00370            slot->token->base.name[0] = 0; /* XXX */
00371            slot->ckFlags &= ~CKF_TOKEN_PRESENT;
00372            return PR_FALSE;
00373        }
00374        return PR_TRUE;
00375     }
00376 }
00377 
00378 #ifdef PURE_STAN_BUILD
00379 NSS_IMPLEMENT NSSModule *
00380 nssSlot_GetModule (
00381   NSSSlot *slot
00382 )
00383 {
00384     return nssModule_AddRef(slot->module);
00385 }
00386 #endif /* PURE_STAN_BUILD */
00387 
00388 NSS_IMPLEMENT void *
00389 nssSlot_GetCryptokiEPV (
00390   NSSSlot *slot
00391 )
00392 {
00393 #ifdef PURE_STAN_BUILD
00394     return nssModule_GetCryptokiEPV(slot->module);
00395 #else
00396     return slot->epv;
00397 #endif
00398 }
00399 
00400 NSS_IMPLEMENT NSSToken *
00401 nssSlot_GetToken (
00402   NSSSlot *slot
00403 )
00404 {
00405     if (nssSlot_IsTokenPresent(slot)) {
00406        return nssToken_AddRef(slot->token);
00407     }
00408     return (NSSToken *)NULL;
00409 }
00410 
00411 #ifdef PURE_STAN_BUILD
00412 NSS_IMPLEMENT PRBool
00413 nssSlot_IsPermanent (
00414   NSSSlot *slot
00415 )
00416 {
00417     return (!(slot->ckFlags & CKF_REMOVABLE_DEVICE));
00418 }
00419 
00420 NSS_IMPLEMENT PRBool
00421 nssSlot_IsFriendly (
00422   NSSSlot *slot
00423 )
00424 {
00425     return PR_TRUE /* XXX NSSSLOT_IS_FRIENDLY(slot)*/;
00426 }
00427 
00428 NSS_IMPLEMENT PRBool
00429 nssSlot_IsHardware (
00430   NSSSlot *slot
00431 )
00432 {
00433     return (slot->ckFlags & CKF_HW_SLOT);
00434 }
00435 
00436 NSS_IMPLEMENT PRStatus
00437 nssSlot_Refresh (
00438   NSSSlot *slot
00439 )
00440 {
00441     /* XXX */
00442 #if 0
00443     nssToken_Destroy(slot->token);
00444     if (slotInfo.flags & CKF_TOKEN_PRESENT) {
00445        slot->token = nssToken_Create(NULL, slotID, slot);
00446     }
00447 #endif
00448     return PR_SUCCESS;
00449 }
00450 
00451 static PRBool
00452 slot_needs_login (
00453   NSSSlot *slot,
00454   nssSession *session
00455 )
00456 {
00457     PRBool needsLogin, logout;
00458     struct nssSlotAuthInfoStr *authInfo = &slot->authInfo;
00459     void *epv = nssModule_GetCryptokiEPV(slot->module);
00460     if (!nssToken_IsLoginRequired(slot->token)) {
00461        return PR_FALSE;
00462     }
00463     if (authInfo->askTimes == nssSlotAskPasswordTimes_EveryTime) {
00464        logout = PR_TRUE;
00465     } else if (authInfo->askTimes == nssSlotAskPasswordTimes_Timeout) {
00466        PRIntervalTime currentTime = PR_IntervalNow();
00467        if (authInfo->lastLogin - currentTime < authInfo->askPasswordTimeout) {
00468            logout = PR_FALSE;
00469        } else {
00470            logout = PR_TRUE;
00471        }
00472     } else { /* nssSlotAskPasswordTimes_FirstTime */
00473        logout = PR_FALSE;
00474     }
00475     if (logout) {
00476        /* The login has expired, timeout */
00477        nssSession_EnterMonitor(session);
00478        CKAPI(epv)->C_Logout(session->handle);
00479        nssSession_ExitMonitor(session);
00480        needsLogin = PR_TRUE;
00481     } else {
00482        CK_RV ckrv;
00483        CK_SESSION_INFO sessionInfo;
00484        nssSession_EnterMonitor(session);
00485        ckrv = CKAPI(epv)->C_GetSessionInfo(session->handle, &sessionInfo);
00486        nssSession_ExitMonitor(session);
00487        if (ckrv != CKR_OK) {
00488            /* XXX error -- invalidate session */ 
00489            return PR_FALSE;
00490        }
00491        switch (sessionInfo.state) {
00492        case CKS_RW_PUBLIC_SESSION:
00493        case CKS_RO_PUBLIC_SESSION:
00494        default:
00495            needsLogin = PR_TRUE;
00496            break;
00497        case CKS_RW_USER_FUNCTIONS:
00498        case CKS_RW_SO_FUNCTIONS:
00499        case CKS_RO_USER_FUNCTIONS:
00500            needsLogin = PR_FALSE;
00501            break;
00502        }
00503     }
00504     return needsLogin;
00505 }
00506 
00507 static PRStatus
00508 slot_login (
00509   NSSSlot *slot, 
00510   nssSession *session, 
00511   CK_USER_TYPE userType, 
00512   NSSCallback *pwcb
00513 )
00514 {
00515     PRStatus nssrv;
00516     PRUint32 attempts;
00517     PRBool keepTrying;
00518     NSSUTF8 *password = NULL;
00519     CK_ULONG pwLen;
00520     CK_RV ckrv;
00521     void *epv;
00522     if (!pwcb->getPW) {
00523        /* set error INVALID_ARG */
00524        return PR_FAILURE;
00525     }
00526     epv = nssModule_GetCryptokiEPV(slot->module);
00527     keepTrying = PR_TRUE;
00528     nssrv = PR_FAILURE;
00529     attempts = 0;
00530     while (keepTrying) {
00531        /* use the token name, since it is present */
00532        NSSUTF8 *tokenName = nssToken_GetName(slot->token);
00533        nssrv = pwcb->getPW(tokenName, attempts, pwcb->arg, &password);
00534        if (nssrv != PR_SUCCESS) {
00535            nss_SetError(NSS_ERROR_USER_CANCELED);
00536            break;
00537        }
00538        pwLen = (CK_ULONG)nssUTF8_Length(password, &nssrv); 
00539        if (nssrv != PR_SUCCESS) {
00540            break;
00541        }
00542        nssSession_EnterMonitor(session);
00543        ckrv = CKAPI(epv)->C_Login(session->handle, userType, 
00544                                    (CK_CHAR_PTR)password, pwLen);
00545        nssSession_ExitMonitor(session);
00546        switch (ckrv) {
00547        case CKR_OK:
00548        case CKR_USER_ALREADY_LOGGED_IN:
00549            slot->authInfo.lastLogin = PR_Now();
00550            nssrv = PR_SUCCESS;
00551            keepTrying = PR_FALSE;
00552            break;
00553        case CKR_PIN_INCORRECT:
00554            nss_SetError(NSS_ERROR_INVALID_PASSWORD);
00555            keepTrying = PR_TRUE; /* received bad pw, keep going */
00556            break;
00557        default:
00558            nssrv = PR_FAILURE;
00559            keepTrying = PR_FALSE;
00560            break;
00561        }
00562        nss_ZFreeIf(password);
00563        password = NULL;
00564        ++attempts;
00565     }
00566     return nssrv;
00567 }
00568 
00569 static PRStatus
00570 init_slot_password (
00571   NSSSlot *slot, 
00572   nssSession *rwSession, 
00573   NSSUTF8 *password
00574 )
00575 {
00576     PRStatus status;
00577     NSSUTF8 *ssoPW = "";
00578     CK_ULONG userPWLen, ssoPWLen;
00579     CK_RV ckrv;
00580     void *epv = nssModule_GetCryptokiEPV(slot->module);
00581     /* Get the SO and user passwords */
00582     userPWLen = (CK_ULONG)nssUTF8_Length(password, &status); 
00583     if (status != PR_SUCCESS) {
00584        goto loser;
00585     }
00586     ssoPWLen = (CK_ULONG)nssUTF8_Length(ssoPW, &status); 
00587     if (status != PR_SUCCESS) {
00588        goto loser;
00589     }
00590     /* First log in as SO */
00591     ckrv = CKAPI(epv)->C_Login(rwSession->handle, CKU_SO, 
00592                                (CK_CHAR_PTR)ssoPW, ssoPWLen);
00593     if (ckrv != CKR_OK) {
00594        /* set error ...SO_LOGIN_FAILED */
00595        goto loser;
00596     }
00597        /* Now change the user PIN */
00598     ckrv = CKAPI(epv)->C_InitPIN(rwSession->handle, 
00599                                  (CK_CHAR_PTR)password, userPWLen);
00600     if (ckrv != CKR_OK) {
00601        /* set error */
00602        goto loser;
00603     }
00604     return PR_SUCCESS;
00605 loser:
00606     return PR_FAILURE;
00607 }
00608 
00609 static PRStatus
00610 change_slot_password (
00611   NSSSlot *slot, 
00612   nssSession *rwSession, 
00613   NSSUTF8 *oldPassword,
00614   NSSUTF8 *newPassword
00615 )
00616 {
00617     PRStatus status;
00618     CK_ULONG userPWLen, newPWLen;
00619     CK_RV ckrv;
00620     void *epv = nssModule_GetCryptokiEPV(slot->module);
00621     userPWLen = (CK_ULONG)nssUTF8_Length(oldPassword, &status); 
00622     if (status != PR_SUCCESS) {
00623        return status;
00624     }
00625     newPWLen = (CK_ULONG)nssUTF8_Length(newPassword, &status); 
00626     if (status != PR_SUCCESS) {
00627        return status;
00628     }
00629     nssSession_EnterMonitor(rwSession);
00630     ckrv = CKAPI(epv)->C_SetPIN(rwSession->handle,
00631                                 (CK_CHAR_PTR)oldPassword, userPWLen,
00632                                 (CK_CHAR_PTR)newPassword, newPWLen);
00633     nssSession_ExitMonitor(rwSession);
00634     switch (ckrv) {
00635     case CKR_OK:
00636        slot->authInfo.lastLogin = PR_Now();
00637        status = PR_SUCCESS;
00638        break;
00639     case CKR_PIN_INCORRECT:
00640        nss_SetError(NSS_ERROR_INVALID_PASSWORD);
00641        status = PR_FAILURE;
00642        break;
00643     default:
00644        status = PR_FAILURE;
00645        break;
00646     }
00647     return status;
00648 }
00649 
00650 NSS_IMPLEMENT PRStatus
00651 nssSlot_Login (
00652   NSSSlot *slot,
00653   NSSCallback *pwcb
00654 )
00655 {
00656     PRStatus status;
00657     CK_USER_TYPE userType = CKU_USER;
00658     NSSToken *token = nssSlot_GetToken(slot);
00659     nssSession *session;
00660     if (!token) {
00661        return PR_FAILURE;
00662     }
00663     if (!nssToken_IsLoginRequired(token)) {
00664        nssToken_Destroy(token);
00665        return PR_SUCCESS;
00666     }
00667     session = nssToken_GetDefaultSession(slot->token);
00668     if (nssToken_NeedsPINInitialization(token)) {
00669        NSSUTF8 *password = NULL;
00670        if (!pwcb->getInitPW) {
00671            nssToken_Destroy(token);
00672            return PR_FAILURE; /* don't know how to get initial password */
00673        }
00674        status = (*pwcb->getInitPW)(slot->base.name, pwcb->arg, &password);
00675        if (status == PR_SUCCESS) {
00676            session = nssSlot_CreateSession(slot, NULL, PR_TRUE);
00677            status = init_slot_password(slot, session, password);
00678            nssSession_Destroy(session);
00679        }
00680     } else if (slot_needs_login(slot, session)) {
00681        status = slot_login(slot, session, userType, pwcb);
00682     } else {
00683        status = PR_SUCCESS;
00684     }
00685     nssToken_Destroy(token);
00686     return status;
00687 }
00688 
00689 NSS_IMPLEMENT PRStatus
00690 nssSlot_Logout (
00691   NSSSlot *slot,
00692   nssSession *sessionOpt
00693 )
00694 {
00695     PRStatus nssrv = PR_SUCCESS;
00696     nssSession *session;
00697     CK_RV ckrv;
00698     void *epv = nssModule_GetCryptokiEPV(slot->module);
00699     session = sessionOpt ? 
00700               sessionOpt : 
00701               nssToken_GetDefaultSession(slot->token);
00702     nssSession_EnterMonitor(session);
00703     ckrv = CKAPI(epv)->C_Logout(session->handle);
00704     nssSession_ExitMonitor(session);
00705     if (ckrv != CKR_OK) {
00706        /* translate the error */
00707        nssrv = PR_FAILURE;
00708     }
00709     return nssrv;
00710 }
00711 
00712 NSS_IMPLEMENT PRBool
00713 nssSlot_IsLoggedIn (
00714   NSSSlot *slot
00715 )
00716 {
00717     nssSession *session = nssToken_GetDefaultSession(slot->token);
00718     return !slot_needs_login(slot, session);
00719 }
00720 
00721 NSS_IMPLEMENT void
00722 nssSlot_SetPasswordDefaults (
00723   NSSSlot *slot,
00724   PRInt32 askPasswordTimeout
00725 )
00726 {
00727     slot->authInfo.askPasswordTimeout = askPasswordTimeout;
00728 }
00729 
00730 
00731 NSS_IMPLEMENT PRStatus
00732 nssSlot_SetPassword (
00733   NSSSlot *slot,
00734   NSSUTF8 *oldPasswordOpt,
00735   NSSUTF8 *newPassword
00736 )
00737 {
00738     PRStatus status;
00739     nssSession *rwSession;
00740     NSSToken *token = nssSlot_GetToken(slot);
00741     if (!token) {
00742        return PR_FAILURE;
00743     }
00744     rwSession = nssSlot_CreateSession(slot, NULL, PR_TRUE);
00745     if (nssToken_NeedsPINInitialization(token)) {
00746        status = init_slot_password(slot, rwSession, newPassword);
00747     } else if (oldPasswordOpt) {
00748        status = change_slot_password(slot, rwSession, 
00749                                      oldPasswordOpt, newPassword);
00750     } else {
00751        /* old password must be given in order to change */
00752        status = PR_FAILURE;
00753     }
00754     nssSession_Destroy(rwSession);
00755     nssToken_Destroy(token);
00756     return status;
00757 }
00758 
00759 NSS_IMPLEMENT nssSession *
00760 nssSlot_CreateSession (
00761   NSSSlot *slot,
00762   NSSArena *arenaOpt,
00763   PRBool readWrite /* so far, this is the only flag used */
00764 )
00765 {
00766     CK_RV ckrv;
00767     CK_FLAGS ckflags;
00768     CK_SESSION_HANDLE handle;
00769     void *epv = nssModule_GetCryptokiEPV(slot->module);
00770     nssSession *rvSession;
00771     ckflags = s_ck_readonly_flags;
00772     if (readWrite) {
00773        ckflags |= CKF_RW_SESSION;
00774     }
00775     ckrv = CKAPI(epv)->C_OpenSession(slot->slotID, ckflags,
00776                                      slot, nss_ck_slot_notify, &handle);
00777     if (ckrv != CKR_OK) {
00778        /* set an error here, eh? */
00779        return (nssSession *)NULL;
00780     }
00781     rvSession = nss_ZNEW(arenaOpt, nssSession);
00782     if (!rvSession) {
00783        return (nssSession *)NULL;
00784     }
00785     if (nssModule_IsThreadSafe(slot->module)) {
00786        /* If the parent module is threadsafe, 
00787          * create lock to protect just this session.
00788         */
00789        rvSession->lock = PZ_NewLock(nssILockOther);
00790        if (!rvSession->lock) {
00791            /* need to translate NSPR error? */
00792            if (arenaOpt) {
00793            } else {
00794               nss_ZFreeIf(rvSession);
00795            }
00796            return (nssSession *)NULL;
00797        }
00798         rvSession->ownLock = PR_TRUE;
00799     } else {
00800         rvSession->lock = slot->lock;
00801         rvSession->ownLock = PR_FALSE;
00802     }
00803        
00804     rvSession->handle = handle;
00805     rvSession->slot = slot;
00806     rvSession->isRW = readWrite;
00807     return rvSession;
00808 }
00809 
00810 NSS_IMPLEMENT PRStatus
00811 nssSession_Destroy (
00812   nssSession *s
00813 )
00814 {
00815     CK_RV ckrv = CKR_OK;
00816     if (s) {
00817        void *epv = s->slot->epv;
00818        ckrv = CKAPI(epv)->C_CloseSession(s->handle);
00819        if (s->ownLock && s->lock) {
00820            PZ_DestroyLock(s->lock);
00821        }
00822        nss_ZFreeIf(s);
00823     }
00824     return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
00825 }
00826 #endif /* PURE_STAN_BUILD */
00827 
00828 NSS_IMPLEMENT PRStatus
00829 nssSession_EnterMonitor (
00830   nssSession *s
00831 )
00832 {
00833     if (s->lock) PZ_Lock(s->lock);
00834     return PR_SUCCESS;
00835 }
00836 
00837 NSS_IMPLEMENT PRStatus
00838 nssSession_ExitMonitor (
00839   nssSession *s
00840 )
00841 {
00842     return (s->lock) ? PZ_Unlock(s->lock) : PR_SUCCESS;
00843 }
00844 
00845 NSS_EXTERN PRBool
00846 nssSession_IsReadWrite (
00847   nssSession *s
00848 )
00849 {
00850     return s->isRW;
00851 }
00852