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 |