Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/nss/lib/pk11wrap/pk11auth.c
Line
Count
Source (jump to first uncovered line)
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
48
pk11_CheckPassword(PK11SlotInfo *slot, CK_SESSION_HANDLE session,
49
                   char *pw, PRBool alreadyLocked, PRBool contextSpecific)
50
0
{
51
0
    int len = 0;
52
0
    CK_RV crv;
53
0
    SECStatus rv;
54
0
    PRTime currtime = PR_Now();
55
0
    PRBool mustRetry;
56
0
    int retry = 0;
57
0
58
0
    if (slot->protectedAuthPath) {
59
0
        len = 0;
60
0
        pw = NULL;
61
0
    } else if (pw == NULL) {
62
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
63
0
        return SECFailure;
64
0
    } else {
65
0
        len = PORT_Strlen(pw);
66
0
    }
67
0
68
0
    do {
69
0
        if (!alreadyLocked)
70
0
            PK11_EnterSlotMonitor(slot);
71
0
        crv = PK11_GETTAB(slot)->C_Login(session,
72
0
                                         contextSpecific ? CKU_CONTEXT_SPECIFIC : CKU_USER,
73
0
                                         (unsigned char *)pw, len);
74
0
        slot->lastLoginCheck = 0;
75
0
        mustRetry = PR_FALSE;
76
0
        if (!alreadyLocked)
77
0
            PK11_ExitSlotMonitor(slot);
78
0
        switch (crv) {
79
0
            /* if we're already logged in, we're good to go */
80
0
            case CKR_OK:
81
0
                /* TODO If it was for CKU_CONTEXT_SPECIFIC should we do this */
82
0
                slot->authTransact = PK11_Global.transaction;
83
0
            /* Fall through */
84
0
            case CKR_USER_ALREADY_LOGGED_IN:
85
0
                slot->authTime = currtime;
86
0
                rv = SECSuccess;
87
0
                break;
88
0
            case CKR_PIN_INCORRECT:
89
0
                PORT_SetError(SEC_ERROR_BAD_PASSWORD);
90
0
                rv = SECWouldBlock; /* everything else is ok, only the pin is bad */
91
0
                break;
92
0
            /* someone called reset while we fetched the password, try again once
93
0
             * if the token is still there. */
94
0
            case CKR_SESSION_HANDLE_INVALID:
95
0
            case CKR_SESSION_CLOSED:
96
0
                if (session != slot->session) {
97
0
                    /* don't bother retrying, we were in a middle of an operation,
98
0
                     * which is now lost. Just fail. */
99
0
                    PORT_SetError(PK11_MapError(crv));
100
0
                    rv = SECFailure;
101
0
                    break;
102
0
                }
103
0
                if (retry++ == 0) {
104
0
                    rv = PK11_InitToken(slot, PR_FALSE);
105
0
                    if (rv == SECSuccess) {
106
0
                        if (slot->session != CK_INVALID_SESSION) {
107
0
                            session = slot->session; /* we should have
108
0
                                                      * a new session now */
109
0
                            mustRetry = PR_TRUE;
110
0
                        } else {
111
0
                            PORT_SetError(PK11_MapError(crv));
112
0
                            rv = SECFailure;
113
0
                        }
114
0
                    }
115
0
                    break;
116
0
                }
117
0
            /* Fall through */
118
0
            default:
119
0
                PORT_SetError(PK11_MapError(crv));
120
0
                rv = SECFailure; /* some failure we can't fix by retrying */
121
0
        }
122
0
    } while (mustRetry);
123
0
    return rv;
124
0
}
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
131
PK11_CheckUserPassword(PK11SlotInfo *slot, const char *pw)
132
0
{
133
0
    int len = 0;
134
0
    CK_RV crv;
135
0
    SECStatus rv;
136
0
    PRTime currtime = PR_Now();
137
0
138
0
    if (slot->protectedAuthPath) {
139
0
        len = 0;
140
0
        pw = NULL;
141
0
    } else if (pw == NULL) {
142
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
143
0
        return SECFailure;
144
0
    } else {
145
0
        len = PORT_Strlen(pw);
146
0
    }
147
0
148
0
    /*
149
0
     * If the token doesn't need a login, don't try to relogin because the
150
0
     * effect is undefined. It's not clear what it means to check a non-empty
151
0
     * password with such a token, so treat that as an error.
152
0
     */
153
0
    if (!slot->needLogin) {
154
0
        if (len == 0) {
155
0
            rv = SECSuccess;
156
0
        } else {
157
0
            PORT_SetError(SEC_ERROR_BAD_PASSWORD);
158
0
            rv = SECFailure;
159
0
        }
160
0
        return rv;
161
0
    }
162
0
163
0
    /* force a logout */
164
0
    PK11_EnterSlotMonitor(slot);
165
0
    PK11_GETTAB(slot)->C_Logout(slot->session);
166
0
167
0
    crv = PK11_GETTAB(slot)->C_Login(slot->session, CKU_USER,
168
0
                                     (unsigned char *)pw, len);
169
0
    slot->lastLoginCheck = 0;
170
0
    PK11_ExitSlotMonitor(slot);
171
0
    switch (crv) {
172
0
        /* if we're already logged in, we're good to go */
173
0
        case CKR_OK:
174
0
            slot->authTransact = PK11_Global.transaction;
175
0
            slot->authTime = currtime;
176
0
            rv = SECSuccess;
177
0
            break;
178
0
        case CKR_PIN_INCORRECT:
179
0
            PORT_SetError(SEC_ERROR_BAD_PASSWORD);
180
0
            rv = SECWouldBlock; /* everything else is ok, only the pin is bad */
181
0
            break;
182
0
        default:
183
0
            PORT_SetError(PK11_MapError(crv));
184
0
            rv = SECFailure; /* some failure we can't fix by retrying */
185
0
    }
186
0
    return rv;
187
0
}
188
189
SECStatus
190
PK11_Logout(PK11SlotInfo *slot)
191
0
{
192
0
    CK_RV crv;
193
0
194
0
    /* force a logout */
195
0
    PK11_EnterSlotMonitor(slot);
196
0
    crv = PK11_GETTAB(slot)->C_Logout(slot->session);
197
0
    slot->lastLoginCheck = 0;
198
0
    PK11_ExitSlotMonitor(slot);
199
0
    if (crv != CKR_OK) {
200
0
        PORT_SetError(PK11_MapError(crv));
201
0
        return SECFailure;
202
0
    }
203
0
    return SECSuccess;
204
0
}
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
211
PK11_StartAuthTransaction(void)
212
0
{
213
0
    PK11_Global.transaction++;
214
0
    PK11_Global.inTransaction = PR_TRUE;
215
0
}
216
217
void
218
PK11_EndAuthTransaction(void)
219
0
{
220
0
    PK11_Global.transaction++;
221
0
    PK11_Global.inTransaction = PR_FALSE;
222
0
}
223
224
/*
225
 * before we do a private key op, we check to see if we
226
 * need to reauthenticate.
227
 */
