Coverage Report

Created: 2024-11-21 07:03

/src/nss-nspr/nss/lib/nss/nssinit.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * NSS utility functions
3
 *
4
 * This Source Code Form is subject to the terms of the Mozilla Public
5
 * License, v. 2.0. If a copy of the MPL was not distributed with this
6
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8
#include <ctype.h>
9
#include <string.h>
10
#include "seccomon.h"
11
#include "prinit.h"
12
#include "prprf.h"
13
#include "prmem.h"
14
#include "cert.h"
15
#include "keyhi.h"
16
#include "secmod.h"
17
#include "secoid.h"
18
#include "nss.h"
19
#include "pk11func.h"
20
#include "secerr.h"
21
#include "nssbase.h"
22
#include "nssutil.h"
23
24
#ifndef NSS_DISABLE_LIBPKIX
25
#include "pkixt.h"
26
#include "pkix.h"
27
#include "pkix_tools.h"
28
#endif /* NSS_DISABLE_LIBPKIX */
29
30
#include "pki3hack.h"
31
#include "certi.h"
32
#include "secmodi.h"
33
#include "ocspti.h"
34
#include "ocspi.h"
35
#include "utilpars.h"
36
37
/*
38
 * On Windows nss3.dll needs to export the symbol 'mktemp' to be
39
 * fully backward compatible with the nss3.dll in NSS 3.2.x and
40
 * 3.3.x.  This symbol was unintentionally exported and its
41
 * definition (in DBM) was moved from nss3.dll to softokn3.dll
42
 * in NSS 3.4.  See bug 142575.
43
 */
44
#ifdef WIN32_NSS3_DLL_COMPAT
45
#include <io.h>
46
47
/* exported as 'mktemp' */
48
char *
49
nss_mktemp(char *path)
50
{
51
    return _mktemp(path);
52
}
53
#endif
54
55
4
#define NSS_MAX_FLAG_SIZE sizeof("readOnly") + sizeof("noCertDB") +                                  \
56
4
                              sizeof("noModDB") + sizeof("forceOpen") + sizeof("passwordRequired") + \
57
4
                              sizeof("optimizeSpace") + sizeof("printPolicyFeedback")
58
2
#define NSS_DEFAULT_MOD_NAME "NSS Internal Module"
59
60
static char *
61
nss_makeFlags(PRBool readOnly, PRBool noCertDB,
62
              PRBool noModDB, PRBool forceOpen,
63
              PRBool passwordRequired, PRBool optimizeSpace)
64
2
{
65
2
    char *flags = (char *)PORT_Alloc(NSS_MAX_FLAG_SIZE);
66
2
    PRBool first = PR_TRUE;
67
68
2
    PORT_Memset(flags, 0, NSS_MAX_FLAG_SIZE);
69
2
    if (readOnly) {
70
2
        PORT_Strcat(flags, "readOnly");
71
2
        first = PR_FALSE;
72
2
    }
73
2
    if (noCertDB) {
74
2
        if (!first)
75
2
            PORT_Strcat(flags, ",");
76
2
        PORT_Strcat(flags, "noCertDB");
77
2
        first = PR_FALSE;
78
2
    }
79
2
    if (noModDB) {
80
2
        if (!first)
81
2
            PORT_Strcat(flags, ",");
82
2
        PORT_Strcat(flags, "noModDB");
83
2
        first = PR_FALSE;
84
2
    }
85
2
    if (forceOpen) {
86
2
        if (!first)
87
2
            PORT_Strcat(flags, ",");
88
2
        PORT_Strcat(flags, "forceOpen");
89
2
        first = PR_FALSE;
90
2
    }
91
2
    if (passwordRequired) {
92
0
        if (!first)
93
0
            PORT_Strcat(flags, ",");
94
0
        PORT_Strcat(flags, "passwordRequired");
95
0
        first = PR_FALSE;
96
0
    }
97
2
    if (optimizeSpace) {
98
2
        if (!first)
99
2
            PORT_Strcat(flags, ",");
100
2
        PORT_Strcat(flags, "optimizeSpace");
101
2
    }
102
2
    return flags;
103
2
}
104
105
/*
106
 * build config string from individual internationalized strings
107
 */
108
char *
109
nss_MkConfigString(const char *man, const char *libdesc, const char *tokdesc,
110
                   const char *ptokdesc, const char *slotdesc, const char *pslotdesc,
111
                   const char *fslotdesc, const char *fpslotdesc, int minPwd)
112
0
{
113
0
    char *strings = NULL;
114
0
    char *newStrings;
115
116
    /* make sure the internationalization was done correctly... */
117
0
    strings = PR_smprintf("");
118
0
    if (strings == NULL)
119
0
        return NULL;
120
121
0
    if (man) {
122
0
        newStrings = PR_smprintf("%s manufacturerID='%s'", strings, man);
123
0
        PR_smprintf_free(strings);
124
0
        strings = newStrings;
125
0
    }
126
0
    if (strings == NULL)
127
0
        return NULL;
128
129
0
    if (libdesc) {
130
0
        newStrings = PR_smprintf("%s libraryDescription='%s'", strings, libdesc);
131
0
        PR_smprintf_free(strings);
132
0
        strings = newStrings;
133
0
    }
134
0
    if (strings == NULL)
135
0
        return NULL;
136
137
0
    if (tokdesc) {
138
0
        newStrings = PR_smprintf("%s cryptoTokenDescription='%s'", strings,
139
0
                                 tokdesc);
140
0
        PR_smprintf_free(strings);
141
0
        strings = newStrings;
142
0
    }
143
0
    if (strings == NULL)
144
0
        return NULL;
145
146
0
    if (ptokdesc) {
147
0
        newStrings = PR_smprintf("%s dbTokenDescription='%s'", strings, ptokdesc);
148
0
        PR_smprintf_free(strings);
149
0
        strings = newStrings;
150
0
    }
151
0
    if (strings == NULL)
152
0
        return NULL;
153
154
0
    if (slotdesc) {
155
0
        newStrings = PR_smprintf("%s cryptoSlotDescription='%s'", strings,
156
0
                                 slotdesc);
157
0
        PR_smprintf_free(strings);
158
0
        strings = newStrings;
159
0
    }
160
0
    if (strings == NULL)
161
0
        return NULL;
162
163
0
    if (pslotdesc) {
164
0
        newStrings = PR_smprintf("%s dbSlotDescription='%s'", strings, pslotdesc);
165
0
        PR_smprintf_free(strings);
166
0
        strings = newStrings;
167
0
    }
168
0
    if (strings == NULL)
169
0
        return NULL;
170
171
0
    if (fslotdesc) {
172
0
        newStrings = PR_smprintf("%s FIPSSlotDescription='%s'",
173
0
                                 strings, fslotdesc);
174
0
        PR_smprintf_free(strings);
175
0
        strings = newStrings;
176
0
    }
177
0
    if (strings == NULL)
178
0
        return NULL;
179
180
0
    if (fpslotdesc) {
181
0
        newStrings = PR_smprintf("%s FIPSTokenDescription='%s'",
182
0
                                 strings, fpslotdesc);
183
0
        PR_smprintf_free(strings);
184
0
        strings = newStrings;
185
0
    }
186
0
    if (strings == NULL)
187
0
        return NULL;
188
189
0
    newStrings = PR_smprintf("%s minPS=%d", strings, minPwd);
190
0
    PR_smprintf_free(strings);
191
0
    strings = newStrings;
192
193
0
    return (strings);
194
0
}
195
196
/*
197
 * statics to remember the PK11_ConfigurePKCS11()
198
 * info.
199
 */
