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