228
void
229
PK11_HandlePasswordCheck(PK11SlotInfo *slot, void *wincx)
230
0
{
231
0
    int askpw = slot->askpw;
232
0
    PRBool NeedAuth = PR_FALSE;
233
0
234
0
    if (!slot->needLogin)
235
0
        return;
236
0
237
0
    if ((slot->defaultFlags & PK11_OWN_PW_DEFAULTS) == 0) {
238
0
        PK11SlotInfo *def_slot = PK11_GetInternalKeySlot();
239
0
240
0
        if (def_slot) {
241
0
            askpw = def_slot->askpw;
242
0
            PK11_FreeSlot(def_slot);
243
0
        }
244
0
    }
245
0
246
0
    /* timeouts are handled by isLoggedIn */
247
0
    if (!PK11_IsLoggedIn(slot, wincx)) {
248
0
        NeedAuth = PR_TRUE;
249
0
    } else if (askpw == -1) {
250
0
        if (!PK11_Global.inTransaction ||
251
0
            (PK11_Global.transaction != slot->authTransact)) {
252
0
            PK11_EnterSlotMonitor(slot);
253
0
            PK11_GETTAB(slot)->C_Logout(slot->session);
254
0
            slot->lastLoginCheck = 0;
255
0
            PK11_ExitSlotMonitor(slot);
256
0
            NeedAuth = PR_TRUE;
257
0
        }
258
0
    }
259
0
    if (NeedAuth)
260
0
        PK11_DoPassword(slot, slot->session, PR_TRUE,
261
0
                        wincx, PR_FALSE, PR_FALSE);
262
0
}
263
264
void
265
PK11_SlotDBUpdate(PK11SlotInfo *slot)
266
0
{
267
0
    SECMOD_UpdateModule(slot->module);
268
0
}
269
270
/*
271
 * set new askpw and timeout values
272
 */
