tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pk11auth.c (23912B)


      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/. */
      4 /*
      5 * This file deals with PKCS #11 passwords and authentication.
      6 */
      7 #include "dev.h"
      8 #include "dev3hack.h"
      9 #include "seccomon.h"
     10 #include "secmod.h"
     11 #include "secmodi.h"
     12 #include "secmodti.h"
     13 #include "pkcs11t.h"
     14 #include "pk11func.h"
     15 #include "secitem.h"
     16 #include "secerr.h"
     17 
     18 #include "pkim.h"
     19 
     20 /*************************************************************
     21 * local static and global data
     22 *************************************************************/
     23 /*
     24 * This structure keeps track of status that spans all the Slots.
     25 * NOTE: This is a global data structure. It semantics expect thread crosstalk
     26 * be very careful when you see it used.
     27 *  It's major purpose in life is to allow the user to log in one PER
     28 * Tranaction, even if a transaction spans threads. The problem is the user
     29 * may have to enter a password one just to be able to look at the
     30 * personalities/certificates (s)he can use. Then if Auth every is one, they
     31 * may have to enter the password again to use the card. See PK11_StartTransac
     32 * and PK11_EndTransaction.
     33 */
     34 static struct PK11GlobalStruct {
     35    int transaction;
     36    PRBool inTransaction;
     37    char *(PR_CALLBACK *getPass)(PK11SlotInfo *, PRBool, void *);
     38    PRBool(PR_CALLBACK *verifyPass)(PK11SlotInfo *, void *);
     39    PRBool(PR_CALLBACK *isLoggedIn)(PK11SlotInfo *, void *);
     40 } PK11_Global = { 1, PR_FALSE, NULL, NULL, NULL };
     41 
     42 /***********************************************************
     43 * Password Utilities
     44 ***********************************************************/
     45 /*
     46 * Check the user's password. Log into the card if it's correct.
     47 * succeed if the user is already logged in.
     48 */
     49 static SECStatus
     50 pk11_CheckPassword(PK11SlotInfo *slot, CK_SESSION_HANDLE session,
     51                   char *pw, PRBool alreadyLocked, PRBool contextSpecific)
     52 {
     53    int len = 0;
     54    CK_RV crv;
     55    SECStatus rv;
     56    PRTime currtime = PR_Now();
     57    PRBool mustRetry;
     58    int retry = 0;
     59 
     60    if (slot->protectedAuthPath) {
     61        len = 0;
     62        pw = NULL;
     63    } else if (pw == NULL) {
     64        PORT_SetError(SEC_ERROR_INVALID_ARGS);
     65        return SECFailure;
     66    } else {
     67        len = PORT_Strlen(pw);
     68    }
     69 
     70    do {
     71        if (!alreadyLocked)
     72            PK11_EnterSlotMonitor(slot);
     73        crv = PK11_GETTAB(slot)->C_Login(session,
     74                                         contextSpecific ? CKU_CONTEXT_SPECIFIC : CKU_USER,
     75                                         (unsigned char *)pw, len);
     76        slot->lastLoginCheck = 0;
     77        mustRetry = PR_FALSE;
     78        if (!alreadyLocked)
     79            PK11_ExitSlotMonitor(slot);
     80        switch (crv) {
     81            /* if we're already logged in, we're good to go */
     82            case CKR_OK:
     83                /* TODO If it was for CKU_CONTEXT_SPECIFIC should we do this */
     84                slot->authTransact = PK11_Global.transaction;
     85            /* Fall through */
     86            case CKR_USER_ALREADY_LOGGED_IN:
     87                slot->authTime = currtime;
     88                rv = SECSuccess;
     89                break;
     90            case CKR_PIN_INCORRECT:
     91                PORT_SetError(SEC_ERROR_BAD_PASSWORD);
     92                rv = SECWouldBlock; /* everything else is ok, only the pin is bad */
     93                break;
     94            /* someone called reset while we fetched the password, try again once
     95             * if the token is still there. */
     96            case CKR_SESSION_HANDLE_INVALID:
     97            case CKR_SESSION_CLOSED:
     98                if (session != slot->session) {
     99                    /* don't bother retrying, we were in a middle of an operation,
    100                     * which is now lost. Just fail. */
    101                    PORT_SetError(PK11_MapError(crv));
    102                    rv = SECFailure;
    103                    break;
    104                }
    105                if (retry++ == 0) {
    106                    rv = PK11_InitToken(slot, PR_FALSE);
    107                    if (rv == SECSuccess) {
    108                        if (slot->session != CK_INVALID_HANDLE) {
    109                            session = slot->session; /* we should have
    110                                                      * a new session now */
    111                            mustRetry = PR_TRUE;
    112                        } else {
    113                            PORT_SetError(PK11_MapError(crv));
    114                            rv = SECFailure;
    115                        }
    116                    }
    117                    break;
    118                }
    119            /* Fall through */
    120            default:
    121                PORT_SetError(PK11_MapError(crv));
    122                rv = SECFailure; /* some failure we can't fix by retrying */
    123        }
    124    } while (mustRetry);
    125    return rv;
    126 }
    127 
    128 /*
    129 * Check the user's password. Logout before hand to make sure that
    130 * we are really checking the password.
    131 */
    132 SECStatus
    133 PK11_CheckUserPassword(PK11SlotInfo *slot, const char *pw)
    134 {
    135    int len = 0;
    136    CK_RV crv;
    137    SECStatus rv;
    138    PRTime currtime = PR_Now();
    139 
    140    if (slot->protectedAuthPath) {
    141        len = 0;
    142        pw = NULL;
    143    } else if (pw == NULL) {
    144        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    145        return SECFailure;
    146    } else {
    147        len = PORT_Strlen(pw);
    148    }
    149 
    150    /*
    151     * If the token doesn't need a login, don't try to relogin because the
    152     * effect is undefined. It's not clear what it means to check a non-empty
    153     * password with such a token, so treat that as an error.
    154     */
    155    if (!slot->needLogin) {
    156        if (len == 0) {
    157            rv = SECSuccess;
    158        } else {
    159            PORT_SetError(SEC_ERROR_BAD_PASSWORD);
    160            rv = SECFailure;
    161        }
    162        return rv;
    163    }
    164 
    165    /* force a logout */
    166    PK11_EnterSlotMonitor(slot);
    167    PK11_GETTAB(slot)->C_Logout(slot->session);
    168 
    169    crv = PK11_GETTAB(slot)->C_Login(slot->session, CKU_USER,
    170                                     (unsigned char *)pw, len);
    171    slot->lastLoginCheck = 0;
    172    PK11_ExitSlotMonitor(slot);
    173    switch (crv) {
    174        /* if we're already logged in, we're good to go */
    175        case CKR_OK:
    176            slot->authTransact = PK11_Global.transaction;
    177            slot->authTime = currtime;
    178            rv = SECSuccess;
    179            break;
    180        case CKR_PIN_INCORRECT:
    181            PORT_SetError(SEC_ERROR_BAD_PASSWORD);
    182            rv = SECWouldBlock; /* everything else is ok, only the pin is bad */
    183            break;
    184        default:
    185            PORT_SetError(PK11_MapError(crv));
    186            rv = SECFailure; /* some failure we can't fix by retrying */
    187    }
    188    return rv;
    189 }
    190 
    191 SECStatus
    192 PK11_Logout(PK11SlotInfo *slot)
    193 {
    194    CK_RV crv;
    195 
    196    /* force a logout */
    197    PK11_EnterSlotMonitor(slot);
    198    crv = PK11_GETTAB(slot)->C_Logout(slot->session);
    199    slot->lastLoginCheck = 0;
    200    PK11_ExitSlotMonitor(slot);
    201    if (crv != CKR_OK) {
    202        PORT_SetError(PK11_MapError(crv));
    203        return SECFailure;
    204    }
    205    return SECSuccess;
    206 }
    207 
    208 /*
    209 * transaction stuff is for when we test for the need to do every
    210 * time auth to see if we already did it for this slot/transaction
    211 */
    212 void
    213 PK11_StartAuthTransaction(void)
    214 {
    215    PK11_Global.transaction++;
    216    PK11_Global.inTransaction = PR_TRUE;
    217 }
    218 
    219 void
    220 PK11_EndAuthTransaction(void)
    221 {
    222    PK11_Global.transaction++;
    223    PK11_Global.inTransaction = PR_FALSE;
    224 }
    225 
    226 /*
    227 * before we do a private key op, we check to see if we
    228 * need to reauthenticate.
    229 */
    230 void
    231 PK11_HandlePasswordCheck(PK11SlotInfo *slot, void *wincx)
    232 {
    233    int askpw = slot->askpw;
    234    PRBool NeedAuth = PR_FALSE;
    235 
    236    if (!slot->needLogin)
    237        return;
    238 
    239    if ((slot->defaultFlags & PK11_OWN_PW_DEFAULTS) == 0) {
    240        PK11SlotInfo *def_slot = PK11_GetInternalKeySlot();
    241 
    242        if (def_slot) {
    243            askpw = def_slot->askpw;
    244            PK11_FreeSlot(def_slot);
    245        }
    246    }
    247 
    248    /* timeouts are handled by isLoggedIn */
    249    if (!PK11_IsLoggedIn(slot, wincx)) {
    250        NeedAuth = PR_TRUE;
    251    } else if (askpw == -1) {
    252        if (!PK11_Global.inTransaction ||
    253            (PK11_Global.transaction != slot->authTransact)) {
    254            PK11_EnterSlotMonitor(slot);
    255            PK11_GETTAB(slot)->C_Logout(slot->session);
    256            slot->lastLoginCheck = 0;
    257            PK11_ExitSlotMonitor(slot);
    258            NeedAuth = PR_TRUE;
    259        }
    260    }
    261    if (NeedAuth)
    262        PK11_DoPassword(slot, slot->session, PR_TRUE,
    263                        wincx, PR_FALSE, PR_FALSE);
    264 }
    265 
    266 void
    267 PK11_SlotDBUpdate(PK11SlotInfo *slot)
    268 {
    269    SECMOD_UpdateModule(slot->module);
    270 }
    271 
    272 /*
    273 * set new askpw and timeout values
    274 */
    275 void
    276 PK11_SetSlotPWValues(PK11SlotInfo *slot, int askpw, int timeout)
    277 {
    278    slot->askpw = askpw;
    279    slot->timeout = timeout;
    280    slot->defaultFlags |= PK11_OWN_PW_DEFAULTS;
    281    PK11_SlotDBUpdate(slot);
    282 }
    283 
    284 /*
    285 * Get the askpw and timeout values for this slot
    286 */
    287 void
    288 PK11_GetSlotPWValues(PK11SlotInfo *slot, int *askpw, int *timeout)
    289 {
    290    *askpw = slot->askpw;
    291    *timeout = slot->timeout;
    292 
    293    if ((slot->defaultFlags & PK11_OWN_PW_DEFAULTS) == 0) {
    294        PK11SlotInfo *def_slot = PK11_GetInternalKeySlot();
    295 
    296        if (def_slot) {
    297            *askpw = def_slot->askpw;
    298            *timeout = def_slot->timeout;
    299            PK11_FreeSlot(def_slot);
    300        }
    301    }
    302 }
    303 
    304 /*
    305 * Returns true if the token is needLogin and isn't logged in.
    306 * This function is used to determine if authentication is needed
    307 * before attempting a potentially privelleged operation.
    308 */
    309 PRBool
    310 pk11_LoginStillRequired(PK11SlotInfo *slot, void *wincx)
    311 {
    312    return slot->needLogin && !PK11_IsLoggedIn(slot, wincx);
    313 }
    314 
    315 /*
    316 * make sure a slot is authenticated...
    317 * This function only does the authentication if it is needed.
    318 */
    319 SECStatus
    320 PK11_Authenticate(PK11SlotInfo *slot, PRBool loadCerts, void *wincx)
    321 {
    322    if (!slot) {
    323        return SECFailure;
    324    }
    325    if (pk11_LoginStillRequired(slot, wincx)) {
    326        return PK11_DoPassword(slot, slot->session, loadCerts, wincx,
    327                               PR_FALSE, PR_FALSE);
    328    }
    329    return SECSuccess;
    330 }
    331 
    332 /*
    333 * Authenticate to "unfriendly" tokens (tokens which need to be logged
    334 * in to find the certs.
    335 */
    336 SECStatus
    337 pk11_AuthenticateUnfriendly(PK11SlotInfo *slot, PRBool loadCerts, void *wincx)
    338 {
    339    SECStatus rv = SECSuccess;
    340    if (!PK11_IsFriendly(slot)) {
    341        rv = PK11_Authenticate(slot, loadCerts, wincx);
    342    }
    343    return rv;
    344 }
    345 
    346 /*
    347 * NOTE: this assumes that we are logged out of the card before hand
    348 */
    349 SECStatus
    350 PK11_CheckSSOPassword(PK11SlotInfo *slot, char *ssopw)
    351 {
    352    CK_SESSION_HANDLE rwsession;
    353    CK_RV crv;
    354    SECStatus rv = SECFailure;
    355    int len = 0;
    356 
    357    /* get a rwsession */
    358    rwsession = PK11_GetRWSession(slot);
    359    if (rwsession == CK_INVALID_HANDLE) {
    360        PORT_SetError(SEC_ERROR_BAD_DATA);
    361        return rv;
    362    }
    363 
    364    if (slot->protectedAuthPath) {
    365        len = 0;
    366        ssopw = NULL;
    367    } else if (ssopw == NULL) {
    368        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    369        return SECFailure;
    370    } else {
    371        len = PORT_Strlen(ssopw);
    372    }
    373 
    374    /* check the password */
    375    crv = PK11_GETTAB(slot)->C_Login(rwsession, CKU_SO,
    376                                     (unsigned char *)ssopw, len);
    377    slot->lastLoginCheck = 0;
    378    switch (crv) {
    379        /* if we're already logged in, we're good to go */
    380        case CKR_OK:
    381            rv = SECSuccess;
    382            break;
    383        case CKR_PIN_INCORRECT:
    384            PORT_SetError(SEC_ERROR_BAD_PASSWORD);
    385            rv = SECWouldBlock; /* everything else is ok, only the pin is bad */
    386            break;
    387        default:
    388            PORT_SetError(PK11_MapError(crv));
    389            rv = SECFailure; /* some failure we can't fix by retrying */
    390    }
    391    PK11_GETTAB(slot)->C_Logout(rwsession);
    392    slot->lastLoginCheck = 0;
    393 
    394    /* release rwsession */
    395    PK11_RestoreROSession(slot, rwsession);
    396    return rv;
    397 }
    398 
    399 /*
    400 * make sure the password conforms to your token's requirements.
    401 */
    402 SECStatus
    403 PK11_VerifyPW(PK11SlotInfo *slot, char *pw)
    404 {
    405    int len = PORT_Strlen(pw);
    406 
    407    if ((slot->minPassword > len) || (slot->maxPassword < len)) {
    408        PORT_SetError(SEC_ERROR_BAD_DATA);
    409        return SECFailure;
    410    }
    411    return SECSuccess;
    412 }
    413 
    414 /*
    415 * initialize a user PIN Value
    416 */
    417 SECStatus
    418 PK11_InitPin(PK11SlotInfo *slot, const char *ssopw, const char *userpw)
    419 {
    420    CK_SESSION_HANDLE rwsession = CK_INVALID_HANDLE;
    421    CK_RV crv;
    422    SECStatus rv = SECFailure;
    423    int len;
    424    int ssolen;
    425 
    426    if (userpw == NULL)
    427        userpw = "";
    428    if (ssopw == NULL)
    429        ssopw = "";
    430 
    431    len = PORT_Strlen(userpw);
    432    ssolen = PORT_Strlen(ssopw);
    433 
    434    /* get a rwsession */
    435    rwsession = PK11_GetRWSession(slot);
    436    if (rwsession == CK_INVALID_HANDLE) {
    437        PORT_SetError(SEC_ERROR_BAD_DATA);
    438        slot->lastLoginCheck = 0;
    439        return rv;
    440    }
    441 
    442    if (slot->protectedAuthPath) {
    443        len = 0;
    444        ssolen = 0;
    445        ssopw = NULL;
    446        userpw = NULL;
    447    }
    448 
    449    /* check the password */
    450    crv = PK11_GETTAB(slot)->C_Login(rwsession, CKU_SO,
    451                                     (unsigned char *)ssopw, ssolen);
    452    slot->lastLoginCheck = 0;
    453    if (crv != CKR_OK) {
    454        PORT_SetError(PK11_MapError(crv));
    455        goto done;
    456    }
    457 
    458    crv = PK11_GETTAB(slot)->C_InitPIN(rwsession, (unsigned char *)userpw, len);
    459    if (crv != CKR_OK) {
    460        PORT_SetError(PK11_MapError(crv));
    461    } else {
    462        rv = SECSuccess;
    463    }
    464 
    465 done:
    466    PK11_GETTAB(slot)->C_Logout(rwsession);
    467    slot->lastLoginCheck = 0;
    468    PK11_RestoreROSession(slot, rwsession);
    469    if (rv == SECSuccess) {
    470        /* update our view of the world */
    471        PK11_InitToken(slot, PR_TRUE);
    472        if (slot->needLogin) {
    473            PK11_EnterSlotMonitor(slot);
    474            PK11_GETTAB(slot)->C_Login(slot->session, CKU_USER,
    475                                       (unsigned char *)userpw, len);
    476            slot->lastLoginCheck = 0;
    477            PK11_ExitSlotMonitor(slot);
    478        }
    479    }
    480    return rv;
    481 }
    482 
    483 /*
    484 * Change an existing user password
    485 */
    486 SECStatus
    487 PK11_ChangePW(PK11SlotInfo *slot, const char *oldpw, const char *newpw)
    488 {
    489    CK_RV crv;
    490    SECStatus rv = SECFailure;
    491    int newLen = 0;
    492    int oldLen = 0;
    493    CK_SESSION_HANDLE rwsession;
    494 
    495    /* use NULL values to trigger the protected authentication path */
    496    if (!slot->protectedAuthPath) {
    497        if (newpw == NULL)
    498            newpw = "";
    499        if (oldpw == NULL)
    500            oldpw = "";
    501    }
    502    if (newpw)
    503        newLen = PORT_Strlen(newpw);
    504    if (oldpw)
    505        oldLen = PORT_Strlen(oldpw);
    506 
    507    /* get a rwsession */
    508    rwsession = PK11_GetRWSession(slot);
    509    if (rwsession == CK_INVALID_HANDLE) {
    510        PORT_SetError(SEC_ERROR_BAD_DATA);
    511        return rv;
    512    }
    513 
    514    crv = PK11_GETTAB(slot)->C_SetPIN(rwsession,
    515                                      (unsigned char *)oldpw, oldLen, (unsigned char *)newpw, newLen);
    516    if (crv == CKR_OK) {
    517        rv = SECSuccess;
    518    } else {
    519        PORT_SetError(PK11_MapError(crv));
    520    }
    521 
    522    PK11_RestoreROSession(slot, rwsession);
    523 
    524    /* update our view of the world */
    525    PK11_InitToken(slot, PR_TRUE);
    526    return rv;
    527 }
    528 
    529 static char *
    530 pk11_GetPassword(PK11SlotInfo *slot, PRBool retry, void *wincx)
    531 {
    532    if (PK11_Global.getPass == NULL)
    533        return NULL;
    534    return (*PK11_Global.getPass)(slot, retry, wincx);
    535 }
    536 
    537 void
    538 PK11_SetPasswordFunc(PK11PasswordFunc func)
    539 {
    540    PK11_Global.getPass = func;
    541 }
    542 
    543 void
    544 PK11_SetVerifyPasswordFunc(PK11VerifyPasswordFunc func)
    545 {
    546    PK11_Global.verifyPass = func;
    547 }
    548 
    549 void
    550 PK11_SetIsLoggedInFunc(PK11IsLoggedInFunc func)
    551 {
    552    PK11_Global.isLoggedIn = func;
    553 }
    554 
    555 /*
    556 * authenticate to a slot. This loops until we can't recover, the user
    557 * gives up, or we succeed. If we're already logged in and this function
    558 * is called we will still prompt for a password, but we will probably
    559 * succeed no matter what the password was (depending on the implementation
    560 * of the PKCS 11 module.
    561 */
    562 SECStatus
    563 PK11_DoPassword(PK11SlotInfo *slot, CK_SESSION_HANDLE session,
    564                PRBool loadCerts, void *wincx, PRBool alreadyLocked,
    565                PRBool contextSpecific)
    566 {
    567    SECStatus rv = SECFailure;
    568    char *password;
    569    PRBool attempt = PR_FALSE;
    570 
    571    if (PK11_NeedUserInit(slot)) {
    572        PORT_SetError(SEC_ERROR_IO);
    573        return SECFailure;
    574    }
    575 
    576    /*
    577     * Central server type applications which control access to multiple
    578     * client applications to single crypto devices need to virtuallize the
    579     * login state. This is done by a callback out of PK11_IsLoggedIn and
    580     * here. If we are actually logged in, then we got here because the
    581     * higher level code told us that the particular client application may
    582     * still need to be logged in. If that is the case, we simply tell the
    583     * server code that it should now verify the clients password and tell us
    584     * the results.
    585     */
    586    if (PK11_IsLoggedIn(slot, NULL) &&
    587        (PK11_Global.verifyPass != NULL)) {
    588        if (!PK11_Global.verifyPass(slot, wincx)) {
    589            PORT_SetError(SEC_ERROR_BAD_PASSWORD);
    590            return SECFailure;
    591        }
    592        return SECSuccess;
    593    }
    594 
    595    /* get the password. This can drop out of the while loop
    596     * for the following reasons:
    597     *  (1) the user refused to enter a password.
    598     *                  (return error to caller)
    599     *  (2) the token user password is disabled [usually due to
    600     *     too many failed authentication attempts].
    601     *                  (return error to caller)
    602     *  (3) the password was successful.
    603     */
    604    while ((password = pk11_GetPassword(slot, attempt, wincx)) != NULL) {
    605        /* if the token has a protectedAuthPath, the application may have
    606         * already issued the C_Login as part of it's pk11_GetPassword call.
    607         * In this case the application will tell us what the results were in
    608         * the password value (retry or the authentication was successful) so
    609         * we can skip our own C_Login call (which would force the token to
    610         * try to login again).
    611         *
    612         * Applications that don't know about protectedAuthPath will return a
    613         * password, which we will ignore and trigger the token to
    614         * 'authenticate' itself anyway. Hopefully the blinking display on
    615         * the reader, or the flashing light under the thumbprint reader will
    616         * attract the user's attention */
    617        attempt = PR_TRUE;
    618        if (slot->protectedAuthPath) {
    619            /* application tried to authenticate and failed. it wants to try
    620             * again, continue looping */
    621            if (strcmp(password, PK11_PW_RETRY) == 0) {
    622                rv = SECWouldBlock;
    623                PORT_Free(password);
    624                continue;
    625            }
    626            /* applicaton tried to authenticate and succeeded we're done */
    627            if (strcmp(password, PK11_PW_AUTHENTICATED) == 0) {
    628                rv = SECSuccess;
    629                PORT_Free(password);
    630                break;
    631            }
    632        }
    633        rv = pk11_CheckPassword(slot, session, password,
    634                                alreadyLocked, contextSpecific);
    635        PORT_Memset(password, 0, PORT_Strlen(password));
    636        PORT_Free(password);
    637        if (rv != SECWouldBlock)
    638            break;
    639    }
    640    if (rv == SECSuccess) {
    641        if (!contextSpecific && !PK11_IsFriendly(slot)) {
    642            NSSToken *token = PK11Slot_GetNSSToken(slot);
    643            if (token) {
    644                nssTrustDomain_UpdateCachedTokenCerts(token->trustDomain, token);
    645                (void)nssToken_Destroy(token);
    646            }
    647        }
    648    } else if (!attempt)
    649        PORT_SetError(SEC_ERROR_BAD_PASSWORD);
    650    return rv;
    651 }
    652 
    653 void
    654 PK11_LogoutAll(void)
    655 {
    656    SECMODListLock *lock = SECMOD_GetDefaultModuleListLock();
    657    SECMODModuleList *modList;
    658    SECMODModuleList *mlp = NULL;
    659    int i;
    660 
    661    /* NSS is not initialized, there are not tokens to log out */
    662    if (lock == NULL) {
    663        return;
    664    }
    665 
    666    SECMOD_GetReadLock(lock);
    667    modList = SECMOD_GetDefaultModuleList();
    668    /* find the number of entries */
    669    for (mlp = modList; mlp != NULL; mlp = mlp->next) {
    670        for (i = 0; i < mlp->module->slotCount; i++) {
    671            PK11_Logout(mlp->module->slots[i]);
    672        }
    673    }
    674 
    675    SECMOD_ReleaseReadLock(lock);
    676 }
    677 
    678 int
    679 PK11_GetMinimumPwdLength(PK11SlotInfo *slot)
    680 {
    681    return ((int)slot->minPassword);
    682 }
    683 
    684 /* Does this slot have a protected pin path? */
    685 PRBool
    686 PK11_ProtectedAuthenticationPath(PK11SlotInfo *slot)
    687 {
    688    return slot->protectedAuthPath;
    689 }
    690 
    691 /*
    692 * we can initialize the password if 1) The toke is not inited
    693 * (need login == true and see need UserInit) or 2) the token has
    694 * a NULL password. (slot->needLogin = false & need user Init = false).
    695 */
    696 PRBool
    697 PK11_NeedPWInitForSlot(PK11SlotInfo *slot)
    698 {
    699    if (slot->needLogin && PK11_NeedUserInit(slot)) {
    700        return PR_TRUE;
    701    }
    702    if (!slot->needLogin && !PK11_NeedUserInit(slot)) {
    703        return PR_TRUE;
    704    }
    705    return PR_FALSE;
    706 }
    707 
    708 PRBool
    709 PK11_NeedPWInit()
    710 {
    711    PK11SlotInfo *slot = PK11_GetInternalKeySlot();
    712    PRBool ret = PR_FALSE;
    713    if (slot) {
    714        ret = PK11_NeedPWInitForSlot(slot);
    715        PK11_FreeSlot(slot);
    716    }
    717    return ret;
    718 }
    719 
    720 PRBool
    721 pk11_InDelayPeriod(PRIntervalTime lastTime, PRIntervalTime delayTime,
    722                   PRIntervalTime *retTime)
    723 {
    724    PRIntervalTime time;
    725 
    726    *retTime = time = PR_IntervalNow();
    727    return (PRBool)(lastTime) && ((time - lastTime) < delayTime);
    728 }
    729 
    730 /*
    731 * Determine if the token is logged in. We have to actually query the token,
    732 * because it's state can change without intervention from us.
    733 */
    734 PRBool
    735 PK11_IsLoggedIn(PK11SlotInfo *slot, void *wincx)
    736 {
    737    CK_SESSION_INFO sessionInfo;
    738    int askpw = slot->askpw;
    739    int timeout = slot->timeout;
    740    CK_RV crv;
    741    PRIntervalTime curTime;
    742    static PRIntervalTime login_delay_time = 0;
    743 
    744    if (login_delay_time == 0) {
    745        login_delay_time = PR_SecondsToInterval(1);
    746    }
    747 
    748    /* If we don't have our own password default values, use the system
    749     * ones */
    750    if ((slot->defaultFlags & PK11_OWN_PW_DEFAULTS) == 0) {
    751        PK11SlotInfo *def_slot = PK11_GetInternalKeySlot();
    752 
    753        if (def_slot) {
    754            askpw = def_slot->askpw;
    755            timeout = def_slot->timeout;
    756            PK11_FreeSlot(def_slot);
    757        }
    758    }
    759 
    760    if ((wincx != NULL) && (PK11_Global.isLoggedIn != NULL) &&
    761        (*PK11_Global.isLoggedIn)(slot, wincx) == PR_FALSE) {
    762        return PR_FALSE;
    763    }
    764 
    765    /* forget the password if we've been inactive too long */
    766    if (askpw == 1) {
    767        PRTime currtime = PR_Now();
    768        PRTime result;
    769        PRTime mult;
    770 
    771        LL_I2L(result, timeout);
    772        LL_I2L(mult, 60 * 1000 * 1000);
    773        LL_MUL(result, result, mult);
    774        LL_ADD(result, result, slot->authTime);
    775        if (LL_CMP(result, <, currtime)) {
    776            PK11_EnterSlotMonitor(slot);
    777            PK11_GETTAB(slot)->C_Logout(slot->session);
    778            slot->lastLoginCheck = 0;
    779            PK11_ExitSlotMonitor(slot);
    780        } else {
    781            slot->authTime = currtime;
    782        }
    783    }
    784 
    785    PK11_EnterSlotMonitor(slot);
    786    if (pk11_InDelayPeriod(slot->lastLoginCheck, login_delay_time, &curTime)) {
    787        sessionInfo.state = slot->lastState;
    788        crv = CKR_OK;
    789    } else {
    790        crv = PK11_GETTAB(slot)->C_GetSessionInfo(slot->session, &sessionInfo);
    791        if (crv == CKR_OK) {
    792            slot->lastState = sessionInfo.state;
    793            slot->lastLoginCheck = curTime;
    794        }
    795    }
    796    PK11_ExitSlotMonitor(slot);
    797    /* if we can't get session info, something is really wrong */
    798    if (crv != CKR_OK) {
    799        slot->session = CK_INVALID_HANDLE;
    800        return PR_FALSE;
    801    }
    802 
    803    switch (sessionInfo.state) {
    804        case CKS_RW_PUBLIC_SESSION:
    805        case CKS_RO_PUBLIC_SESSION:
    806        default:
    807            break; /* fail */
    808        case CKS_RW_USER_FUNCTIONS:
    809        case CKS_RW_SO_FUNCTIONS:
    810        case CKS_RO_USER_FUNCTIONS:
    811            return PR_TRUE;
    812    }
    813    return PR_FALSE;
    814 }