200
static char *pk11_config_strings = NULL;
201
static char *pk11_config_name = NULL;
202
static PRBool pk11_password_required = PR_FALSE;
203
204
/*
205
 * this is a legacy configuration function which used to be part of
206
 * the PKCS #11 internal token.
207
 */
208
void
209
PK11_ConfigurePKCS11(const char *man, const char *libdesc, const char *tokdesc,
210
                     const char *ptokdesc, const char *slotdesc, const char *pslotdesc,
211
                     const char *fslotdesc, const char *fpslotdesc, int minPwd,
212
                     int pwRequired)
213
0
{
214
0
    char *strings;
215
216
0
    strings = nss_MkConfigString(man, libdesc, tokdesc, ptokdesc, slotdesc,
217
0
                                 pslotdesc, fslotdesc, fpslotdesc, minPwd);
218
0
    if (strings == NULL) {
219
0
        return;
220
0
    }
221
222
0
    if (libdesc) {
223
0
        if (pk11_config_name != NULL) {
224
0
            PORT_Free(pk11_config_name);
225
0
        }
226
0
        pk11_config_name = PORT_Strdup(libdesc);
227
0
    }
228
229
0
    if (pk11_config_strings != NULL) {
230
0
        PR_smprintf_free(pk11_config_strings);
231
0
    }
232
0
    pk11_config_strings = strings;
233
0
    pk11_password_required = pwRequired;
234
235
0
    return;
236
0
}
237
238
void
239
PK11_UnconfigurePKCS11(void)
240
0
{
241
0
    if (pk11_config_strings != NULL) {
242
0
        PR_smprintf_free(pk11_config_strings);
243
0
        pk11_config_strings = NULL;
244
0
    }
245
0
    if (pk11_config_name) {
246
0
        PORT_Free(pk11_config_name);
247
0
        pk11_config_name = NULL;
248
0
    }
249
0
}
250
251
/*
252
 * The following code is an attempt to automagically find the external root
253
 * module.
254
 * Note: Keep the #if-defined chunks in order. HPUX must select before UNIX.
255
 */
256
257
static const char *dllname =
258
#if defined(XP_WIN32)
259
    "nssckbi.dll";
260
#elif defined(HPUX) && !defined(__ia64) /* HP-UX PA-RISC */
261
    "libnssckbi.sl";
262
#elif defined(DARWIN)
263
    "libnssckbi.dylib";
264
#elif defined(XP_UNIX)
265
    "libnssckbi.so";
266
#else
267
#error "Uh! Oh! I don't know about this platform."
268
#endif
269
270
/* Should we have platform ifdefs here??? */
271
0
#define FILE_SEP '/'
272
273
static void
274
nss_FindExternalRootPaths(const char *dbpath,
275
                          const char *secmodprefix,
276
                          char **retoldpath, char **retnewpath)
277
0
{
278
0
    char *path, *oldpath = NULL, *lastsep;
279
0
    int len, path_len, secmod_len, dll_len;
280
281
0
    path_len = PORT_Strlen(dbpath);
282
0
    secmod_len = secmodprefix ? PORT_Strlen(secmodprefix) : 0;
283
0
    dll_len = PORT_Strlen(dllname);
284
0
    len = path_len + secmod_len + dll_len + 2; /* FILE_SEP + NULL */
285
286
0
    path = PORT_Alloc(len);
287
0
    if (path == NULL)
288
0
        return;
289
290
    /* back up to the top of the directory */
291
0
    PORT_Memcpy(path, dbpath, path_len);
292
0
    if (path[path_len - 1] != FILE_SEP) {
293
0
        path[path_len++] = FILE_SEP;
294
0
    }
295
0
    PORT_Strcpy(&path[path_len], dllname);
296
0
    if (secmod_len > 0) {
297
0
        lastsep = PORT_Strrchr(secmodprefix, FILE_SEP);
298
0
        if (lastsep) {
299
0
            int secmoddir_len = lastsep - secmodprefix + 1; /* FILE_SEP */
300
0
            oldpath = PORT_Alloc(len);
301
0
            if (oldpath == NULL) {
302
0
                PORT_Free(path);
303
0
                return;
304
0
            }
305
0
            PORT_Memcpy(oldpath, path, path_len);
306
0
            PORT_Memcpy(&oldpath[path_len], secmodprefix, secmoddir_len);
307
0
            PORT_Strcpy(&oldpath[path_len + secmoddir_len], dllname);
308
0
        }
309
0
    }
310
0
    *retoldpath = oldpath;
311
0
    *retnewpath = path;
312
0
    return;
313
0
}
314
315
static void
316
nss_FreeExternalRootPaths(char *oldpath, char *path)
317
0
{
318
0
    if (path) {
319
0
        PORT_Free(path);
320
0
    }
321
0
    if (oldpath) {
322
0
        PORT_Free(oldpath);
323
0
    }
324
0
}
325
326
static void
327
nss_FindExternalRoot(const char *dbpath, const char *secmodprefix)
328
0
{
329
0
    char *path = NULL;
330
0
    char *oldpath = NULL;
331
0
    PRBool hasrootcerts = PR_FALSE;
332
333
    /*
334
     * 'oldpath' is the external root path in NSS 3.3.x or older.
335
     * For backward compatibility we try to load the root certs
336
     * module with the old path first.
337
     */
338
0
    nss_FindExternalRootPaths(dbpath, secmodprefix, &oldpath, &path);
339
0
    if (oldpath) {
340
0
        (void)SECMOD_AddNewModule("Root Certs", oldpath, 0, 0);
341
0
        hasrootcerts = SECMOD_HasRootCerts();
342
0
    }
343
0
    if (path && !hasrootcerts) {
344
0
        (void)SECMOD_AddNewModule("Root Certs", path, 0, 0);
345
0
    }
346
0
    nss_FreeExternalRootPaths(oldpath, path);
347
0
    return;
348
0
}
349
350
/*
351
 * see nss_Init for definitions of the various options.
352
 *
353
 * this function builds a moduleSpec string from the options and previously
354
 * set statics (from PKCS11_Configure, for instance), and uses it to kick off
355
 * the loading of the various PKCS #11 modules.
356
 */
357
static SECMODModule *
358
nss_InitModules(const char *configdir, const char *certPrefix,
359
                const char *keyPrefix, const char *secmodName,
360
                const char *updateDir, const char *updCertPrefix,
361
                const char *updKeyPrefix, const char *updateID,
362
                const char *updateName, char *configName, char *configStrings,
363
                PRBool pwRequired, PRBool readOnly, PRBool noCertDB,
364
                PRBool noModDB, PRBool forceOpen, PRBool optimizeSpace,
365
                PRBool isContextInit)
366
2
{
367
2
    SECMODModule *module = NULL;
368
2
    char *moduleSpec = NULL;
369
2
    char *flags = NULL;
370
2
    char *lconfigdir = NULL;
371
2
    char *lcertPrefix = NULL;
372
2
    char *lkeyPrefix = NULL;
373
2
    char *lsecmodName = NULL;
374
2
    char *lupdateDir = NULL;
375
2
    char *lupdCertPrefix = NULL;
376
2
    char *lupdKeyPrefix = NULL;
377
2
    char *lupdateID = NULL;
378
2
    char *lupdateName = NULL;
379
380
2
    if (NSS_InitializePRErrorTable() != SECSuccess) {
381
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
382
0
        return NULL;
383
0
    }
384
385
2
    flags = nss_makeFlags(readOnly, noCertDB, noModDB, forceOpen,
386
2
                          pwRequired, optimizeSpace);
387
2
    if (flags == NULL)
388
0
        return NULL;
389
390
    /*
391
     * configdir is double nested, and Windows uses the same character
392
     * for file seps as we use for escapes! (sigh).
393
     */
394
2
    lconfigdir = NSSUTIL_DoubleEscape(configdir, '\'', '\"');
395
2
    if (lconfigdir == NULL) {
396
0
        goto loser;
397
0
    }
398
2
    lcertPrefix = NSSUTIL_DoubleEscape(certPrefix, '\'', '\"');
399
2
    if (lcertPrefix == NULL) {
400
0
        goto loser;
401
0
    }
402
2
    lkeyPrefix = NSSUTIL_DoubleEscape(keyPrefix, '\'', '\"');
403
2
    if (lkeyPrefix == NULL) {
404
0
        goto loser;
405
0
    }
406
2
    lsecmodName = NSSUTIL_DoubleEscape(secmodName, '\'', '\"');
407
2
    if (lsecmodName == NULL) {
408
0
        goto loser;
409
0
    }
410
2
    lupdateDir = NSSUTIL_DoubleEscape(updateDir, '\'', '\"');
411
2
    if (lupdateDir == NULL) {
412
0
        goto loser;
413
0
    }
414
2
    lupdCertPrefix = NSSUTIL_DoubleEscape(updCertPrefix, '\'', '\"');
415
2
    if (lupdCertPrefix == NULL) {
416
0
        goto loser;
417
0
    }
418
2
    lupdKeyPrefix = NSSUTIL_DoubleEscape(updKeyPrefix, '\'', '\"');
419
2
    if (lupdKeyPrefix == NULL) {
420
0
        goto loser;
421
0
    }
422
2
    lupdateID = NSSUTIL_DoubleEscape(updateID, '\'', '\"');
423
2
    if (lupdateID == NULL) {
424
0
        goto loser;
425
0
    }
426
2
    lupdateName = NSSUTIL_DoubleEscape(updateName, '\'', '\"');
427
2
    if (lupdateName == NULL) {
428
0
        goto loser;
429
0
    }
430
431
2
    moduleSpec = PR_smprintf(
432
2
        "name=\"%s\" parameters=\"configdir='%s' certPrefix='%s' keyPrefix='%s' "
433
2
        "secmod='%s' flags=%s updatedir='%s' updateCertPrefix='%s' "
434
2
        "updateKeyPrefix='%s' updateid='%s' updateTokenDescription='%s' %s\" "
435
2
        "NSS=\"flags=internal,moduleDB,moduleDBOnly,critical%s\"",
436
2
        configName ? configName : NSS_DEFAULT_MOD_NAME,
437
2
        lconfigdir, lcertPrefix, lkeyPrefix, lsecmodName, flags,
438
2
        lupdateDir, lupdCertPrefix, lupdKeyPrefix, lupdateID,
439
2
        lupdateName, configStrings ? configStrings : "",
440
2
        isContextInit ? "" : ",defaultModDB,internalKeySlot");
441
442
2
loser:
443
2
    PORT_Free(flags);
444
2
    if (lconfigdir)
445
2
        PORT_Free(lconfigdir);
446
2
    if (lcertPrefix)
447
2
        PORT_Free(lcertPrefix);
448
2
    if (lkeyPrefix)
449
2
        PORT_Free(lkeyPrefix);
450
2
    if (lsecmodName)
451
2
        PORT_Free(lsecmodName);
452
2
    if (lupdateDir)
453
2
        PORT_Free(lupdateDir);
454
2
    if (lupdCertPrefix)
455
2
        PORT_Free(lupdCertPrefix);
456
2
    if (lupdKeyPrefix)
457
2
        PORT_Free(lupdKeyPrefix);
458
2
    if (lupdateID)
459
2
        PORT_Free(lupdateID);
460
2
    if (lupdateName)
461
2
        PORT_Free(lupdateName);
462
463
2
    if (moduleSpec) {
464
2
        module = SECMOD_LoadModule(moduleSpec, NULL, PR_TRUE);
465
2
        PR_smprintf_free(moduleSpec);
466
2
        if (module && !module->loaded) {
467
0
            SECMOD_DestroyModule(module);
468
0
            return NULL;
469
0
        }
470
2
    }
471
2
    return module;
472
2
}
473
474
/*
475
 * OK there are now lots of options here, lets go through them all:
476
 *
477
 * configdir - base directory where all the cert, key, and module datbases live.
478
 * certPrefix - prefix added to the beginning of the cert database example: "
479
 *             "https-server1-"
480
 * keyPrefix - prefix added to the beginning of the key database example: "
481
 *             "https-server1-"
482
 * secmodName - name of the security module database (usually "secmod.db").
483
 * updateDir - used in initMerge, old directory to update from.
484
 * updateID - used in initMerge, unique ID to represent the updated directory.
485
 * updateName - used in initMerge, token name when updating.
486
 * initContextPtr -  used in initContext, pointer to return a unique context
487
 *            value.
488
 * readOnly - Boolean: true if the databases are to be opened read only.
489
 * nocertdb - Don't open the cert DB and key DB's, just initialize the
490
 *             Volatile certdb.
491
 * nomoddb - Don't open the security module DB, just initialize the
492
 *             PKCS #11 module.
493
 * forceOpen - Continue to force initializations even if the databases cannot
494
 *             be opened.
495
 * noRootInit - don't try to automatically load the root cert store if one is
496
 *           not found.
497
 * optimizeSpace - tell NSS to use fewer hash table buckets.
498
 *
499
 * The next three options are used in an attempt to share PKCS #11 modules
500
 * with other loaded, running libraries. PKCS #11 was not designed with this
501
 * sort of sharing in mind, so use of these options may lead to questionable
502
 * results. These options are may be incompatible with NSS_LoadContext() calls.
503
 *
504
 * noSingleThreadedModules - don't load modules that are not thread safe (many
505
 *           smart card tokens will not work).
506
 * allowAlreadyInitializedModules - if a module has already been loaded and
507
 *           initialize try to use it.
508
 * don'tFinalizeModules -  dont shutdown modules we may have loaded.
509
 */
510
511
static PRBool nssIsInitted = PR_FALSE;
512
static NSSInitContext *nssInitContextList = NULL;
513
514
#ifndef NSS_DISABLE_LIBPKIX
515
static void *plContext = NULL;
516
#endif /* NSS_DISABLE_LIBPKIX */
517
518
struct NSSInitContextStr {
519
    NSSInitContext *next;
520
    PRUint32 magic;
521
};
522
523
0
#define NSS_INIT_MAGIC 0x1413A91C
524
static SECStatus nss_InitShutdownList(void);
525
526
/* All initialized to zero in BSS */
527
static PRCallOnceType nssInitOnce;
528
static PZLock *nssInitLock;
529
static PZCondVar *nssInitCondition;
530
static int nssIsInInit;
531
532
static PRStatus
533
nss_doLockInit(void)
534
2
{
535
2
    nssInitLock = PZ_NewLock(nssILockOther);
536
2
    if (nssInitLock == NULL) {
537
0
        return PR_FAILURE;
538
0
    }
539
2
    nssInitCondition = PZ_NewCondVar(nssInitLock);
540
2
    if (nssInitCondition == NULL) {
541
0
        return PR_FAILURE;
542
0
    }
543
2
    return PR_SUCCESS;
544
2
}
545
546
static SECStatus
547
nss_Init(const char *configdir, const char *certPrefix, const char *keyPrefix,
548
         const char *secmodName, const char *updateDir,
549
         const char *updCertPrefix, const char *updKeyPrefix,
550
         const char *updateID, const char *updateName,
551
         NSSInitContext **initContextPtr,
552
         NSSInitParameters *initParams,
553
         PRBool readOnly, PRBool noCertDB,
554
         PRBool noModDB, PRBool forceOpen, PRBool noRootInit,
555
         PRBool optimizeSpace, PRBool noSingleThreadedModules,
556
         PRBool allowAlreadyInitializedModules,
557
         PRBool dontFinalizeModules)
558
2
{
559
2
    SECMODModule *parent = NULL;
560
#ifndef NSS_DISABLE_LIBPKIX
561
    PKIX_UInt32 actualMinorVersion = 0;
562
    PKIX_Error *pkixError = NULL;
563
#endif /* NSS_DISABLE_LIBPKIX */
564
2
    PRBool isReallyInitted;
565
2
    char *configStrings = NULL;
566
2
    char *configName = NULL;
567
2
    PRBool passwordRequired = PR_FALSE;
568
#ifdef POLICY_FILE
569
    char *ignoreVar;
570
#endif
571
572
    /* if we are trying to init with a traditional NSS_Init call, maintain
573
     * the traditional idempotent behavior. */
574
2
    if (!initContextPtr && nssIsInitted) {
575
0
        return SECSuccess;
576
0
    }
577
578
    /* make sure our lock and condition variable are initialized one and only
579
     * one time */
580
2
    if (PR_CallOnce(&nssInitOnce, nss_doLockInit) != PR_SUCCESS) {
581
0
        return SECFailure;
582
0
    }
583
584
    /*
585
     * if we haven't done basic initialization, single thread the
586
     * initializations.
587
     */
588
2
    PZ_Lock(nssInitLock);
589
2
    isReallyInitted = NSS_IsInitialized();
590
2
    if (!isReallyInitted) {
591
2
        while (!isReallyInitted && nssIsInInit) {
592
0
            PZ_WaitCondVar(nssInitCondition, PR_INTERVAL_NO_TIMEOUT);
593
0
            isReallyInitted = NSS_IsInitialized();
594
0
        }
595
        /* once we've completed basic initialization, we can allow more than
596
         * one process initialize NSS at a time. */
597
2
    }
598
2
    nssIsInInit++;
599
2
    PZ_Unlock(nssInitLock);
600
601
    /* this tells us whether or not some library has already initialized us.
602
     * if so, we don't want to double call some of the basic initialization
603
     * functions */
604
605
2
    if (!isReallyInitted) {
606
2
#ifdef DEBUG
607
2
        CERTCertificate dummyCert;
608
        /* New option bits must not change the size of CERTCertificate. */
609
2
        PORT_Assert(sizeof(dummyCert.options) == sizeof(void *));
610
2
#endif
611
612
2
        if (SECSuccess != cert_InitLocks()) {
613
0
            goto loser;
614
0
        }
615
616
2
        if (SECSuccess != InitCRLCache()) {
617
0
            goto loser;
618
0
        }
619
620
2
        if (SECSuccess != OCSP_InitGlobal()) {
621
0
            goto loser;
622
0
        }
623
2
    }
624
625
2
    if (noSingleThreadedModules || allowAlreadyInitializedModules ||
626
2
        dontFinalizeModules) {
627
0
        pk11_setGlobalOptions(noSingleThreadedModules,
628
0
                              allowAlreadyInitializedModules,
629
0
                              dontFinalizeModules);
630
0
    }
631
632
2
    if (initContextPtr) {
633
0
        *initContextPtr = PORT_ZNew(NSSInitContext);
634
0
        if (*initContextPtr == NULL) {
635
0
            goto loser;
636
0
        }
637
        /*
638
         * For traditional NSS_Init, we used the PK11_Configure() call to set
639
         * globals. with InitContext, we pass those strings in as parameters.
640
         *
641
         * This allows old NSS_Init calls to work as before, while at the same
642
         * time new calls and old calls will not interfere with each other.
643
         */
644
0
        if (initParams) {
645
0
            if (initParams->length < sizeof(NSSInitParameters)) {
646
0
                PORT_SetError(SEC_ERROR_INVALID_ARGS);
647
0
                goto loser;
648
0
            }
649
0
            configStrings = nss_MkConfigString(initParams->manufactureID,
650
0
                                               initParams->libraryDescription,
651
0
                                               initParams->cryptoTokenDescription,
652
0
                                               initParams->dbTokenDescription,
653
0
                                               initParams->cryptoSlotDescription,
654
0
                                               initParams->dbSlotDescription,
655
0
                                               initParams->FIPSSlotDescription,
656
0
                                               initParams->FIPSTokenDescription,
657
0
                                               initParams->minPWLen);
658
0
            if (configStrings == NULL) {
659
0
                PORT_SetError(SEC_ERROR_NO_MEMORY);
660
0
                goto loser;
661
0
            }
662
0
            configName = initParams->libraryDescription;
663
0
            passwordRequired = initParams->passwordRequired;
664
0
        }
665
666
        /* If we're NSS_ContextInit, we're probably a library. It could be
667
         * possible that the application initialized NSS then forked(). The
668
         * library would have no knowledge of that. If we call
669
         * SECMOD_RestartModules() here, we will be able to continue on with
670
         * NSS as normal. SECMOD_RestartModules() does have the side affect
671
         * of losing all our PKCS #11 objects in the new process, but only if
672
         * the module needs to be reinited. If it needs to be reinit those
673
         * objects are inaccessible anyway, it's always save to call
674
         * SECMOD_RestartModules(PR_FALSE).
675
         */
676
        /* NOTE: We could call SECMOD_Init() here, but if we aren't already
677
         * inited, then there's no modules to restart, so SECMOD_RestartModules
678
         * will return immediately */
679
0
        SECMOD_RestartModules(PR_FALSE);
680
2
    } else {
681
2
        configStrings = pk11_config_strings;
682
2
        configName = pk11_config_name;
683
2
        passwordRequired = pk11_password_required;
684
2
    }
685
686
    /* Skip the module init if we are already initted and we are trying
687
     * to init with noCertDB and noModDB */
688
2
    if (!(isReallyInitted && noCertDB && noModDB)) {
689
2
        parent = nss_InitModules(configdir, certPrefix, keyPrefix, secmodName,
690
2
                                 updateDir, updCertPrefix, updKeyPrefix, updateID,
691
2
                                 updateName, configName, configStrings, passwordRequired,
692
2
                                 readOnly, noCertDB, noModDB, forceOpen, optimizeSpace,
693
2
                                 (initContextPtr != NULL));
694
695
2
        if (parent == NULL) {
696
0
            goto loser;
697
0
        }
698
2
    }
699
700
    /* finish up initialization */
701
2
    if (!isReallyInitted) {
702
2
        if (SECOID_Init() != SECSuccess) {
703
0
            goto loser;
704
0
        }
705
#ifdef POLICY_FILE
706
        /* Load the system crypto policy file if it exists,
707
         * unless the NSS_IGNORE_SYSTEM_POLICY environment
708
         * variable has been set to 1. */
709
        ignoreVar = PR_GetEnvSecure("NSS_IGNORE_SYSTEM_POLICY");
710
        if (ignoreVar == NULL || strncmp(ignoreVar, "1", sizeof("1")) != 0) {
711
            if (PR_Access(POLICY_PATH "/" POLICY_FILE, PR_ACCESS_READ_OK) == PR_SUCCESS) {
712
                SECMODModule *module = SECMOD_LoadModule(
713
                    "name=\"Policy File\" "
714
                    "parameters=\"configdir='sql:" POLICY_PATH "' "
715
                    "secmod='" POLICY_FILE "' "
716
                    "flags=readOnly,noCertDB,forceSecmodChoice,forceOpen\" "
717
                    "NSS=\"flags=internal,moduleDB,skipFirst,moduleDBOnly,critical\"",
718
                    parent, PR_TRUE);
719
                if (module) {
720
                    PRBool isLoaded = module->loaded;
721
                    SECMOD_DestroyModule(module);
722
                    if (!isLoaded) {
723
                        goto loser;
724
                    }
725
                }
726
            }
727
        }
728
#endif
729
2
        if (STAN_LoadDefaultNSS3TrustDomain() != PR_SUCCESS) {
730
0
            goto loser;
731
0
        }
732
2
        if (nss_InitShutdownList() != SECSuccess) {
733
0
            goto loser;
734
0
        }
735
2
        CERT_SetDefaultCertDB((CERTCertDBHandle *)
736
2
                                  STAN_GetDefaultTrustDomain());
737
2
        if ((!noModDB) && (!noCertDB) && (!noRootInit)) {
738
0
            if (!SECMOD_HasRootCerts()) {
739
0
                const char *dbpath = configdir;
740
                /* handle supported database modifiers */
741
0
                if (strncmp(dbpath, "sql:", 4) == 0) {
742
0
                    dbpath += 4;
743
0
                } else if (strncmp(dbpath, "dbm:", 4) == 0) {
744
0
                    dbpath += 4;
745
0
                } else if (strncmp(dbpath, "extern:", 7) == 0) {
746
0
                    dbpath += 7;
747
0
                } else if (strncmp(dbpath, "rdb:", 4) == 0) {
748
                    /* if rdb: is specified, the configdir isn't really a
749
                     * path. Skip it */
750
0
                    dbpath = NULL;
751
0
                }
752
0
                if (dbpath) {
753
0
                    nss_FindExternalRoot(dbpath, secmodName);
754
0
                }
755
0
            }
756
0
        }
757
2
        pk11sdr_Init();
758
2
        cert_CreateSubjectKeyIDHashTable();
759
760
#ifndef NSS_DISABLE_LIBPKIX
761
        pkixError = PKIX_Initialize(PKIX_FALSE, PKIX_MAJOR_VERSION, PKIX_MINOR_VERSION,
762
                                    PKIX_MINOR_VERSION, &actualMinorVersion, &plContext);
763
764
        if (pkixError != NULL) {
765
            goto loser;
766
        } else {
767
            char *ev = PR_GetEnvSecure("NSS_DISABLE_PKIX_VERIFY");
768
            if (ev && ev[0]) {
769
                CERT_SetUsePKIXForValidation(PR_FALSE);
770
            }
771
        }
772
#endif /* NSS_DISABLE_LIBPKIX */
773
2
    }
774
775
    /*
776
     * Now mark the appropriate init state. If initContextPtr was passed
777
     * in, then return the new context pointer and add it to the
778
     * nssInitContextList. Otherwise set the global nss_isInitted flag
779
     */
780
2
    PZ_Lock(nssInitLock);
781
2
    if (!initContextPtr) {
782
2
        nssIsInitted = PR_TRUE;
783
2
    } else {
784
0
        (*initContextPtr)->magic = NSS_INIT_MAGIC;
785
0
        (*initContextPtr)->next = nssInitContextList;
786
0
        nssInitContextList = (*initContextPtr);
787
0
    }
788
2
    nssIsInInit--;
789
    /* now that we are inited, all waiters can move forward */
790
2
    PZ_NotifyAllCondVar(nssInitCondition);
791
2
    PZ_Unlock(nssInitLock);
792
793
2
    if (initContextPtr && configStrings) {
794
0
        PR_smprintf_free(configStrings);
795
0
    }
796
2
    if (parent) {
797
2
        SECMOD_DestroyModule(parent);
798
2
    }
799
800
2
    return SECSuccess;
801
802
0
loser:
803
0
    if (initContextPtr && *initContextPtr) {
804
0
        PORT_Free(*initContextPtr);
805
0
        *initContextPtr = NULL;
806
0
        if (configStrings) {
807
0
            PR_smprintf_free(configStrings);
808
0
        }
809
0
    }
810
0
    PZ_Lock(nssInitLock);
811
0
    nssIsInInit--;
812
    /* We failed to init, allow one to move forward */
813
0
    PZ_NotifyCondVar(nssInitCondition);
814
0
    PZ_Unlock(nssInitLock);
815
0
    if (parent) {
816
0
        SECMOD_DestroyModule(parent);
817
0
    }
818
0
    return SECFailure;
819
2
}
820
821
SECStatus
822
NSS_Init(const char *configdir)
823
0
{
824
0
    return nss_Init(configdir, "", "", SECMOD_DB, "", "", "", "", "", NULL,
825
0
                    NULL, PR_TRUE, PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE,
826
0
                    PR_TRUE, PR_FALSE, PR_FALSE, PR_FALSE);
827
0
}
828
829
SECStatus
830
NSS_InitReadWrite(const char *configdir)
831
0
{
832
0
    return nss_Init(configdir, "", "", SECMOD_DB, "", "", "", "", "", NULL,
833
0
                    NULL, PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE,
834
0
                    PR_TRUE, PR_FALSE, PR_FALSE, PR_FALSE);
835
0
}
836
837
/*
838
 * OK there are now lots of options here, lets go through them all:
839
 *
840
 * configdir - base directory where all the cert, key, and module datbases live.
841
 * certPrefix - prefix added to the beginning of the cert database example: "
842
 *             "https-server1-"
843
 * keyPrefix - prefix added to the beginning of the key database example: "
844
 *             "https-server1-"
845
 * secmodName - name of the security module database (usually "secmod.db").
846
 * flags - change the open options of NSS_Initialize as follows:
847
 *   NSS_INIT_READONLY - Open the databases read only.
848
 *   NSS_INIT_NOCERTDB - Don't open the cert DB and key DB's, just
849
 *             initialize the volatile certdb.
850
 *   NSS_INIT_NOMODDB  - Don't open the security module DB, just
851
 *             initialize the      PKCS #11 module.
852
 *      NSS_INIT_FORCEOPEN - Continue to force initializations even if the
853
 *             databases cannot be opened.
854
 *      NSS_INIT_PK11THREADSAFE - only load PKCS#11 modules that are
855
 *                      thread-safe, ie. that support locking - either OS
856
 *                      locking or NSS-provided locks . If a PKCS#11
857
 *                      module isn't thread-safe, don't serialize its
858
 *                      calls; just don't load it instead. This is necessary
859
 *                      if another piece of code is using the same PKCS#11
860
 *                      modules that NSS is accessing without going through
861
 *                      NSS, for example the Java SunPKCS11 provider.
862
 *      NSS_INIT_PK11RELOAD - ignore the CKR_CRYPTOKI_ALREADY_INITIALIZED
863
 *                      error when loading PKCS#11 modules. This is necessary
864
 *                      if another piece of code is using the same PKCS#11
865
 *                      modules that NSS is accessing without going through
866
 *                      NSS, for example Java SunPKCS11 provider.
867
 *      NSS_INIT_NOPK11FINALIZE - never call C_Finalize on any
868
 *                      PKCS#11 module. This may be necessary in order to
869
 *                      ensure continuous operation and proper shutdown
870
 *                      sequence if another piece of code is using the same
871
 *                      PKCS#11 modules that NSS is accessing without going
872
 *                      through NSS, for example Java SunPKCS11 provider.
873
 *                      The following limitation applies when this is set :
874
 *                      SECMOD_WaitForAnyTokenEvent will not use
875
 *                      C_WaitForSlotEvent, in order to prevent the need for
876
 *                      C_Finalize. This call will be emulated instead.
877
 *      NSS_INIT_RESERVED - Currently has no effect, but may be used in the
878
 *                      future to trigger better cooperation between PKCS#11
879
 *                      modules used by both NSS and the Java SunPKCS11
880
 *                      provider. This should occur after a new flag is defined
881
 *                      for C_Initialize by the PKCS#11 working group.
882
 *      NSS_INIT_COOPERATE - Sets 4 recommended options for applications that
883
 *                      use both NSS and the Java SunPKCS11 provider.
884
 */
885
SECStatus
886
NSS_Initialize(const char *configdir, const char *certPrefix,
887
               const char *keyPrefix, const char *secmodName, PRUint32 flags)
888
0
{
889
0
    return nss_Init(configdir, certPrefix, keyPrefix, secmodName,
890
0
                    "", "", "", "", "", NULL, NULL,
891
0
                    ((flags & NSS_INIT_READONLY) == NSS_INIT_READONLY),
892
0
                    ((flags & NSS_INIT_NOCERTDB) == NSS_INIT_NOCERTDB),
893
0
                    ((flags & NSS_INIT_NOMODDB) == NSS_INIT_NOMODDB),
894
0
                    ((flags & NSS_INIT_FORCEOPEN) == NSS_INIT_FORCEOPEN),
895
0
                    ((flags & NSS_INIT_NOROOTINIT) == NSS_INIT_NOROOTINIT),
896
0
                    ((flags & NSS_INIT_OPTIMIZESPACE) == NSS_INIT_OPTIMIZESPACE),
897
0
                    ((flags & NSS_INIT_PK11THREADSAFE) == NSS_INIT_PK11THREADSAFE),
898
0
                    ((flags & NSS_INIT_PK11RELOAD) == NSS_INIT_PK11RELOAD),
899
0
                    ((flags & NSS_INIT_NOPK11FINALIZE) == NSS_INIT_NOPK11FINALIZE));
900
0
}
901
902
NSSInitContext *
903
NSS_InitContext(const char *configdir, const char *certPrefix,
904
                const char *keyPrefix, const char *secmodName,
905
                NSSInitParameters *initParams, PRUint32 flags)
