/security/nss/lib/nss/nssinit.c

http://github.com/zpao/v8monkey · C · 1308 lines · 925 code · 125 blank · 258 comment · 268 complexity · 0106f3a7a9d2abfcdb2557777b8374eb MD5 · raw file

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