Back to index

lightning-sunbird  0.9+nobinonly
pk11auth.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  * This file deals with PKCS #11 passwords and authentication.
00038  */
00039 #include "seccomon.h"
00040 #include "secmod.h"
00041 #include "secmodi.h"
00042 #include "secmodti.h"
00043 #include "pkcs11t.h"
00044 #include "pk11func.h"
00045 #include "secitem.h"
00046 #include "secerr.h"
00047 
00048 #include "pkim.h" 
00049 
00050 
00051 /*************************************************************
00052  * local static and global data
00053  *************************************************************/
00054 /*
00055  * This structure keeps track of status that spans all the Slots.
00056  * NOTE: This is a global data structure. It semantics expect thread crosstalk
00057  * be very careful when you see it used. 
00058  *  It's major purpose in life is to allow the user to log in one PER 
00059  * Tranaction, even if a transaction spans threads. The problem is the user
00060  * may have to enter a password one just to be able to look at the 
00061  * personalities/certificates (s)he can use. Then if Auth every is one, they
00062  * may have to enter the password again to use the card. See PK11_StartTransac
00063  * and PK11_EndTransaction.
00064  */
00065 static struct PK11GlobalStruct {
00066    int transaction;
00067    PRBool inTransaction;
00068    char *(PR_CALLBACK *getPass)(PK11SlotInfo *,PRBool,void *);
00069    PRBool (PR_CALLBACK *verifyPass)(PK11SlotInfo *,void *);
00070    PRBool (PR_CALLBACK *isLoggedIn)(PK11SlotInfo *,void *);
00071 } PK11_Global = { 1, PR_FALSE, NULL, NULL, NULL };
00072  
00073 /***********************************************************
00074  * Password Utilities
00075  ***********************************************************/
00076 /*
00077  * Check the user's password. Log into the card if it's correct.
00078  * succeed if the user is already logged in.
00079  */
00080 SECStatus
00081 pk11_CheckPassword(PK11SlotInfo *slot,char *pw)
00082 {
00083     int len = 0;
00084     CK_RV crv;
00085     SECStatus rv;
00086     int64 currtime = PR_Now();
00087 
00088     if (slot->protectedAuthPath) {
00089        len = 0;
00090        pw = NULL;
00091     } else if (pw == NULL) {
00092        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00093        return SECFailure;
00094     } else {
00095        len = PORT_Strlen(pw);
00096     }
00097 
00098     PK11_EnterSlotMonitor(slot);
00099     crv = PK11_GETTAB(slot)->C_Login(slot->session,CKU_USER,
00100                                           (unsigned char *)pw,len);
00101     slot->lastLoginCheck = 0;
00102     PK11_ExitSlotMonitor(slot);
00103     switch (crv) {
00104     /* if we're already logged in, we're good to go */
00105     case CKR_OK:
00106        slot->authTransact = PK11_Global.transaction;
00107     case CKR_USER_ALREADY_LOGGED_IN:
00108        slot->authTime = currtime;
00109        rv = SECSuccess;
00110        break;
00111     case CKR_PIN_INCORRECT:
00112        PORT_SetError(SEC_ERROR_BAD_PASSWORD);
00113        rv = SECWouldBlock; /* everything else is ok, only the pin is bad */
00114        break;
00115     default:
00116        PORT_SetError(PK11_MapError(crv));
00117        rv = SECFailure; /* some failure we can't fix by retrying */
00118     }
00119     return rv;
00120 }
00121 
00122 /*
00123  * Check the user's password. Logout before hand to make sure that
00124  * we are really checking the password.
00125  */
00126 SECStatus
00127 PK11_CheckUserPassword(PK11SlotInfo *slot,char *pw)
00128 {
00129     int len = 0;
00130     CK_RV crv;
00131     SECStatus rv;
00132     int64 currtime = PR_Now();
00133 
00134     if (slot->protectedAuthPath) {
00135        len = 0;
00136        pw = NULL;
00137     } else if (pw == NULL) {
00138        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00139        return SECFailure;
00140     } else {
00141        len = PORT_Strlen(pw);
00142     }
00143 
00144     /* force a logout */
00145     PK11_EnterSlotMonitor(slot);
00146     PK11_GETTAB(slot)->C_Logout(slot->session);
00147 
00148     crv = PK11_GETTAB(slot)->C_Login(slot->session,CKU_USER,
00149                                    (unsigned char *)pw,len);
00150     slot->lastLoginCheck = 0;
00151     PK11_ExitSlotMonitor(slot);
00152     switch (crv) {
00153     /* if we're already logged in, we're good to go */
00154     case CKR_OK:
00155        slot->authTransact = PK11_Global.transaction;
00156        slot->authTime = currtime;
00157        rv = SECSuccess;
00158        break;
00159     case CKR_PIN_INCORRECT:
00160        PORT_SetError(SEC_ERROR_BAD_PASSWORD);
00161        rv = SECWouldBlock; /* everything else is ok, only the pin is bad */
00162        break;
00163     default:
00164        PORT_SetError(PK11_MapError(crv));
00165        rv = SECFailure; /* some failure we can't fix by retrying */
00166     }
00167     return rv;
00168 }
00169 
00170 SECStatus
00171 PK11_Logout(PK11SlotInfo *slot)
00172 {
00173     CK_RV crv;
00174 
00175     /* force a logout */
00176     PK11_EnterSlotMonitor(slot);
00177     crv = PK11_GETTAB(slot)->C_Logout(slot->session);
00178     slot->lastLoginCheck = 0;
00179     PK11_ExitSlotMonitor(slot);
00180     if (crv != CKR_OK) {
00181        PORT_SetError(PK11_MapError(crv));
00182        return SECFailure;
00183     }
00184     return  SECSuccess;
00185 }
00186 
00187 /*
00188  * transaction stuff is for when we test for the need to do every
00189  * time auth to see if we already did it for this slot/transaction
00190  */
00191 void PK11_StartAuthTransaction(void)
00192 {
00193 PK11_Global.transaction++;
00194 PK11_Global.inTransaction = PR_TRUE;
00195 }
00196 
00197 void PK11_EndAuthTransaction(void)
00198 {
00199 PK11_Global.transaction++;
00200 PK11_Global.inTransaction = PR_FALSE;
00201 }
00202 
00203 /*
00204  * before we do a private key op, we check to see if we
00205  * need to reauthenticate.
00206  */
00207 void
00208 PK11_HandlePasswordCheck(PK11SlotInfo *slot,void *wincx)
00209 {
00210     int askpw = slot->askpw;
00211     PRBool NeedAuth = PR_FALSE;
00212 
00213     if (!slot->needLogin) return;
00214 
00215     if ((slot->defaultFlags & PK11_OWN_PW_DEFAULTS) == 0) {
00216        PK11SlotInfo *def_slot = PK11_GetInternalKeySlot();
00217 
00218        if (def_slot) {
00219            askpw = def_slot->askpw;
00220            PK11_FreeSlot(def_slot);
00221        }
00222     }
00223 
00224     /* timeouts are handled by isLoggedIn */
00225     if (!PK11_IsLoggedIn(slot,wincx)) {
00226        NeedAuth = PR_TRUE;
00227     } else if (askpw == -1) {
00228        if (!PK11_Global.inTransaction     ||
00229                       (PK11_Global.transaction != slot->authTransact)) {
00230            PK11_EnterSlotMonitor(slot);
00231            PK11_GETTAB(slot)->C_Logout(slot->session);
00232            slot->lastLoginCheck = 0;
00233            PK11_ExitSlotMonitor(slot);
00234            NeedAuth = PR_TRUE;
00235        }
00236     }
00237     if (NeedAuth) PK11_DoPassword(slot,PR_TRUE,wincx);
00238 }
00239 
00240 void
00241 PK11_SlotDBUpdate(PK11SlotInfo *slot)
00242 {
00243     SECMOD_UpdateModule(slot->module);
00244 }
00245 
00246 /*
00247  * set new askpw and timeout values
00248  */
00249 void
00250 PK11_SetSlotPWValues(PK11SlotInfo *slot,int askpw, int timeout)
00251 {
00252         slot->askpw = askpw;
00253         slot->timeout = timeout;
00254         slot->defaultFlags |= PK11_OWN_PW_DEFAULTS;
00255         PK11_SlotDBUpdate(slot);
00256 }
00257 
00258 /*
00259  * Get the askpw and timeout values for this slot
00260  */
00261 void
00262 PK11_GetSlotPWValues(PK11SlotInfo *slot,int *askpw, int *timeout)
00263 {
00264     *askpw = slot->askpw;
00265     *timeout = slot->timeout;
00266 
00267     if ((slot->defaultFlags & PK11_OWN_PW_DEFAULTS) == 0) {
00268        PK11SlotInfo *def_slot = PK11_GetInternalKeySlot();
00269 
00270        if (def_slot) {
00271            *askpw = def_slot->askpw;
00272            *timeout = def_slot->timeout;
00273            PK11_FreeSlot(def_slot);
00274        }
00275     }
00276 }
00277 
00278 /*
00279  * Returns true if the token is needLogin and isn't logged in.
00280  * This function is used to determine if authentication is needed
00281  * before attempting a potentially privelleged operation.
00282  */
00283 PRBool
00284 pk11_LoginStillRequired(PK11SlotInfo *slot, void *wincx)
00285 {
00286     return slot->needLogin && !PK11_IsLoggedIn(slot,wincx);
00287 }
00288 
00289 /*
00290  * make sure a slot is authenticated...
00291  * This function only does the authentication if it is needed.
00292  */
00293 SECStatus
00294 PK11_Authenticate(PK11SlotInfo *slot, PRBool loadCerts, void *wincx) {
00295     if (pk11_LoginStillRequired(slot,wincx)) {
00296        return PK11_DoPassword(slot,loadCerts,wincx);
00297     }
00298     return SECSuccess;
00299 }
00300 
00301 /*
00302  * Authenticate to "unfriendly" tokens (tokens which need to be logged
00303  * in to find the certs.
00304  */
00305 SECStatus
00306 pk11_AuthenticateUnfriendly(PK11SlotInfo *slot, PRBool loadCerts, void *wincx)
00307 {
00308     SECStatus rv = SECSuccess;
00309     if (!PK11_IsFriendly(slot)) {
00310        rv = PK11_Authenticate(slot, loadCerts, wincx);
00311     }
00312     return rv;
00313 }
00314 
00315 
00316 /*
00317  * NOTE: this assumes that we are logged out of the card before hand
00318  */
00319 SECStatus
00320 PK11_CheckSSOPassword(PK11SlotInfo *slot, char *ssopw)
00321 {
00322     CK_SESSION_HANDLE rwsession;
00323     CK_RV crv;
00324     SECStatus rv = SECFailure;
00325     int len = 0;
00326 
00327     /* get a rwsession */
00328     rwsession = PK11_GetRWSession(slot);
00329     if (rwsession == CK_INVALID_SESSION) {
00330        PORT_SetError(SEC_ERROR_BAD_DATA);
00331        return rv;
00332     }
00333 
00334     if (slot->protectedAuthPath) {
00335        len = 0;
00336        ssopw = NULL;
00337     } else if (ssopw == NULL) {
00338        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00339        return SECFailure;
00340     } else {
00341        len = PORT_Strlen(ssopw);
00342     }
00343 
00344     /* check the password */
00345     crv = PK11_GETTAB(slot)->C_Login(rwsession,CKU_SO,
00346                                           (unsigned char *)ssopw,len);
00347     slot->lastLoginCheck = 0;
00348     switch (crv) {
00349     /* if we're already logged in, we're good to go */
00350     case CKR_OK:
00351        rv = SECSuccess;
00352        break;
00353     case CKR_PIN_INCORRECT:
00354        PORT_SetError(SEC_ERROR_BAD_PASSWORD);
00355        rv = SECWouldBlock; /* everything else is ok, only the pin is bad */
00356        break;
00357     default:
00358        PORT_SetError(PK11_MapError(crv));
00359        rv = SECFailure; /* some failure we can't fix by retrying */
00360     }
00361     PK11_GETTAB(slot)->C_Logout(rwsession);
00362     slot->lastLoginCheck = 0;
00363 
00364     /* release rwsession */
00365     PK11_RestoreROSession(slot,rwsession);
00366     return rv;
00367 }
00368 
00369 /*
00370  * make sure the password conforms to your token's requirements.
00371  */
00372 SECStatus
00373 PK11_VerifyPW(PK11SlotInfo *slot,char *pw)
00374 {
00375     int len = PORT_Strlen(pw);
00376 
00377     if ((slot->minPassword > len) || (slot->maxPassword < len)) {
00378        PORT_SetError(SEC_ERROR_BAD_DATA);
00379        return SECFailure;
00380     }
00381     return SECSuccess;
00382 }
00383 
00384 /*
00385  * initialize a user PIN Value
00386  */
00387 SECStatus
00388 PK11_InitPin(PK11SlotInfo *slot,char *ssopw, char *userpw)
00389 {
00390     CK_SESSION_HANDLE rwsession = CK_INVALID_SESSION;
00391     CK_RV crv;
00392     SECStatus rv = SECFailure;
00393     int len;
00394     int ssolen;
00395 
00396     if (userpw == NULL) userpw = "";
00397     if (ssopw == NULL) ssopw = "";
00398 
00399     len = PORT_Strlen(userpw);
00400     ssolen = PORT_Strlen(ssopw);
00401 
00402     /* get a rwsession */
00403     rwsession = PK11_GetRWSession(slot);
00404     if (rwsession == CK_INVALID_SESSION) {
00405        PORT_SetError(SEC_ERROR_BAD_DATA);
00406        slot->lastLoginCheck = 0;
00407        return rv;
00408     }
00409 
00410     if (slot->protectedAuthPath) {
00411        len = 0;
00412        ssolen = 0;
00413        ssopw = NULL;
00414        userpw = NULL;
00415     }
00416 
00417     /* check the password */
00418     crv = PK11_GETTAB(slot)->C_Login(rwsession,CKU_SO, 
00419                                      (unsigned char *)ssopw,ssolen);
00420     slot->lastLoginCheck = 0;
00421     if (crv != CKR_OK) {
00422        PORT_SetError(PK11_MapError(crv));
00423        goto done;
00424     }
00425 
00426     crv = PK11_GETTAB(slot)->C_InitPIN(rwsession,(unsigned char *)userpw,len);
00427     if (crv != CKR_OK) {
00428        PORT_SetError(PK11_MapError(crv));
00429     } else {
00430        rv = SECSuccess;
00431     }
00432 
00433 done:
00434     PK11_GETTAB(slot)->C_Logout(rwsession);
00435     slot->lastLoginCheck = 0;
00436     PK11_RestoreROSession(slot,rwsession);
00437     if (rv == SECSuccess) {
00438         /* update our view of the world */
00439         PK11_InitToken(slot,PR_TRUE);
00440        PK11_EnterSlotMonitor(slot);
00441        PK11_GETTAB(slot)->C_Login(slot->session,CKU_USER,
00442                                           (unsigned char *)userpw,len);
00443        slot->lastLoginCheck = 0;
00444        PK11_ExitSlotMonitor(slot);
00445     }
00446     return rv;
00447 }
00448 
00449 /*
00450  * Change an existing user password
00451  */
00452 SECStatus
00453 PK11_ChangePW(PK11SlotInfo *slot,char *oldpw, char *newpw)
00454 {
00455     CK_RV crv;
00456     SECStatus rv = SECFailure;
00457     int newLen;
00458     int oldLen;
00459     CK_SESSION_HANDLE rwsession;
00460 
00461     if (newpw == NULL) newpw = "";
00462     if (oldpw == NULL) oldpw = "";
00463     newLen = PORT_Strlen(newpw);
00464     oldLen = PORT_Strlen(oldpw);
00465 
00466     /* get a rwsession */
00467     rwsession = PK11_GetRWSession(slot);
00468     if (rwsession == CK_INVALID_SESSION) {
00469        PORT_SetError(SEC_ERROR_BAD_DATA);
00470        return rv;
00471     }
00472 
00473     crv = PK11_GETTAB(slot)->C_SetPIN(rwsession,
00474               (unsigned char *)oldpw,oldLen,(unsigned char *)newpw,newLen);
00475     if (crv == CKR_OK) {
00476        rv = SECSuccess;
00477     } else {
00478        PORT_SetError(PK11_MapError(crv));
00479     }
00480 
00481     PK11_RestoreROSession(slot,rwsession);
00482 
00483     /* update our view of the world */
00484     PK11_InitToken(slot,PR_TRUE);
00485     return rv;
00486 }
00487 
00488 static char *
00489 pk11_GetPassword(PK11SlotInfo *slot, PRBool retry, void * wincx)
00490 {
00491     if (PK11_Global.getPass == NULL) return NULL;
00492     return (*PK11_Global.getPass)(slot, retry, wincx);
00493 }
00494 
00495 void
00496 PK11_SetPasswordFunc(PK11PasswordFunc func)
00497 {
00498     PK11_Global.getPass = func;
00499 }
00500 
00501 void
00502 PK11_SetVerifyPasswordFunc(PK11VerifyPasswordFunc func)
00503 {
00504     PK11_Global.verifyPass = func;
00505 }
00506 
00507 void
00508 PK11_SetIsLoggedInFunc(PK11IsLoggedInFunc func)
00509 {
00510     PK11_Global.isLoggedIn = func;
00511 }
00512 
00513 
00514 /*
00515  * authenticate to a slot. This loops until we can't recover, the user
00516  * gives up, or we succeed. If we're already logged in and this function
00517  * is called we will still prompt for a password, but we will probably
00518  * succeed no matter what the password was (depending on the implementation
00519  * of the PKCS 11 module.
00520  */
00521 SECStatus
00522 PK11_DoPassword(PK11SlotInfo *slot, PRBool loadCerts, void *wincx)
00523 {
00524     SECStatus rv = SECFailure;
00525     char * password;
00526     PRBool attempt = PR_FALSE;
00527 
00528     if (PK11_NeedUserInit(slot)) {
00529        PORT_SetError(SEC_ERROR_IO);
00530        return SECFailure;
00531     }
00532 
00533 
00534     /*
00535      * Central server type applications which control access to multiple
00536      * slave applications to single crypto devices need to virtuallize the
00537      * login state. This is done by a callback out of PK11_IsLoggedIn and
00538      * here. If we are actually logged in, then we got here because the
00539      * higher level code told us that the particular client application may
00540      * still need to be logged in. If that is the case, we simply tell the
00541      * server code that it should now verify the clients password and tell us
00542      * the results.
00543      */
00544     if (PK11_IsLoggedIn(slot,NULL) && 
00545                      (PK11_Global.verifyPass != NULL)) {
00546        if (!PK11_Global.verifyPass(slot,wincx)) {
00547            PORT_SetError(SEC_ERROR_BAD_PASSWORD);
00548            return SECFailure;
00549        }
00550        return SECSuccess;
00551     }
00552 
00553     /* get the password. This can drop out of the while loop
00554      * for the following reasons:
00555      *        (1) the user refused to enter a password. 
00556      *               (return error to caller)
00557      * (2) the token user password is disabled [usually due to
00558      *    too many failed authentication attempts].
00559      *               (return error to caller)
00560      * (3) the password was successful.
00561      */
00562     while ((password = pk11_GetPassword(slot, attempt, wincx)) != NULL) {
00563        /* if the token has a protectedAuthPath, the application may have
00564          * already issued the C_Login as part of it's pk11_GetPassword call.
00565          * In this case the application will tell us what the results were in 
00566          * the password value (retry or the authentication was successful) so
00567         * we can skip our own C_Login call (which would force the token to
00568         * try to login again).
00569         * 
00570         * Applications that don't know about protectedAuthPath will return a 
00571         * password, which we will ignore and trigger the token to 
00572         * 'authenticate' itself anyway. Hopefully the blinking display on 
00573         * the reader, or the flashing light under the thumbprint reader will 
00574         * attract the user's attention */
00575        attempt = PR_TRUE;
00576        if (slot->protectedAuthPath) {
00577            /* application tried to authenticate and failed. it wants to try
00578             * again, continue looping */
00579            if (strcmp(password, PK11_PW_RETRY) == 0) {
00580               rv = SECWouldBlock;
00581               PORT_Free(password);
00582               continue;
00583            }
00584            /* applicaton tried to authenticate and succeeded we're done */
00585            if (strcmp(password, PK11_PW_AUTHENTICATED) == 0) {
00586               rv = SECSuccess;
00587               PORT_Free(password);
00588               break;
00589            }
00590        }
00591        rv = pk11_CheckPassword(slot,password);
00592        PORT_Memset(password, 0, PORT_Strlen(password));
00593        PORT_Free(password);
00594        if (rv != SECWouldBlock) break;
00595     }
00596     if (rv == SECSuccess) {
00597        rv = pk11_CheckVerifyTest(slot);
00598        if (!PK11_IsFriendly(slot)) {
00599            nssTrustDomain_UpdateCachedTokenCerts(slot->nssToken->trustDomain,
00600                                              slot->nssToken);
00601        }
00602     } else if (!attempt) PORT_SetError(SEC_ERROR_BAD_PASSWORD);
00603     return rv;
00604 }
00605 
00606 void PK11_LogoutAll(void)
00607 {
00608     SECMODListLock *lock = SECMOD_GetDefaultModuleListLock();
00609     SECMODModuleList *modList = SECMOD_GetDefaultModuleList();
00610     SECMODModuleList *mlp = NULL;
00611     int i;
00612 
00613     /* NSS is not initialized, there are not tokens to log out */
00614     if (lock == NULL) {
00615        return;
00616     }
00617 
00618     SECMOD_GetReadLock(lock);
00619     /* find the number of entries */
00620     for (mlp = modList; mlp != NULL; mlp = mlp->next) {
00621        for (i=0; i < mlp->module->slotCount; i++) {
00622            PK11_Logout(mlp->module->slots[i]);
00623        }
00624     }
00625 
00626     SECMOD_ReleaseReadLock(lock);
00627 }
00628 
00629 int
00630 PK11_GetMinimumPwdLength(PK11SlotInfo *slot)
00631 {
00632     return ((int)slot->minPassword);
00633 }
00634 
00635 /* Does this slot have a protected pin path? */
00636 PRBool
00637 PK11_ProtectedAuthenticationPath(PK11SlotInfo *slot)
00638 {
00639        return slot->protectedAuthPath;
00640 }
00641 
00642 /*
00643  * we can initialize the password if 1) The toke is not inited 
00644  * (need login == true and see need UserInit) or 2) the token has
00645  * a NULL password. (slot->needLogin = false & need user Init = false).
00646  */
00647 PRBool PK11_NeedPWInitForSlot(PK11SlotInfo *slot)
00648 {
00649     if (slot->needLogin && PK11_NeedUserInit(slot)) {
00650        return PR_TRUE;
00651     }
00652     if (!slot->needLogin && !PK11_NeedUserInit(slot)) {
00653        return PR_TRUE;
00654     }
00655     return PR_FALSE;
00656 }
00657 
00658 PRBool PK11_NeedPWInit()
00659 {
00660     PK11SlotInfo *slot = PK11_GetInternalKeySlot();
00661     PRBool ret = PK11_NeedPWInitForSlot(slot);
00662 
00663     PK11_FreeSlot(slot);
00664     return ret;
00665 }
00666 
00667 PRBool 
00668 pk11_InDelayPeriod(PRIntervalTime lastTime, PRIntervalTime delayTime, 
00669                                           PRIntervalTime *retTime)
00670 {
00671     PRIntervalTime time;
00672 
00673     *retTime = time = PR_IntervalNow();
00674     return (PRBool) (lastTime) && ((time-lastTime) < delayTime);
00675 }
00676 
00677 /*
00678  * Determine if the token is logged in. We have to actually query the token,
00679  * because it's state can change without intervention from us.
00680  */
00681 PRBool
00682 PK11_IsLoggedIn(PK11SlotInfo *slot,void *wincx)
00683 {
00684     CK_SESSION_INFO sessionInfo;
00685     int askpw = slot->askpw;
00686     int timeout = slot->timeout;
00687     CK_RV crv;
00688     PRIntervalTime curTime;
00689     static PRIntervalTime login_delay_time = 0;
00690 
00691     if (login_delay_time == 0) {
00692        login_delay_time = PR_SecondsToInterval(1);
00693     }
00694 
00695     /* If we don't have our own password default values, use the system
00696      * ones */
00697     if ((slot->defaultFlags & PK11_OWN_PW_DEFAULTS) == 0) {
00698        PK11SlotInfo *def_slot = PK11_GetInternalKeySlot();
00699 
00700        if (def_slot) {
00701            askpw = def_slot->askpw;
00702            timeout = def_slot->timeout;
00703            PK11_FreeSlot(def_slot);
00704        }
00705     }
00706 
00707     if ((wincx != NULL) && (PK11_Global.isLoggedIn != NULL) &&
00708        (*PK11_Global.isLoggedIn)(slot, wincx) == PR_FALSE) { return PR_FALSE; }
00709 
00710 
00711     /* forget the password if we've been inactive too long */
00712     if (askpw == 1) {
00713        int64 currtime = PR_Now();
00714        int64 result;
00715        int64 mult;
00716        
00717        LL_I2L(result, timeout);
00718        LL_I2L(mult, 60*1000*1000);
00719        LL_MUL(result,result,mult);
00720        LL_ADD(result, result, slot->authTime);
00721        if (LL_CMP(result, <, currtime) ) {
00722            PK11_EnterSlotMonitor(slot);
00723            PK11_GETTAB(slot)->C_Logout(slot->session);
00724            slot->lastLoginCheck = 0;
00725            PK11_ExitSlotMonitor(slot);
00726        } else {
00727            slot->authTime = currtime;
00728        }
00729     }
00730 
00731     PK11_EnterSlotMonitor(slot);
00732     if (pk11_InDelayPeriod(slot->lastLoginCheck,login_delay_time, &curTime)) {
00733        sessionInfo.state = slot->lastState;
00734        crv = CKR_OK;
00735     } else {
00736        crv = PK11_GETTAB(slot)->C_GetSessionInfo(slot->session,&sessionInfo);
00737        if (crv == CKR_OK) {
00738            slot->lastState = sessionInfo.state;
00739            slot->lastLoginCheck = curTime;
00740        }
00741     }
00742     PK11_ExitSlotMonitor(slot);
00743     /* if we can't get session info, something is really wrong */
00744     if (crv != CKR_OK) {
00745        slot->session = CK_INVALID_SESSION;
00746        return PR_FALSE;
00747     }
00748 
00749     switch (sessionInfo.state) {
00750     case CKS_RW_PUBLIC_SESSION:
00751     case CKS_RO_PUBLIC_SESSION:
00752     default:
00753        break; /* fail */
00754     case CKS_RW_USER_FUNCTIONS:
00755     case CKS_RW_SO_FUNCTIONS:
00756     case CKS_RO_USER_FUNCTIONS:
00757        return PR_TRUE;
00758     }
00759     return PR_FALSE; 
00760 }