Back to index

lightning-sunbird  0.9+nobinonly
nssinit.c
Go to the documentation of this file.
00001 /*
00002  * NSS utility functions
00003  *
00004  * ***** BEGIN LICENSE BLOCK *****
00005  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  * The contents of this file are subject to the Mozilla Public License Version
00008  * 1.1 (the "License"); you may not use this file except in compliance with
00009  * the License. You may obtain a copy of the License at
00010  * http://www.mozilla.org/MPL/
00011  *
00012  * Software distributed under the License is distributed on an "AS IS" basis,
00013  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00014  * for the specific language governing rights and limitations under the
00015  * License.
00016  *
00017  * The Original Code is the Netscape security libraries.
00018  *
00019  * The Initial Developer of the Original Code is
00020  * Netscape Communications Corporation.
00021  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00022  * the Initial Developer. All Rights Reserved.
00023  *
00024  * Contributor(s):
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 /* $Id: nssinit.c,v 1.69.2.9 2007/12/06 00:45:12 julien.pierre.boogz%sun.com Exp $ */
00040 
00041 #include <ctype.h>
00042 #include "seccomon.h"
00043 #include "prinit.h"
00044 #include "prprf.h"
00045 #include "prmem.h"
00046 #include "cert.h"
00047 #include "key.h"
00048 #include "ssl.h"
00049 #include "sslproto.h"
00050 #include "secmod.h"
00051 #include "secoid.h"
00052 #include "nss.h"
00053 #include "pk11func.h"
00054 #include "secerr.h"
00055 #include "nssbase.h"
00056 
00057 #include "pki3hack.h"
00058 #include "certi.h"
00059 #include "secmodi.h"
00060 #include "ocspi.h"
00061 
00062 /*
00063  * On Windows nss3.dll needs to export the symbol 'mktemp' to be
00064  * fully backward compatible with the nss3.dll in NSS 3.2.x and
00065  * 3.3.x.  This symbol was unintentionally exported and its
00066  * definition (in DBM) was moved from nss3.dll to softokn3.dll
00067  * in NSS 3.4.  See bug 142575.
00068  */
00069 #ifdef WIN32_NSS3_DLL_COMPAT
00070 #include <io.h>
00071 
00072 /* exported as 'mktemp' */
00073 char *
00074 nss_mktemp(char *path)
00075 {
00076     return _mktemp(path);
00077 }
00078 #endif
00079 
00080 #define NSS_MAX_FLAG_SIZE  sizeof("readOnly")+sizeof("noCertDB")+ \
00081        sizeof("noModDB")+sizeof("forceOpen")+sizeof("passwordRequired")+ \
00082        sizeof ("optimizeSpace")
00083 #define NSS_DEFAULT_MOD_NAME "NSS Internal Module"
00084 
00085 static char *
00086 nss_makeFlags(PRBool readOnly, PRBool noCertDB, 
00087                             PRBool noModDB, PRBool forceOpen, 
00088                             PRBool passwordRequired, PRBool optimizeSpace) 
00089 {
00090     char *flags = (char *)PORT_Alloc(NSS_MAX_FLAG_SIZE);
00091     PRBool first = PR_TRUE;
00092 
00093     PORT_Memset(flags,0,NSS_MAX_FLAG_SIZE);
00094     if (readOnly) {
00095         PORT_Strcat(flags,"readOnly");
00096         first = PR_FALSE;
00097     }
00098     if (noCertDB) {
00099         if (!first) PORT_Strcat(flags,",");
00100         PORT_Strcat(flags,"noCertDB");
00101         first = PR_FALSE;
00102     }
00103     if (noModDB) {
00104         if (!first) PORT_Strcat(flags,",");
00105         PORT_Strcat(flags,"noModDB");
00106         first = PR_FALSE;
00107     }
00108     if (forceOpen) {
00109         if (!first) PORT_Strcat(flags,",");
00110         PORT_Strcat(flags,"forceOpen");
00111         first = PR_FALSE;
00112     }
00113     if (passwordRequired) {
00114         if (!first) PORT_Strcat(flags,",");
00115         PORT_Strcat(flags,"passwordRequired");
00116         first = PR_FALSE;
00117     }
00118     if (optimizeSpace) {
00119         if (!first) PORT_Strcat(flags,",");
00120         PORT_Strcat(flags,"optimizeSpace");
00121         first = PR_FALSE;
00122     }
00123     return flags;
00124 }
00125 
00126 /*
00127  * statics to remember the PK11_ConfigurePKCS11()
00128  * info.
00129  */
00130 static char * pk11_config_strings = NULL;
00131 static char * pk11_config_name = NULL;
00132 static PRBool pk11_password_required = PR_FALSE;
00133 
00134 /*
00135  * this is a legacy configuration function which used to be part of
00136  * the PKCS #11 internal token.
00137  */
00138 void
00139 PK11_ConfigurePKCS11(const char *man, const char *libdes, const char *tokdes,
00140        const char *ptokdes, const char *slotdes, const char *pslotdes, 
00141        const char *fslotdes, const char *fpslotdes, int minPwd, int pwRequired)
00142 {
00143    char *strings = NULL;
00144    char *newStrings;
00145 
00146    /* make sure the internationalization was done correctly... */
00147    strings = PR_smprintf("");
00148    if (strings == NULL) return;
00149 
00150     if (man) {
00151         newStrings = PR_smprintf("%s manufacturerID='%s'",strings,man);
00152        PR_smprintf_free(strings);
00153        strings = newStrings;
00154     }
00155    if (strings == NULL) return;
00156 
00157     if (libdes) {
00158         newStrings = PR_smprintf("%s libraryDescription='%s'",strings,libdes);
00159        PR_smprintf_free(strings);
00160        strings = newStrings;
00161        if (pk11_config_name != NULL) {
00162            PORT_Free(pk11_config_name);
00163        }
00164        pk11_config_name = PORT_Strdup(libdes);
00165     }
00166    if (strings == NULL) return;
00167 
00168     if (tokdes) {
00169         newStrings = PR_smprintf("%s cryptoTokenDescription='%s'",strings,
00170                                                         tokdes);
00171        PR_smprintf_free(strings);
00172        strings = newStrings;
00173     }
00174    if (strings == NULL) return;
00175 
00176     if (ptokdes) {
00177         newStrings = PR_smprintf("%s dbTokenDescription='%s'",strings,ptokdes);
00178        PR_smprintf_free(strings);
00179        strings = newStrings;
00180     }
00181    if (strings == NULL) return;
00182 
00183     if (slotdes) {
00184         newStrings = PR_smprintf("%s cryptoSlotDescription='%s'",strings,
00185                                                         slotdes);
00186        PR_smprintf_free(strings);
00187        strings = newStrings;
00188     }
00189    if (strings == NULL) return;
00190 
00191     if (pslotdes) {
00192         newStrings = PR_smprintf("%s dbSlotDescription='%s'",strings,pslotdes);
00193        PR_smprintf_free(strings);
00194        strings = newStrings;
00195     }
00196    if (strings == NULL) return;
00197 
00198     if (fslotdes) {
00199         newStrings = PR_smprintf("%s FIPSSlotDescription='%s'",
00200                                                  strings,fslotdes);
00201        PR_smprintf_free(strings);
00202        strings = newStrings;
00203     }
00204    if (strings == NULL) return;
00205 
00206     if (fpslotdes) {
00207         newStrings = PR_smprintf("%s FIPSTokenDescription='%s'",
00208                                                  strings,fpslotdes);
00209        PR_smprintf_free(strings);
00210        strings = newStrings;
00211     }
00212    if (strings == NULL) return;
00213 
00214     newStrings = PR_smprintf("%s minPS=%d", strings, minPwd);
00215     PR_smprintf_free(strings);
00216     strings = newStrings;
00217    if (strings == NULL) return;
00218 
00219     if (pk11_config_strings != NULL) {
00220        PR_smprintf_free(pk11_config_strings);
00221     }
00222     pk11_config_strings = strings;
00223     pk11_password_required = pwRequired;
00224 
00225     return;
00226 }
00227 
00228 void PK11_UnconfigurePKCS11(void)
00229 {
00230     if (pk11_config_strings != NULL) {
00231        PR_smprintf_free(pk11_config_strings);
00232         pk11_config_strings = NULL;
00233     }
00234     if (pk11_config_name) {
00235         PORT_Free(pk11_config_name);
00236         pk11_config_name = NULL;
00237     }
00238 }
00239 
00240 static char *
00241 nss_addEscape(const char *string, char quote)
00242 {
00243     char *newString = 0;
00244     int escapes = 0, size = 0;
00245     const char *src;
00246     char *dest;
00247 
00248     for (src=string; *src ; src++) {
00249        if ((*src == quote) || (*src == '\\')) escapes++;
00250        size++;
00251     }
00252 
00253     newString = PORT_ZAlloc(escapes+size+1); 
00254     if (newString == NULL) {
00255        return NULL;
00256     }
00257 
00258     for (src=string, dest=newString; *src; src++,dest++) {
00259        if ((*src == '\\') || (*src == quote)) {
00260            *dest++ = '\\';
00261        }
00262        *dest = *src;
00263     }
00264 
00265     return newString;
00266 }
00267 
00268 static char *
00269 nss_doubleEscape(const char *string)
00270 {
00271     char *round1 = NULL;
00272     char *retValue = NULL;
00273     if (string == NULL) {
00274        goto done;
00275     }
00276     round1 = nss_addEscape(string,'\'');
00277     if (round1) {
00278        retValue = nss_addEscape(round1,'"');
00279        PORT_Free(round1);
00280     }
00281 
00282 done:
00283     if (retValue == NULL) {
00284        retValue = PORT_Strdup("");
00285     }
00286     return retValue;
00287 }
00288 
00289 
00290 #ifndef XP_MAC
00291 /*
00292  * The following code is an attempt to automagically find the external root
00293  * module. NOTE: This code should be checked out on the MAC! There must be
00294  * some cross platform support out there to help out with this?
00295  * Note: Keep the #if-defined chunks in order. HPUX must select before UNIX.
00296  */
00297 
00298 static const char *dllname =
00299 #if defined(XP_WIN32) || defined(XP_OS2)
00300        "nssckbi.dll";
00301 #elif defined(HPUX) && !defined(__ia64)  /* HP-UX PA-RISC */
00302        "libnssckbi.sl";
00303 #elif defined(DARWIN)
00304        "libnssckbi.dylib";
00305 #elif defined(XP_UNIX) || defined(XP_BEOS)
00306        "libnssckbi.so";
00307 #elif defined(XP_MAC)
00308        "NSS Builtin Root Certs";
00309 #else
00310        #error "Uh! Oh! I don't know about this platform."
00311 #endif
00312 
00313 /* Should we have platform ifdefs here??? */
00314 #define FILE_SEP '/'
00315 
00316 static void nss_FindExternalRootPaths(const char *dbpath, 
00317                                       const char* secmodprefix,
00318                               char** retoldpath, char** retnewpath)
00319 {
00320     char *path, *oldpath = NULL, *lastsep;
00321     int len, path_len, secmod_len, dll_len;
00322 
00323     path_len = PORT_Strlen(dbpath);
00324     secmod_len = secmodprefix ? PORT_Strlen(secmodprefix) : 0;
00325     dll_len = PORT_Strlen(dllname);
00326     len = path_len + secmod_len + dll_len + 2; /* FILE_SEP + NULL */
00327 
00328     path = PORT_Alloc(len);
00329     if (path == NULL) return;
00330 
00331     /* back up to the top of the directory */
00332     PORT_Memcpy(path,dbpath,path_len);
00333     if (path[path_len-1] != FILE_SEP) {
00334         path[path_len++] = FILE_SEP;
00335     }
00336     PORT_Strcpy(&path[path_len],dllname);
00337     if (secmod_len > 0) {
00338         lastsep = PORT_Strrchr(secmodprefix, FILE_SEP);
00339         if (lastsep) {
00340             int secmoddir_len = lastsep-secmodprefix+1; /* FILE_SEP */
00341             oldpath = PORT_Alloc(len);
00342             if (oldpath == NULL) {
00343                 PORT_Free(path);
00344                 return;
00345             }
00346             PORT_Memcpy(oldpath,path,path_len);
00347             PORT_Memcpy(&oldpath[path_len],secmodprefix,secmoddir_len);
00348             PORT_Strcpy(&oldpath[path_len+secmoddir_len],dllname);
00349         }
00350     }
00351     *retoldpath = oldpath;
00352     *retnewpath = path;
00353     return;
00354 }
00355 
00356 static void nss_FreeExternalRootPaths(char* oldpath, char* path)
00357 {
00358     if (path) {
00359         PORT_Free(path);
00360     }
00361     if (oldpath) {
00362         PORT_Free(oldpath);
00363     }
00364 }
00365 
00366 static void
00367 nss_FindExternalRoot(const char *dbpath, const char* secmodprefix)
00368 {
00369        char *path = NULL;
00370         char *oldpath = NULL;
00371         PRBool hasrootcerts = PR_FALSE;
00372 
00373         /*
00374          * 'oldpath' is the external root path in NSS 3.3.x or older.
00375          * For backward compatibility we try to load the root certs
00376          * module with the old path first.
00377          */
00378         nss_FindExternalRootPaths(dbpath, secmodprefix, &oldpath, &path);
00379         if (oldpath) {
00380             (void) SECMOD_AddNewModule("Root Certs",oldpath, 0, 0);
00381             hasrootcerts = SECMOD_HasRootCerts();
00382         }
00383         if (path && !hasrootcerts) {
00384            (void) SECMOD_AddNewModule("Root Certs",path, 0, 0);
00385         }
00386         nss_FreeExternalRootPaths(oldpath, path);
00387        return;
00388 }
00389 #endif
00390 
00391 /*
00392  * OK there are now lots of options here, lets go through them all:
00393  *
00394  * configdir - base directory where all the cert, key, and module datbases live.
00395  * certPrefix - prefix added to the beginning of the cert database example: "
00396  *                   "https-server1-"
00397  * keyPrefix - prefix added to the beginning of the key database example: "
00398  *                   "https-server1-"
00399  * secmodName - name of the security module database (usually "secmod.db").
00400  * readOnly - Boolean: true if the databases are to be openned read only.
00401  * nocertdb - Don't open the cert DB and key DB's, just initialize the 
00402  *                   Volatile certdb.
00403  * nomoddb - Don't open the security module DB, just initialize the 
00404  *                   PKCS #11 module.
00405  * forceOpen - Continue to force initializations even if the databases cannot
00406  *                   be opened.
00407  */
00408 
00409 static PRBool nss_IsInitted = PR_FALSE;
00410 
00411 extern SECStatus secoid_Init(void);
00412 static SECStatus nss_InitShutdownList(void);
00413 
00414 #ifdef DEBUG
00415 static CERTCertificate dummyCert;
00416 #endif
00417 
00418 static SECStatus
00419 nss_Init(const char *configdir, const char *certPrefix, const char *keyPrefix,
00420                const char *secmodName, PRBool readOnly, PRBool noCertDB, 
00421                      PRBool noModDB, PRBool forceOpen, PRBool noRootInit,
00422                      PRBool optimizeSpace, PRBool noSingleThreadedModules,
00423                      PRBool allowAlreadyInitializedModules,
00424                      PRBool dontFinalizeModules)
00425 {
00426     char *moduleSpec = NULL;
00427     char *flags = NULL;
00428     SECStatus rv = SECFailure;
00429     char *lconfigdir = NULL;
00430     char *lcertPrefix = NULL;
00431     char *lkeyPrefix = NULL;
00432     char *lsecmodName = NULL;
00433 
00434     if (nss_IsInitted) {
00435        return SECSuccess;
00436     }
00437 
00438     /* New option bits must not change the size of CERTCertificate. */
00439     PORT_Assert(sizeof(dummyCert.options) == sizeof(void *));
00440 
00441     if (SECSuccess != cert_InitLocks()) {
00442         return SECFailure;
00443     }
00444 
00445     if (SECSuccess != InitCRLCache()) {
00446         return SECFailure;
00447     }
00448     
00449     if (SECSuccess != OCSP_InitGlobal()) {
00450         return SECFailure;
00451     }
00452 
00453     flags = nss_makeFlags(readOnly,noCertDB,noModDB,forceOpen,
00454                                    pk11_password_required, optimizeSpace);
00455     if (flags == NULL) return rv;
00456 
00457     /*
00458      * configdir is double nested, and Windows uses the same character
00459      * for file seps as we use for escapes! (sigh).
00460      */
00461     lconfigdir = nss_doubleEscape(configdir);
00462     if (lconfigdir == NULL) {
00463        goto loser;
00464     }
00465     lcertPrefix = nss_doubleEscape(certPrefix);
00466     if (lcertPrefix == NULL) {
00467        goto loser;
00468     }
00469     lkeyPrefix = nss_doubleEscape(keyPrefix);
00470     if (lkeyPrefix == NULL) {
00471        goto loser;
00472     }
00473     lsecmodName = nss_doubleEscape(secmodName);
00474     if (lsecmodName == NULL) {
00475        goto loser;
00476     }
00477     if (noSingleThreadedModules || allowAlreadyInitializedModules ||
00478         dontFinalizeModules) {
00479         pk11_setGlobalOptions(noSingleThreadedModules,
00480                               allowAlreadyInitializedModules,
00481                               dontFinalizeModules);
00482     }
00483 
00484     moduleSpec = PR_smprintf("name=\"%s\" parameters=\"configdir='%s' certPrefix='%s' keyPrefix='%s' secmod='%s' flags=%s %s\" NSS=\"flags=internal,moduleDB,moduleDBOnly,critical\"",
00485               pk11_config_name ? pk11_config_name : NSS_DEFAULT_MOD_NAME,
00486               lconfigdir,lcertPrefix,lkeyPrefix,lsecmodName,flags,
00487               pk11_config_strings ? pk11_config_strings : "");
00488 
00489 loser:
00490     PORT_Free(flags);
00491     if (lconfigdir) PORT_Free(lconfigdir);
00492     if (lcertPrefix) PORT_Free(lcertPrefix);
00493     if (lkeyPrefix) PORT_Free(lkeyPrefix);
00494     if (lsecmodName) PORT_Free(lsecmodName);
00495 
00496     if (moduleSpec) {
00497        SECMODModule *module = SECMOD_LoadModule(moduleSpec,NULL,PR_TRUE);
00498        PR_smprintf_free(moduleSpec);
00499        if (module) {
00500            if (module->loaded) rv=SECSuccess;
00501            SECMOD_DestroyModule(module);
00502        }
00503     }
00504 
00505     if (rv == SECSuccess) {
00506        if (secoid_Init() != SECSuccess) {
00507            return SECFailure;
00508        }
00509        if (STAN_LoadDefaultNSS3TrustDomain() != PR_SUCCESS) {
00510            return SECFailure;
00511        }
00512        if (nss_InitShutdownList() != SECSuccess) {
00513            return SECFailure;
00514        }
00515        CERT_SetDefaultCertDB((CERTCertDBHandle *)
00516                             STAN_GetDefaultTrustDomain());
00517 #ifndef XP_MAC
00518        /* only servers need this. We currently do not have a mac server */
00519        if ((!noModDB) && (!noCertDB) && (!noRootInit)) {
00520            if (!SECMOD_HasRootCerts()) {
00521               nss_FindExternalRoot(configdir, secmodName);
00522            }
00523        }
00524 #endif
00525        pk11sdr_Init();
00526        cert_CreateSubjectKeyIDHashTable();
00527        nss_IsInitted = PR_TRUE;
00528     }
00529     return rv;
00530 }
00531 
00532 
00533 SECStatus
00534 NSS_Init(const char *configdir)
00535 {
00536     return nss_Init(configdir, "", "", SECMOD_DB, PR_TRUE, 
00537               PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE, PR_TRUE, PR_FALSE, PR_FALSE, PR_FALSE);
00538 }
00539 
00540 SECStatus
00541 NSS_InitReadWrite(const char *configdir)
00542 {
00543     return nss_Init(configdir, "", "", SECMOD_DB, PR_FALSE, 
00544               PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE, PR_TRUE, PR_FALSE, PR_FALSE, PR_FALSE);
00545 }
00546 
00547 /*
00548  * OK there are now lots of options here, lets go through them all:
00549  *
00550  * configdir - base directory where all the cert, key, and module datbases live.
00551  * certPrefix - prefix added to the beginning of the cert database example: "
00552  *                   "https-server1-"
00553  * keyPrefix - prefix added to the beginning of the key database example: "
00554  *                   "https-server1-"
00555  * secmodName - name of the security module database (usually "secmod.db").
00556  * flags - change the open options of NSS_Initialize as follows:
00557  *     NSS_INIT_READONLY - Open the databases read only.
00558  *     NSS_INIT_NOCERTDB - Don't open the cert DB and key DB's, just 
00559  *                   initialize the volatile certdb.
00560  *     NSS_INIT_NOMODDB  - Don't open the security module DB, just 
00561  *                   initialize the       PKCS #11 module.
00562  *      NSS_INIT_FORCEOPEN - Continue to force initializations even if the 
00563  *                   databases cannot be opened.
00564  *      NSS_INIT_PK11THREADSAFE - only load PKCS#11 modules that are
00565  *                      thread-safe, ie. that support locking - either OS
00566  *                      locking or NSS-provided locks . If a PKCS#11
00567  *                      module isn't thread-safe, don't serialize its
00568  *                      calls; just don't load it instead. This is necessary
00569  *                      if another piece of code is using the same PKCS#11
00570  *                      modules that NSS is accessing without going through
00571  *                      NSS, for example the Java SunPKCS11 provider.
00572  *      NSS_INIT_PK11RELOAD - ignore the CKR_CRYPTOKI_ALREADY_INITIALIZED
00573  *                      error when loading PKCS#11 modules. This is necessary
00574  *                      if another piece of code is using the same PKCS#11
00575  *                      modules that NSS is accessing without going through
00576  *                      NSS, for example Java SunPKCS11 provider.
00577  *      NSS_INIT_NOPK11FINALIZE - never call C_Finalize on any
00578  *                      PKCS#11 module. This may be necessary in order to
00579  *                      ensure continuous operation and proper shutdown
00580  *                      sequence if another piece of code is using the same
00581  *                      PKCS#11 modules that NSS is accessing without going
00582  *                      through NSS, for example Java SunPKCS11 provider.
00583  *                      The following limitation applies when this is set :
00584  *                      SECMOD_WaitForAnyTokenEvent will not use
00585  *                      C_WaitForSlotEvent, in order to prevent the need for
00586  *                      C_Finalize. This call will be emulated instead.
00587  *      NSS_INIT_RESERVED - Currently has no effect, but may be used in the
00588  *                      future to trigger better cooperation between PKCS#11
00589  *                      modules used by both NSS and the Java SunPKCS11
00590  *                      provider. This should occur after a new flag is defined
00591  *                      for C_Initialize by the PKCS#11 working group.
00592  *      NSS_INIT_COOPERATE - Sets 4 recommended options for applications that
00593  *                      use both NSS and the Java SunPKCS11 provider. 
00594  */
00595 SECStatus
00596 NSS_Initialize(const char *configdir, const char *certPrefix, 
00597        const char *keyPrefix, const char *secmodName, PRUint32 flags)
00598 {
00599     return nss_Init(configdir, certPrefix, keyPrefix, secmodName, 
00600        ((flags & NSS_INIT_READONLY) == NSS_INIT_READONLY),
00601        ((flags & NSS_INIT_NOCERTDB) == NSS_INIT_NOCERTDB),
00602        ((flags & NSS_INIT_NOMODDB) == NSS_INIT_NOMODDB),
00603        ((flags & NSS_INIT_FORCEOPEN) == NSS_INIT_FORCEOPEN),
00604        ((flags & NSS_INIT_NOROOTINIT) == NSS_INIT_NOROOTINIT),
00605        ((flags & NSS_INIT_OPTIMIZESPACE) == NSS_INIT_OPTIMIZESPACE),
00606         ((flags & NSS_INIT_PK11THREADSAFE) == NSS_INIT_PK11THREADSAFE),
00607         ((flags & NSS_INIT_PK11RELOAD) == NSS_INIT_PK11RELOAD),
00608         ((flags & NSS_INIT_NOPK11FINALIZE) == NSS_INIT_NOPK11FINALIZE));
00609 }
00610 
00611 /*
00612  * initialize NSS without a creating cert db's, key db's, or secmod db's.
00613  */
00614 SECStatus
00615 NSS_NoDB_Init(const char * configdir)
00616 {
00617       return nss_Init("","","","",
00618                      PR_TRUE,PR_TRUE,PR_TRUE,PR_TRUE,PR_TRUE,PR_TRUE,
00619                      PR_FALSE,PR_FALSE,PR_FALSE);
00620 }
00621 
00622 
00623 #define NSS_SHUTDOWN_STEP 10
00624 
00625 struct NSSShutdownFuncPair {
00626     NSS_ShutdownFunc func;
00627     void             *appData;
00628 };
00629 
00630 static struct NSSShutdownListStr {
00631     PZLock           *lock;
00632     int                     maxFuncs;
00633     int                     numFuncs;
00634     struct NSSShutdownFuncPair     *funcs;
00635 } nssShutdownList = { 0 };
00636 
00637 /*
00638  * find and existing shutdown function
00639  */
00640 static int 
00641 nss_GetShutdownEntry(NSS_ShutdownFunc sFunc, void *appData)
00642 {
00643     int count, i;
00644     count = nssShutdownList.numFuncs;
00645     /* expect the list to be short, just do a linear search */
00646     for (i=0; i < count; i++) {
00647        if ((nssShutdownList.funcs[i].func == sFunc) &&
00648            (nssShutdownList.funcs[i].appData == appData)){
00649            return i;
00650        }
00651     }
00652     return -1;
00653 }
00654     
00655 /*
00656  * register a callback to be called when NSS shuts down
00657  */
00658 SECStatus
00659 NSS_RegisterShutdown(NSS_ShutdownFunc sFunc, void *appData)
00660 {
00661     int i;
00662 
00663     if (!nss_IsInitted) {
00664        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
00665        return SECFailure;
00666     }
00667     if (sFunc == NULL) {
00668        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00669        return SECFailure;
00670     }
00671 
00672     PORT_Assert(nssShutdownList.lock);
00673     PZ_Lock(nssShutdownList.lock);
00674 
00675     /* make sure we don't have a duplicate */
00676     i = nss_GetShutdownEntry(sFunc, appData);
00677     if (i > 0) {
00678        PZ_Unlock(nssShutdownList.lock);
00679        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
00680        return SECFailure;
00681     }
00682     /* find an empty slot */
00683     i = nss_GetShutdownEntry(NULL, NULL);
00684     if (i > 0) {
00685        nssShutdownList.funcs[i].func = sFunc;
00686        nssShutdownList.funcs[i].appData = appData;
00687        PZ_Unlock(nssShutdownList.lock);
00688        return SECFailure;
00689     }
00690     if (nssShutdownList.maxFuncs == nssShutdownList.numFuncs) {
00691        struct NSSShutdownFuncPair *funcs = 
00692               (struct NSSShutdownFuncPair *)PORT_Realloc
00693               (nssShutdownList.funcs, 
00694               (nssShutdownList.maxFuncs + NSS_SHUTDOWN_STEP) 
00695               *sizeof(struct NSSShutdownFuncPair));
00696        if (!funcs) {
00697            return SECFailure;
00698        }
00699        nssShutdownList.funcs = funcs;
00700        nssShutdownList.maxFuncs += NSS_SHUTDOWN_STEP;
00701     }
00702     nssShutdownList.funcs[nssShutdownList.numFuncs].func = sFunc;
00703     nssShutdownList.funcs[nssShutdownList.numFuncs].appData = appData;
00704     nssShutdownList.numFuncs++;
00705     PZ_Unlock(nssShutdownList.lock);
00706     return SECSuccess;
00707 }
00708 
00709 /*
00710  * unregister a callback so it won't get called on shutdown.
00711  */
00712 SECStatus
00713 NSS_UnregisterShutdown(NSS_ShutdownFunc sFunc, void *appData)
00714 {
00715     int i;
00716     if (!nss_IsInitted) {
00717        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
00718        return SECFailure;
00719     }
00720 
00721     PORT_Assert(nssShutdownList.lock);
00722     PZ_Lock(nssShutdownList.lock);
00723     i = nss_GetShutdownEntry(sFunc, appData);
00724     if (i > 0) {
00725        nssShutdownList.funcs[i].func = NULL;
00726        nssShutdownList.funcs[i].appData = NULL;
00727     }
00728     PZ_Unlock(nssShutdownList.lock);
00729 
00730     if (i < 0) {
00731        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
00732        return SECFailure;
00733     }
00734     return SECSuccess;
00735 }
00736 
00737 /*
00738  * bring up and shutdown the shutdown list
00739  */
00740 static SECStatus
00741 nss_InitShutdownList(void)
00742 {
00743     nssShutdownList.lock = PZ_NewLock(nssILockOther);
00744     if (nssShutdownList.lock == NULL) {
00745        return SECFailure;
00746     }
00747     nssShutdownList.funcs = PORT_ZNewArray(struct NSSShutdownFuncPair, 
00748                                        NSS_SHUTDOWN_STEP);
00749     if (nssShutdownList.funcs == NULL) {
00750        PZ_DestroyLock(nssShutdownList.lock);
00751        nssShutdownList.lock = NULL;
00752        return SECFailure;
00753     }
00754     nssShutdownList.maxFuncs = NSS_SHUTDOWN_STEP;
00755     nssShutdownList.numFuncs = 0;
00756 
00757     return SECSuccess;
00758 }
00759 
00760 static SECStatus
00761 nss_ShutdownShutdownList(void)
00762 {
00763     SECStatus rv = SECSuccess;
00764     int i;
00765 
00766     /* call all the registerd functions first */
00767     for (i=0; i < nssShutdownList.numFuncs; i++) {
00768        struct NSSShutdownFuncPair *funcPair = &nssShutdownList.funcs[i];
00769        if (funcPair->func) {
00770            if ((*funcPair->func)(funcPair->appData,NULL) != SECSuccess) {
00771               rv = SECFailure;
00772            }
00773        }
00774     }
00775 
00776     nssShutdownList.numFuncs = 0;
00777     nssShutdownList.maxFuncs = 0;
00778     PORT_Free(nssShutdownList.funcs);
00779     nssShutdownList.funcs = NULL;
00780     if (nssShutdownList.lock) {
00781        PZ_DestroyLock(nssShutdownList.lock);
00782     }
00783     nssShutdownList.lock = NULL;
00784     return rv;
00785 }
00786 
00787 
00788 extern const NSSError NSS_ERROR_BUSY;
00789 
00790 SECStatus
00791 NSS_Shutdown(void)
00792 {
00793     SECStatus shutdownRV = SECSuccess;
00794     SECStatus rv;
00795     PRStatus status;
00796 
00797     if (!nss_IsInitted) {
00798        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
00799        return SECFailure;
00800     }
00801 
00802     rv = nss_ShutdownShutdownList();
00803     if (rv != SECSuccess) {
00804        shutdownRV = SECFailure;
00805     }
00806     cert_DestroyLocks();
00807     ShutdownCRLCache();
00808     OCSP_ShutdownCache();
00809     SECOID_Shutdown();
00810     status = STAN_Shutdown();
00811     cert_DestroySubjectKeyIDHashTable();
00812     rv = SECMOD_Shutdown();
00813     if (rv != SECSuccess) {
00814        shutdownRV = SECFailure;
00815     }
00816     pk11sdr_Shutdown();
00817     if (status == PR_FAILURE) {
00818        if (NSS_GetError() == NSS_ERROR_BUSY) {
00819            PORT_SetError(SEC_ERROR_BUSY);
00820        }
00821        shutdownRV = SECFailure;
00822     }
00823     nss_IsInitted = PR_FALSE;
00824     return shutdownRV;
00825 }
00826 
00827 PRBool
00828 NSS_IsInitialized(void)
00829 {
00830     return nss_IsInitted;
00831 }
00832 
00833 
00834 extern const char __nss_base_rcsid[];
00835 extern const char __nss_base_sccsid[];
00836 
00837 PRBool
00838 NSS_VersionCheck(const char *importedVersion)
00839 {
00840     /*
00841      * This is the secret handshake algorithm.
00842      *
00843      * This release has a simple version compatibility
00844      * check algorithm.  This release is not backward
00845      * compatible with previous major releases.  It is
00846      * not compatible with future major, minor, or
00847      * patch releases.
00848      */
00849     int vmajor = 0, vminor = 0, vpatch = 0;
00850     const char *ptr = importedVersion;
00851     volatile char c; /* force a reference that won't get optimized away */
00852 
00853     c = __nss_base_rcsid[0] + __nss_base_sccsid[0]; 
00854 
00855     while (isdigit(*ptr)) {
00856         vmajor = 10 * vmajor + *ptr - '0';
00857         ptr++;
00858     }
00859     if (*ptr == '.') {
00860         ptr++;
00861         while (isdigit(*ptr)) {
00862             vminor = 10 * vminor + *ptr - '0';
00863             ptr++;
00864         }
00865         if (*ptr == '.') {
00866             ptr++;
00867             while (isdigit(*ptr)) {
00868                 vpatch = 10 * vpatch + *ptr - '0';
00869                 ptr++;
00870             }
00871         }
00872     }
00873 
00874     if (vmajor != NSS_VMAJOR) {
00875         return PR_FALSE;
00876     }
00877     if (vmajor == NSS_VMAJOR && vminor > NSS_VMINOR) {
00878         return PR_FALSE;
00879     }
00880     if (vmajor == NSS_VMAJOR && vminor == NSS_VMINOR && vpatch > NSS_VPATCH) {
00881         return PR_FALSE;
00882     }
00883     /* Check dependent libraries */
00884     if (PR_VersionCheck(PR_VERSION) == PR_FALSE) {
00885         return PR_FALSE;
00886     }
00887     return PR_TRUE;
00888 }
00889 
00890