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 }