273
void
274
PK11_SetSlotPWValues(PK11SlotInfo *slot, int askpw, int timeout)
275
0
{
276
0
    slot->askpw = askpw;
277
0
    slot->timeout = timeout;
278
0
    slot->defaultFlags |= PK11_OWN_PW_DEFAULTS;
279
0
    PK11_SlotDBUpdate(slot);
280
0
}
281
282
/*
283
 * Get the askpw and timeout values for this slot
284
 */
285
void
286
PK11_GetSlotPWValues(PK11SlotInfo *slot, int *askpw, int *timeout)
287
0
{
288
0
    *askpw = slot->askpw;
289
0
    *timeout = slot->timeout;
290
0
291
0
    if ((slot->defaultFlags & PK11_OWN_PW_DEFAULTS) == 0) {
292
0
        PK11SlotInfo *def_slot = PK11_GetInternalKeySlot();
293
0
294
0
        if (def_slot) {
295
0
            *askpw = def_slot->askpw;
296
0
            *timeout = def_slot->timeout;
297
0
            PK11_FreeSlot(def_slot);
298
0
        }
299
0
    }
300
0
}
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
308
pk11_LoginStillRequired(PK11SlotInfo *slot, void *wincx)
309
0
{
310
0
    return slot->needLogin && !PK11_IsLoggedIn(slot, wincx);
311
0
}
312
313
/*
314
 * make sure a slot is authenticated...
315
 * This function only does the authentication if it is needed.
316
 */
317
SECStatus
318
PK11_Authenticate(PK11SlotInfo *slot, PRBool loadCerts, void *wincx)
319
0
{
320
0
    if (!slot) {
321
0
        return SECFailure;
322
0
    }
323
0
    if (pk11_LoginStillRequired(slot, wincx)) {
324
0
        return PK11_DoPassword(slot, slot->session, loadCerts, wincx,
325
0
                               PR_FALSE, PR_FALSE);
326
0
    }
327
0
    return SECSuccess;
328
0
}
329
330
/*
331
 * Authenticate to "unfriendly" tokens (tokens which need to be logged
332
 * in to find the certs.
333
 */
334
SECStatus
335
pk11_AuthenticateUnfriendly(PK11SlotInfo *slot, PRBool loadCerts, void *wincx)
336
0
{
337
0
    SECStatus rv = SECSuccess;
338
0
    if (!PK11_IsFriendly(slot)) {
339
0
        rv = PK11_Authenticate(slot, loadCerts, wincx);
340
0
    }
341
0
    return rv;
342
0
}
343
344
/*
345
 * NOTE: this assumes that we are logged out of the card before hand
346
 */
347
SECStatus
348
PK11_CheckSSOPassword(PK11SlotInfo *slot, char *ssopw)
349
0
{
350
0
    CK_SESSION_HANDLE rwsession;
351
0
    CK_RV crv;
352
0
    SECStatus rv = SECFailure;
353
0
    int len = 0;
354
0
355
0
    /* get a rwsession */
356
0
    rwsession = PK11_GetRWSession(slot);
357
0
    if (rwsession == CK_INVALID_SESSION) {
358
0
        PORT_SetError(SEC_ERROR_BAD_DATA);
359
0
        return rv;
360
0
    }
361
0
362
0
    if (slot->protectedAuthPath) {
363
0
        len = 0;
364
0
        ssopw = NULL;
365
0
    } else if (ssopw == NULL) {
366
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
367
0
        return SECFailure;
368
0
    } else {
369
0
        len = PORT_Strlen(ssopw);
370
0
    }
371
0
372
0
    /* check the password */
373
0
    crv = PK11_GETTAB(slot)->C_Login(rwsession, CKU_SO,
374
0
                                     (unsigned char *)ssopw, len);
375
0
    slot->lastLoginCheck = 0;
376
0
    switch (crv) {
377
0
        /* if we're already logged in, we're good to go */
378
0
        case CKR_OK:
379
0
            rv = SECSuccess;
380
0
            break;
381
0
        case CKR_PIN_INCORRECT:
382
0
            PORT_SetError(SEC_ERROR_BAD_PASSWORD);
383
0
            rv = SECWouldBlock; /* everything else is ok, only the pin is bad */
384
0
            break;
385
0
        default:
386
0
            PORT_SetError(PK11_MapError(crv));
387
0
            rv = SECFailure; /* some failure we can't fix by retrying */
388
0
    }
389
0
    PK11_GETTAB(slot)->C_Logout(rwsession);
390
0
    slot->lastLoginCheck = 0;
391
0
392
0
    /* release rwsession */
393
0
    PK11_RestoreROSession(slot, rwsession);
394
0
    return rv;
395
0
}
396
397
/*
398
 * make sure the password conforms to your token's requirements.
399
 */