906
0
{
907
0
    SECStatus rv;
908
0
    NSSInitContext *context;
909
910
0
    rv = nss_Init(configdir, certPrefix, keyPrefix, secmodName,
911
0
                  "", "", "", "", "", &context, initParams,
912
0
                  ((flags & NSS_INIT_READONLY) == NSS_INIT_READONLY),
913
0
                  ((flags & NSS_INIT_NOCERTDB) == NSS_INIT_NOCERTDB),
914
0
                  ((flags & NSS_INIT_NOMODDB) == NSS_INIT_NOMODDB),
915
0
                  ((flags & NSS_INIT_FORCEOPEN) == NSS_INIT_FORCEOPEN), PR_TRUE,
916
0
                  ((flags & NSS_INIT_OPTIMIZESPACE) == NSS_INIT_OPTIMIZESPACE),
917
0
                  ((flags & NSS_INIT_PK11THREADSAFE) == NSS_INIT_PK11THREADSAFE),
918
0
                  ((flags & NSS_INIT_PK11RELOAD) == NSS_INIT_PK11RELOAD),
919
0
                  ((flags & NSS_INIT_NOPK11FINALIZE) == NSS_INIT_NOPK11FINALIZE));
920
0
    return (rv == SECSuccess) ? context : NULL;
921
0
}
922
923
SECStatus
924
NSS_InitWithMerge(const char *configdir, const char *certPrefix,
925
                  const char *keyPrefix, const char *secmodName,
926
                  const char *updateDir, const char *updCertPrefix,
927
                  const char *updKeyPrefix, const char *updateID,
928
                  const char *updateName, PRUint32 flags)
929
0
{
930
0
    return nss_Init(configdir, certPrefix, keyPrefix, secmodName,
931
0
                    updateDir, updCertPrefix, updKeyPrefix, updateID, updateName,
932
0
                    NULL, NULL,
933
0
                    ((flags & NSS_INIT_READONLY) == NSS_INIT_READONLY),
934
0
                    ((flags & NSS_INIT_NOCERTDB) == NSS_INIT_NOCERTDB),
935
0
                    ((flags & NSS_INIT_NOMODDB) == NSS_INIT_NOMODDB),
936
0
                    ((flags & NSS_INIT_FORCEOPEN) == NSS_INIT_FORCEOPEN),
937
0
                    ((flags & NSS_INIT_NOROOTINIT) == NSS_INIT_NOROOTINIT),
938
0
                    ((flags & NSS_INIT_OPTIMIZESPACE) == NSS_INIT_OPTIMIZESPACE),
939
0
                    ((flags & NSS_INIT_PK11THREADSAFE) == NSS_INIT_PK11THREADSAFE),
940
0
                    ((flags & NSS_INIT_PK11RELOAD) == NSS_INIT_PK11RELOAD),
941
0
                    ((flags & NSS_INIT_NOPK11FINALIZE) == NSS_INIT_NOPK11FINALIZE));
942
0
}
943
944
/*
945
 * initialize NSS without a creating cert db's, key db's, or secmod db's.
946
 */
947
SECStatus
948
NSS_NoDB_Init(const char *configdir)
949
2
{
950
2
    return nss_Init("", "", "", "", "", "", "", "", "", NULL, NULL,
951
2
                    PR_TRUE, PR_TRUE, PR_TRUE, PR_TRUE, PR_TRUE, PR_TRUE,
952
2
                    PR_FALSE, PR_FALSE, PR_FALSE);
953
2
}
954
955
2
#define NSS_SHUTDOWN_STEP 10
956
957
struct NSSShutdownFuncPair {
958
    NSS_ShutdownFunc func;
959
    void *appData;
960
};
961
962
static struct NSSShutdownListStr {
963
    PZLock *lock;
964
    int allocatedFuncs;
965
    int peakFuncs;
966
    struct NSSShutdownFuncPair *funcs;
967
} nssShutdownList = { 0 };
968
969
/*
970
 * find and existing shutdown function
971
 */
972
static int
973
nss_GetShutdownEntry(NSS_ShutdownFunc sFunc, void *appData)
974
0
{
975
0
    int count, i;
976
0
    count = nssShutdownList.peakFuncs;
977
978
0
    for (i = 0; i < count; i++) {
979
0
        if ((nssShutdownList.funcs[i].func == sFunc) &&
980
0
            (nssShutdownList.funcs[i].appData == appData)) {
981
0
            return i;
982
0
        }
983
0
    }
984
0
    return -1;
985
0
}
986
987
/*
988
 * register a callback to be called when NSS shuts down
989
 */
