Coverage Report

Created: 2024-11-21 07:03

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