400
SECStatus
401
PK11_VerifyPW(PK11SlotInfo *slot, char *pw)
402
0
{
403
0
    int len = PORT_Strlen(pw);
404
0
405
0
    if ((slot->minPassword > len) || (slot->maxPassword < len)) {
406
0
        PORT_SetError(SEC_ERROR_BAD_DATA);
407
0
        return SECFailure;
408
0
    }
409
0
    return SECSuccess;
410
0
}
411
412
/*
413
 * initialize a user PIN Value
414
 */
415
SECStatus
416
PK11_InitPin(PK11SlotInfo *slot, const char *ssopw, const char *userpw)
417
0
{
418
0
    CK_SESSION_HANDLE rwsession = CK_INVALID_SESSION;
419
0
    CK_RV crv;
420
0
    SECStatus rv = SECFailure;
421
0
    int len;
422
0
    int ssolen;
423
0
424
0
    if (userpw == NULL)
425
0
        userpw = "";
426
0
    if (ssopw == NULL)
427
0
        ssopw = "";
428
0
429
0
    len = PORT_Strlen(userpw);
430
0
    ssolen = PORT_Strlen(ssopw);
431
0
432
0
    /* get a rwsession */
433
0
    rwsession = PK11_GetRWSession(slot);
434
0
    if (rwsession == CK_INVALID_SESSION) {
435
0
        PORT_SetError(SEC_ERROR_BAD_DATA);
436
0
        slot->lastLoginCheck = 0;
437
0
        return rv;
438
0
    }
439
0
440
0
    if (slot->protectedAuthPath) {
441
0
        len = 0;
442
0
        ssolen = 0;
443
0
        ssopw = NULL;
444
0
        userpw = NULL;
445
0
    }
446
0
447
0
    /* check the password */
448
0
    crv = PK11_GETTAB(slot)->C_Login(rwsession, CKU_SO,
449
0
                                     (unsigned char *)ssopw, ssolen);
450
0
    slot->lastLoginCheck = 0;
451
0
    if (crv != CKR_OK) {
452
0
        PORT_SetError(PK11_MapError(crv));
453
0
        goto done;
454
0
    }
455
0
456
0
    crv = PK11_GETTAB(slot)->C_InitPIN(rwsession, (unsigned char *)userpw, len);
457
0
    if (crv != CKR_OK) {
458
0
        PORT_SetError(PK11_MapError(crv));
459
0
    } else {
460
0
        rv = SECSuccess;
461
0
    }
462
0
463
0
done:
464
0
    PK11_GETTAB(slot)->C_Logout(rwsession);
465
0
    slot->lastLoginCheck = 0;
466
0
    PK11_RestoreROSession(slot, rwsession);
467
0
    if (rv == SECSuccess) {
468
0
        /* update our view of the world */
469
0
        PK11_InitToken(slot, PR_TRUE);
470
0
        if (slot->needLogin) {
471
0
            PK11_EnterSlotMonitor(slot);
472
0
            PK11_GETTAB(slot)->C_Login(slot->session, CKU_USER,
473
0
                                       (unsigned char *)userpw, len);
474
0
            slot->lastLoginCheck = 0;
475
0
            PK11_ExitSlotMonitor(slot);
476
0
        }
477
0
    }
478
0
    return rv;
479
0
}
480
481
/*
482
 * Change an existing user password
483
 */
484
SECStatus
485
PK11_ChangePW(PK11SlotInfo *slot, const char *oldpw, const char *newpw)
486
0
{
487
0
    CK_RV crv;
488
0
    SECStatus rv = SECFailure;
489
0
    int newLen = 0;
490
0
    int oldLen = 0;
491
0
    CK_SESSION_HANDLE rwsession;
492
0
493
0
    /* use NULL values to trigger the protected authentication path */
494
0
    if (!slot->protectedAuthPath) {
495
0
        if (newpw == NULL)
496
0
            newpw = "";
497
0
        if (oldpw == NULL)
498
0
            oldpw = "";
499
0
    }
500
0
    if (newpw)
501
0
        newLen = PORT_Strlen(newpw);
502
0
    if (oldpw)
503
0
        oldLen = PORT_Strlen(oldpw);
504
0
505
0
    /* get a rwsession */
506
0
    rwsession = PK11_GetRWSession(slot);
507
0
    if (rwsession == CK_INVALID_SESSION) {
508
0
        PORT_SetError(SEC_ERROR_BAD_DATA);
509
0
        return rv;
510
0
    }
511
0
512
0
    crv = PK11_GETTAB(slot)->C_SetPIN(rwsession,
513
0
                                      (unsigned char *)oldpw, oldLen, (unsigned char *)newpw, newLen);
514
0
    if (crv == CKR_OK) {
515
0
        rv = SECSuccess;
516
0
    } else {
517
0
        PORT_SetError(PK11_MapError(crv));
518
0
    }
519
0
520
0
    PK11_RestoreROSession(slot, rwsession);
521
0
522
0
    /* update our view of the world */
523
0
    PK11_InitToken(slot, PR_TRUE);
524
0
    return rv;
525
0
}
526
527
static char *
528
pk11_GetPassword(PK11SlotInfo *slot, PRBool retry, void *wincx)
529
0
{
530
0
    if (PK11_Global.getPass == NULL)
531
0
        return NULL;
532
0
    return (*PK11_Global.getPass)(slot, retry, wincx);
533
0
}
534
535
void
536
PK11_SetPasswordFunc(PK11PasswordFunc func)
537
0
{
538
0
    PK11_Global.getPass = func;
539
0
}
540
541
void
542
PK11_SetVerifyPasswordFunc(PK11VerifyPasswordFunc func)
543
0
{
544
0
    PK11_Global.verifyPass = func;
545
0
}
546
547
void
548
PK11_SetIsLoggedInFunc(PK11IsLoggedInFunc func)
549
0
{
550
0
    PK11_Global.isLoggedIn = func;
551
0
}
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
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
649
PK11_LogoutAll(void)
650
0
{
651
0
    SECMODListLock *lock = SECMOD_GetDefaultModuleListLock();
652
0
    SECMODModuleList *modList;
653
0
    SECMODModuleList *mlp = NULL;
654
0
    int i;
655
0
656
0
    /* NSS is not initialized, there are not tokens to log out */
657
0
    if (lock == NULL) {
658
0
        return;
659
0
    }
660
0
661
0
    SECMOD_GetReadLock(lock);
662
0
    modList = SECMOD_GetDefaultModuleList();
663
0
    /* find the number of entries */
664
0
    for (mlp = modList; mlp != NULL; mlp = mlp->next) {
665
0
        for (i = 0; i < mlp->module->slotCount; i++) {
666
0
            PK11_Logout(mlp->module->slots[i]);
667
0
        }
668
0
    }
669
0
670
0
    SECMOD_ReleaseReadLock(lock);
671
0
}
672
673
int
674
PK11_GetMinimumPwdLength(PK11SlotInfo *slot)
675
0
{
676
0
    return ((int)slot->minPassword);
677
0
}
678
679
/* Does this slot have a protected pin path? */
680
PRBool
681
PK11_ProtectedAuthenticationPath(PK11SlotInfo *slot)
682
0
{
683
0
    return slot->protectedAuthPath;
684
0
}
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
692
PK11_NeedPWInitForSlot(PK11SlotInfo *slot)
693
0
{
694
0
    if (slot->needLogin && PK11_NeedUserInit(slot)) {
695
0
        return PR_TRUE;
696
0
    }
697
0
    if (!slot->needLogin && !PK11_NeedUserInit(slot)) {
698
0
        return PR_TRUE;
699
0
    }
700
0
    return PR_FALSE;
701
0
}
702
703
PRBool
704
PK11_NeedPWInit()
705
0
{
706
0
    PK11SlotInfo *slot = PK11_GetInternalKeySlot();
707
0
    PRBool ret = PR_FALSE;
708
0
    if (slot) {
709
0
        ret = PK11_NeedPWInitForSlot(slot);
710
0
        PK11_FreeSlot(slot);
711
0
    }
712
0
    return ret;
713
0
}
714
715
PRBool
716
pk11_InDelayPeriod(PRIntervalTime lastTime, PRIntervalTime delayTime,
717
                   PRIntervalTime *retTime)
