security/nss/lib/pk11wrap/pk11auth.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial