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