718
0
{
719
0
    PRIntervalTime time;
720
0
721
0
    *retTime = time = PR_IntervalNow();
722
0
    return (PRBool)(lastTime) && ((time - lastTime) < delayTime);
723
0
}
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
730
PK11_IsLoggedIn(PK11SlotInfo *slot, void *wincx)
731
0
{
732
0
    CK_SESSION_INFO sessionInfo;
733
0
    int askpw = slot->askpw;
734
0
    int timeout = slot->timeout;
735
0
    CK_RV crv;
736
0
    PRIntervalTime curTime;
737
0
    static PRIntervalTime login_delay_time = 0;
738
0
739
0
    if (login_delay_time == 0) {
740
0
        login_delay_time = PR_SecondsToInterval(1);
741
0
    }
742
0
743
0
    /* If we don't have our own password default values, use the system
744
0
     * ones */
745
0
    if ((slot->defaultFlags & PK11_OWN_PW_DEFAULTS) == 0) {
746
0
        PK11SlotInfo *def_slot = PK11_GetInternalKeySlot();
747
0
748
0
        if (def_slot) {
749
0
            askpw = def_slot->askpw;
750
0
            timeout = def_slot->timeout;
751
0
            PK11_FreeSlot(def_slot);
752
0
        }
753
0
    }
754
0
755
0
    if ((wincx != NULL) && (PK11_Global.isLoggedIn != NULL) &&
756
0
        (*PK11_Global.isLoggedIn)(slot, wincx) == PR_FALSE) {
757
0
        return PR_FALSE;
758
0
    }
759
0
760
0
    /* forget the password if we've been inactive too long */
761
0
    if (askpw == 1) {
762
0
        PRTime currtime = PR_Now();
763
0
        PRTime result;
764
0
        PRTime mult;
765
0
766
0
        LL_I2L(result, timeout);
767
0
        LL_I2L(mult, 60 * 1000 * 1000);
768
0
        LL_MUL(result, result, mult);
769
0
        LL_ADD(result, result, slot->authTime);
770
0
        if (LL_CMP(result, <, currtime)) {
771
0
            PK11_EnterSlotMonitor(slot);
772
0
            PK11_GETTAB(slot)->C_Logout(slot->session);
773
0
            slot->lastLoginCheck = 0;
774
0
            PK11_ExitSlotMonitor(slot);
775
0
        } else {
776
0
            slot->authTime = currtime;
777
0
        }
778
0
    }
779
0
780
0
    PK11_EnterSlotMonitor(slot);
781
0
    if (pk11_InDelayPeriod(slot->lastLoginCheck, login_delay_time, &curTime)) {
782
0
        sessionInfo.state = slot->lastState;
783
0
        crv = CKR_OK;
784
0
    } else {
785
0
        crv = PK11_GETTAB(slot)->C_GetSessionInfo(slot->session, &sessionInfo);
786
0
        if (crv == CKR_OK) {
787
0
            slot->lastState = sessionInfo.state;
788
0
            slot->lastLoginCheck = curTime;
789
0
        }
790
0
    }
791
0
    PK11_ExitSlotMonitor(slot);
792
0
    /* if we can't get session info, something is really wrong */
793
0
    if (crv != CKR_OK) {
794
0
        slot->session = CK_INVALID_SESSION;
795
0
        return PR_FALSE;
796
0
    }
797
0
798
0
    switch (sessionInfo.state) {
799
0
        case CKS_RW_PUBLIC_SESSION:
800
0
        case CKS_RO_PUBLIC_SESSION:
801
0
        default:
802
0
            break; /* fail */
803
0
        case CKS_RW_USER_FUNCTIONS:
804
0
        case CKS_RW_SO_FUNCTIONS:
805
0
        case CKS_RO_USER_FUNCTIONS:
806
0
            return PR_TRUE;
807
0
    }
808
0
    return PR_FALSE;
809
0
}