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