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