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