990
SECStatus
991
NSS_RegisterShutdown(NSS_ShutdownFunc sFunc, void *appData)
992
0
{
993
0
    int i;
994
995
    /* make sure our lock and condition variable are initialized one and only
996
     * one time */
997
0
    if (PR_CallOnce(&nssInitOnce, nss_doLockInit) != PR_SUCCESS) {
998
0
        return SECFailure;
999
0
    }
1000
1001
0
    PZ_Lock(nssInitLock);
1002
0
    if (!NSS_IsInitialized()) {
1003
0
        PZ_Unlock(nssInitLock);
1004
0
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
1005
0
        return SECFailure;
1006
0
    }
1007
0
    PZ_Unlock(nssInitLock);
1008
0
    if (sFunc == NULL) {
1009
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1010
0
        return SECFailure;
1011
0
    }
1012
1013
0
    PORT_Assert(nssShutdownList.lock);
1014
0
    PZ_Lock(nssShutdownList.lock);
1015
1016
    /* make sure we don't have a duplicate */
1017
0
    i = nss_GetShutdownEntry(sFunc, appData);
1018
0
    if (i >= 0) {
1019
0
        PZ_Unlock(nssShutdownList.lock);
1020
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1021
0
        return SECFailure;
1022
0
    }
1023
    /* find an empty slot */
1024
0
    i = nss_GetShutdownEntry(NULL, NULL);
1025
0
    if (i >= 0) {
1026
0
        nssShutdownList.funcs[i].func = sFunc;
1027
0
        nssShutdownList.funcs[i].appData = appData;
1028
0
        PZ_Unlock(nssShutdownList.lock);
1029
0
        return SECSuccess;
1030
0
    }
1031
0
    if (nssShutdownList.allocatedFuncs == nssShutdownList.peakFuncs) {
1032
0
        struct NSSShutdownFuncPair *funcs =
1033
0
            (struct NSSShutdownFuncPair *)PORT_Realloc(nssShutdownList.funcs,
1034
0
                                                       (nssShutdownList.allocatedFuncs + NSS_SHUTDOWN_STEP) * sizeof(struct NSSShutdownFuncPair));
1035
0
        if (!funcs) {
1036
0
            PZ_Unlock(nssShutdownList.lock);
1037
0
            return SECFailure;
1038
0
        }
1039
0
        nssShutdownList.funcs = funcs;
1040
0
        nssShutdownList.allocatedFuncs += NSS_SHUTDOWN_STEP;
1041
0
    }
1042
0
    nssShutdownList.funcs[nssShutdownList.peakFuncs].func = sFunc;
1043
0
    nssShutdownList.funcs[nssShutdownList.peakFuncs].appData = appData;
1044
0
    nssShutdownList.peakFuncs++;
1045
0
    PZ_Unlock(nssShutdownList.lock);
1046
0
    return SECSuccess;
1047
0
}
1048
1049
/*
1050
 * unregister a callback so it won't get called on shutdown.
1051
 */
1052
SECStatus
1053
NSS_UnregisterShutdown(NSS_ShutdownFunc sFunc, void *appData)
1054
0
{
1055
0
    int i;
1056
1057
    /* make sure our lock and condition variable are initialized one and only
1058
     * one time */
1059
0
    if (PR_CallOnce(&nssInitOnce, nss_doLockInit) != PR_SUCCESS) {
1060
0
        return SECFailure;
1061
0
    }
1062
0
    PZ_Lock(nssInitLock);
1063
0
    if (!NSS_IsInitialized()) {
1064
0
        PZ_Unlock(nssInitLock);
1065
0
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
1066
0
        return SECFailure;
1067
0
    }
1068
0
    PZ_Unlock(nssInitLock);
1069
1070
0
    PORT_Assert(nssShutdownList.lock);
1071
0
    PZ_Lock(nssShutdownList.lock);
1072
0
    i = nss_GetShutdownEntry(sFunc, appData);
1073
0
    if (i >= 0) {
1074
0
        nssShutdownList.funcs[i].func = NULL;
1075
0
        nssShutdownList.funcs[i].appData = NULL;
1076
0
    }
1077
0
    PZ_Unlock(nssShutdownList.lock);
1078
1079
0
    if (i < 0) {
1080
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1081
0
        return SECFailure;
1082
0
    }
1083
0
    return SECSuccess;
1084
0
}
1085
1086
/*
1087
 * bring up and shutdown the shutdown list
1088
 */
1089
static SECStatus
1090
nss_InitShutdownList(void)
1091
2
{
1092
2
    if (nssShutdownList.lock != NULL) {
1093
0
        return SECSuccess;
1094
0
    }
1095
2
    nssShutdownList.lock = PZ_NewLock(nssILockOther);
1096
2
    if (nssShutdownList.lock == NULL) {
1097
0
        return SECFailure;
1098
0
    }
1099
2
    nssShutdownList.funcs = PORT_ZNewArray(struct NSSShutdownFuncPair,
1100
2
                                           NSS_SHUTDOWN_STEP);
1101
2
    if (nssShutdownList.funcs == NULL) {
1102
0
        PZ_DestroyLock(nssShutdownList.lock);
1103
0
        nssShutdownList.lock = NULL;
1104
0
        return SECFailure;
1105
0
    }
1106
2
    nssShutdownList.allocatedFuncs = NSS_SHUTDOWN_STEP;
1107
2
    nssShutdownList.peakFuncs = 0;
1108
1109
2
    return SECSuccess;
1110
2
}
1111
1112
static SECStatus
1113
nss_ShutdownShutdownList(void)
1114
0
{
1115
0
    SECStatus rv = SECSuccess;
1116
0
    int i;
1117
1118
    /* call all the registerd functions first */
1119
0
    for (i = 0; i < nssShutdownList.peakFuncs; i++) {
1120
0
        struct NSSShutdownFuncPair *funcPair = &nssShutdownList.funcs[i];
1121
0
        if (funcPair->func) {
1122
0
            if ((*funcPair->func)(funcPair->appData, NULL) != SECSuccess) {
1123
0
                rv = SECFailure;
1124
0
            }
1125
0
        }
1126
0
    }
1127
1128
0
    nssShutdownList.peakFuncs = 0;
1129
0
    nssShutdownList.allocatedFuncs = 0;
1130
0
    PORT_Free(nssShutdownList.funcs);
1131
0
    nssShutdownList.funcs = NULL;
1132
0
    if (nssShutdownList.lock) {
1133
0
        PZ_DestroyLock(nssShutdownList.lock);
1134
0
    }
1135
0
    nssShutdownList.lock = NULL;
1136
0
    return rv;
1137
0
}
1138
1139
extern const NSSError NSS_ERROR_BUSY;
1140
1141
SECStatus
1142
nss_Shutdown(void)
1143
0
{
1144
0
    SECStatus shutdownRV = SECSuccess;
1145
0
    SECStatus rv;
1146
0
    PRStatus status;
1147
0
    NSSInitContext *temp;
1148
1149
0
    rv = nss_ShutdownShutdownList();
1150
0
    if (rv != SECSuccess) {
1151
0
        shutdownRV = SECFailure;
1152
0
    }
1153
0
    cert_DestroyLocks();
1154
0
    ShutdownCRLCache();
1155
0
    OCSP_ShutdownGlobal();
1156
#ifndef NSS_DISABLE_LIBPKIX
1157
    PKIX_Shutdown(plContext);
1158
#endif /* NSS_DISABLE_LIBPKIX */
1159
0
    SECOID_Shutdown();
1160
0
    status = STAN_Shutdown();
1161
0
    cert_DestroySubjectKeyIDHashTable();
1162
0
    pk11_SetInternalKeySlot(NULL);
1163
0
    rv = SECMOD_Shutdown();
1164
0
    if (rv != SECSuccess) {
1165
0
        shutdownRV = SECFailure;
1166
0
    }
1167
0
    pk11sdr_Shutdown();
1168
0
    nssArena_Shutdown();
1169
0
    if (status == PR_FAILURE) {
1170
0
        if (NSS_GetError() == NSS_ERROR_BUSY) {
1171
0
            PORT_SetError(SEC_ERROR_BUSY);
1172
0
        }
1173
0
        shutdownRV = SECFailure;
1174
0
    }
1175
    /*
1176
     * A thread's error stack is automatically destroyed when the thread
1177
     * terminates, except for the primordial thread, whose error stack is
1178
     * destroyed by PR_Cleanup.  Since NSS is usually shut down by the
1179
     * primordial thread and many NSS-based apps don't call PR_Cleanup,
1180
     * we destroy the calling thread's error stack here. This must be
1181
     * done after any NSS_GetError call, otherwise NSS_GetError will
1182
     * create the error stack again.
1183
     */
1184
0
    nss_DestroyErrorStack();
1185
0
    nssIsInitted = PR_FALSE;
1186
0
    temp = nssInitContextList;
1187
0
    nssInitContextList = NULL;
1188
    /* free the old list. This is necessary when we are called from
1189
     * NSS_Shutdown(). */
1190
0
    while (temp) {
1191
0
        NSSInitContext *next = temp->next;
1192
0
        temp->magic = 0;
1193
0
        PORT_Free(temp);
1194
0
        temp = next;
1195
0
    }
1196
0
    return shutdownRV;
1197
0
}
1198
1199
SECStatus
1200
NSS_Shutdown(void)
1201
0
{
1202
0
    SECStatus rv;
1203
    /* make sure our lock and condition variable are initialized one and only
1204
     * one time */
1205
0
    if (PR_CallOnce(&nssInitOnce, nss_doLockInit) != PR_SUCCESS) {
1206
0
        return SECFailure;
1207
0
    }
1208
0
    PZ_Lock(nssInitLock);
1209
1210
0
    if (!nssIsInitted) {
1211
0
        PZ_Unlock(nssInitLock);
1212
0
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
1213
0
        return SECFailure;
1214
0
    }
1215
1216
    /* If one or more threads are in the middle of init, wait for them
1217
     * to complete */
1218
0
    while (nssIsInInit) {
1219
0
        PZ_WaitCondVar(nssInitCondition, PR_INTERVAL_NO_TIMEOUT);
1220
0
    }
1221
0
    rv = nss_Shutdown();
1222
0
    PZ_Unlock(nssInitLock);
1223
0
    return rv;
1224
0
}
1225
1226
/*
1227
 * remove the context from a list. return true if found, false if not
1228
 */
