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