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