1229
PRBool
1230
nss_RemoveList(NSSInitContext *context)
1231
0
{
1232
0
    NSSInitContext *this = nssInitContextList;
1233
0
    NSSInitContext **last = &nssInitContextList;
1234
1235
0
    while (this) {
1236
0
        if (this == context) {
1237
0
            *last = this->next;
1238
0
            this->magic = 0;
1239
0
            PORT_Free(this);
1240
0
            return PR_TRUE;
1241
0
        }
1242
0
        last = &this->next;
1243
0
        this = this->next;
1244
0
    }
1245
0
    return PR_FALSE;
1246
0
}
1247
1248
/*
1249
 * This form of shutdown is safe in the case where we may have multiple
1250
 * entities using NSS in a single process. Each entity calls shutdown with
1251
 * it's own context. The application (which doesn't get a context), calls
1252
 * shutdown with NULL. Once all users have 'checked in' NSS will shutdown.
1253
 * This is different than NSS_Shutdown, where calling it will shutdown NSS
1254
 * irreguardless of who else may have NSS open.
1255
 */
1256
SECStatus
1257
NSS_ShutdownContext(NSSInitContext *context)
1258
0
{
1259
0
    SECStatus rv = SECSuccess;
1260
1261
    /* make sure our lock and condition variable are initialized one and only
1262
     * one time */
1263
0
    if (PR_CallOnce(&nssInitOnce, nss_doLockInit) != PR_SUCCESS) {
1264
0
        return SECFailure;
1265
0
    }
1266
0
    PZ_Lock(nssInitLock);
1267
    /* If one or more threads are in the middle of init, wait for them
1268
     * to complete */
1269
0
    while (nssIsInInit) {
1270
0
        PZ_WaitCondVar(nssInitCondition, PR_INTERVAL_NO_TIMEOUT);
1271
0
    }
1272
1273
    /* OK, we are the only thread now either initializing or shutting down */
1274
1275
0
    if (!context) {
1276
0
        if (!nssIsInitted) {
1277
0
            PZ_Unlock(nssInitLock);
1278
0
            PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
1279
0
            return SECFailure;
1280
0
        }
1281
0
        nssIsInitted = 0;
1282
0
    } else if (!nss_RemoveList(context)) {
1283
0
        PZ_Unlock(nssInitLock);
1284
        /* context was already freed or wasn't valid */
1285
0
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
1286
0
        return SECFailure;
1287
0
    }
1288
0
    if ((nssIsInitted == 0) && (nssInitContextList == NULL)) {
1289
0
        rv = nss_Shutdown();
1290
0
    }
1291
1292
    /* NOTE: we don't try to free the nssInitLocks to prevent races against
1293
     * the locks. There may be a thread, right now, waiting in NSS_Init for us
1294
     * to free the lock below. If we delete the locks, bad things would happen
1295
     * to that thread */
1296
0
    PZ_Unlock(nssInitLock);
1297
1298
0
    return rv;
1299
0
}
1300
1301
PRBool
1302
NSS_IsInitialized(void)
1303
2
{
1304
2
    return (nssIsInitted) || (nssInitContextList != NULL);
1305
2
}
1306
1307
extern const char __nss_base_version[];
1308
1309
PRBool
1310
NSS_VersionCheck(const char *importedVersion)
1311
0
{
1312
    /*
1313
     * This is the secret handshake algorithm.
1314
     *
1315
     * This release has a simple version compatibility
1316
     * check algorithm.  This release is not backward
1317
     * compatible with previous major releases.  It is
1318
     * not compatible with future major, minor, or
1319
     * patch releases or builds.
1320
     */
1321
0
    int vmajor = 0, vminor = 0, vpatch = 0, vbuild = 0;
1322
0
    const char *ptr = importedVersion;
1323
0
#define NSS_VERSION_VARIABLE __nss_base_version
1324
0
#include "verref.h"
1325
1326
0
    while (isdigit((unsigned char)*ptr)) {
1327
0
        vmajor = 10 * vmajor + *ptr - '0';
1328
0
        ptr++;
1329
0
    }
1330
0
    if (*ptr == '.') {
1331
0
        ptr++;
1332
0
        while (isdigit((unsigned char)*ptr)) {
1333
0
            vminor = 10 * vminor + *ptr - '0';
1334
0
            ptr++;
1335
0
        }
1336
0
        if (*ptr == '.') {
1337
0
            ptr++;
1338
0
            while (isdigit((unsigned char)*ptr)) {
1339
0
                vpatch = 10 * vpatch + *ptr - '0';
1340
0
                ptr++;
1341
0
            }
1342
0
            if (*ptr == '.') {
1343
0
                ptr++;
1344
0
                while (isdigit((unsigned char)*ptr)) {
1345
0
                    vbuild = 10 * vbuild + *ptr - '0';
1346
0
                    ptr++;
1347
0
                }
1348
0
            }
1349
0
        }
1350
0
    }
1351
1352
0
    if (vmajor != NSS_VMAJOR) {
1353
0
        return PR_FALSE;
1354
0
    }
1355
0
    if (vmajor == NSS_VMAJOR && vminor > NSS_VMINOR) {
1356
0
        return PR_FALSE;
1357
0
    }
1358
0
    if (vmajor == NSS_VMAJOR && vminor == NSS_VMINOR && vpatch > NSS_VPATCH) {
1359
0
        return PR_FALSE;
1360
0
    }
1361
0
    if (vmajor == NSS_VMAJOR && vminor == NSS_VMINOR &&
1362
0
        vpatch == NSS_VPATCH && vbuild > NSS_VBUILD) {
1363
0
        return PR_FALSE;
1364
0
    }
1365
0
    return PR_TRUE;
1366
0
}
1367
1368
const char *
1369
NSS_GetVersion(void)
1370
0
{
1371
0
    return NSS_VERSION;
1372
0
}