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
pk11_CheckPassword(PK11SlotInfo * slot,CK_SESSION_HANDLE session,char * pw,PRBool alreadyLocked,PRBool contextSpecific)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
PK11_CheckUserPassword(PK11SlotInfo * slot,const char * pw)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
PK11_Logout(PK11SlotInfo * slot)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
PK11_StartAuthTransaction(void)213 PK11_StartAuthTransaction(void)
214 {
215 PK11_Global.transaction++;
216 PK11_Global.inTransaction = PR_TRUE;
217 }
218
219 void
PK11_EndAuthTransaction(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
PK11_HandlePasswordCheck(PK11SlotInfo * slot,void * wincx)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
PK11_SlotDBUpdate(PK11SlotInfo * slot)267 PK11_SlotDBUpdate(PK11SlotInfo *slot)
268 {
269 SECMOD_UpdateModule(slot->module);
270 }
271
272 /*
273 * set new askpw and timeout values
274 */
275 void
PK11_SetSlotPWValues(PK11SlotInfo * slot,int askpw,int timeout)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
PK11_GetSlotPWValues(PK11SlotInfo * slot,int * askpw,int * timeout)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
pk11_LoginStillRequired(PK11SlotInfo * slot,void * wincx)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
PK11_Authenticate(PK11SlotInfo * slot,PRBool loadCerts,void * wincx)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
pk11_AuthenticateUnfriendly(PK11SlotInfo * slot,PRBool loadCerts,void * wincx)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
PK11_CheckSSOPassword(PK11SlotInfo * slot,char * ssopw)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
PK11_VerifyPW(PK11SlotInfo * slot,char * pw)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
PK11_InitPin(PK11SlotInfo * slot,const char * ssopw,const char * userpw)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
PK11_ChangePW(PK11SlotInfo * slot,const char * oldpw,const char * newpw)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 *
pk11_GetPassword(PK11SlotInfo * slot,PRBool retry,void * wincx)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
PK11_SetPasswordFunc(PK11PasswordFunc func)538 PK11_SetPasswordFunc(PK11PasswordFunc func)
539 {
540 PK11_Global.getPass = func;
541 }
542
543 void
PK11_SetVerifyPasswordFunc(PK11VerifyPasswordFunc func)544 PK11_SetVerifyPasswordFunc(PK11VerifyPasswordFunc func)
545 {
546 PK11_Global.verifyPass = func;
547 }
548
549 void
PK11_SetIsLoggedInFunc(PK11IsLoggedInFunc func)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
PK11_DoPassword(PK11SlotInfo * slot,CK_SESSION_HANDLE session,PRBool loadCerts,void * wincx,PRBool alreadyLocked,PRBool contextSpecific)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 * slave 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
PK11_LogoutAll(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
PK11_GetMinimumPwdLength(PK11SlotInfo * slot)679 PK11_GetMinimumPwdLength(PK11SlotInfo *slot)
680 {
681 return ((int)slot->minPassword);
682 }
683
684 /* Does this slot have a protected pin path? */
685 PRBool
PK11_ProtectedAuthenticationPath(PK11SlotInfo * slot)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
PK11_NeedPWInitForSlot(PK11SlotInfo * slot)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
PK11_NeedPWInit()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
pk11_InDelayPeriod(PRIntervalTime lastTime,PRIntervalTime delayTime,PRIntervalTime * retTime)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
PK11_IsLoggedIn(PK11SlotInfo * slot,void * wincx)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 }
815