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.6 2006/09/21 20:09:48 julien.pierre.bugs%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 PKCS11_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 static char *
00229 nss_addEscape(const char *string, char quote)
00230 {
00231     char *newString = 0;
00232     int escapes = 0, size = 0;
00233     const char *src;
00234     char *dest;
00235 
00236     for (src=string; *src ; src++) {
00237        if ((*src == quote) || (*src == '\\')) escapes++;
00238        size++;
00239     }
00240 
00241     newString = PORT_ZAlloc(escapes+size+1); 
00242     if (newString == NULL) {
00243        return NULL;
00244     }
00245 
00246     for (src=string, dest=newString; *src; src++,dest++) {
00247        if ((*src == '\\') || (*src == quote)) {
00248            *dest++ = '\\';
00249        }
00250        *dest = *src;
00251     }
00252 
00253     return newString;
00254 }
00255 
00256 static char *
00257 nss_doubleEscape(const char *string)
00258 {
00259     char *round1 = NULL;
00260     char *retValue = NULL;
00261     if (string == NULL) {
00262        goto done;
00263     }
00264     round1 = nss_addEscape(string,'\'');
00265     if (round1) {
00266        retValue = nss_addEscape(round1,'"');
00267        PORT_Free(round1);
00268     }
00269 
00270 done:
00271     if (retValue == NULL) {
00272        retValue = PORT_Strdup("");
00273     }
00274     return retValue;
00275 }
00276 
00277 
00278 #ifndef XP_MAC
00279 /*
00280  * The following code is an attempt to automagically find the external root
00281  * module. NOTE: This code should be checked out on the MAC! There must be
00282  * some cross platform support out there to help out with this?
00283  * Note: Keep the #if-defined chunks in order. HPUX must select before UNIX.
00284  */
00285 
00286 static const char *dllname =
00287 #if defined(XP_WIN32) || defined(XP_OS2)
00288        "nssckbi.dll";
00289 #elif defined(HPUX) && !defined(__ia64)  /* HP-UX PA-RISC */
00290        "libnssckbi.sl";
00291 #elif defined(DARWIN)
00292        "libnssckbi.dylib";
00293 #elif defined(XP_UNIX) || defined(XP_BEOS)
00294        "libnssckbi.so";
00295 #elif defined(XP_MAC)
00296        "NSS Builtin Root Certs";
00297 #else
00298        #error "Uh! Oh! I don't know about this platform."
00299 #endif
00300 
00301 /* Should we have platform ifdefs here??? */
00302 #define FILE_SEP '/'
00303 
00304 static void nss_FindExternalRootPaths(const char *dbpath, 
00305                                       const char* secmodprefix,
00306                               char** retoldpath, char** retnewpath)
00307 {
00308     char *path, *oldpath = NULL, *lastsep;
00309     int len, path_len, secmod_len, dll_len;
00310 
00311     path_len = PORT_Strlen(dbpath);
00312     secmod_len = secmodprefix ? PORT_Strlen(secmodprefix) : 0;
00313     dll_len = PORT_Strlen(dllname);
00314     len = path_len + secmod_len + dll_len + 2; /* FILE_SEP + NULL */
00315 
00316     path = PORT_Alloc(len);
00317     if (path == NULL) return;
00318 
00319     /* back up to the top of the directory */
00320     PORT_Memcpy(path,dbpath,path_len);
00321     if (path[path_len-1] != FILE_SEP) {
00322         path[path_len++] = FILE_SEP;
00323     }
00324     PORT_Strcpy(&path[path_len],dllname);
00325     if (secmod_len > 0) {
00326         lastsep = PORT_Strrchr(secmodprefix, FILE_SEP);
00327         if (lastsep) {
00328             int secmoddir_len = lastsep-secmodprefix+1; /* FILE_SEP */
00329             oldpath = PORT_Alloc(len);
00330             if (oldpath == NULL) {
00331                 PORT_Free(path);
00332                 return;
00333             }
00334             PORT_Memcpy(oldpath,path,path_len);
00335             PORT_Memcpy(&oldpath[path_len],secmodprefix,secmoddir_len);
00336             PORT_Strcpy(&oldpath[path_len+secmoddir_len],dllname);
00337         }
00338     }
00339     *retoldpath = oldpath;
00340     *retnewpath = path;
00341     return;
00342 }
00343 
00344 static void nss_FreeExternalRootPaths(char* oldpath, char* path)
00345 {
00346     if (path) {
00347         PORT_Free(path);
00348     }
00349     if (oldpath) {
00350         PORT_Free(oldpath);
00351     }
00352 }
00353 
00354 static void
00355 nss_FindExternalRoot(const char *dbpath, const char* secmodprefix)
00356 {
00357        char *path = NULL;
00358         char *oldpath = NULL;
00359         PRBool hasrootcerts = PR_FALSE;
00360 
00361         /*
00362          * 'oldpath' is the external root path in NSS 3.3.x or older.
00363          * For backward compatibility we try to load the root certs
00364          * module with the old path first.
00365          */
00366         nss_FindExternalRootPaths(dbpath, secmodprefix, &oldpath, &path);
00367         if (oldpath) {
00368             (void) SECMOD_AddNewModule("Root Certs",oldpath, 0, 0);
00369             hasrootcerts = SECMOD_HasRootCerts();
00370         }
00371         if (path && !hasrootcerts) {
00372            (void) SECMOD_AddNewModule("Root Certs",path, 0, 0);
00373         }
00374         nss_FreeExternalRootPaths(oldpath, path);
00375        return;
00376 }
00377 #endif
00378 
00379 /*
00380  * OK there are now lots of options here, lets go through them all:
00381  *
00382  * configdir - base directory where all the cert, key, and module datbases live.
00383  * certPrefix - prefix added to the beginning of the cert database example: "
00384  *                   "https-server1-"
00385  * keyPrefix - prefix added to the beginning of the key database example: "
00386  *                   "https-server1-"
00387  * secmodName - name of the security module database (usually "secmod.db").
00388  * readOnly - Boolean: true if the databases are to be openned read only.
00389  * nocertdb - Don't open the cert DB and key DB's, just initialize the 
00390  *                   Volatile certdb.
00391  * nomoddb - Don't open the security module DB, just initialize the 
00392  *                   PKCS #11 module.
00393  * forceOpen - Continue to force initializations even if the databases cannot
00394  *                   be opened.
00395  */
00396 
00397 static PRBool nss_IsInitted = PR_FALSE;
00398 
00399 extern SECStatus secoid_Init(void);
00400 static SECStatus nss_InitShutdownList(void);
00401 
00402 #ifdef DEBUG
00403 static CERTCertificate dummyCert;
00404 #endif
00405 
00406 static SECStatus
00407 nss_Init(const char *configdir, const char *certPrefix, const char *keyPrefix,
00408                const char *secmodName, PRBool readOnly, PRBool noCertDB, 
00409                      PRBool noModDB, PRBool forceOpen, PRBool noRootInit,
00410                      PRBool optimizeSpace, PRBool noSingleThreadedModules,
00411                      PRBool allowAlreadyInitializedModules,
00412                      PRBool dontFinalizeModules)
00413 {
00414     char *moduleSpec = NULL;
00415     char *flags = NULL;
00416     SECStatus rv = SECFailure;
00417     char *lconfigdir = NULL;
00418     char *lcertPrefix = NULL;
00419     char *lkeyPrefix = NULL;
00420     char *lsecmodName = NULL;
00421 
00422     if (nss_IsInitted) {
00423        return SECSuccess;
00424     }
00425 
00426     /* New option bits must not change the size of CERTCertificate. */
00427     PORT_Assert(sizeof(dummyCert.options) == sizeof(void *));
00428 
00429     if (SECSuccess != InitCRLCache()) {
00430         return SECFailure;
00431     }
00432     
00433     if (SECSuccess != InitOCSPGlobal()) {
00434         return SECFailure;
00435     }
00436 
00437     flags = nss_makeFlags(readOnly,noCertDB,noModDB,forceOpen,
00438                                    pk11_password_required, optimizeSpace);
00439     if (flags == NULL) return rv;
00440 
00441     /*
00442      * configdir is double nested, and Windows uses the same character
00443      * for file seps as we use for escapes! (sigh).
00444      */
00445     lconfigdir = nss_doubleEscape(configdir);
00446     if (lconfigdir == NULL) {
00447        goto loser;
00448     }
00449     lcertPrefix = nss_doubleEscape(certPrefix);
00450     if (lcertPrefix == NULL) {
00451        goto loser;
00452     }
00453     lkeyPrefix = nss_doubleEscape(keyPrefix);
00454     if (lkeyPrefix == NULL) {
00455        goto loser;
00456     }
00457     lsecmodName = nss_doubleEscape(secmodName);
00458     if (lsecmodName == NULL) {
00459        goto loser;
00460     }
00461     if (noSingleThreadedModules || allowAlreadyInitializedModules ||
00462         dontFinalizeModules) {
00463         pk11_setGlobalOptions(noSingleThreadedModules,
00464                               allowAlreadyInitializedModules,
00465                               dontFinalizeModules);
00466     }
00467 
00468     moduleSpec = PR_smprintf("name=\"%s\" parameters=\"configdir='%s' certPrefix='%s' keyPrefix='%s' secmod='%s' flags=%s %s\" NSS=\"flags=internal,moduleDB,moduleDBOnly,critical\"",
00469               pk11_config_name ? pk11_config_name : NSS_DEFAULT_MOD_NAME,
00470               lconfigdir,lcertPrefix,lkeyPrefix,lsecmodName,flags,
00471               pk11_config_strings ? pk11_config_strings : "");
00472 
00473 loser:
00474     PORT_Free(flags);
00475     if (lconfigdir) PORT_Free(lconfigdir);
00476     if (lcertPrefix) PORT_Free(lcertPrefix);
00477     if (lkeyPrefix) PORT_Free(lkeyPrefix);
00478     if (lsecmodName) PORT_Free(lsecmodName);
00479 
00480     if (moduleSpec) {
00481        SECMODModule *module = SECMOD_LoadModule(moduleSpec,NULL,PR_TRUE);
00482        PR_smprintf_free(moduleSpec);
00483        if (module) {
00484            if (module->loaded) rv=SECSuccess;
00485            SECMOD_DestroyModule(module);
00486        }
00487     }
00488 
00489     if (rv == SECSuccess) {
00490        if (secoid_Init() != SECSuccess) {
00491            return SECFailure;
00492        }
00493        if (STAN_LoadDefaultNSS3TrustDomain() != PR_SUCCESS) {
00494            return SECFailure;
00495        }
00496        if (nss_InitShutdownList() != SECSuccess) {
00497            return SECFailure;
00498        }
00499        CERT_SetDefaultCertDB((CERTCertDBHandle *)
00500                             STAN_GetDefaultTrustDomain());
00501 #ifndef XP_MAC
00502        /* only servers need this. We currently do not have a mac server */
00503        if ((!noModDB) && (!noCertDB) && (!noRootInit)) {
00504            if (!SECMOD_HasRootCerts()) {
00505               nss_FindExternalRoot(configdir, secmodName);
00506            }
00507        }
00508 #endif
00509        pk11sdr_Init();
00510        cert_CreateSubjectKeyIDHashTable();
00511        nss_IsInitted = PR_TRUE;
00512     }
00513     return rv;
00514 }
00515 
00516 
00517 SECStatus
00518 NSS_Init(const char *configdir)
00519 {
00520     return nss_Init(configdir, "", "", SECMOD_DB, PR_TRUE, 
00521               PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE, PR_TRUE, PR_FALSE, PR_FALSE, PR_FALSE);
00522 }
00523 
00524 SECStatus
00525 NSS_InitReadWrite(const char *configdir)
00526 {
00527     return nss_Init(configdir, "", "", SECMOD_DB, PR_FALSE, 
00528               PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE, PR_TRUE, PR_FALSE, PR_FALSE, PR_FALSE);
00529 }
00530 
00531 /*
00532  * OK there are now lots of options here, lets go through them all:
00533  *
00534  * configdir - base directory where all the cert, key, and module datbases live.
00535  * certPrefix - prefix added to the beginning of the cert database example: "
00536  *                   "https-server1-"
00537  * keyPrefix - prefix added to the beginning of the key database example: "
00538  *                   "https-server1-"
00539  * secmodName - name of the security module database (usually "secmod.db").
00540  * flags - change the open options of NSS_Initialize as follows:
00541  *     NSS_INIT_READONLY - Open the databases read only.
00542  *     NSS_INIT_NOCERTDB - Don't open the cert DB and key DB's, just 
00543  *                   initialize the volatile certdb.
00544  *     NSS_INIT_NOMODDB  - Don't open the security module DB, just 
00545  *                   initialize the       PKCS #11 module.
00546  *      NSS_INIT_FORCEOPEN - Continue to force initializations even if the 
00547  *                   databases cannot be opened.
00548  *      NSS_INIT_PK11THREADSAFE - only load PKCS#11 modules that are
00549  *                      thread-safe, ie. that support locking - either OS
00550  *                      locking or NSS-provided locks . If a PKCS#11
00551  *                      module isn't thread-safe, don't serialize its
00552  *                      calls; just don't load it instead. This is necessary
00553  *                      if another piece of code is using the same PKCS#11
00554  *                      modules that NSS is accessing without going through
00555  *                      NSS, for example the Java SunPKCS11 provider.
00556  *      NSS_INIT_PK11RELOAD - ignore the CKR_CRYPTOKI_ALREADY_INITIALIZED
00557  *                      error when loading PKCS#11 modules. This is necessary
00558  *                      if another piece of code is using the same PKCS#11
00559  *                      modules that NSS is accessing without going through
00560  *                      NSS, for example Java SunPKCS11 provider.
00561  *      NSS_INIT_NOPK11FINALIZE - never call C_Finalize on any
00562  *                      PKCS#11 module. This may be necessary in order to
00563  *                      ensure continuous operation and proper shutdown
00564  *                      sequence if another piece of code is using the same
00565  *                      PKCS#11 modules that NSS is accessing without going
00566  *                      through NSS, for example Java SunPKCS11 provider.
00567  *                      The following limitation applies when this is set :
00568  *                      SECMOD_WaitForAnyTokenEvent will not use
00569  *                      C_WaitForSlotEvent, in order to prevent the need for
00570  *                      C_Finalize. This call will be emulated instead.
00571  *      NSS_INIT_RESERVED - Currently has no effect, but may be used in the
00572  *                      future to trigger better cooperation between PKCS#11
00573  *                      modules used by both NSS and the Java SunPKCS11
00574  *                      provider. This should occur after a new flag is defined
00575  *                      for C_Initialize by the PKCS#11 working group.
00576  *      NSS_INIT_COOPERATE - Sets 4 recommended options for applications that
00577  *                      use both NSS and the Java SunPKCS11 provider. 
00578  */
00579 SECStatus
00580 NSS_Initialize(const char *configdir, const char *certPrefix, 
00581        const char *keyPrefix, const char *secmodName, PRUint32 flags)
00582 {
00583     return nss_Init(configdir, certPrefix, keyPrefix, secmodName, 
00584        ((flags & NSS_INIT_READONLY) == NSS_INIT_READONLY),
00585        ((flags & NSS_INIT_NOCERTDB) == NSS_INIT_NOCERTDB),
00586        ((flags & NSS_INIT_NOMODDB) == NSS_INIT_NOMODDB),
00587        ((flags & NSS_INIT_FORCEOPEN) == NSS_INIT_FORCEOPEN),
00588        ((flags & NSS_INIT_NOROOTINIT) == NSS_INIT_NOROOTINIT),
00589        ((flags & NSS_INIT_OPTIMIZESPACE) == NSS_INIT_OPTIMIZESPACE),
00590         ((flags & NSS_INIT_PK11THREADSAFE) == NSS_INIT_PK11THREADSAFE),
00591         ((flags & NSS_INIT_PK11RELOAD) == NSS_INIT_PK11RELOAD),
00592         ((flags & NSS_INIT_NOPK11FINALIZE) == NSS_INIT_NOPK11FINALIZE));
00593 }
00594 
00595 /*
00596  * initialize NSS without a creating cert db's, key db's, or secmod db's.
00597  */
00598 SECStatus
00599 NSS_NoDB_Init(const char * configdir)
00600 {
00601       return nss_Init("","","","",
00602                      PR_TRUE,PR_TRUE,PR_TRUE,PR_TRUE,PR_TRUE,PR_TRUE,
00603                      PR_FALSE,PR_FALSE,PR_FALSE);
00604 }
00605 
00606 
00607 #define NSS_SHUTDOWN_STEP 10
00608 
00609 struct NSSShutdownFuncPair {
00610     NSS_ShutdownFunc func;
00611     void             *appData;
00612 };
00613 
00614 static struct NSSShutdownListStr {
00615     PZLock           *lock;
00616     int                     maxFuncs;
00617     int                     numFuncs;
00618     struct NSSShutdownFuncPair     *funcs;
00619 } nssShutdownList = { 0 };
00620 
00621 /*
00622  * find and existing shutdown function
00623  */
00624 static int 
00625 nss_GetShutdownEntry(NSS_ShutdownFunc sFunc, void *appData)
00626 {
00627     int count, i;
00628     count = nssShutdownList.numFuncs;
00629     /* expect the list to be short, just do a linear search */
00630     for (i=0; i < count; i++) {
00631        if ((nssShutdownList.funcs[i].func == sFunc) &&
00632            (nssShutdownList.funcs[i].appData == appData)){
00633            return i;
00634        }
00635     }
00636     return -1;
00637 }
00638     
00639 /*
00640  * register a callback to be called when NSS shuts down
00641  */
00642 SECStatus
00643 NSS_RegisterShutdown(NSS_ShutdownFunc sFunc, void *appData)
00644 {
00645     int i;
00646 
00647     if (!nss_IsInitted) {
00648        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
00649        return SECFailure;
00650     }
00651     if (sFunc == NULL) {
00652        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00653        return SECFailure;
00654     }
00655 
00656     PORT_Assert(nssShutdownList.lock);
00657     PZ_Lock(nssShutdownList.lock);
00658 
00659     /* make sure we don't have a duplicate */
00660     i = nss_GetShutdownEntry(sFunc, appData);
00661     if (i > 0) {
00662        PZ_Unlock(nssShutdownList.lock);
00663        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
00664        return SECFailure;
00665     }
00666     /* find an empty slot */
00667     i = nss_GetShutdownEntry(NULL, NULL);
00668     if (i > 0) {
00669        nssShutdownList.funcs[i].func = sFunc;
00670        nssShutdownList.funcs[i].appData = appData;
00671        PZ_Unlock(nssShutdownList.lock);
00672        return SECFailure;
00673     }
00674     if (nssShutdownList.maxFuncs == nssShutdownList.numFuncs) {
00675        struct NSSShutdownFuncPair *funcs = 
00676               (struct NSSShutdownFuncPair *)PORT_Realloc
00677               (nssShutdownList.funcs, 
00678               (nssShutdownList.maxFuncs + NSS_SHUTDOWN_STEP) 
00679               *sizeof(struct NSSShutdownFuncPair));
00680        if (!funcs) {
00681            return SECFailure;
00682        }
00683        nssShutdownList.funcs = funcs;
00684        nssShutdownList.maxFuncs += NSS_SHUTDOWN_STEP;
00685     }
00686     nssShutdownList.funcs[nssShutdownList.numFuncs].func = sFunc;
00687     nssShutdownList.funcs[nssShutdownList.numFuncs].appData = appData;
00688     nssShutdownList.numFuncs++;
00689     PZ_Unlock(nssShutdownList.lock);
00690     return SECSuccess;
00691 }
00692 
00693 /*
00694  * unregister a callback so it won't get called on shutdown.
00695  */
00696 SECStatus
00697 NSS_UnregisterShutdown(NSS_ShutdownFunc sFunc, void *appData)
00698 {
00699     int i;
00700     if (!nss_IsInitted) {
00701        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
00702        return SECFailure;
00703     }
00704 
00705     PORT_Assert(nssShutdownList.lock);
00706     PZ_Lock(nssShutdownList.lock);
00707     i = nss_GetShutdownEntry(sFunc, appData);
00708     if (i > 0) {
00709        nssShutdownList.funcs[i].func = NULL;
00710        nssShutdownList.funcs[i].appData = NULL;
00711     }
00712     PZ_Unlock(nssShutdownList.lock);
00713 
00714     if (i < 0) {
00715        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
00716        return SECFailure;
00717     }
00718     return SECSuccess;
00719 }
00720 
00721 /*
00722  * bring up and shutdown the shutdown list
00723  */
00724 static SECStatus
00725 nss_InitShutdownList(void)
00726 {
00727     nssShutdownList.lock = PZ_NewLock(nssILockOther);
00728     if (nssShutdownList.lock == NULL) {
00729        return SECFailure;
00730     }
00731     nssShutdownList.funcs = PORT_ZNewArray(struct NSSShutdownFuncPair, 
00732                                        NSS_SHUTDOWN_STEP);
00733     if (nssShutdownList.funcs == NULL) {
00734        PZ_DestroyLock(nssShutdownList.lock);
00735        nssShutdownList.lock = NULL;
00736        return SECFailure;
00737     }
00738     nssShutdownList.maxFuncs = NSS_SHUTDOWN_STEP;
00739     nssShutdownList.numFuncs = 0;
00740 
00741     return SECSuccess;
00742 }
00743 
00744 static SECStatus
00745 nss_ShutdownShutdownList(void)
00746 {
00747     SECStatus rv = SECSuccess;
00748     int i;
00749 
00750     /* call all the registerd functions first */
00751     for (i=0; i < nssShutdownList.numFuncs; i++) {
00752        struct NSSShutdownFuncPair *funcPair = &nssShutdownList.funcs[i];
00753        if (funcPair->func) {
00754            if ((*funcPair->func)(funcPair->appData,NULL) != SECSuccess) {
00755               rv = SECFailure;
00756            }
00757        }
00758     }
00759 
00760     nssShutdownList.numFuncs = 0;
00761     nssShutdownList.maxFuncs = 0;
00762     PORT_Free(nssShutdownList.funcs);
00763     nssShutdownList.funcs = NULL;
00764     if (nssShutdownList.lock) {
00765        PZ_DestroyLock(nssShutdownList.lock);
00766     }
00767     nssShutdownList.lock = NULL;
00768     return rv;
00769 }
00770 
00771 
00772 extern const NSSError NSS_ERROR_BUSY;
00773 
00774 SECStatus
00775 NSS_Shutdown(void)
00776 {
00777     SECStatus shutdownRV = SECSuccess;
00778     SECStatus rv;
00779     PRStatus status;
00780 
00781     if (!nss_IsInitted) {
00782        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
00783        return SECFailure;
00784     }
00785 
00786     rv = nss_ShutdownShutdownList();
00787     if (rv != SECSuccess) {
00788        shutdownRV = SECFailure;
00789     }
00790     ShutdownCRLCache();
00791     SECOID_Shutdown();
00792     status = STAN_Shutdown();
00793     cert_DestroySubjectKeyIDHashTable();
00794     rv = SECMOD_Shutdown();
00795     if (rv != SECSuccess) {
00796        shutdownRV = SECFailure;
00797     }
00798     pk11sdr_Shutdown();
00799     if (status == PR_FAILURE) {
00800        if (NSS_GetError() == NSS_ERROR_BUSY) {
00801            PORT_SetError(SEC_ERROR_BUSY);
00802        }
00803        shutdownRV = SECFailure;
00804     }
00805     nss_IsInitted = PR_FALSE;
00806     return shutdownRV;
00807 }
00808 
00809 PRBool
00810 NSS_IsInitialized(void)
00811 {
00812     return nss_IsInitted;
00813 }
00814 
00815 
00816 extern const char __nss_base_rcsid[];
00817 extern const char __nss_base_sccsid[];
00818 
00819 PRBool
00820 NSS_VersionCheck(const char *importedVersion)
00821 {
00822     /*
00823      * This is the secret handshake algorithm.
00824      *
00825      * This release has a simple version compatibility
00826      * check algorithm.  This release is not backward
00827      * compatible with previous major releases.  It is
00828      * not compatible with future major, minor, or
00829      * patch releases.
00830      */
00831     int vmajor = 0, vminor = 0, vpatch = 0;
00832     const char *ptr = importedVersion;
00833     volatile char c; /* force a reference that won't get optimized away */
00834 
00835     c = __nss_base_rcsid[0] + __nss_base_sccsid[0]; 
00836 
00837     while (isdigit(*ptr)) {
00838         vmajor = 10 * vmajor + *ptr - '0';
00839         ptr++;
00840     }
00841     if (*ptr == '.') {
00842         ptr++;
00843         while (isdigit(*ptr)) {
00844             vminor = 10 * vminor + *ptr - '0';
00845             ptr++;
00846         }
00847         if (*ptr == '.') {
00848             ptr++;
00849             while (isdigit(*ptr)) {
00850                 vpatch = 10 * vpatch + *ptr - '0';
00851                 ptr++;
00852             }
00853         }
00854     }
00855 
00856     if (vmajor != NSS_VMAJOR) {
00857         return PR_FALSE;
00858     }
00859     if (vmajor == NSS_VMAJOR && vminor > NSS_VMINOR) {
00860         return PR_FALSE;
00861     }
00862     if (vmajor == NSS_VMAJOR && vminor == NSS_VMINOR && vpatch > NSS_VPATCH) {
00863         return PR_FALSE;
00864     }
00865     /* Check dependent libraries */
00866     if (PR_VersionCheck(PR_VERSION) == PR_FALSE) {
00867         return PR_FALSE;
00868     }
00869     return PR_TRUE;
00870 }
00871 
00872