fixup commit for tag 'NSS_3_3_RTM' NSS_3_3_RTM
authorcvs2hg
Wed, 11 Jul 2001 23:58:01 +0000
changeset 1736 8ab2a547794830fd2bca4f3f17ed23a01b5526e9
parent 1676 e73430331e94bfda25ec97e357dd49e57e0a22c8
child 1739 dcccee7447322f8532a873273138d0d04dc64ffb
push idunknown
push userunknown
push dateunknown
fixup commit for tag 'NSS_3_3_RTM'
dbm/tests/Makefile.in
security/nss/cmd/signtool/list.c
security/nss/cmd/signtool/sign.c
security/nss/cmd/signtool/verify.c
security/nss/cmd/tstclnt/tstclnt.c
security/nss/lib/certdb/pcertdb.c
security/nss/lib/freebl/mpi/mpprime.c
security/nss/lib/nss/nss.def
security/nss/lib/nss/nss.h
security/nss/lib/pk11wrap/pk11skey.c
security/nss/lib/pk11wrap/pk11util.c
security/nss/lib/ssl/manifest.mn
security/nss/lib/ssl/ssl.def
security/nss/lib/ssl/ssl.h
security/nss/lib/ssl/sslcon.c
security/nss/lib/ssl/sslimpl.h
security/nss/lib/ssl/sslnonce.c
security/nss/lib/ssl/sslsecur.c
security/nss/lib/ssl/sslsnce.c
security/nss/lib/util/mac_rand.c
security/nss/manifest.mn
security/nss/tests/ssl/sslauth.txt
--- a/dbm/tests/Makefile.in
+++ b/dbm/tests/Makefile.in
@@ -28,19 +28,15 @@ include $(DEPTH)/config/autoconf.mk
 
 MODULE		= dbm
 PROGRAM		= lots$(BIN_SUFFIX)
 
 CSRCS		= lots.c
 
 EXTRA_DSO_LIBS	= mozdbm_s
 
-ifeq ($(MOZ_OS2_TOOLS),VACPP)
-LIBS		= $(DIST)/lib/libmozdbm_s.$(LIB_SUFFIX)
-else
 LIBS		= $(EXTRA_DSO_LIBS)
-endif
 
 include $(topsrcdir)/config/rules.mk
 
 ifeq ($(OS_ARCH), Linux)
 DEFINES         += -D_BSD_SOURCE
 endif
--- a/security/nss/cmd/signtool/list.c
+++ b/security/nss/cmd/signtool/list.c
@@ -41,16 +41,17 @@ static SECStatus cert_trav_callback(CERT
 
 /*********************************************************************
  *
  * L i s t C e r t s
  */
 int
 ListCerts(char *key, int list_certs)
 {
+	int failed = 0;
 	SECStatus rv;
 	char *ugly_list;
 	CERTCertDBHandle *db;
 
 	CERTCertificate *cert;
 	CERTVerifyLog errlog;
 
 	errlog.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
@@ -80,34 +81,40 @@ ListCerts(char *key, int list_certs)
 	}
 
 	num_trav_certs = 0;
 
 	/* Traverse non-internal DBs */
 	rv = PK11_TraverseSlotCerts(cert_trav_callback, (void*)&list_certs,
 		NULL /*wincx*/);
 
+	if (rv) {
+		PR_fprintf(outputFD, "**Traverse of non-internal DBs failed**\n");
+		return -1;
+	}
+
 	/* Traverse Internal DB */
 	rv = SEC_TraversePermCerts(db, cert_trav_callback, (void*)&list_certs);
 
+	if (rv) {
+		PR_fprintf(outputFD, "**Traverse of internal DB failed**\n");
+		return -1;
+	}
+
 	if (num_trav_certs == 0) {
 		PR_fprintf(outputFD,
 			"You don't appear to have any object signing certificates.\n");
 	}
 
 	if (list_certs == 2) {
 		PR_fprintf(outputFD, "- ------------\n");
 	} else {
 		PR_fprintf(outputFD, "---------------------------------------\n");
 	}
 
-	if (rv) {
-		return -1;
-	}
-
 	if (list_certs == 1) {
 		PR_fprintf(outputFD,
 			"For a list including CA's, use \"%s -L\"\n", PROGRAM_NAME);
 	}
 
 	if(list_certs == 2) {
 		PR_fprintf(outputFD,
 			"Certificates that can be used to sign objects have *'s to "
@@ -136,41 +143,43 @@ ListCerts(char *key, int list_certs)
 			} else {
 				PR_fprintf(outputFD, "This certificate is not expired.\n");
 			}
 
 			rv = CERT_VerifyCert (db, cert, PR_TRUE,
 			certUsageObjectSigner, PR_Now(), NULL, &errlog);
 
 			if (rv != SECSuccess) {
+				failed = 1;
 				if(errlog.count > 0) {
 					PR_fprintf(outputFD,
 						"**Certificate validation failed for the "
 					 "following reason(s):**\n");
 				} else {
 					PR_fprintf(outputFD, "**Certificate validation failed**");
 				}
 			} else {
 				PR_fprintf(outputFD, "This certificate is valid.\n");
 			}
 			displayVerifyLog(&errlog);
 
 
 		} else {
+			failed = 1;
 			PR_fprintf(outputFD,
 				"The certificate with nickname \"%s\" was NOT FOUND\n",
 			 key);
 		}
     }
 
 	if(errlog.arena != NULL) {
 		PORT_FreeArena(errlog.arena, PR_FALSE);
 	}
 
-	if (rv != SECSuccess) {
+	if (failed) {
 		return -1;
 	}
 	return 0;
 }
 
 /********************************************************************
  *
  * c e r t _ t r a v _ c a l l b a c k
--- a/security/nss/cmd/signtool/sign.c
+++ b/security/nss/cmd/signtool/sign.c
@@ -163,16 +163,18 @@ sign_all_arc_fn(char *relpath, char *bas
 	SignArcInfo *infop = (SignArcInfo*)arg;
 
 	/* Make sure there is one and only one ".arc" in the relative path, 
 	 * and that it is at the end of the path (don't sign .arcs within .arcs) */
 	if ( (PL_strcaserstr(relpath, ".arc") == relpath + strlen(relpath) - 4) &&
 		 (PL_strcasestr(relpath, ".arc") == relpath + strlen(relpath) - 4) ) {
 
 		if(!infop) {
+			PR_fprintf(errorFD, "%s: Internal failure\n", PROGRAM_NAME);
+			errorCount++;
 			retval = -1;
 			goto finish;
 		}
 		archive = PR_smprintf("%s/%s", basedir, relpath);
 
 		zipfile = PL_strdup(archive);
 		arc = PORT_Strrchr (zipfile, '.');
 
--- a/security/nss/cmd/signtool/verify.c
+++ b/security/nss/cmd/signtool/verify.c
@@ -69,16 +69,17 @@ VerifyJar(char *filename)
 
   JAR_set_callback (JAR_CB_SIGNAL, jar, jar_cb);
 
 
   status = JAR_pass_archive (jar, jarArchGuess, filename, "some-url");
 
   if (status < 0 || jar->valid < 0)
     {
+    failed = 1;
     PR_fprintf(outputFD, "\nNOTE -- \"%s\" archive DID NOT PASS crypto verification.\n", filename);
     if (status < 0)
       {
       char *errtext;
 
       if (status >= JAR_BASE && status <= JAR_BASE_END)
         {
         errtext = JAR_get_error (status);
@@ -88,17 +89,17 @@ VerifyJar(char *filename)
         errtext = SECU_ErrorString ((int16) PORT_GetError());
         }
 
       PR_fprintf(outputFD, "  (reported reason: %s)\n\n", errtext);
  
       /* corrupt files should not have their contents listed */ 
 
       if (status == JAR_ERR_CORRUPT)
-        return status;
+        return -1;
       }
     PR_fprintf(outputFD,
 		"entries shown below will have their digests checked only.\n"); 
     jar->valid = 0;
     }
   else
     PR_fprintf(outputFD,
 		"archive \"%s\" has passed crypto verification.\n", filename);
@@ -135,27 +136,26 @@ VerifyJar(char *filename)
         PR_fprintf(outputFD, "      (reason: %s)\n", JAR_get_error (ret));
       }
     }
 
   JAR_find_end (ctx);
 
   if (status < 0 || jar->valid < 0)
     {
+    failed = 1;
     PR_fprintf(outputFD,
 		"\nNOTE -- \"%s\" archive DID NOT PASS crypto verification.\n", filename);
     give_help (status);
     }
 
   JAR_destroy (jar);
 
-  if (status < 0)
-    return status;
-  if (jar->valid < 0 || failed)
-    return ERRX;
+  if (failed)
+    return -1;
   return 0;
 }
 
 /***************************************************************************
  *
  * v e r i f y _ g l o b a l
  */
 static int
@@ -350,17 +350,20 @@ JarWho(char *filename)
       if (cert->nickname) 
         PR_fprintf(outputFD, "nickname: %s\n", cert->nickname);
       if (cert->subjectName)
         PR_fprintf(outputFD, "subject name: %s\n", cert->subjectName);
       if (cert->issuerName)
         PR_fprintf(outputFD, "issuer name: %s\n", cert->issuerName);
       }
     else
+      {
       PR_fprintf(outputFD, "no certificate could be found\n");
+      retval = -1;
+      }
 
     prev = cert;
     }
 
   JAR_find_end (ctx);
 
   JAR_destroy (jar);
   return retval;
--- a/security/nss/cmd/tstclnt/tstclnt.c
+++ b/security/nss/cmd/tstclnt/tstclnt.c
@@ -628,17 +628,17 @@ int main(int argc, char **argv)
 		PRINTF("%s: Writing %d bytes to server\n", progName, nb);
 		do {
 		    PRInt32 cc = PR_Write(s, bufp, nb);
 		    if (cc < 0) {
 		    	PRErrorCode err = PR_GetError();
 			if (err != PR_WOULD_BLOCK_ERROR) {
 			    SECU_PrintError(progName, 
 			                    "write to SSL socket failed");
-			    error=2;
+			    error=254;
 			    goto done;
 			}
 			cc = 0;
 		    }
 		    bufp += cc;
 		    nb   -= cc;
 		    if (nb <= 0) 
 		    	break;
--- a/security/nss/lib/certdb/pcertdb.c
+++ b/security/nss/lib/certdb/pcertdb.c
@@ -7193,16 +7193,23 @@ CERT_SaveImportedCert(CERTCertificate *c
 		trust.emailFlags = CERTDB_VALID_PEER;
 	    }
 	    
 	    if ( certtype & NS_CERT_TYPE_OBJECT_SIGNING ) {
 		trust.objectSigningFlags = CERTDB_VALID_PEER;
 	    }
 	}
 	break;
+      case certUsageAnyCA:
+	trust.sslFlags = CERTDB_VALID_CA;
+	break;
+      case certUsageSSLCA:
+	trust.sslFlags = CERTDB_VALID_CA | 
+			CERTDB_TRUSTED_CA | CERTDB_TRUSTED_CLIENT_CA;
+	break;
       default:	/* XXX added to quiet warnings; no other cases needed? */
 	break;
     }
 
     if ( saveit ) {
 	if ( cert->isperm ) {
 	    /* Cert already in the DB.  Just adjust flags */
 	    tmptrust = *cert->trust;
--- a/security/nss/lib/freebl/mpi/mpprime.c
+++ b/security/nss/lib/freebl/mpi/mpprime.c
@@ -475,32 +475,32 @@ mp_err mpp_make_prime(mp_int *start, mp_
     --nBits;
   MP_CHECKOK( mpl_set_bit(start, nBits - 1, 1) );
   MP_CHECKOK( mpl_set_bit(start,         0, 1) );
   for (i = mpl_significant_bits(start) - 1; i >= nBits; --i) {
     MP_CHECKOK( mpl_set_bit(start, i, 0) );
   }
   /* start sieveing with prime value of 3. */
   MP_CHECKOK(mpp_sieve(start, prime_tab + 1, prime_tab_size - 1, 
-		       sieve, sizeof sieve) );
+		       sieve, SIEVE_SIZE) );
 
 #ifdef DEBUG_SIEVE
   res = 0;
-  for (i = 0; i < sizeof sieve; ++i) {
+  for (i = 0; i < SIEVE_SIZE; ++i) {
     if (!sieve[i])
       ++res;
   }
   fprintf(stderr,"sieve found %d potential primes.\n", res);
 #define FPUTC(x,y) fputc(x,y)
 #else
 #define FPUTC(x,y) 
 #endif
 
   res = MP_NO;
-  for(i = 0; i < sizeof sieve; ++i) {
+  for(i = 0; i < SIEVE_SIZE; ++i) {
     if (sieve[i])	/* this number is composite */
       continue;
     MP_CHECKOK( mp_add_d(start, 2 * i, &trial) );
     FPUTC('.', stderr);
     /* run a Fermat test */
     res = mpp_fermat(&trial, 2);
     if (res != MP_OKAY) {
       if (res == MP_NO)
--- a/security/nss/lib/nss/nss.def
+++ b/security/nss/lib/nss/nss.def
@@ -454,18 +454,22 @@ CERT_AddRDN;
 CERT_CreateRDN;
 CERT_CreateAVA;
 CERT_CreateName;
 ;+    local:
 ;+       *;
 ;+};
 ;+NSS_3.3 { 	# NSS 3.3. release
 ;+    global:
+CERT_CheckCertUsage;
+CERT_FindCertIssuer;
+PK11_GetModule;
 SECKEY_CreateDHPrivateKey;
-CERT_CheckCertUsage;
+SECKEY_GetPublicKeyType;
+SECMOD_AddNewModule;
 ;+#
 ;+# The following symbols are exported only to make JSS work.
 ;+# These are still private!!!
 ;+#
 CERT_DisableOCSPChecking;
 CERT_DisableOCSPDefaultResponder;
 CERT_EnableOCSPDefaultResponder;
 CERT_GetCertTimes;
@@ -476,70 +480,70 @@ CERT_IsCADERCert;
 CERT_SetOCSPDefaultResponder;
 PBE_CreateContext;
 PBE_DestroyContext;
 PBE_GenerateBits;
 PK11_CheckSSOPassword;
 PK11_CopySymKeyForSigning;
 PK11_DeleteTokenCertAndKey;
 PK11_DEREncodePublicKey;
+PK11_ExtractKeyValue;
 PK11_FindCertsFromNickname;
 PK11_FindKeyByKeyID;
 PK11_GetIVLength;
 PK11_GetKeyData;
 PK11_GetKeyType;
 PK11_GetLowLevelKeyIDForCert;
 PK11_GetLowLevelKeyIDForPrivateKey;
+PK11_GetSlotPWValues;
 PK11_ImportCertForKey;
 PK11_ImportDERCertForKey;
 PK11_ImportDERPrivateKeyInfo;
+PK11_ImportSymKey;
 PK11_IsLoggedIn;
 PK11_KeyForDERCertExists;
 PK11_KeyForCertExists;
+PK11_ListPrivateKeysInSlot;
+PK11_ListCertsInSlot;
 PK11_Logout;
 PK11_NeedPWInit;
 PK11_MakeIDFromPubKey;
 PK11_PQG_DestroyParams;
 PK11_PQG_DestroyVerify;
 PK11_PQG_GetBaseFromParams;
 PK11_PQG_GetCounterFromVerify;
 PK11_PQG_GetHFromVerify;
 PK11_PQG_GetPrimeFromParams;
 PK11_PQG_GetSeedFromVerify;
 PK11_PQG_GetSubPrimeFromParams;
 PK11_PQG_NewParams;
 PK11_PQG_NewVerify;
 PK11_PQG_ParamGen;
 PK11_PQG_ParamGenSeedLen;
 PK11_PQG_VerifyParams;
+PK11_ReferenceSlot;
 PK11_SeedRandom;
 PK11_UnwrapPrivKey;
 PK11_VerifyRecover;
 PK11_WrapPrivKey;
-PK11_ReferenceSlot;
-PK11_GetSlotPWValues;
-PK11_ImportSymKey;
-PK11_ExtractKeyValue;
 SEC_CertNicknameConflict;
+SEC_PKCS5GetIV;
 SECMOD_DeleteInternalModule;
 SECMOD_DestroyModule;
 SECMOD_GetDefaultModuleList;
 SECMOD_GetDefaultModuleListLock;
 SECMOD_GetInternalModule;
 SECMOD_GetReadLock;
 SECMOD_ReferenceModule;
 SECMOD_ReleaseReadLock;
-SECKEY_GetPrivateKeyType;
+SECKEY_AddPrivateKeyToListTail;
 SECKEY_EncodeDERSubjectPublicKeyInfo;
 SECKEY_ExtractPublicKey;
+SECKEY_DestroyPrivateKeyList;
+SECKEY_GetPrivateKeyType;
 SECKEY_HashPassword;
 SECKEY_ImportDERPublicKey;
 SECKEY_NewPrivateKeyList;
-SECKEY_DestroyPrivateKeyList;
 SECKEY_RemovePrivateKeyListNode;
-SECKEY_AddPrivateKeyToListTail;
-SEC_PKCS5GetIV;
-PK11_ListPrivateKeysInSlot;
-PK11_ListCertsInSlot;
 VFY_EndWithSignature;
 ;+    local:
 ;+       *;
 ;+};
--- a/security/nss/lib/nss/nss.h
+++ b/security/nss/lib/nss/nss.h
@@ -44,21 +44,21 @@ SEC_BEGIN_PROTOS
 
 /*
  * NSS's major version, minor version, patch level, and whether
  * this is a beta release.
  *
  * The format of the version string should be
  *     "<major version>.<minor version>[.<patch level>] [<Beta>]"
  */
-#define NSS_VERSION  "3.3 Beta"
+#define NSS_VERSION  "3.3"
 #define NSS_VMAJOR   3
 #define NSS_VMINOR   3
 #define NSS_VPATCH   0
-#define NSS_BETA     PR_TRUE
+#define NSS_BETA     PR_FALSE
 
 
 /*
  * Return a boolean that indicates whether the underlying library
  * will perform as the caller expects.
  *
  * The only argument is a string, which should be the verson
  * identifier of the NSS library. That string will be compared
--- a/security/nss/lib/pk11wrap/pk11skey.c
+++ b/security/nss/lib/pk11wrap/pk11skey.c
@@ -1211,30 +1211,31 @@ PK11_TokenKeyGen(PK11SlotInfo *slot, CK_
     CK_ATTRIBUTE *attrs = genTemplate;
     int count = sizeof(genTemplate)/sizeof(genTemplate[0]);
     CK_SESSION_HANDLE session;
     CK_MECHANISM mechanism;
     CK_RV crv;
     PRBool weird = PR_FALSE;   /* hack for fortezza */
     CK_BBOOL ckfalse = CK_FALSE;
     CK_BBOOL cktrue = CK_TRUE;
+    CK_ULONG ck_key_size;       /* only used for variable-length keys */
 
     if ((keySize == -1) && (type == CKM_SKIPJACK_CBC64)) {
 	weird = PR_TRUE;
 	keySize = 0;
     }
 
     /* TNH: Isn't this redundant, since "handleKey" will set defaults? */
     PK11_SETATTRS(attrs, (!weird) 
 	? CKA_ENCRYPT : CKA_DECRYPT, &cktrue, sizeof(CK_BBOOL)); attrs++;
     
     if (keySize != 0) {
-        CK_ULONG key_size = keySize; /* Convert to PK11 type */
-
-        PK11_SETATTRS(attrs, CKA_VALUE_LEN, &key_size, sizeof(key_size)); 
+        ck_key_size = keySize; /* Convert to PK11 type */
+
+        PK11_SETATTRS(attrs, CKA_VALUE_LEN, &ck_key_size, sizeof(ck_key_size)); 
 							attrs++;
     }
 
     /* Include key id value if provided */
     if (keyid) {
         PK11_SETATTRS(attrs, CKA_ID, keyid->data, keyid->len); attrs++;
     }
 
--- a/security/nss/lib/pk11wrap/pk11util.c
+++ b/security/nss/lib/pk11wrap/pk11util.c
@@ -227,16 +227,22 @@ SECMOD_GetInternalModule(void) {
 /* called from  security/cmd/swfort/instinit, which doesn't need a full 
  * security LIBRARY (it used the swfortezza code, but it does have to verify
  * cert chains against it's own list of certs. We need to initialize the 
  * security code without any database.
  */
 void
 SECMOD_SetInternalModule( SECMODModule *mod) {
    internalModule = SECMOD_ReferenceModule(mod);
+   modules = SECMOD_NewModuleListElement();
+   modules->module = SECMOD_ReferenceModule(mod);
+   modules->next = NULL;
+   if (!moduleLock) {
+       moduleLock = SECMOD_NewListLock();
+   }
 }
 
 /*
  * get the list of PKCS11 modules that are available.
  */
 SECMODModuleList *SECMOD_GetDefaultModuleList() { return modules; }
 SECMODListLock *SECMOD_GetDefaultModuleListLock() { return moduleLock; }
 
--- a/security/nss/lib/ssl/manifest.mn
+++ b/security/nss/lib/ssl/manifest.mn
@@ -55,17 +55,16 @@ CSRCS = \
 	ssl3con.c \
 	ssl3gthr.c \
 	sslauth.c \
 	sslcon.c \
 	ssldef.c \
 	sslenum.c \
 	sslerr.c \
 	sslgathr.c \
-	sslmutex.c \
 	sslnonce.c \
 	sslreveal.c \
 	sslsecur.c \
 	sslsnce.c \
 	sslsock.c \
 	ssltrace.c \
 	sslver.c \
 	authcert.c \
--- a/security/nss/lib/ssl/ssl.def
+++ b/security/nss/lib/ssl/ssl.def
@@ -100,18 +100,8 @@ SSL_SetURL;
 ;+*;
 ;+};
 ;+NSS_3.2.1 {       # NSS 3.2.1 release
 ;+    global:
 NSSSSL_VersionCheck;
 ;+    local:
 ;+*;
 ;+};
-;+NSS_3.3 {         # NSS 3.3   release
-;+    global:
-;+#   We have not yet decided whether these functions will be exported
-;-#   in the final 3.3 release, so please treat them as exported private
-;-#   functions for now.
-SSL_GetMaxServerCacheLocks;
-SSL_SetMaxServerCacheLocks;
-;+    local:
-;+*;
-;+};
--- a/security/nss/lib/ssl/ssl.h
+++ b/security/nss/lib/ssl/ssl.h
@@ -46,16 +46,18 @@
 #include "keyt.h"
 
 #if defined(_WIN32) && !defined(IN_LIBSSL) && !defined(NSS_USE_STATIC_LIBS)
 #define SSL_IMPORT extern __declspec(dllimport)
 #else
 #define SSL_IMPORT extern
 #endif
 
+SEC_BEGIN_PROTOS
+
 /* constant table enumerating all implemented SSL 2 and 3 cipher suites. */
 SSL_IMPORT const PRUint16 SSL_ImplementedCiphers[];
 
 /* number of entries in the above table. */
 SSL_IMPORT const PRUint16 SSL_NumImplementedCiphers;
 
 /* Macro to tell which ciphers in table are SSL2 vs SSL3/TLS. */
 #define SSL_IS_SSL2_CIPHER(which) (((which) & 0xfff0) == 0xff00)
@@ -72,19 +74,16 @@ typedef struct SSL3StatisticsStr {
     long hsh_sid_cache_not_ok;
 
     /* statistics from ssl3_HandleClientHello (hch) */
     long hch_sid_cache_hits;
     long hch_sid_cache_misses;
     long hch_sid_cache_not_ok;
 } SSL3Statistics;
 
-SEC_BEGIN_PROTOS
-
-
 /*
 ** Imports fd into SSL, returning a new socket.  Copies SSL configuration
 ** from model.
 */
 SSL_IMPORT PRFileDesc *SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd);
 
 /*
 ** Enable/disable an ssl mode
@@ -294,27 +293,16 @@ SSL_IMPORT SECStatus SSL_ConfigServerSes
 ** This function sets up a Server Session ID (SID) cache that is safe for
 ** access by multiple processes on the same system.
 */
 SSL_IMPORT SECStatus SSL_ConfigMPServerSIDCache(int      maxCacheEntries, 
 				                PRUint32 timeout,
 			       	                PRUint32 ssl3_timeout, 
 		                          const char *   directory);
 
-/* Get and set the configured maximum number of mutexes used for the 
-** server's store of SSL sessions.  This value is used by the server 
-** session ID cache initialization functions shown above.  Note that on 
-** some platforms, these mutexes are actually implemented with POSIX 
-** semaphores, or with unnamed pipes.  The default value varies by platform.
-** An attempt to set a too-low maximum will return an error and the 
-** configured value will not be changed.
-*/
-SSL_IMPORT PRUint32  SSL_GetMaxServerCacheLocks(void);
-SSL_IMPORT SECStatus SSL_SetMaxServerCacheLocks(PRUint32 maxLocks);
-
 /* environment variable set by SSL_ConfigMPServerSIDCache, and queried by
  * SSL_InheritMPServerSIDCache when envString is NULL.
  */
 #define SSL_ENV_VAR_NAME            "SSL_INHERITANCE"
 
 /* called in child to inherit SID Cache variables. 
  * If envString is NULL, this function will use the value of the environment
  * variable "SSL_INHERITANCE", otherwise the string value passed in will be 
--- a/security/nss/lib/ssl/sslcon.c
+++ b/security/nss/lib/ssl/sslcon.c
@@ -2526,17 +2526,17 @@ ssl2_HandleMessage(sslSocket *ss)
 
     case SSL_MT_SERVER_FINISHED:
 	if (ci->elements & CIS_HAVE_FINISHED) {
 	    SSL_DBG(("%d: SSL[%d]: dup server-finished message",
 		     SSL_GETPID(), ss->fd));
 	    goto bad_peer;
 	}
 
-	if (gs->recordLen - 1 != SSL2_SESSIONID_BYTES) {
+	if (gs->recordLen - 1 != SSL_SESSIONID_BYTES) {
 	    SSL_DBG(("%d: SSL[%d]: bad server-finished message, len=%d",
 		     SSL_GETPID(), ss->fd, gs->recordLen));
 	    goto bad_peer;
 	}
 	ssl2_ClientRegSessionID(ss, data+1);
 	SSL_TRC(5, ("%d: SSL[%d]: got server finished, waiting for 0x%d",
 		    SSL_GETPID(), ss->fd, ci->requiredElements ^ ci->elements));
 	ci->elements |= CIS_HAVE_FINISHED;
@@ -3544,17 +3544,17 @@ ssl2_HandleClientHelloMessage(sslSocket 
 	    goto loser;
 	}
 	sid->references = 1;
 	sid->addr = ci->peer;
 	sid->port = ci->port;
 
 	/* Invent a session-id */
 	ci->sid = sid;
-	PK11_GenerateRandom(sid->u.ssl2.sessionID+2, SSL2_SESSIONID_BYTES-2);
+	PK11_GenerateRandom(sid->u.ssl2.sessionID+2, SSL_SESSIONID_BYTES-2);
 
 	pid = SSL_GETPID();
 	sid->u.ssl2.sessionID[0] = MSB(pid);
 	sid->u.ssl2.sessionID[1] = LSB(pid);
 	cert = ss->serverCert[kt_rsa]->derCert.data;
 	certLen = ss->serverCert[kt_rsa]->derCert.len;
     }
 
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -108,17 +108,17 @@ typedef enum { SSLAppOpRead = 0,
 	       SSLAppOpRDWR,
 	       SSLAppOpPost,
 	       SSLAppOpHeader
 } SSLAppOperation;
 
 #define SSL_MIN_MASTER_KEY_BYTES	5
 #define SSL_MAX_MASTER_KEY_BYTES	64
 
-#define SSL2_SESSIONID_BYTES		16
+#define SSL_SESSIONID_BYTES		16
 #define SSL3_SESSIONID_BYTES		32
 
 #define SSL_MIN_CHALLENGE_BYTES		16
 #define SSL_MAX_CHALLENGE_BYTES		32
 #define SSL_CHALLENGE_BYTES		16
 
 #define SSL_CONNECTIONID_BYTES		16
 
@@ -203,17 +203,17 @@ struct sslBufferStr {
     unsigned int 	len;
     unsigned int 	space;
 };
 
 /*
 ** SSL3 cipher suite policy and preference struct.
 */
 typedef struct {
-#if !defined(_WIN32)
+#ifdef AIX
     unsigned int    cipher_suite : 16;
     unsigned int    policy       :  8;
     unsigned int    enabled      :  1;
     unsigned int    isPresent    :  1;
 #else
     ssl3CipherSuite cipher_suite;
     PRUint8         policy;
     unsigned char   enabled   : 1;
@@ -706,17 +706,17 @@ struct sslSessionIDStr {
 
     PRUint32              time;
     Cached                cached;
     int                   references;
 
     union {
 	struct {
 	    /* the V2 code depends upon the size of sessionID.  */
-	    unsigned char         sessionID[SSL2_SESSIONID_BYTES];
+	    unsigned char         sessionID[SSL_SESSIONID_BYTES];
 
 	    /* Stuff used to recreate key and read/write cipher objects */
 	    SECItem               masterKey;
 	    int                   cipherType;
 	    SECItem               cipherArg;
 	    int                   keyBits;
 	    int                   secretKeyBits;
 	} ssl2;
@@ -1242,18 +1242,15 @@ ssl_EmulateSendFile( PRFileDesc *       
 #define SSL_TRACE(msg)
 #endif
 
 void ssl_Trace(const char *format, ...);
 
 SEC_END_PROTOS
 
 
-#if defined(XP_UNIX)
+#ifdef XP_UNIX
 #define SSL_GETPID() getpid()
-#elif defined(WIN32)
-/* #define SSL_GETPID() GetCurrentProcessId() */
-#define SSL_GETPID() _getpid()
 #else
 #define SSL_GETPID() 0
 #endif
 
 #endif /* __sslimpl_h_ */
--- a/security/nss/lib/ssl/sslnonce.c
+++ b/security/nss/lib/ssl/sslnonce.c
@@ -39,19 +39,17 @@
 #include "cert.h"
 #include "secitem.h"
 #include "ssl.h"
 
 #include "sslimpl.h"
 #include "sslproto.h"
 #include "nssilock.h"
 #include "nsslocks.h"
-#if defined(XP_UNIX) || defined(XP_WIN) || defined(_WINDOWS)
-#include <time.h>
-#endif
+
 
 PRUint32 ssl_sid_timeout = 100;
 PRUint32 ssl3_sid_timeout = 86400L; /* 24 hours */
 
 static sslSessionID *cache;
 static PZLock *      cacheLock;
 
 /* sids can be in one of 4 states:
@@ -334,24 +332,19 @@ SSL_ClearSessionCache(void)
 	UncacheSID(cache);
     UNLOCK_CACHE;
 }
 
 /* returns an unsigned int containing the number of seconds in PR_Now() */
 PRUint32
 ssl_Time(void)
 {
-    PRUint32 myTime;
-#if defined(XP_UNIX) || defined(XP_WIN) || defined(_WINDOWS)
-    myTime = time(NULL);	/* accurate until the year 2038. */
-#else
-    /* portable, but possibly slower */
     PRTime now;
     PRInt64 ll;
+    PRUint32 time;
 
     now = PR_Now();
     LL_I2L(ll, 1000000L);
     LL_DIV(now, now, ll);
-    LL_L2UI(myTime, now);
-#endif
-    return myTime;
+    LL_L2UI(time, now);
+    return time;
 }
 
--- a/security/nss/lib/ssl/sslsecur.c
+++ b/security/nss/lib/ssl/sslsecur.c
@@ -930,22 +930,16 @@ ssl_SecureClose(sslSocket *ss)
     int rv;
 
     if (ss->version >= SSL_LIBRARY_VERSION_3_0 	&&
     	ss->firstHsDone 			&& 
 	!(ss->shutdownHow & ssl_SHUTDOWN_SEND)	&&
 	!ss->recvdCloseNotify                   &&
 	(ss->ssl3 != NULL)) {
 
-	/* We don't want the final alert to be Nagle delayed. */
-	if (!ss->delayDisabled) {
-	    ssl_EnableNagleDelay(ss, PR_FALSE);
-	    ss->delayDisabled = 1;
-	}
-
 	(void) SSL3_SendAlert(ss, alert_warning, close_notify);
     }
     rv = ssl_DefClose(ss);
     return rv;
 }
 
 /* Caller handles all locking */
 int
@@ -1234,17 +1228,17 @@ SSL_GetSessionID(PRFileDesc *fd)
     if (ss) {
 	ssl_Get1stHandshakeLock(ss);
 	ssl_GetSSL3HandshakeLock(ss);
 
 	if (ss->useSecurity && ss->firstHsDone && ss->sec && ss->sec->ci.sid) {
 	    sid = ss->sec->ci.sid;
 	    item = (SECItem *)PORT_Alloc(sizeof(SECItem));
 	    if (sid->version < SSL_LIBRARY_VERSION_3_0) {
-		item->len = SSL2_SESSIONID_BYTES;
+		item->len = SSL_SESSIONID_BYTES;
 		item->data = (unsigned char*)PORT_Alloc(item->len);
 		PORT_Memcpy(item->data, sid->u.ssl2.sessionID, item->len);
 	    } else {
 		item->len = sid->u.ssl3.sessionIDLength;
 		item->data = (unsigned char*)PORT_Alloc(item->len);
 		PORT_Memcpy(item->data, sid->u.ssl3.sessionID, item->len);
 	    }
 	}
--- a/security/nss/lib/ssl/sslsnce.c
+++ b/security/nss/lib/ssl/sslsnce.c
@@ -38,485 +38,814 @@
 /* Note: ssl_FreeSID() in sslnonce.c gets used for both client and server 
  * cache sids!
  *
  * About record locking among different server processes:
  *
  * All processes that are part of the same conceptual server (serving on 
  * the same address and port) MUST share a common SSL session cache. 
  * This code makes the content of the shared cache accessible to all
- * processes on the same "server".  This code works on Unix and Win32 only.
+ * processes on the same "server".  This code works on Unix and Win32 only,
+ * and is platform specific. 
  *
- * We use NSPR anonymous shared memory and move data to & from shared memory.
- * We must do explicit locking of the records for all reads and writes.
- * The set of Cache entries are divided up into "sets" of 128 entries. 
- * Each set is protected by a lock.  There may be one or more sets protected
- * by each lock.  That is, locks to sets are 1:N.
- * There is one lock for the entire cert cache.
- * There is one lock for the set of wrapped sym wrap keys.
+ * Unix: Multiple processes share a single (inherited) FD for a disk 
+ * file all share one single file position.  If one lseeks, the position for 
+ * all processes is changed.  Since the set of platforms we support do not 
+ * all share portable lseek-and-read or lseek-and-write functions, a global 
+ * lock must be used to make the lseek call and the subsequent read or write 
+ * call be one atomic operation.  It is no longer necessary for cache element 
+ * sizes to be a power of 2, or a multiple of a sector size.
  *
- * The anonymous shared memory is laid out as if it were declared like this:
+ * For Win32, where (a) disk I/O is not atomic, and (b) we use memory-mapped
+ * files and move data to & from memory instead of calling read or write,
+ * we must do explicit locking of the records for all reads and writes.
+ * We have just one lock, for the entire file, using an NT semaphore.
+ * We avoid blocking on "local threads" since it's bad to block on a local 
+ * thread - If NSPR offered portable semaphores, it would handle this itself.
  *
- * struct {
- *     cacheDescriptor          desc;
- *     sidCacheLock             sidCacheLocks[ numSIDCacheLocks];
- *     sidCacheLock             keyCacheLock;
- *     sidCacheLock             certCacheLock;
- *     sidCacheSet              sidCacheSets[ numSIDCacheSets ];
- *     sidCacheEntry            sidCacheData[ numSIDCacheEntries];
- *     certCacheEntry           certCacheData[numCertCacheEntries];
- *     SSLWrappedSymWrappingKey keyCacheData[kt_kea_size][SSL_NUM_WRAP_MECHS];
- * } sharedMemCacheData;
+ * Since this file has to do lots of platform specific I/O, the system
+ * dependent error codes need to be mapped back into NSPR error codes.
+ * Since NSPR's error mapping functions are private, the code is necessarily
+ * duplicated in libSSL.
+ *
+ * Note, now that NSPR provides portable anonymous shared memory, for all
+ * platforms except Mac, the implementation below should be replaced with 
+ * one that uses anonymous shared memory ASAP.  This will eliminate most 
+ * platform dependent code in this file, and improve performance big time.
+ *
+ * Now that NSPR offers portable cross-process locking (semaphores) on Unix
+ * and Win32, semaphores should be used here for all platforms.
  */
 #include "nssrenam.h"
 #include "seccomon.h"
 
 #if defined(XP_UNIX) || defined(XP_WIN32)
+#ifndef NADA_VERISON
 
 #include "cert.h"
 #include "ssl.h"
 #include "sslimpl.h"
 #include "sslproto.h"
 #include "pk11func.h"
 #include "base64.h"
 
 #include <stdio.h>
 
 #ifdef XP_UNIX
 
 #include <syslog.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>
-#include <signal.h>
 #include "unix_err.h"
 
 #else /* XP_WIN32 */
+#ifdef MC_HTTPD
+#include <ereport.h>
+#endif /* MC_HTTPD */
 #include <wtypes.h>
 #include "win32err.h"
 #endif /* XP_WIN32 */
 #include <sys/types.h>
 
 #define SET_ERROR_CODE /* reminder */
 
 #include "nspr.h"
 #include "nsslocks.h"
-#include "sslmutex.h"
+
+static PZLock *cacheLock;
 
 /*
-** Format of a cache entry in the shared memory.
+** The server session-id cache uses a simple flat cache. The cache is
+** sized during initialization. We hash the ip-address + session-id value
+** into an index into the cache and do the lookup. No buckets, nothing
+** fancy.
+*/
+
+static PRBool isMultiProcess  = PR_FALSE;
+
+static PRUint32 numSIDCacheEntries  = 10000; 
+static PRUint32 sidCacheFileSize;
+static PRUint32 sidCacheWrapOffset;
+
+static PRUint32 numCertCacheEntries = 250;
+static PRUint32 certCacheFileSize;
+
+#define MIN_CERT_CACHE_ENTRIES 125 /* the effective size in old releases. */
+
+
+/*
+** Format of a cache entry.
 */ 
-struct sidCacheEntryStr {
-/* 16 */    PRIPv6Addr  addr;	/* client's IP address */
-/*  4 */    PRUint32    time;	/* expiration time of this entry */
-/*  2 */    PRUint16	version;
-/*  1 */    PRUint8	valid;
-/*  1 */    PRUint8     sessionIDLength;
-/* 32 */    PRUint8     sessionID[SSL3_SESSIONID_BYTES];
-/* 56  - common header total */
+typedef struct SIDCacheEntryStr SIDCacheEntry;
+struct SIDCacheEntryStr {
+    PRIPv6Addr addr;
+    PRUint32 time;
 
     union {
 	struct {
-/* 64 */    PRUint8	masterKey[SSL_MAX_MASTER_KEY_BYTES];
-/* 32 */    PRUint8	cipherArg[SSL_MAX_CYPHER_ARG_BYTES];
+	    /* This is gross.  We have to have version and valid in both arms
+	     * of the union for alignment reasons.  This probably won't work
+	     * on a 64-bit machine. XXXX
+	     */
+/*  2 */    uint16        version;
+/*  1 */    unsigned char valid;
+/*  1 */    unsigned char cipherType;
 
-/*  1 */    PRUint8	cipherType;
-/*  1 */    PRUint8	masterKeyLen;
-/*  1 */    PRUint8	keyBits;
-/*  1 */    PRUint8	secretKeyBits;
-/*  1 */    PRUint8	cipherArgLen;
-/*101 */} ssl2;
+/* 16 */    unsigned char sessionID[SSL_SESSIONID_BYTES];
+/* 64 */    unsigned char masterKey[SSL_MAX_MASTER_KEY_BYTES];
+/* 32 */    unsigned char cipherArg[SSL_MAX_CYPHER_ARG_BYTES];
+
+/*  1 */    unsigned char masterKeyLen;
+/*  1 */    unsigned char keyBits;
+
+/*  1 */    unsigned char secretKeyBits;
+/*  1 */    unsigned char cipherArgLen;
+/*120 */} ssl2;
 
 	struct {
-/*  2 */    ssl3CipherSuite  cipherSuite;
-/*  2 */    PRUint16    compression; 	/* SSL3CompressionMethod */
+/*  2 */    uint16           version;
+/*  1 */    unsigned char    valid;
+/*  1 */    uint8            sessionIDLength;
 
-/*122 */    ssl3SidKeys keys;	/* keys and ivs, wrapped as needed. */
-/*  1 */    PRUint8     hasFortezza;
-/*  1 */    PRUint8     resumable;
+/* 32 */    unsigned char    sessionID[SSL3_SESSIONID_BYTES];
+
+/*  2 */    ssl3CipherSuite  cipherSuite;
+/*  2 */    uint16           compression; 	/* SSL3CompressionMethod */
 
-/*  4 */    PRUint32    masterWrapMech; 
-/*  4 */    SSL3KEAType exchKeyType;
-/*  4 */    PRInt32     certIndex;
-/*140 */} ssl3;
-#if defined(LINUX)
+/*122 */    ssl3SidKeys      keys;	/* keys and ivs, wrapped as needed. */
+/*  4 */    PRUint32         masterWrapMech; 
+/*  4 */    SSL3KEAType      exchKeyType;
+
+/*  2 */    int16            certIndex;
+/*  1 */    uint8            hasFortezza;
+/*  1 */    uint8            resumable;
+	} ssl3;
+	/* We can't make this struct fit in 128 bytes 
+	 * so, force the struct size up to the next power of two.
+	 */
 	struct {
-	    PRUint8     filler[144];	
-	} forceSize;
-#endif
+	    unsigned char filler[256 - sizeof(PRIPv6Addr) - sizeof(PRUint32)];
+	} force256;
     } u;
 };
-typedef struct sidCacheEntryStr sidCacheEntry;
+
 
+typedef struct CertCacheEntryStr CertCacheEntry;
 
 /* The length of this struct is supposed to be a power of 2, e.g. 4KB */
-struct certCacheEntryStr {
-    PRUint16    certLength;				/*    2 */
-    PRUint16    sessionIDLength;			/*    2 */
-    PRUint8 	sessionID[SSL3_SESSIONID_BYTES];	/*   32 */
-    PRUint8 	cert[SSL_MAX_CACHED_CERT_LEN];		/* 4060 */
+struct CertCacheEntryStr {
+    uint16        certLength;				/*    2 */
+    uint16        sessionIDLength;			/*    2 */
+    unsigned char sessionID[SSL3_SESSIONID_BYTES];	/*   32 */
+    unsigned char cert[SSL_MAX_CACHED_CERT_LEN];	/* 4060 */
 };						/* total   4096 */
-typedef struct certCacheEntryStr certCacheEntry;
-
-struct sidCacheLockStr {
-    PRUint32	timeStamp;
-    sslMutex	mutex;
-    sslPID	pid;
-};
-typedef struct sidCacheLockStr sidCacheLock;
-
-struct sidCacheSetStr {
-    PRIntn	next;
-};
-typedef struct sidCacheSetStr sidCacheSet;
-
-struct cacheDescStr {
-
-    PRUint32            sharedMemSize;
-
-    PRUint32		numSIDCacheLocks;
-    PRUint32		numSIDCacheSets;
-    PRUint32		numSIDCacheSetsPerLock;
-
-    PRUint32            numSIDCacheEntries; 
-    PRUint32            sidCacheSize;
 
-    PRUint32            numCertCacheEntries;
-    PRUint32            certCacheSize;
 
-    PRUint32            numKeyCacheEntries;
-    PRUint32            keyCacheSize;
-
-    PRUint32		ssl2Timeout;
-    PRUint32		ssl3Timeout;
-
-    /* These values are volatile, and are accessed through sharedCache-> */
-    PRUint32		nextCertCacheEntry;	/* certCacheLock protects */
-    PRBool      	stopPolling;
-
-    /* The private copies of these values are pointers into shared mem */
-    /* The copies of these values in shared memory are merely offsets */
-    sidCacheLock    *          sidCacheLocks;
-    sidCacheLock    *          keyCacheLock;
-    sidCacheLock    *          certCacheLock;
-    sidCacheSet     *          sidCacheSets;
-    sidCacheEntry   *          sidCacheData;
-    certCacheEntry  *          certCacheData;
-    SSLWrappedSymWrappingKey * keyCacheData;
-
-    /* Only the private copies of these pointers are valid */
-    char *                     sharedMem;
-    struct cacheDescStr *      sharedCache;  /* shared copy of this struct */
-    PRFileMap *                cacheMemMap;
-    PRThread  *                poller;
-};
-typedef struct cacheDescStr cacheDesc;
-
-static cacheDesc globalCache;
+static void IOError(int rv, char *type);
+static PRUint32 Offset(const PRIPv6Addr *addr, unsigned char *s, unsigned nl);
+static void Invalidate(SIDCacheEntry *sce);
+/************************************************************************/
 
 static const char envVarName[] = { SSL_ENV_VAR_NAME };
 
-static PRBool isMultiProcess  = PR_FALSE;
-
+#ifdef _WIN32
 
-#define DEF_SID_CACHE_ENTRIES  10000
-#define DEF_CERT_CACHE_ENTRIES 250
-#define MIN_CERT_CACHE_ENTRIES 125 /* the effective size in old releases. */
-#define DEF_KEY_CACHE_ENTRIES  250
+struct winInheritanceStr {
+    PRUint32 numSIDCacheEntries;
+    PRUint32 sidCacheFileSize;
+    PRUint32 sidCacheWrapOffset;
+    PRUint32 numCertCacheEntries;
+    PRUint32 certCacheFileSize;
 
-#define SID_CACHE_ENTRIES_PER_SET  128
-#define SID_ALIGNMENT          16
+    DWORD         parentProcessID;
+    HANDLE        parentProcessHandle;
+    HANDLE        SIDCacheFDMAP;
+    HANDLE        certCacheFDMAP;
+    HANDLE        svrCacheSem;
+};
+typedef struct winInheritanceStr winInheritance;
 
-#define DEF_SSL2_TIMEOUT	100   /* seconds */
-#define MAX_SSL2_TIMEOUT	100   /* seconds */
-#define MIN_SSL2_TIMEOUT	  5   /* seconds */
-
-#define DEF_SSL3_TIMEOUT      86400L  /* 24 hours */
-#define MAX_SSL3_TIMEOUT      86400L  /* 24 hours */
-#define MIN_SSL3_TIMEOUT          5   /* seconds  */
+static HANDLE svrCacheSem    = INVALID_HANDLE_VALUE;
 
-#if defined(AIX) || defined(LINUX)
-#define MAX_SID_CACHE_LOCKS 8	/* two FDs per lock */
-#elif defined(OSF1)
-#define MAX_SID_CACHE_LOCKS 16	/* one FD per lock */
-#else
-#define MAX_SID_CACHE_LOCKS 256
-#endif
+static char * SIDCacheData    = NULL;
+static HANDLE SIDCacheFD      = INVALID_HANDLE_VALUE;
+static HANDLE SIDCacheFDMAP   = INVALID_HANDLE_VALUE;
 
-#define SID_HOWMANY(val, size) (((val) + ((size) - 1)) / (size))
-#define SID_ROUNDUP(val, size) ((size) * SID_HOWMANY((val), (size)))
+static char * certCacheData   = NULL;
+static HANDLE certCacheFD     = INVALID_HANDLE_VALUE;
+static HANDLE certCacheFDMAP  = INVALID_HANDLE_VALUE;
 
-
-static sslPID myPid;
-static PRUint32  ssl_max_sid_cache_locks = MAX_SID_CACHE_LOCKS;
+static PRUint32 myPid;
 
-/* forward static function declarations */
-static void IOError(int rv, char *type);
-static PRUint32 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, unsigned nl);
-static SECStatus LaunchLockPoller(cacheDesc *cache);
-
-
-
+/* The presence of the TRUE element in this struct makes the semaphore 
+ * inheritable. The NULL means use process's default security descriptor. 
+ */
+static SECURITY_ATTRIBUTES semaphoreAttributes = 
+				{ sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
 
-struct inheritanceStr {
-    PRUint32 sharedMemSize;
-    PRUint16 fmStrLen;
-};
+static SECURITY_ATTRIBUTES sidCacheFDMapAttributes = 
+				{ sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
 
-typedef struct inheritanceStr inheritance;
-
-#ifdef _WIN32
+static SECURITY_ATTRIBUTES certCacheFDMapAttributes = 
+				{ sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
 
 #define DEFAULT_CACHE_DIRECTORY "\\temp"
 
+static SECStatus
+createServerCacheSemaphore(void)
+{
+    PR_ASSERT(svrCacheSem == INVALID_HANDLE_VALUE);
+
+    /* inheritable, starts signalled, 1 signal max, no file name. */
+    svrCacheSem = CreateSemaphore(&semaphoreAttributes, 1, 1, NULL);
+    if (svrCacheSem == NULL) {
+	svrCacheSem = INVALID_HANDLE_VALUE;
+	/* We could get the error code, but what could be do with it ? */
+	nss_MD_win32_map_default_error(GetLastError());
+    	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+static SECStatus
+_getServerCacheSemaphore(void)
+{
+    DWORD     event;
+    DWORD     lastError;
+    SECStatus rv;
+
+    PR_ASSERT(svrCacheSem != INVALID_HANDLE_VALUE);
+    if (svrCacheSem == INVALID_HANDLE_VALUE &&
+    	SECSuccess   != createServerCacheSemaphore()) {
+	return SECFailure;	/* what else ? */
+    }
+    event = WaitForSingleObject(svrCacheSem, INFINITE);
+    switch (event) {
+    case WAIT_OBJECT_0:
+    case WAIT_ABANDONED:
+	rv = SECSuccess;
+    	break;
+
+    case WAIT_TIMEOUT:
+    case WAIT_IO_COMPLETION:
+    default: 		/* should never happen. nothing we can do. */
+	PR_ASSERT(("WaitForSingleObject returned invalid value.", 0));
+	/* fall thru */
+
+    case WAIT_FAILED:		/* failure returns this */
+	rv = SECFailure;
+	lastError = GetLastError();	/* for debugging */
+	nss_MD_win32_map_default_error(lastError);
+	break;
+    }
+    return rv;
+}
+
+static void
+_doGetServerCacheSemaphore(void * arg)
+{
+    SECStatus * rv = (SECStatus *)arg;
+    *rv = _getServerCacheSemaphore();
+}
+
+static SECStatus
+getServerCacheSemaphore(void)
+{
+    PRThread *    selectThread;
+    PRThread *    me    	= PR_GetCurrentThread();
+    PRThreadScope scope 	= PR_GetThreadScope(me);
+    SECStatus     rv    	= SECFailure;
+
+    if (scope == PR_GLOBAL_THREAD) {
+        rv = _getServerCacheSemaphore();
+    } else {
+        selectThread = PR_CreateThread(PR_USER_THREAD,
+				       _doGetServerCacheSemaphore, &rv,
+				       PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+				       PR_JOINABLE_THREAD, 0);
+        if (selectThread != NULL) {
+	    /* rv will be set by _doGetServerCacheSemaphore() */
+	    PR_JoinThread(selectThread);
+        }
+    }
+    return rv;
+}
+
+static SECStatus
+releaseServerCacheSemaphore(void)
+{
+    BOOL success = FALSE;
+
+    PR_ASSERT(svrCacheSem != INVALID_HANDLE_VALUE);
+    if (svrCacheSem != INVALID_HANDLE_VALUE) {
+	/* Add 1, don't want previous value. */
+	success = ReleaseSemaphore(svrCacheSem, 1, NULL);
+    }
+    if (!success) {
+	nss_MD_win32_map_default_error(GetLastError());
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+static void
+destroyServerCacheSemaphore(void)
+{
+    PR_ASSERT(svrCacheSem != INVALID_HANDLE_VALUE);
+    if (svrCacheSem != INVALID_HANDLE_VALUE) {
+	CloseHandle(svrCacheSem);
+	/* ignore error */
+	svrCacheSem = INVALID_HANDLE_VALUE;
+    }
+}
+
+#define GET_SERVER_CACHE_READ_LOCK(fd, offset, size) \
+    if (isMultiProcess) getServerCacheSemaphore();
+
+#define GET_SERVER_CACHE_WRITE_LOCK(fd, offset, size) \
+    if (isMultiProcess) getServerCacheSemaphore();
+
+#define RELEASE_SERVER_CACHE_LOCK(fd, offset, size) \
+    if (isMultiProcess) releaseServerCacheSemaphore();
+
 #endif /* _win32 */
 
+/************************************************************************/
+
 #ifdef XP_UNIX
+static int    SIDCacheFD      = -1;
+static int    certCacheFD     = -1;
+
+static pid_t  myPid;
+
+struct unixInheritanceStr {
+    PRUint32 numSIDCacheEntries;
+    PRUint32 sidCacheFileSize;
+    PRUint32 sidCacheWrapOffset;
+    PRUint32 numCertCacheEntries;
+    PRUint32 certCacheFileSize;
+
+    PRInt32  SIDCacheFD;
+    PRInt32  certCacheFD;
+};
+
+typedef struct unixInheritanceStr unixInheritance;
+
 
 #define DEFAULT_CACHE_DIRECTORY "/tmp"
 
+#ifdef TRACE
+static void 
+fcntlFailed(struct flock *lock) 
+{
+    fprintf(stderr,
+    "fcntl failed, errno = %d, PR_GetError = %d, lock.l_type = %d\n",
+	errno, PR_GetError(), lock->l_type);
+    fflush(stderr);
+}
+#define FCNTL_FAILED(lock) fcntlFailed(lock)
+#else
+#define FCNTL_FAILED(lock) 
+#endif
+
+/* NOTES:  Because there are no atomic seek-and-read and seek-and-write
+** functions that are supported on all our UNIX platforms, we need
+** to prevent all simultaeous seek-and-read operations.  For that reason,
+** we use mutually exclusive (write) locks for read and write operations,
+** and use them all at the same offset (zero).
+*/
+static SECStatus
+_getServerCacheLock(int fd, short type, PRUint32 offset, PRUint32 size)
+{
+    int          result;
+    struct flock lock;
+
+    memset(&lock, 0, sizeof lock);
+    lock.l_type   = /* type */ F_WRLCK;
+    lock.l_whence = SEEK_SET;	/* absolute file offsets. */
+    lock.l_start  = 0;
+    lock.l_len    = 128;
+
+#ifdef TRACE
+    if (ssl_trace) {
+	fprintf(stderr, "%d: %s lock, offset %8x, size %4d\n", myPid,
+	    (type == F_RDLCK) ? "read " : "write", offset, size);
+	fflush(stderr);
+    }
+#endif
+    result = fcntl(fd, F_SETLKW, &lock);
+    if (result == -1) {
+        nss_MD_unix_map_default_error(errno);
+	FCNTL_FAILED(&lock);
+    	return SECFailure;
+    }
+#ifdef TRACE
+    if (ssl_trace) {
+	fprintf(stderr, "%d:   got lock, offset %8x, size %4d\n", 
+	    myPid, offset, size);
+	fflush(stderr);
+    }
+#endif
+    return SECSuccess;
+}
+
+typedef struct sslLockArgsStr {
+    PRUint32    offset;
+    PRUint32    size;
+    PRErrorCode err;
+    SECStatus   rv;
+    int         fd;
+    short       type;
+} sslLockArgs;
+
+static void
+_doGetServerCacheLock(void * arg)
+{
+    sslLockArgs * args = (sslLockArgs *)arg;
+    args->rv = _getServerCacheLock(args->fd, args->type, args->offset, 
+				   args->size );
+    if (args->rv != SECSuccess) {
+	args->err = PR_GetError();
+    }
+}
+
+static SECStatus
+getServerCacheLock(int fd, short type, PRUint32 offset, PRUint32 size)
+{
+    PRThread *    selectThread;
+    PRThread *    me    	= PR_GetCurrentThread();
+    PRThreadScope scope 	= PR_GetThreadScope(me);
+    SECStatus     rv    	= SECFailure;
+
+    if (scope == PR_GLOBAL_THREAD) {
+        rv = _getServerCacheLock(fd, type, offset, size);
+    } else {
+	/* Ib some platforms, one thread cannot read local/automatic 
+	** variables from another thread's stack.  So, get this space
+	** from the heap, not the stack.
+	*/
+	sslLockArgs * args = PORT_New(sslLockArgs);
+
+	if (!args)
+	    return rv;
+
+	args->offset = offset;
+	args->size   = size;
+	args->rv     = SECFailure;
+	args->fd     = fd;
+	args->type   = type;
+        selectThread = PR_CreateThread(PR_USER_THREAD,
+				       _doGetServerCacheLock, args,
+				       PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+				       PR_JOINABLE_THREAD, 0);
+        if (selectThread != NULL) {
+	    /* rv will be set by _doGetServerCacheLock() */
+	    PR_JoinThread(selectThread);
+	    rv = args->rv;
+	    if (rv != SECSuccess) {
+		PORT_SetError(args->err);
+	    }
+        }
+	PORT_Free(args);
+    }
+    return rv;
+}
+
+static SECStatus
+releaseServerCacheLock(int fd, PRUint32 offset, PRUint32 size)
+{
+    int          result;
+    struct flock lock;
+
+    memset(&lock, 0, sizeof lock);
+    lock.l_type   = F_UNLCK;
+    lock.l_whence = SEEK_SET;	/* absolute file offsets. */
+    lock.l_start  = 0;
+    lock.l_len    = 128;
+
+#ifdef TRACE
+    if (ssl_trace) {
+	fprintf(stderr, "%d:     unlock, offset %8x, size %4d\n", 
+	    myPid, offset, size);
+	fflush(stderr);
+    }
+#endif
+    result = fcntl(fd, F_SETLK, &lock);
+    if (result == -1) {
+        nss_MD_unix_map_default_error(errno);
+	FCNTL_FAILED(&lock);
+    	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+
+/* these defines take the arguments needed to do record locking, 
+ * however the present implementation does only file locking.
+ */
+
+#define GET_SERVER_CACHE_READ_LOCK( fd, offset, size) \
+    if (isMultiProcess) getServerCacheLock(fd, F_RDLCK, offset, size);
+
+#define GET_SERVER_CACHE_WRITE_LOCK(fd, offset, size) \
+    if (isMultiProcess) getServerCacheLock(fd, F_WRLCK, offset, size);
+
+#define RELEASE_SERVER_CACHE_LOCK(  fd, offset, size) \
+    if (isMultiProcess) releaseServerCacheLock(fd, offset, size);
+
+/*
+** Zero a file out to nb bytes
+*/
+static SECStatus 
+ZeroFile(int fd, int nb)
+{
+    off_t off;
+    int amount, rv;
+    char buf[16384];
+
+    PORT_Memset(buf, 0, sizeof(buf));
+    off = lseek(fd, 0, SEEK_SET);
+    if (off != 0) {
+	if (off == -1) 
+	    nss_MD_unix_map_lseek_error(errno);
+    	else
+	    PORT_SetError(PR_FILE_SEEK_ERROR);
+    	return SECFailure;
+    }
+
+    while (nb > 0) {
+	amount = (nb > sizeof buf) ? sizeof buf : nb;
+	rv = write(fd, buf, amount);
+	if (rv <= 0) {
+	    if (!rv)
+	    	PORT_SetError(PR_IO_ERROR);
+	    else
+		nss_MD_unix_map_write_error(errno);
+	    IOError(rv, "zero-write");
+	    return SECFailure;
+	}
+	nb -= rv;
+    }
+    return SECSuccess;
+}
+
 #endif /* XP_UNIX */
 
 
 /************************************************************************/
 
-static void 
-IOError(int rv, char *type)
-{
-#ifdef XP_UNIX
-    syslog(LOG_ALERT,
-	   "SSL: %s error with session-id cache, pid=%d, rv=%d, error='%m'",
-	   type, myPid, rv);
-#else /* XP_WIN32 */
-    /* wish win32 had something like syslog() */
-#endif /* XP_UNIX */
-}
-
-static PRUint32
-LockSidCacheLock(sidCacheLock *lock, PRUint32 now)
+/*
+** Reconstitute a cert from the cache
+** This is only called from ConvertToSID().
+** Caller must hold the cache lock before calling this.
+*/
+static CERTCertificate *
+GetCertFromCache(SIDCacheEntry *sce, CERTCertDBHandle *dbHandle)
 {
-    SECStatus      rv      = sslMutex_Lock(&lock->mutex);
-    if (rv != SECSuccess)
-    	return 0;
-    if (!now)
-	now  = ssl_Time();
-    lock->timeStamp = now;
-    lock->pid       = myPid;
-    return now;
-}
+    CERTCertificate *cert;
+    PRUint32         offset;
+    int              rv;
+#ifdef XP_UNIX
+    off_t            off;
+#endif
+    SECItem          derCert;
+    CertCacheEntry   cce;
 
-static SECStatus
-UnlockSidCacheLock(sidCacheLock *lock)
-{
-    SECStatus      rv;
+    offset = (PRUint32)sce->u.ssl3.certIndex * sizeof(CertCacheEntry);
+    GET_SERVER_CACHE_READ_LOCK(certCacheFD, offset, sizeof(CertCacheEntry));
+#ifdef XP_UNIX
+    off = lseek(certCacheFD, offset, SEEK_SET);
+    rv = -1;
+    if (off != offset) {
+	if (off == -1) 
+	    nss_MD_unix_map_lseek_error(errno);
+	else 
+	    PORT_SetError(PR_FILE_SEEK_ERROR);
+    } else {
+	rv = read(certCacheFD, &cce, sizeof(CertCacheEntry));
+	if (rv != sizeof(CertCacheEntry)) {
+	    if (rv == -1)
+		nss_MD_unix_map_read_error(errno);
+	    else
+	    	PORT_SetError(PR_IO_ERROR);
+	}
+    }
+#else /* XP_WIN32 */
+    /* Use memory mapped I/O and just memcpy() the data */
+    CopyMemory(&cce, &certCacheData[offset], sizeof(CertCacheEntry));
+    rv = sizeof cce;
+#endif /* XP_WIN32 */
+    RELEASE_SERVER_CACHE_LOCK(certCacheFD, offset, sizeof(CertCacheEntry))
 
-    lock->pid = 0;
-    rv        = sslMutex_Unlock(&lock->mutex);
-    return rv;
+    if (rv != sizeof(CertCacheEntry)) {
+	IOError(rv, "read");	/* error set above */
+	return NULL;
+    }
+
+    /* See if the session ID matches with that in the sce cache. */
+    if((cce.sessionIDLength != sce->u.ssl3.sessionIDLength) ||
+       PORT_Memcmp(cce.sessionID, sce->u.ssl3.sessionID, cce.sessionIDLength)) {
+        /* this is a cache miss, not an error */
+	PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND);
+	return NULL;
+    }
+
+    derCert.len  = cce.certLength;
+    derCert.data = cce.cert;
+
+    cert = CERT_NewTempCertificate(dbHandle, &derCert, NULL,
+				   PR_FALSE, PR_TRUE);
+
+    return cert;
 }
 
-/* returns the value of ssl_Time on success, zero on failure. */
-static PRUint32
-LockSet(cacheDesc *cache, PRUint32 set, PRUint32 now)
+/* Put a certificate in the cache.  We assume that the certIndex in
+** sid is valid.
+*/
+static void
+CacheCert(CERTCertificate *cert, SIDCacheEntry *sce)
 {
-    PRUint32       lockNum = set % cache->numSIDCacheLocks;
-    sidCacheLock * lock    = cache->sidCacheLocks + lockNum;
-
-    return LockSidCacheLock(lock, now);
-}
-
-static SECStatus
-UnlockSet(cacheDesc *cache, PRUint32 set)
-{
-    PRUint32       lockNum = set % cache->numSIDCacheLocks;
-    sidCacheLock * lock    = cache->sidCacheLocks + lockNum;
-
-    return UnlockSidCacheLock(lock);
-}
+    PRUint32       offset;
+    CertCacheEntry cce;
+#ifdef XP_UNIX
+    off_t          off;
+    int            rv;
+#endif
 
-/************************************************************************/
-
-
-/* Put a certificate in the cache.  Update the cert index in the sce.
-*/
-static PRUint32
-CacheCert(cacheDesc * cache, CERTCertificate *cert, sidCacheEntry *sce)
-{
-    PRUint32        now;
-    certCacheEntry  cce;
-
-    if ((cert->derCert.len > SSL_MAX_CACHED_CERT_LEN) ||
-        (cert->derCert.len <= 0) ||
-	(cert->derCert.data == NULL)) {
-	PORT_SetError(SEC_ERROR_INVALID_ARGS);
-	return 0;
-    }
-
-    cce.sessionIDLength = sce->sessionIDLength;
-    PORT_Memcpy(cce.sessionID, sce->sessionID, cce.sessionIDLength);
+    offset = (PRUint32)sce->u.ssl3.certIndex * sizeof(CertCacheEntry);
+    if (cert->derCert.len > SSL_MAX_CACHED_CERT_LEN)
+	return;
+    
+    cce.sessionIDLength = sce->u.ssl3.sessionIDLength;
+    PORT_Memcpy(cce.sessionID, sce->u.ssl3.sessionID, cce.sessionIDLength);
 
     cce.certLength = cert->derCert.len;
     PORT_Memcpy(cce.cert, cert->derCert.data, cce.certLength);
 
-    /* get lock on cert cache */
-    now = LockSidCacheLock(cache->certCacheLock, 0);
-    if (now) {
-
-	/* Find where to place the next cert cache entry. */
-	cacheDesc * sharedCache = cache->sharedCache;
-	PRUint32    ndx         = sharedCache->nextCertCacheEntry;
-
-	/* write the entry */
-	cache->certCacheData[ndx] = cce;
+    GET_SERVER_CACHE_WRITE_LOCK(certCacheFD, offset, sizeof cce);
+#ifdef XP_UNIX
+    off = lseek(certCacheFD, offset, SEEK_SET);
+    if (off != offset) {
+	if (off == -1) 
+	    nss_MD_unix_map_lseek_error(errno);
+	else 
+	    PORT_SetError(PR_FILE_SEEK_ERROR);
+    } else {
+	rv = write(certCacheFD, &cce, sizeof cce);
+	if (rv != sizeof(CertCacheEntry)) {
+	    if (rv == -1)
+		nss_MD_unix_map_write_error(errno);
+	    else
+	    	PORT_SetError(PR_IO_ERROR);
+	    IOError(rv, "cert-write");
+	    Invalidate(sce);
+	}
+    }
+#else /* WIN32 */
+    /* Use memory mapped I/O and just memcpy() the data */
+    CopyMemory(&certCacheData[offset], &cce, sizeof cce);
+#endif /* XP_UNIX */
 
-	/* remember where we put it. */
-	sce->u.ssl3.certIndex = ndx;
-
-	/* update the "next" cache entry index */
-	sharedCache->nextCertCacheEntry = 
-					(ndx + 1) % cache->numCertCacheEntries;
-
-	UnlockSidCacheLock(cache->certCacheLock);
-    }
-    return now;
-
+    RELEASE_SERVER_CACHE_LOCK(certCacheFD, offset, sizeof cce);
+    return;
 }
 
 /*
 ** Convert memory based SID to file based one
 */
 static void 
-ConvertFromSID(sidCacheEntry *to, sslSessionID *from)
+ConvertFromSID(SIDCacheEntry *to, sslSessionID *from)
 {
-    to->valid   = 1;
-    to->version = from->version;
-    to->addr    = from->addr;
-    to->time    = from->time;
+    to->u.ssl2.valid = 1;
+    to->u.ssl2.version = from->version;
+    to->addr = from->addr;
+    to->time = from->time;
 
     if (from->version < SSL_LIBRARY_VERSION_3_0) {
 	if ((from->u.ssl2.masterKey.len > SSL_MAX_MASTER_KEY_BYTES) ||
 	    (from->u.ssl2.cipherArg.len > SSL_MAX_CYPHER_ARG_BYTES)) {
 	    SSL_DBG(("%d: SSL: masterKeyLen=%d cipherArgLen=%d",
 		     myPid, from->u.ssl2.masterKey.len,
 		     from->u.ssl2.cipherArg.len));
-	    to->valid = 0;
+	    to->u.ssl2.valid = 0;
 	    return;
 	}
 
 	to->u.ssl2.cipherType    = from->u.ssl2.cipherType;
 	to->u.ssl2.masterKeyLen  = from->u.ssl2.masterKey.len;
 	to->u.ssl2.cipherArgLen  = from->u.ssl2.cipherArg.len;
 	to->u.ssl2.keyBits       = from->u.ssl2.keyBits;
 	to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits;
-	to->sessionIDLength      = SSL2_SESSIONID_BYTES;
-	PORT_Memcpy(to->sessionID, from->u.ssl2.sessionID, SSL2_SESSIONID_BYTES);
+	PORT_Memcpy(to->u.ssl2.sessionID, from->u.ssl2.sessionID,
+		  sizeof(to->u.ssl2.sessionID));
 	PORT_Memcpy(to->u.ssl2.masterKey, from->u.ssl2.masterKey.data,
 		  from->u.ssl2.masterKey.len);
 	PORT_Memcpy(to->u.ssl2.cipherArg, from->u.ssl2.cipherArg.data,
 		  from->u.ssl2.cipherArg.len);
 #ifdef DEBUG
 	PORT_Memset(to->u.ssl2.masterKey+from->u.ssl2.masterKey.len, 0,
 		  sizeof(to->u.ssl2.masterKey) - from->u.ssl2.masterKey.len);
 	PORT_Memset(to->u.ssl2.cipherArg+from->u.ssl2.cipherArg.len, 0,
 		  sizeof(to->u.ssl2.cipherArg) - from->u.ssl2.cipherArg.len);
 #endif
 	SSL_TRC(8, ("%d: SSL: ConvertSID: masterKeyLen=%d cipherArgLen=%d "
 		    "time=%d addr=0x%08x%08x%08x%08x cipherType=%d", myPid,
 		    to->u.ssl2.masterKeyLen, to->u.ssl2.cipherArgLen,
-		    to->time, to->addr.pr_s6_addr32[0],
+		    to->time, to->addr.pr_s6_addr32[0], 
 		    to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2],
 		    to->addr.pr_s6_addr32[3], to->u.ssl2.cipherType));
     } else {
 	/* This is an SSL v3 session */
 
+	to->u.ssl3.sessionIDLength  = from->u.ssl3.sessionIDLength;
 	to->u.ssl3.cipherSuite      = from->u.ssl3.cipherSuite;
 	to->u.ssl3.compression      = (uint16)from->u.ssl3.compression;
 	to->u.ssl3.resumable        = from->u.ssl3.resumable;
 	to->u.ssl3.hasFortezza      = from->u.ssl3.hasFortezza;
 	to->u.ssl3.keys             = from->u.ssl3.keys;
 	to->u.ssl3.masterWrapMech   = from->u.ssl3.masterWrapMech;
 	to->u.ssl3.exchKeyType      = from->u.ssl3.exchKeyType;
-	to->sessionIDLength         = from->u.ssl3.sessionIDLength;
-	to->u.ssl3.certIndex        = -1;
 
-	PORT_Memcpy(to->sessionID, from->u.ssl3.sessionID,
-		    to->sessionIDLength);
+	PORT_Memcpy(to->u.ssl3.sessionID, 
+	            from->u.ssl3.sessionID,
+		    from->u.ssl3.sessionIDLength);
 
-	SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x "
-	            "cipherSuite=%d",
+	SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x cipherSuite=%d",
 		    myPid, to->time, to->addr.pr_s6_addr32[0],
 		    to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2],
 		    to->addr.pr_s6_addr32[3], to->u.ssl3.cipherSuite));
     }
 }
 
 /*
 ** Convert file based cache-entry to memory based one
 ** This is only called from ServerSessionIDLookup().
 ** Caller must hold cache lock when calling this.
 */
 static sslSessionID *
-ConvertToSID(sidCacheEntry *from, certCacheEntry *pcce, 
-             CERTCertDBHandle * dbHandle)
+ConvertToSID(SIDCacheEntry *from, CERTCertDBHandle * dbHandle)
 {
     sslSessionID *to;
-    uint16 version = from->version;
+    uint16 version = from->u.ssl2.version;
 
     to = (sslSessionID*) PORT_ZAlloc(sizeof(sslSessionID));
     if (!to) {
 	return 0;
     }
 
     if (version < SSL_LIBRARY_VERSION_3_0) {
 	/* This is an SSL v2 session */
 	to->u.ssl2.masterKey.data =
 	    (unsigned char*) PORT_Alloc(from->u.ssl2.masterKeyLen);
 	if (!to->u.ssl2.masterKey.data) {
 	    goto loser;
 	}
 	if (from->u.ssl2.cipherArgLen) {
-	    to->u.ssl2.cipherArg.data = 
-	    	(unsigned char*)PORT_Alloc(from->u.ssl2.cipherArgLen);
+	    to->u.ssl2.cipherArg.data = (unsigned char*)
+		PORT_Alloc(from->u.ssl2.cipherArgLen);
 	    if (!to->u.ssl2.cipherArg.data) {
 		goto loser;
 	    }
 	    PORT_Memcpy(to->u.ssl2.cipherArg.data, from->u.ssl2.cipherArg,
-		        from->u.ssl2.cipherArgLen);
+		      from->u.ssl2.cipherArgLen);
 	}
 
 	to->u.ssl2.cipherType    = from->u.ssl2.cipherType;
 	to->u.ssl2.masterKey.len = from->u.ssl2.masterKeyLen;
 	to->u.ssl2.cipherArg.len = from->u.ssl2.cipherArgLen;
 	to->u.ssl2.keyBits       = from->u.ssl2.keyBits;
 	to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits;
-/*	to->sessionIDLength      = SSL2_SESSIONID_BYTES; */
-	PORT_Memcpy(to->u.ssl2.sessionID, from->sessionID, SSL2_SESSIONID_BYTES);
+	PORT_Memcpy(to->u.ssl2.sessionID, from->u.ssl2.sessionID,
+		  sizeof from->u.ssl2.sessionID);
 	PORT_Memcpy(to->u.ssl2.masterKey.data, from->u.ssl2.masterKey,
-		    from->u.ssl2.masterKeyLen);
+		  from->u.ssl2.masterKeyLen);
 
 	SSL_TRC(8, ("%d: SSL: ConvertToSID: masterKeyLen=%d cipherArgLen=%d "
 		    "time=%d addr=0x%08x%08x%08x%08x cipherType=%d",
 		    myPid, to->u.ssl2.masterKey.len,
-		    to->u.ssl2.cipherArg.len, to->time,
+		    to->u.ssl2.cipherArg.len, to->time, 
 		    to->addr.pr_s6_addr32[0], to->addr.pr_s6_addr32[1],
-		    to->addr.pr_s6_addr32[2], to->addr.pr_s6_addr32[3],
+		    to->addr.pr_s6_addr32[2], to->addr.pr_s6_addr32[3], 
 		    to->u.ssl2.cipherType));
     } else {
 	/* This is an SSL v3 session */
 
-	to->u.ssl3.sessionIDLength  = from->sessionIDLength;
+	to->u.ssl3.sessionIDLength  = from->u.ssl3.sessionIDLength;
 	to->u.ssl3.cipherSuite      = from->u.ssl3.cipherSuite;
 	to->u.ssl3.compression      = (SSL3CompressionMethod)from->u.ssl3.compression;
 	to->u.ssl3.resumable        = from->u.ssl3.resumable;
 	to->u.ssl3.hasFortezza      = from->u.ssl3.hasFortezza;
 	to->u.ssl3.keys             = from->u.ssl3.keys;
 	to->u.ssl3.masterWrapMech   = from->u.ssl3.masterWrapMech;
 	to->u.ssl3.exchKeyType      = from->u.ssl3.exchKeyType;
 
-	PORT_Memcpy(to->u.ssl3.sessionID, from->sessionID, from->sessionIDLength);
+	PORT_Memcpy(to->u.ssl3.sessionID, 
+	            from->u.ssl3.sessionID,
+		    from->u.ssl3.sessionIDLength);
 
 	/* the portions of the SID that are only restored on the client
 	 * are set to invalid values on the server.
 	 */
 	to->u.ssl3.clientWriteKey   = NULL;
 	to->u.ssl3.serverWriteKey   = NULL;
 	to->u.ssl3.tek              = NULL;
 	to->urlSvrName              = NULL;
@@ -529,988 +858,1098 @@ ConvertToSID(sidCacheEntry *from, certCa
 
 	to->u.ssl3.clAuthModuleID   = (SECMODModuleID)-1; /* invalid value */
 	to->u.ssl3.clAuthSlotID     = (CK_SLOT_ID)-1;     /* invalid value */
 	to->u.ssl3.clAuthSeries     = 0;
 	to->u.ssl3.clAuthValid      = PR_FALSE;
 
 	to->u.ssl3.clientWriteSaveLen = 0;
 
-	if (from->u.ssl3.certIndex != -1 && pcce) {
-	    SECItem          derCert;
-
-	    derCert.len  = pcce->certLength;
-	    derCert.data = pcce->cert;
-
-	    to->peerCert = CERT_NewTempCertificate(dbHandle, &derCert, NULL,
-					           PR_FALSE, PR_TRUE);
+	if (from->u.ssl3.certIndex != -1) {
+	    to->peerCert = GetCertFromCache(from, dbHandle);
 	    if (to->peerCert == NULL)
 		goto loser;
 	}
     }
 
-    to->version    = from->version;
-    to->time       = from->time;	/* XXX ??? is expiration time */
+    to->version    = from->u.ssl2.version;
+    to->time       = from->time;
     to->cached     = in_server_cache;
     to->addr       = from->addr;
     to->references = 1;
     
     return to;
 
   loser:
+    Invalidate(from);
     if (to) {
 	if (version < SSL_LIBRARY_VERSION_3_0) {
 	    if (to->u.ssl2.masterKey.data)
 		PORT_Free(to->u.ssl2.masterKey.data);
 	    if (to->u.ssl2.cipherArg.data)
 		PORT_Free(to->u.ssl2.cipherArg.data);
 	}
 	PORT_Free(to);
     }
     return NULL;
 }
 
 
+/* Invalidate a SID cache entry. 
+ * Called from CacheCert, ConvertToSid, and ServerSessionIDUncache. 
+ */
+static void 
+Invalidate(SIDCacheEntry *sce)
+{
+    PRUint32	offset;
+#ifdef XP_UNIX
+    off_t	off;
+    int 	rv;
+#endif
+
+    if (sce == NULL) return;
+
+    if (sce->u.ssl2.version < SSL_LIBRARY_VERSION_3_0) {
+	offset = Offset(&sce->addr, sce->u.ssl2.sessionID,
+			sizeof sce->u.ssl2.sessionID); 
+    } else {
+	offset = Offset(&sce->addr, sce->u.ssl3.sessionID,
+			sce->u.ssl3.sessionIDLength); 
+    }
+	
+    sce->u.ssl2.valid = 0;
+    SSL_TRC(7, ("%d: SSL: uncaching session-id at offset %ld",
+		    myPid, offset));
+
+    GET_SERVER_CACHE_WRITE_LOCK(SIDCacheFD, offset, sizeof *sce);
+
+#ifdef XP_UNIX
+    off = lseek(SIDCacheFD, offset, SEEK_SET);
+    if (off != offset) {
+	if (off == -1) 
+	    nss_MD_unix_map_lseek_error(errno);
+	else 
+	    PORT_SetError(PR_FILE_SEEK_ERROR);
+    } else {
+	rv = write(SIDCacheFD, sce, sizeof *sce);
+	if (rv != sizeof *sce) {
+	    if (rv == -1)
+		nss_MD_unix_map_write_error(errno);
+	    else
+	    	PORT_SetError(PR_IO_ERROR);
+	    IOError(rv, "invalidate-write");
+    	}
+    }
+#else /* WIN32 */
+    /* Use memory mapped I/O and just memcpy() the data */
+    CopyMemory(&SIDCacheData[offset], sce, sizeof *sce);
+#endif /* XP_UNIX */
+
+    RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, offset, sizeof *sce);
+}
+
+
+static void 
+IOError(int rv, char *type)
+{
+#ifdef XP_UNIX
+    syslog(LOG_ALERT,
+	   "SSL: %s error with session-id cache, pid=%d, rv=%d, error='%m'",
+	   type, myPid, rv);
+#else /* XP_WIN32 */
+#ifdef MC_HTTPD 
+    ereport(LOG_FAILURE, "%s error with session-id cache rv=%d\n",type, rv);
+#endif /* MC_HTTPD */
+#endif /* XP_UNIX */
+}
+
+static void 
+lock_cache(void)
+{
+    PZ_Lock(cacheLock);
+}
+
+static void 
+unlock_cache(void)
+{
+    PZ_Unlock(cacheLock);
+}
 
 /*
 ** Perform some mumbo jumbo on the ip-address and the session-id value to
 ** compute a hash value.
 */
 static PRUint32 
-SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, unsigned nl)
+Offset(const PRIPv6Addr *addr, unsigned char *s, unsigned nl)
 {
     PRUint32 rv;
-    PRUint32 x[8];
 
-    memset(x, 0, sizeof x);
-    if (nl > sizeof x)
-    	nl = sizeof x;
-    memcpy(x, s, nl);
-
-    rv = (addr->pr_s6_addr32[0] ^ addr->pr_s6_addr32[1] ^
-	  addr->pr_s6_addr32[2] ^ addr->pr_s6_addr32[3] ^
-          x[0] ^ x[1] ^ x[2] ^ x[3] ^ x[4] ^ x[5] ^ x[6] ^ x[7])
-	  % cache->numSIDCacheSets;
-    return rv;
+    rv = addr->pr_s6_addr32[3] ^ (((PRUint32)s[0] << 24) | ((PRUint32)s[1] << 16)
+		 | (s[2] << 8) | s[nl-1]);
+    return (rv % numSIDCacheEntries) * sizeof(SIDCacheEntry);
 }
 
 
 
 /*
 ** Look something up in the cache. This will invalidate old entries
-** in the process. Caller has locked the cache set!
+** in the process. Caller has locked the cache!
 ** Returns PR_TRUE if found a valid match.  PR_FALSE otherwise.
 */
-static sidCacheEntry *
-FindSID(cacheDesc *cache, PRUint32 setNum, PRUint32 now,
-        const PRIPv6Addr *addr, unsigned char *sessionID,
-	unsigned sessionIDLength)
+static PRBool 
+FindSID(const PRIPv6Addr *addr, unsigned char *sessionID,
+	unsigned sessionIDLength, SIDCacheEntry *sce)
 {
-    PRUint32      ndx   = cache->sidCacheSets[setNum].next;
-    int           i;
-
-    sidCacheEntry * set = cache->sidCacheData + 
-    			 (setNum * SID_CACHE_ENTRIES_PER_SET);
-
-    for (i = SID_CACHE_ENTRIES_PER_SET; i > 0; --i) {
-	sidCacheEntry * sce;
-
-	ndx  = (ndx - 1) % SID_CACHE_ENTRIES_PER_SET;
-	sce = set + ndx;
-
-	if (!sce->valid)
-	    continue;
+    PRUint32      offset;
+    PRUint32      now;
+    int           rv;
+#ifdef XP_UNIX
+    off_t         off;
+#endif
 
-	if (now > sce->time) {
-	    /* SessionID has timed out. Invalidate the entry. */
-	    SSL_TRC(7, ("%d: timed out sid entry addr=%08x%08x%08x%08x now=%x "
-			"time+=%x",
-			myPid, sce->addr.pr_s6_addr32[0],
-			sce->addr.pr_s6_addr32[1], sce->addr.pr_s6_addr32[2],
-			sce->addr.pr_s6_addr32[3], now,
-			sce->time + ssl_sid_timeout));
-	    sce->valid = 0;
-	    continue;
-	}
+    /* Read in cache entry after hashing ip address and session-id value */
+    offset = Offset(addr, sessionID, sessionIDLength); 
+    now = ssl_Time();
+    GET_SERVER_CACHE_READ_LOCK(SIDCacheFD, offset, sizeof *sce);
+#ifdef XP_UNIX
+    off = lseek(SIDCacheFD, offset, SEEK_SET);
+    rv = -1;
+    if (off != offset) {
+	if (off == -1) 
+	    nss_MD_unix_map_lseek_error(errno);
+	else 
+	    PORT_SetError(PR_FILE_SEEK_ERROR);
+    } else {
+	rv = read(SIDCacheFD, sce, sizeof *sce);
+	if (rv != sizeof *sce) {
+	    if (rv == -1) 
+		nss_MD_unix_map_read_error(errno);
+	    else 
+		PORT_SetError(PR_IO_ERROR);
+    	}
+    }
+#else /* XP_WIN32 */
+    /* Use memory mapped I/O and just memcpy() the data */
+    CopyMemory(sce, &SIDCacheData[offset], sizeof *sce);
+    rv = sizeof *sce;
+#endif /* XP_WIN32 */
+    RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, offset, sizeof *sce);
 
-	/*
-	** Next, examine specific session-id/addr data to see if the cache
-	** entry matches our addr+session-id value
-	*/
-	if (sessionIDLength == sce->sessionIDLength      &&
-	    !memcmp(&sce->addr, addr, sizeof(PRIPv6Addr)) &&
-	    !memcmp(sce->sessionID, sessionID, sessionIDLength)) {
-	    /* Found it */
-	    return sce;
-	}
+    if (rv != sizeof *sce) {
+	IOError(rv, "server sid cache read");
+	return PR_FALSE;
+    }
+
+    if (!sce->u.ssl2.valid) {
+	/* Entry is not valid */
+	PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND);
+	return PR_FALSE;
     }
 
+    if (((sce->u.ssl2.version < SSL_LIBRARY_VERSION_3_0) &&
+	 (now > sce->time + ssl_sid_timeout)) ||
+	((sce->u.ssl2.version >= SSL_LIBRARY_VERSION_3_0) &&
+	 (now > sce->time + ssl3_sid_timeout))) {
+	/* SessionID has timed out. Invalidate the entry. */
+	SSL_TRC(7, ("%d: timed out sid entry addr=%08x%08x%08x%08x now=%x time+=%x",
+		    myPid, sce->addr.pr_s6_addr32[0],
+		    sce->addr.pr_s6_addr32[1], sce->addr.pr_s6_addr32[2],
+		    sce->addr.pr_s6_addr32[3], now, 
+		    sce->time + ssl_sid_timeout));
+	sce->u.ssl2.valid = 0;
+
+	GET_SERVER_CACHE_WRITE_LOCK(SIDCacheFD, offset, sizeof *sce);
+#ifdef XP_UNIX
+	off = lseek(SIDCacheFD, offset, SEEK_SET);
+	rv = -1;
+	if (off != offset) {
+	    if (off == -1) 
+		nss_MD_unix_map_lseek_error(errno);
+	    else
+	    	PORT_SetError(PR_IO_ERROR);
+	} else {
+	    rv = write(SIDCacheFD, sce, sizeof *sce);
+	    if (rv != sizeof *sce) {
+		if (rv == -1) 
+		    nss_MD_unix_map_write_error(errno);
+		else 
+		    PORT_SetError(PR_IO_ERROR);
+		IOError(rv, "timeout-write");
+	    }
+	}
+#else /* WIN32 */
+	/* Use memory mapped I/O and just memcpy() the data */
+	CopyMemory(&SIDCacheData[offset], sce, sizeof *sce);
+	rv = sizeof *sce;
+#endif /* XP_UNIX */
+	RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, offset, sizeof *sce);
+	if (rv == sizeof *sce)
+	    PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND);
+	return PR_FALSE;
+    }
+
+    /*
+    ** Finally, examine specific session-id/addr data to see if the cache
+    ** entry matches our addr+session-id value
+    */
+    if (!memcmp(&sce->addr, addr, sizeof(PRIPv6Addr)) &&
+	(PORT_Memcmp(sce->u.ssl2.sessionID, sessionID, sessionIDLength) == 0)) {
+	/* Found it */
+	return PR_TRUE;
+    }
     PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND);
-    return NULL;
+    return PR_FALSE;
 }
 
 /************************************************************************/
 
 /* This is the primary function for finding entries in the server's sid cache.
  * Although it is static, this function is called via the global function 
  * pointer ssl_sid_lookup.
  */
 static sslSessionID *
-ServerSessionIDLookup(const PRIPv6Addr *addr,
+ServerSessionIDLookup(	const PRIPv6Addr  *addr,
 			unsigned char *sessionID,
 			unsigned int   sessionIDLength,
                         CERTCertDBHandle * dbHandle)
 {
-    sslSessionID *  sid      = 0;
-    sidCacheEntry * psce;
-    certCacheEntry *pcce     = 0;
-    cacheDesc *     cache    = &globalCache;
-    PRUint32        now;
-    PRUint32        set;
-    PRInt32         cndx;
-    sidCacheEntry   sce;
-    certCacheEntry  cce;
-
-    set = SIDindex(cache, addr, sessionID, sessionIDLength);
-    now = LockSet(cache, set, 0);
-    if (!now)
-    	return NULL;
-
-    psce = FindSID(cache, set, now, addr, sessionID, sessionIDLength);
-    if (psce) {
-	if (psce->version >= SSL_LIBRARY_VERSION_3_0 && 
-	    (cndx = psce->u.ssl3.certIndex) != -1) {
-
-	    PRUint32 gotLock = LockSidCacheLock(cache->certCacheLock, now);
-	    if (gotLock) {
-		pcce = &cache->certCacheData[cndx];
+    SIDCacheEntry sce;
+    sslSessionID *sid;
 
-		/* See if the cert's session ID matches the sce cache. */
-		if ((pcce->sessionIDLength == psce->sessionIDLength) &&
-		    !PORT_Memcmp(pcce->sessionID, psce->sessionID, 
-		                 pcce->sessionIDLength)) {
-		    cce = *pcce;
-		} else {
-		    /* The cert doesen't match the SID cache entry, 
-		    ** so invalidate the SID cache entry. 
-		    */
-		    psce->valid = 0;
-		    psce = 0;
-		    pcce = 0;
-		}
-		UnlockSidCacheLock(cache->certCacheLock);
-	    } else {
-		/* what the ??.  Didn't get the cert cache lock.
-		** Don't invalidate the SID cache entry, but don't find it.
-		*/
-		PORT_Assert(!("Didn't get cert Cache Lock!"));
-		psce = 0;
-		pcce = 0;
-	    }
-	}
-	if (psce) {
-	    sce = *psce;	/* grab a copy while holding the lock */
-    	}
+    sid = 0;
+    lock_cache();
+    if (FindSID(addr, sessionID, sessionIDLength, &sce)) {
+	/* Found it. Convert file format to internal format */
+	sid = ConvertToSID(&sce, dbHandle);
     }
-    UnlockSet(cache, set);
-    if (psce) {
-	/* sce conains a copy of the cache entry.
-	** Convert file format to internal format 
-	*/
-	sid = ConvertToSID(&sce, pcce ? &cce : 0, dbHandle);
-    }
+    unlock_cache();
     return sid;
 }
 
 /*
-** Place a sid into the cache, if it isn't already there. 
+** Place an sid into the cache, if it isn't already there. Note that if
+** some other server process has replaced a session-id cache entry that has
+** the same cache index as this sid, then all is ok. Somebody has to lose
+** when this condition occurs, so it might as well be this sid.
 */
 static void 
 ServerSessionIDCache(sslSessionID *sid)
 {
-    sidCacheEntry sce;
-    PRUint32      now     = 0;
-    uint16        version = sid->version;
-    cacheDesc *   cache   = &globalCache;
+    SIDCacheEntry sce;
+    PRUint32      offset;
+#ifdef XP_UNIX
+    off_t         off;
+    int           rv;
+#endif
+    uint16 version = sid->version;
 
     if ((version >= SSL_LIBRARY_VERSION_3_0) &&
 	(sid->u.ssl3.sessionIDLength == 0)) {
 	return;
     }
 
     if (sid->cached == never_cached || sid->cached == invalid_cache) {
-	PRUint32 set;
+	lock_cache();
 
+	sid->time = ssl_Time();
 	if (version < SSL_LIBRARY_VERSION_3_0) {
-	    sid->time = ssl_Time() + ssl_sid_timeout;
 	    SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
-			"cipher=%d", myPid, sid->cached,
+			"cipher=%d", myPid, sid->cached, 
 			sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
 			sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
 			sid->time, sid->u.ssl2.cipherType));
 	    PRINT_BUF(8, (0, "sessionID:", sid->u.ssl2.sessionID,
-			  SSL2_SESSIONID_BYTES));
+			  sizeof(sid->u.ssl2.sessionID)));
 	    PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data,
 			  sid->u.ssl2.masterKey.len));
 	    PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data,
 			  sid->u.ssl2.cipherArg.len));
 
+	    /* Write out new cache entry */
+	    offset = Offset(&sid->addr, sid->u.ssl2.sessionID,
+			    sizeof(sid->u.ssl2.sessionID)); 
 	} else {
-	    sid->time = ssl_Time() + ssl3_sid_timeout;
 	    SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
-			"cipherSuite=%d", myPid, sid->cached,
+			"cipherSuite=%d", myPid, sid->cached, 
 			sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
-			sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
+			sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], 
 			sid->time, sid->u.ssl3.cipherSuite));
 	    PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID,
 			  sid->u.ssl3.sessionIDLength));
+
+	    offset = Offset(&sid->addr, sid->u.ssl3.sessionID,
+			    sid->u.ssl3.sessionIDLength);
+	    
 	}
 
 	ConvertFromSID(&sce, sid);
+	if (version >= SSL_LIBRARY_VERSION_3_0) {
+	    if (sid->peerCert == NULL) {
+		sce.u.ssl3.certIndex = -1;
+	    } else {
+		sce.u.ssl3.certIndex = (int16)
+		    ((offset / sizeof(SIDCacheEntry)) % numCertCacheEntries);
+	    }
+	}
+	
+	GET_SERVER_CACHE_WRITE_LOCK(SIDCacheFD, offset, sizeof sce);
+#ifdef XP_UNIX
+	off = lseek(SIDCacheFD, offset, SEEK_SET);
+	if (off != offset) {
+	    if (off == -1) 
+		nss_MD_unix_map_lseek_error(errno);
+	    else
+	    	PORT_SetError(PR_IO_ERROR);
+	} else {
+	    rv = write(SIDCacheFD, &sce, sizeof sce);
+	    if (rv != sizeof(sce)) {
+		if (rv == -1) 
+		    nss_MD_unix_map_write_error(errno);
+		else 
+		    PORT_SetError(PR_IO_ERROR);
+		IOError(rv, "update-write");
+	    }
+	}
+#else /* WIN32 */
+	CopyMemory(&SIDCacheData[offset], &sce, sizeof sce);
+#endif /* XP_UNIX */
+	RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, offset, sizeof sce);
 
 	if ((version >= SSL_LIBRARY_VERSION_3_0) && 
 	    (sid->peerCert != NULL)) {
-	    now = CacheCert(cache, sid->peerCert, &sce);
+	    CacheCert(sid->peerCert, &sce);
 	}
 
-	set = SIDindex(cache, &sce.addr, sce.sessionID, sce.sessionIDLength);
-	now = LockSet(cache, set, now);
-	if (now) {
-	    PRUint32  next = cache->sidCacheSets[set].next;
-	    PRUint32  ndx  = set * SID_CACHE_ENTRIES_PER_SET + next;
-
-	    /* Write out new cache entry */
-	    cache->sidCacheData[ndx] = sce;
-
-	    cache->sidCacheSets[set].next = 
-	    				(next + 1) % SID_CACHE_ENTRIES_PER_SET;
-
-	    UnlockSet(cache, set);
-	    sid->cached = in_server_cache;
-	}
+	sid->cached = in_server_cache;
+	unlock_cache();
     }
 }
 
-/*
-** Although this is static, it is called from ssl via global function pointer
-**	ssl_sid_uncache.  This invalidates the referenced cache entry.
-*/
 static void 
 ServerSessionIDUncache(sslSessionID *sid)
 {
-    cacheDesc *    cache   = &globalCache;
-    PRUint8 *      sessionID;
-    unsigned int   sessionIDLength;
-    PRErrorCode    err;
-    PRUint32       set;
-    PRUint32       now;
-    sidCacheEntry *psce;
+    SIDCacheEntry sce;
+    PRErrorCode   err;
+    int rv;
 
-    if (sid == NULL) 
-    	return;
+    if (sid == NULL) return;
     
     /* Uncaching a SID should never change the error code. 
     ** So save it here and restore it before exiting.
     */
     err = PR_GetError();
-
+    lock_cache();
     if (sid->version < SSL_LIBRARY_VERSION_3_0) {
-	sessionID       = sid->u.ssl2.sessionID;
-	sessionIDLength = SSL2_SESSIONID_BYTES;
 	SSL_TRC(8, ("%d: SSL: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
-		    "cipher=%d", myPid, sid->cached,
+		    "cipher=%d", myPid, sid->cached, 
 		    sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
-		    sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
+		    sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], 
 		    sid->time, sid->u.ssl2.cipherType));
-	PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength));
+	PRINT_BUF(8, (0, "sessionID:", sid->u.ssl2.sessionID,
+		      sizeof(sid->u.ssl2.sessionID)));
 	PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data,
 		      sid->u.ssl2.masterKey.len));
 	PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data,
 		      sid->u.ssl2.cipherArg.len));
+	rv = FindSID(&sid->addr, sid->u.ssl2.sessionID,
+		     sizeof(sid->u.ssl2.sessionID), &sce);
     } else {
-	sessionID       = sid->u.ssl3.sessionID;
-	sessionIDLength = sid->u.ssl3.sessionIDLength;
 	SSL_TRC(8, ("%d: SSL3: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
-		    "cipherSuite=%d", myPid, sid->cached,
+		    "cipherSuite=%d", myPid, sid->cached, 
 		    sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
-		    sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
+		    sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], 
 		    sid->time, sid->u.ssl3.cipherSuite));
-	PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength));
+	PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID,
+		      sid->u.ssl3.sessionIDLength));
+	rv = FindSID(&sid->addr, sid->u.ssl3.sessionID,
+		     sid->u.ssl3.sessionIDLength, &sce);
     }
-    set = SIDindex(cache, &sid->addr, sessionID, sessionIDLength);
-    now = LockSet(cache, set, 0);
-    if (now) {
-	psce = FindSID(cache, set, now, &sid->addr, sessionID, sessionIDLength);
-	if (psce) {
-	    psce->valid = 0;
-	}
-	UnlockSet(cache, set);
+    
+    if (rv) {
+	Invalidate(&sce);
     }
     sid->cached = invalid_cache;
+    unlock_cache();
     PORT_SetError(err);
 }
 
 static SECStatus
-InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout, 
-          PRUint32 ssl3_timeout, const char *directory)
+InitSessionIDCache(int maxCacheEntries, PRUint32 timeout,
+		   PRUint32 ssl3_timeout, const char *directory)
 {
-    ptrdiff_t     ptr;
-    sidCacheLock *pLock;
-    char *        sharedMem;
-    PRFileMap *   cacheMemMap;
-    char *        cfn = NULL;	/* cache file name */
-    int           locks_initialized = 0;
-    int           locks_to_initialize = 0;
-    PRUint32      init_time;
-
-    if (cache->sharedMem) {
+    char *cfn;
+#ifdef XP_UNIX
+    int rv;
+    if (SIDCacheFD >= 0) {
 	/* Already done */
 	return SECSuccess;
     }
-
-    cache->numSIDCacheEntries = maxCacheEntries ? maxCacheEntries 
-                                                : DEF_SID_CACHE_ENTRIES;
-    cache->numSIDCacheSets    = 
-    	SID_HOWMANY(cache->numSIDCacheEntries, SID_CACHE_ENTRIES_PER_SET);
+#else /* WIN32 */
+	if(SIDCacheFDMAP != INVALID_HANDLE_VALUE) {
+	/* Already done */
+	return SECSuccess;
+	}
+#endif /* XP_UNIX */
 
-    cache->numSIDCacheEntries = 
-    	cache->numSIDCacheSets * SID_CACHE_ENTRIES_PER_SET;
-
-    cache->numSIDCacheLocks   = 
-    	PR_MIN(cache->numSIDCacheSets, ssl_max_sid_cache_locks);
-
-    cache->numSIDCacheSetsPerLock = 
-    	SID_HOWMANY(cache->numSIDCacheSets, cache->numSIDCacheLocks);
 
-    /* compute size of shared memory, and offsets of all pointers */
-    ptr = 0;
-    cache->sharedMem     = (char *)ptr;
-    ptr += SID_ROUNDUP(sizeof(cacheDesc), SID_ALIGNMENT);
+    if (maxCacheEntries) {
+	numSIDCacheEntries = maxCacheEntries;
+    }
+    sidCacheWrapOffset = numSIDCacheEntries * sizeof(SIDCacheEntry);
+    sidCacheFileSize = sidCacheWrapOffset +
+         (kt_kea_size * SSL_NUM_WRAP_MECHS * sizeof(SSLWrappedSymWrappingKey));
 
-    cache->sidCacheLocks = (sidCacheLock *)ptr;
-    cache->keyCacheLock  = cache->sidCacheLocks + cache->numSIDCacheLocks;
-    cache->certCacheLock = cache->keyCacheLock  + 1;
-    ptr = (ptrdiff_t)(cache->certCacheLock + 1);
-    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
-
-    cache->sidCacheSets  = (sidCacheSet *)ptr;
-    ptr = (ptrdiff_t)(cache->sidCacheSets + cache->numSIDCacheSets);
-    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
-
-    cache->sidCacheData  = (sidCacheEntry *)ptr;
-    ptr = (ptrdiff_t)(cache->sidCacheData + cache->numSIDCacheEntries);
-    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
+    /* Create file names */
+    cfn = (char*) PORT_Alloc(PORT_Strlen(directory) + 100);
+    if (!cfn) {
+	return SECFailure;
+    }
+#ifdef XP_UNIX
+    sprintf(cfn, "%s/.sslsidc.%d", directory, getpid());
+#else /* XP_WIN32 */
+	sprintf(cfn, "%s\\ssl.sidc.%d.%d", directory,
+			GetCurrentProcessId(), GetCurrentThreadId());
+#endif /* XP_WIN32 */
 
-    cache->certCacheData = (certCacheEntry *)ptr;
-    cache->sidCacheSize  = 
-    	(char *)cache->certCacheData - (char *)cache->sidCacheData;
-
-    /* This is really a poor way to computer this! */
-    cache->numCertCacheEntries = cache->sidCacheSize / sizeof(certCacheEntry);
-    if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES)
-    	cache->numCertCacheEntries = MIN_CERT_CACHE_ENTRIES;
-    ptr = (ptrdiff_t)(cache->certCacheData + cache->numCertCacheEntries);
-    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
-
-    cache->keyCacheData  = (SSLWrappedSymWrappingKey *)ptr;
-    cache->certCacheSize = 
-    	(char *)cache->keyCacheData - (char *)cache->certCacheData;
+    /* Create session-id cache file */
+#ifdef XP_UNIX
+    do {
+	(void) unlink(cfn);
+	SIDCacheFD = open(cfn, O_EXCL|O_CREAT|O_RDWR, 0600);
+    } while (SIDCacheFD < 0 && errno == EEXIST);
+    if (SIDCacheFD < 0) {
+	nss_MD_unix_map_open_error(errno);
+	IOError(SIDCacheFD, "create");
+	goto loser;
+    }
+    rv = unlink(cfn);
+    if (rv < 0) {
+	nss_MD_unix_map_unlink_error(errno);
+	IOError(rv, "unlink");
+	goto loser;
+    }
+#else  /* WIN32 */
+    SIDCacheFDMAP = 
+    	CreateFileMapping(INVALID_HANDLE_VALUE, /* allocate in swap file */
+			  &sidCacheFDMapAttributes, /* inheritable. */
+			  PAGE_READWRITE,
+			  0,                    /* size, high word. */
+			  sidCacheFileSize,     /* size, low  word. */
+			  NULL);		/* no map name in FS */
+    if(! SIDCacheFDMAP) {
+	nss_MD_win32_map_default_error(GetLastError());
+	goto loser;
+    }
+    SIDCacheData = (char *)MapViewOfFile(SIDCacheFDMAP, 
+                                         FILE_MAP_ALL_ACCESS, 	/* R/W    */
+					 0, 0, 			/* offset */
+				         sidCacheFileSize);	/* size   */
+    if (! SIDCacheData) {
+	nss_MD_win32_map_default_error(GetLastError());
+	goto loser;
+    }
+#endif /* XP_UNIX */
 
-    cache->numKeyCacheEntries = kt_kea_size * SSL_NUM_WRAP_MECHS;
-    ptr = (ptrdiff_t)(cache->keyCacheData + cache->numKeyCacheEntries);
-    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
-
-    cache->sharedMemSize = ptr;
-
-    cache->keyCacheSize  = (char *)ptr - (char *)cache->keyCacheData;
+    if (!cacheLock)
+	nss_InitLock(&cacheLock, nssILockCache);
+    if (!cacheLock) {
+	SET_ERROR_CODE
+	goto loser;
+    }
+#ifdef _WIN32
+    if (isMultiProcess  && (SECSuccess != createServerCacheSemaphore())) {
+	SET_ERROR_CODE
+	goto loser;
+    }
+#endif
 
-    if (ssl2_timeout) {   
-	if (ssl2_timeout > MAX_SSL2_TIMEOUT) {
-	    ssl2_timeout = MAX_SSL2_TIMEOUT;
+    if (timeout) {   
+	if (timeout > 100) {
+	    timeout = 100;
 	}
-	if (ssl2_timeout < MIN_SSL2_TIMEOUT) {
-	    ssl2_timeout = MIN_SSL2_TIMEOUT;
+	if (timeout < 5) {
+	    timeout = 5;
 	}
-	cache->ssl2Timeout = ssl2_timeout;
-    } else {
-	cache->ssl2Timeout = DEF_SSL2_TIMEOUT;
+	ssl_sid_timeout = timeout;
     }
 
     if (ssl3_timeout) {   
-	if (ssl3_timeout > MAX_SSL3_TIMEOUT) {
-	    ssl3_timeout = MAX_SSL3_TIMEOUT;
-	}
-	if (ssl3_timeout < MIN_SSL3_TIMEOUT) {
-	    ssl3_timeout = MIN_SSL3_TIMEOUT;
+	if (ssl3_timeout > 86400L) {
+	    ssl3_timeout = 86400L;
 	}
-	cache->ssl3Timeout = ssl3_timeout;
-    } else {
-	cache->ssl3Timeout = DEF_SSL3_TIMEOUT;
-    }
-
-    /* Create file names */
-#ifdef XP_UNIX
-    /* there's some confusion here about whether PR_OpenAnonFileMap wants
-    ** a directory name or a file name for its first argument.
-    cfn = PR_smprintf("%s/.sslsvrcache.%d", directory, myPid);
-    */
-    cfn = PR_smprintf("%s", directory);
-#else /* XP_WIN32 */
-    cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid, 
-    			GetCurrentThreadId());
-#endif /* XP_WIN32 */
-    if (!cfn) {
-	goto loser;
-    }
-
-    /* Create cache */
-    cacheMemMap = PR_OpenAnonFileMap(cfn, cache->sharedMemSize, 
-                                            PR_PROT_READWRITE);
-    PR_smprintf_free(cfn);
-    if(! cacheMemMap) {
-	goto loser;
-    }
-    sharedMem = PR_MemMap(cacheMemMap, 0, cache->sharedMemSize);
-    if (! sharedMem) {
-	goto loser;
+	if (ssl3_timeout < 5) {
+	    ssl3_timeout = 5;
+	}
+	ssl3_sid_timeout = ssl3_timeout;
     }
 
-    /* Initialize shared memory. This may not be necessary on all platforms */
-    memset(sharedMem, 0, cache->sharedMemSize);
-
-    /* Copy cache descriptor header into shared memory */
-    memcpy(sharedMem, cache, sizeof *cache);
-
-    /* save private copies of these values */
-    cache->cacheMemMap = cacheMemMap;
-    cache->sharedMem   = sharedMem;
-    cache->sharedCache = (cacheDesc *)sharedMem;
-
-    /* Fix pointers in our private copy of cache descriptor to point to 
-    ** spaces in shared memory 
-    */
-    ptr = (ptrdiff_t)cache->sharedMem;
-    *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
-    *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
-    *(ptrdiff_t *)(&cache->certCacheLock) += ptr;
-    *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr;
-    *(ptrdiff_t *)(&cache->sidCacheData ) += ptr;
-    *(ptrdiff_t *)(&cache->certCacheData) += ptr;
-    *(ptrdiff_t *)(&cache->keyCacheData ) += ptr;
-
-    /* initialize the locks */
-    init_time = ssl_Time();
-    pLock = cache->sidCacheLocks;
-    for (locks_to_initialize = cache->numSIDCacheLocks + 2;
-         locks_initialized < locks_to_initialize; 
-	 ++locks_initialized, ++pLock ) {
-
-	SECStatus err = sslMutex_Init(&pLock->mutex, isMultiProcess);
-	if (err)
-	    goto loser;
-        pLock->timeStamp = init_time;
-	pLock->pid       = 0;
+    GET_SERVER_CACHE_WRITE_LOCK(SIDCacheFD, 0, sidCacheFileSize);
+#ifdef XP_UNIX
+    /* Initialize the files */
+    if (ZeroFile(SIDCacheFD, sidCacheFileSize)) {
+	/* Bummer */
+	close(SIDCacheFD);
+	SIDCacheFD = -1;
+	goto loser;
     }
-
+#else /* XP_WIN32 */
+    ZeroMemory(SIDCacheData, sidCacheFileSize);
+#endif /* XP_UNIX */
+    RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, 0, sidCacheFileSize);
+    PORT_Free(cfn);
     return SECSuccess;
 
-loser:
-    if (cache->cacheMemMap) {
-	if (cache->sharedMem) {
-	    if (locks_initialized > 0) {
-		pLock = cache->sidCacheLocks;
-		for (; locks_initialized > 0; --locks_initialized, ++pLock ) {
-		    sslMutex_Destroy(&pLock->mutex);
-		}
-	    }
-	    PR_MemUnmap(cache->sharedMem, cache->sharedMemSize);
-	    cache->sharedMem = NULL;
-	}
-    	PR_CloseFileMap(cache->cacheMemMap);
-	cache->cacheMemMap = NULL;
+  loser:
+#ifdef _WIN32
+    if (svrCacheSem)
+	destroyServerCacheSemaphore();
+#endif
+    if (cacheLock) {
+	PZ_DestroyLock(cacheLock);
+	cacheLock = NULL;
     }
+    PORT_Free(cfn);
     return SECFailure;
 }
 
-PRUint32
-SSL_GetMaxServerCacheLocks(void)
+static SECStatus 
+InitCertCache(const char *directory)
 {
-    return ssl_max_sid_cache_locks + 2;
-    /* The extra two are the cert cache lock and the key cache lock. */
+    char *cfn;
+#ifdef XP_UNIX
+    int rv;
+    if (certCacheFD >= 0) {
+	/* Already done */
+	return SECSuccess;
+    }
+#else /* WIN32 */
+    if(certCacheFDMAP != INVALID_HANDLE_VALUE) {
+	/* Already done */
+	return SECSuccess;
+    }
+#endif /* XP_UNIX */
+
+    numCertCacheEntries = sidCacheFileSize / sizeof(CertCacheEntry);
+    if (numCertCacheEntries < MIN_CERT_CACHE_ENTRIES)
+    	numCertCacheEntries = MIN_CERT_CACHE_ENTRIES;
+    certCacheFileSize = numCertCacheEntries * sizeof(CertCacheEntry);
+
+    /* Create file names */
+    cfn = (char*) PORT_Alloc(PORT_Strlen(directory) + 100);
+    if (!cfn) {
+	return SECFailure;
+    }
+#ifdef XP_UNIX
+    sprintf(cfn, "%s/.sslcertc.%d", directory, getpid());
+#else /* XP_WIN32 */
+    sprintf(cfn, "%s\\ssl.certc.%d.%d", directory,
+	    GetCurrentProcessId(), GetCurrentThreadId());
+#endif /* XP_WIN32 */
+
+    /* Create certificate cache file */
+#ifdef XP_UNIX
+    do {
+	(void) unlink(cfn);
+	certCacheFD = open(cfn, O_EXCL|O_CREAT|O_RDWR, 0600);
+    } while (certCacheFD < 0 && errno == EEXIST);
+    if (certCacheFD < 0) {
+	nss_MD_unix_map_open_error(errno);
+	IOError(certCacheFD, "create");
+	goto loser;
+    }
+    rv = unlink(cfn);
+    if (rv < 0) {
+	nss_MD_unix_map_unlink_error(errno);
+	IOError(rv, "unlink");
+	goto loser;
+    }
+#else  /* WIN32 */
+    certCacheFDMAP = 
+    	CreateFileMapping(INVALID_HANDLE_VALUE, /* allocate in swap file */
+			  &certCacheFDMapAttributes, /* inheritable. */
+			  PAGE_READWRITE,
+			  0,                /* size, high word. */
+			  certCacheFileSize, /* size, low word. */
+			  NULL);           /* no map name in FS */
+    if (! certCacheFDMAP) {
+	nss_MD_win32_map_default_error(GetLastError());
+	goto loser;
+    }
+    certCacheData = (char *) MapViewOfFile(certCacheFDMAP, 
+                                           FILE_MAP_ALL_ACCESS, /* R/W    */
+					   0, 0, 		/* offset */
+					   certCacheFileSize);	/* size   */
+    if (! certCacheData) {
+	nss_MD_win32_map_default_error(GetLastError());
+	goto loser;
+    }
+#endif /* XP_UNIX */
+
+/*  GET_SERVER_CACHE_WRITE_LOCK(certCacheFD, 0, certCacheFileSize); */
+#ifdef XP_UNIX
+    /* Initialize the files */
+    if (ZeroFile(certCacheFD, certCacheFileSize)) {
+	/* Bummer */
+	close(certCacheFD);
+	certCacheFD = -1;
+	goto loser;
+    }
+#else /* XP_WIN32 */
+    ZeroMemory(certCacheData, certCacheFileSize);
+#endif /* XP_UNIX */
+/*  RELEASE_SERVER_CACHE_LOCK(certCacheFD, 0, certCacheFileSize);   */
+    PORT_Free(cfn);
+    return SECSuccess;
+
+  loser:
+    PORT_Free(cfn);
+    return SECFailure;
 }
 
 SECStatus
-SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
-{
-    /* Minimum is 1 sid cache lock, 1 cert cache lock and 1 key cache lock.
-    ** We'd like to test for a maximum value, but not all platforms' header
-    ** files provide a symbol or function or other means of determining
-    ** the maximum, other than trial and error.
-    */
-    if (maxLocks < 3) {
-	PORT_SetError(SEC_ERROR_INVALID_ARGS);
-	return SECFailure;
-    }
-    ssl_max_sid_cache_locks = maxLocks - 2;
-    /* The extra two are the cert cache lock and the key cache lock. */
-    return SECSuccess;
-}
-
-SECStatus
-SSL_ConfigServerSessionIDCacheInstance(	cacheDesc *cache,
-                                int      maxCacheEntries, 
-				PRUint32 ssl2_timeout,
+SSL_ConfigServerSessionIDCache(	int      maxCacheEntries, 
+				PRUint32 timeout,
 			       	PRUint32 ssl3_timeout, 
 			  const char *   directory)
 {
     SECStatus rv;
 
-#if defined(DEBUG_nelsonb)
-    printf("sizeof(sidCacheEntry) == %u\n", sizeof(sidCacheEntry));
-#endif
-#if !(defined(SOLARIS) && defined(i386))
-    PORT_Assert(sizeof(sidCacheEntry) % 8 == 0);
-#endif
-    PORT_Assert(sizeof(certCacheEntry) == 4096);
+    PORT_Assert(sizeof(SIDCacheEntry) == 256);
+    PORT_Assert(sizeof(CertCacheEntry) == 4096);
 
     myPid = SSL_GETPID();
     if (!directory) {
 	directory = DEFAULT_CACHE_DIRECTORY;
     }
-    rv = InitCache(cache, maxCacheEntries, ssl2_timeout, ssl3_timeout, 
-                   directory);
+    rv = InitSessionIDCache(maxCacheEntries, timeout, ssl3_timeout, directory);
+    if (rv) {
+	SET_ERROR_CODE
+    	return SECFailure;
+    }
+    rv = InitCertCache(directory);
     if (rv) {
 	SET_ERROR_CODE
     	return SECFailure;
     }
 
     ssl_sid_lookup  = ServerSessionIDLookup;
     ssl_sid_cache   = ServerSessionIDCache;
     ssl_sid_uncache = ServerSessionIDUncache;
     return SECSuccess;
 }
 
-SECStatus
-SSL_ConfigServerSessionIDCache(	int      maxCacheEntries, 
-				PRUint32 ssl2_timeout,
-			       	PRUint32 ssl3_timeout, 
-			  const char *   directory)
-{
-    return SSL_ConfigServerSessionIDCacheInstance(&globalCache, 
-    		maxCacheEntries, ssl2_timeout, ssl3_timeout, directory);
-}
-
 /* Use this function, instead of SSL_ConfigServerSessionIDCache,
  * if the cache will be shared by multiple processes.
  */
 SECStatus
 SSL_ConfigMPServerSIDCache(	int      maxCacheEntries, 
-				PRUint32 ssl2_timeout,
+				PRUint32 timeout,
 			       	PRUint32 ssl3_timeout, 
 		          const char *   directory)
 {
     char *	envValue;
-    char *	inhValue;
-    cacheDesc * cache         = &globalCache;
-    PRUint32    fmStrLen;
     SECStatus 	result;
-    PRStatus 	prStatus;
     SECStatus	putEnvFailed;
-    inheritance inherit;
-    char        fmString[PR_FILEMAP_STRING_BUFSIZE];
 
     isMultiProcess = PR_TRUE;
-    result = SSL_ConfigServerSessionIDCacheInstance(cache, maxCacheEntries, 
-					ssl2_timeout, ssl3_timeout, directory);
-    if (result != SECSuccess) 
-        return result;
-
-    prStatus = PR_ExportFileMapAsString(cache->cacheMemMap, 
-                                        sizeof fmString, fmString);
-    if ((prStatus != PR_SUCCESS) || !(fmStrLen = strlen(fmString))) {
-	SET_ERROR_CODE
-	return SECFailure;
-    }
-
-    inherit.sharedMemSize	= cache->sharedMemSize;
-    inherit.fmStrLen            = fmStrLen;
+    result = SSL_ConfigServerSessionIDCache(maxCacheEntries, timeout, 
+                                            ssl3_timeout, directory);
+    if (result == SECSuccess) {
+#ifdef _WIN32
+	winInheritance winherit;
 
-    inhValue = BTOA_DataToAscii((unsigned char *)&inherit, sizeof inherit);
-    if (!inhValue || !strlen(inhValue)) {
-	SET_ERROR_CODE
-	return SECFailure;
+	winherit.numSIDCacheEntries	= numSIDCacheEntries;
+	winherit.sidCacheFileSize	= sidCacheFileSize;
+	winherit.sidCacheWrapOffset	= sidCacheWrapOffset;
+	winherit.numCertCacheEntries	= numCertCacheEntries;
+	winherit.certCacheFileSize	= certCacheFileSize;
+	winherit.SIDCacheFDMAP		= SIDCacheFDMAP;
+	winherit.certCacheFDMAP		= certCacheFDMAP;
+	winherit.svrCacheSem		= svrCacheSem;
+	winherit.parentProcessID	= GetCurrentProcessId();
+	winherit.parentProcessHandle	= 
+	    OpenProcess(PROCESS_DUP_HANDLE, TRUE, winherit.parentProcessID);
+        if (winherit.parentProcessHandle == NULL) {
+	    SET_ERROR_CODE
+	    return SECFailure;
+	}
+        envValue = BTOA_DataToAscii((unsigned char *)&winherit, 
+	                             sizeof winherit);
+    	if (!envValue) {
+	    SET_ERROR_CODE
+	    return SECFailure;
+	}
+#else
+	unixInheritance uinherit;
+
+	uinherit.numSIDCacheEntries	= numSIDCacheEntries;
+	uinherit.sidCacheFileSize	= sidCacheFileSize;
+	uinherit.sidCacheWrapOffset	= sidCacheWrapOffset;
+	uinherit.numCertCacheEntries	= numCertCacheEntries;
+	uinherit.certCacheFileSize	= certCacheFileSize;
+	uinherit.SIDCacheFD		= SIDCacheFD;
+	uinherit.certCacheFD		= certCacheFD;
+
+        envValue = BTOA_DataToAscii((unsigned char *)&uinherit, 
+	                             sizeof uinherit);
+    	if (!envValue) {
+	    SET_ERROR_CODE
+	    return SECFailure;
+	}
+#endif
     }
-    envValue = PR_smprintf("%s,%s", inhValue, fmString);
-    if (!envValue || !strlen(envValue)) {
-	SET_ERROR_CODE
-	return SECFailure;
-    }
-    PORT_Free(inhValue);
-
     putEnvFailed = (SECStatus)NSS_PutEnv(envVarName, envValue);
-    PR_smprintf_free(envValue);
+    PORT_Free(envValue);
     if (putEnvFailed) {
         SET_ERROR_CODE
         result = SECFailure;
     }
-
-#if !defined(WIN32)
-    /* Launch thread to poll cache for expired locks */
-    LaunchLockPoller(cache);
-#endif
     return result;
 }
 
 SECStatus
-SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString)
+SSL_InheritMPServerSIDCache(const char * envString)
 {
     unsigned char * decoString = NULL;
-    char *          fmString   = NULL;
     unsigned int    decoLen;
-    ptrdiff_t       ptr;
-    inheritance     inherit;
-    cacheDesc       my;
+#ifdef _WIN32
+    winInheritance  inherit;
+#else
+    unixInheritance inherit;
+#endif
 
     myPid = SSL_GETPID();
-
-    /* If this child was created by fork(), and not by exec() on unix,
-    ** then isMultiProcess will already be set.
-    ** If not, we'll set it below.
-    */
     if (isMultiProcess)
     	return SECSuccess;	/* already done. */
 
     ssl_sid_lookup  = ServerSessionIDLookup;
     ssl_sid_cache   = ServerSessionIDCache;
     ssl_sid_uncache = ServerSessionIDUncache;
 
     if (!envString) {
     	envString  = getenv(envVarName);
 	if (!envString) {
 	    SET_ERROR_CODE
 	    return SECFailure;
 	}
     }
-    envString = PORT_Strdup(envString);
-    if (!envString) 
-	return SECFailure;
-    fmString = strchr(envString, ',');
-    if (!fmString) 
-    	goto loser;
-    *fmString++ = 0;
 
     decoString = ATOB_AsciiToData(envString, &decoLen);
     if (!decoString) {
     	SET_ERROR_CODE
-	goto loser;
+	return SECFailure;
     }
     if (decoLen != sizeof inherit) {
     	SET_ERROR_CODE
     	goto loser;
     }
 
     PORT_Memcpy(&inherit, decoString, sizeof inherit);
+    PORT_Free(decoString);
 
-    if (strlen(fmString)  != inherit.fmStrLen ) {
+    numSIDCacheEntries	= inherit.numSIDCacheEntries;
+    sidCacheFileSize	= inherit.sidCacheFileSize;
+    sidCacheWrapOffset	= inherit.sidCacheWrapOffset;
+    numCertCacheEntries	= inherit.numCertCacheEntries;
+    certCacheFileSize	= inherit.certCacheFileSize;
+
+#ifdef _WIN32
+    SIDCacheFDMAP	= inherit.SIDCacheFDMAP;
+    certCacheFDMAP	= inherit.certCacheFDMAP;
+    svrCacheSem		= inherit.svrCacheSem;
+
+#if 0
+    /* call DuplicateHandle ?? */
+    inherit.parentProcessID;
+    inherit.parentProcessHandle;
+#endif
+
+    if(!SIDCacheFDMAP) {
+    	SET_ERROR_CODE
+    	goto loser;
+    }
+    SIDCacheData = (char *)MapViewOfFile(SIDCacheFDMAP, 
+                                         FILE_MAP_ALL_ACCESS, 	/* R/W    */
+					 0, 0, 			/* offset */
+				         sidCacheFileSize);	/* size   */
+    if(!SIDCacheData) {
+	nss_MD_win32_map_default_error(GetLastError());
     	goto loser;
     }
 
-    memset(&my, 0, sizeof my);
-    my.sharedMemSize	= inherit.sharedMemSize;
-
-    /* Create cache */
-    my.cacheMemMap = PR_ImportFileMapFromString(fmString);
-    if(! my.cacheMemMap) {
-	goto loser;
+    if(!certCacheFDMAP) {
+    	SET_ERROR_CODE
+    	goto loser;
     }
-    my.sharedMem = PR_MemMap(my.cacheMemMap, 0, my.sharedMemSize);
-    if (! my.sharedMem) {
-	goto loser;
-    }
-    my.sharedCache   = (cacheDesc *)my.sharedMem;
-
-    if (my.sharedCache->sharedMemSize != my.sharedMemSize) {
-	SET_ERROR_CODE
+    certCacheData = (char *) MapViewOfFile(certCacheFDMAP, 
+                                           FILE_MAP_ALL_ACCESS, /* R/W    */
+					   0, 0, 		/* offset */
+					   certCacheFileSize);	/* size   */
+    if(!certCacheData) {
+	nss_MD_win32_map_default_error(GetLastError());
     	goto loser;
     }
 
-    memcpy(cache, my.sharedCache, sizeof *cache);
-    cache->cacheMemMap = my.cacheMemMap;
-    cache->sharedMem   = my.sharedMem;
-    cache->sharedCache = my.sharedCache;
+#else /* must be unix */
+    SIDCacheFD		= inherit.SIDCacheFD;
+    certCacheFD		= inherit.certCacheFD;
+    if (SIDCacheFD < 0 || certCacheFD < 0) {
+    	SET_ERROR_CODE
+    	goto loser;
+    }
+#endif
 
-    /* Fix pointers in our private copy of cache descriptor to point to 
-    ** spaces in shared memory 
-    */
-    ptr = (ptrdiff_t)cache->sharedMem;
-    *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
-    *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
-    *(ptrdiff_t *)(&cache->certCacheLock) += ptr;
-    *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr;
-    *(ptrdiff_t *)(&cache->sidCacheData ) += ptr;
-    *(ptrdiff_t *)(&cache->certCacheData) += ptr;
-    *(ptrdiff_t *)(&cache->keyCacheData ) += ptr;
-
-    PORT_Free(decoString);
+    if (!cacheLock) {
+	nss_InitLock(&cacheLock, nssILockCache);
+	if (!cacheLock) 
+	    goto loser;
+    }
     isMultiProcess = PR_TRUE;
     return SECSuccess;
 
 loser:
     if (decoString) 
 	PORT_Free(decoString);
+#if _WIN32
+    if (SIDCacheFDMAP) {
+	CloseHandle(SIDCacheFDMAP);
+	SIDCacheFDMAP = NULL;
+    }
+    if (certCacheFDMAP) {
+	CloseHandle(certCacheFDMAP);
+	certCacheFDMAP = NULL;
+    }
+#else
+    if (SIDCacheFD >= 0) {
+	close(SIDCacheFD);
+	SIDCacheFD = -1;
+    }
+    if (certCacheFD >= 0) {
+	close(certCacheFD);
+	certCacheFD = -1;
+    }
+#endif
     return SECFailure;
 
 }
 
-SECStatus
-SSL_InheritMPServerSIDCache(const char * envString)
-{
-    return SSL_InheritMPServerSIDCacheInstance(&globalCache, envString);
-}
-
-#if !defined(WIN32)
-
-#define SID_LOCK_EXPIRATION_TIMEOUT  30 /* seconds */
-
-static void
-LockPoller(void * arg)
-{
-    cacheDesc *    cache         = (cacheDesc *)arg;
-    cacheDesc *    sharedCache   = cache->sharedCache;
-    sidCacheLock * pLock;
-    const char *   timeoutString;
-    PRIntervalTime timeout;
-    PRUint32       now;
-    PRUint32       then;
-    int            locks_polled  = 0;
-    int            locks_to_poll = cache->numSIDCacheLocks + 2;
-    PRUint32       expiration    = SID_LOCK_EXPIRATION_TIMEOUT;
-
-    timeoutString = getenv("NSS_SSL_SERVER_CACHE_MUTEX_TIMEOUT");
-    if (timeoutString) {
-	long newTime = strtol(timeoutString, 0, 0);
-	if (newTime == 0) 
-	    return;  /* application doesn't want this function */
-	if (newTime > 0)
-	    expiration = (PRUint32)newTime;
-	/* if error (newTime < 0) ignore it and use default */
-    }
-
-    timeout = PR_SecondsToInterval(expiration);
-    while(!sharedCache->stopPolling) {
-    	PR_Sleep(timeout);
-	if (sharedCache->stopPolling)
-	    break;
-
-	now   = ssl_Time();
-	then  = now - expiration;
-	for (pLock = cache->sidCacheLocks, locks_polled = 0;
-	     locks_to_poll > locks_polled && !sharedCache->stopPolling; 
-	     ++locks_polled, ++pLock ) {
-	    pid_t pid;
-
-	    if (pLock->timeStamp   < then && 
-	        pLock->timeStamp   != 0 && 
-		(pid = pLock->pid) != 0) {
-
-	    	/* maybe we should try the lock? */
-		int result = kill(pid, 0);
-		if (result < 0 && errno == ESRCH) {
-		    SECStatus rv;
-		    /* No process exists by that pid any more.
-		    ** Treat this mutex as abandoned.
-		    */
-		    pLock->timeStamp = now;
-		    pLock->pid       = 0;
-		    rv = sslMutex_Unlock(&pLock->mutex);
-		    if (rv != SECSuccess) {
-		    	/* Now what? */
-		    }
-		}
-	    }
-	} /* end of loop over locks */
-    } /* end of entire polling loop */
-}
-
-/* Launch thread to poll cache for expired locks */
-static SECStatus 
-LaunchLockPoller(cacheDesc *cache)
-{
-    PRThread * pollerThread;
-
-    pollerThread = 
-	PR_CreateThread(PR_USER_THREAD, LockPoller, cache, PR_PRIORITY_NORMAL, 
-	                PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
-    if (!pollerThread) {
-    	return SECFailure;
-    }
-    cache->poller = pollerThread;
-    return SECSuccess;
-}
-#endif
-
 /************************************************************************
  *  Code dealing with shared wrapped symmetric wrapping keys below      *
  ************************************************************************/
 
-/* If now is zero, it implies that the lock is not held, and must be 
-** aquired here.  
-*/
+
 static PRBool
-getSvrWrappingKey(PRInt32                symWrapMechIndex,
+getWrappingKey(PRInt32                   symWrapMechIndex,
                SSL3KEAType               exchKeyType, 
                SSLWrappedSymWrappingKey *wswk, 
-	       cacheDesc *               cache,
-	       PRUint32                  lockTime)
+               PRBool                    grabSharedLock)
 {
-    PRUint32  ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
-    SSLWrappedSymWrappingKey * pwswk = cache->keyCacheData + ndx;
-    PRUint32  now = 0;
-    PRBool    rv  = PR_FALSE;
+    PRUint32      offset = sidCacheWrapOffset + 
+	       ((exchKeyType * SSL_NUM_WRAP_MECHS + symWrapMechIndex) *
+		   sizeof(SSLWrappedSymWrappingKey));
+    PRBool        rv     = PR_TRUE;
+#ifdef XP_UNIX
+    off_t         lrv;
+    ssize_t       rrv;
+#endif
+
+    if (grabSharedLock) {
+	GET_SERVER_CACHE_READ_LOCK(SIDCacheFD, offset, sizeof *wswk);
+    }
 
-    if (!lockTime) {
-	lockTime = now = LockSidCacheLock(cache->keyCacheLock, now);
-	if (!lockTime) {
-	    return rv;
+#ifdef XP_UNIX
+    lrv = lseek(SIDCacheFD, offset, SEEK_SET);
+    if (lrv != offset) {
+	if (lrv == -1) 
+	    nss_MD_unix_map_lseek_error(errno);
+	else
+	    PORT_SetError(PR_IO_ERROR);
+	    IOError(rv, "wrapping-read");
+	rv = PR_FALSE;
+    } else {
+	rrv = read(SIDCacheFD, wswk, sizeof *wswk);
+	if (rrv != sizeof *wswk) {
+	    if (rrv == -1) 
+		nss_MD_unix_map_read_error(errno);
+	    else 
+		PORT_SetError(PR_IO_ERROR);
+	    IOError(rv, "wrapping-read");
+	    rv = PR_FALSE;
 	}
     }
-    if (pwswk->exchKeyType      == exchKeyType && 
-	pwswk->symWrapMechIndex == symWrapMechIndex &&
-	pwswk->wrappedSymKeyLen != 0) {
-	*wswk = *pwswk;
-	rv = PR_TRUE;
+#else /* XP_WIN32 */
+    /* Use memory mapped I/O and just memcpy() the data */
+    CopyMemory(wswk, &SIDCacheData[offset], sizeof *wswk);
+#endif /* XP_WIN32 */
+    if (grabSharedLock) {
+	RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, offset, sizeof *wswk);
     }
-    if (now) {
-	UnlockSidCacheLock(cache->keyCacheLock);
+    if (rv) {
+    	if (wswk->exchKeyType      != exchKeyType || 
+	    wswk->symWrapMechIndex != symWrapMechIndex ||
+	    wswk->wrappedSymKeyLen == 0) {
+	    memset(wswk, 0, sizeof *wswk);
+	    rv = PR_FALSE;
+	}
     }
     return rv;
 }
 
 PRBool
 ssl_GetWrappingKey( PRInt32                   symWrapMechIndex,
                     SSL3KEAType               exchKeyType, 
 		    SSLWrappedSymWrappingKey *wswk)
 {
     PRBool rv;
 
+    lock_cache();
+
     PORT_Assert( (unsigned)exchKeyType < kt_kea_size);
     PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
     if ((unsigned)exchKeyType < kt_kea_size &&
         (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS) {
-	rv = getSvrWrappingKey(symWrapMechIndex, exchKeyType, wswk, 
-	                       &globalCache, 0);
+	rv = getWrappingKey(symWrapMechIndex, exchKeyType, wswk, PR_TRUE);
     } else {
     	rv = PR_FALSE;
     }
-
+    unlock_cache();
     return rv;
 }
 
 /* The caller passes in the new value it wants
  * to set.  This code tests the wrapped sym key entry in the file on disk.  
  * If it is uninitialized, this function writes the caller's value into 
  * the disk entry, and returns false.  
  * Otherwise, it overwrites the caller's wswk with the value obtained from 
  * the disk, and returns PR_TRUE.  
- * This is all done while holding the locks/mutexes necessary to make 
+ * This is all done while holding the locks/semaphores necessary to make 
  * the operation atomic.
  */
 PRBool
 ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
 {
-    cacheDesc *   cache            = &globalCache;
-    PRBool        rv               = PR_FALSE;
+    PRBool        rv;
     SSL3KEAType   exchKeyType      = wswk->exchKeyType;   
                                 /* type of keys used to wrap SymWrapKey*/
     PRInt32       symWrapMechIndex = wswk->symWrapMechIndex;
-    PRUint32      ndx;
-    PRUint32      now = 0;
+    PRUint32      offset;
     SSLWrappedSymWrappingKey myWswk;
 
     PORT_Assert( (unsigned)exchKeyType < kt_kea_size);
     if ((unsigned)exchKeyType >= kt_kea_size)
     	return 0;
 
     PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
     if ((unsigned)symWrapMechIndex >=  SSL_NUM_WRAP_MECHS)
     	return 0;
 
-    ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
+    offset = sidCacheWrapOffset + 
+	       ((exchKeyType * SSL_NUM_WRAP_MECHS + symWrapMechIndex) *
+		   sizeof(SSLWrappedSymWrappingKey));
     PORT_Memset(&myWswk, 0, sizeof myWswk);	/* eliminate UMRs. */
+    lock_cache();
+    GET_SERVER_CACHE_WRITE_LOCK(SIDCacheFD, offset, sizeof *wswk);
+
+    rv = getWrappingKey(wswk->symWrapMechIndex, wswk->exchKeyType, &myWswk, 
+                        PR_FALSE);
+    if (rv) {
+	/* we found it on disk, copy it out to the caller. */
+	PORT_Memcpy(wswk, &myWswk, sizeof *wswk);
+    } else {
+	/* Wasn't on disk, and we're still holding the lock, so write it. */
+
+#ifdef XP_UNIX
+	off_t         lrv;
+	ssize_t       rrv;
 
-    now = LockSidCacheLock(cache->keyCacheLock, now);
-    if (now) {
-	rv = getSvrWrappingKey(wswk->symWrapMechIndex, wswk->exchKeyType, 
-	                       &myWswk, cache, now);
-	if (rv) {
-	    /* we found it on disk, copy it out to the caller. */
-	    PORT_Memcpy(wswk, &myWswk, sizeof *wswk);
+	lrv = lseek(SIDCacheFD, offset, SEEK_SET);
+	if (lrv != offset) {
+	    if (lrv == -1) 
+		nss_MD_unix_map_lseek_error(errno);
+	    else
+		PORT_SetError(PR_IO_ERROR);
+	    IOError(rv, "wrapping-read");
+	    rv = PR_FALSE;
 	} else {
-	    /* Wasn't on disk, and we're still holding the lock, so write it. */
-	    cache->keyCacheData[ndx] = *wswk;
+	    rrv = write(SIDCacheFD, wswk, sizeof *wswk);
+	    if (rrv != sizeof *wswk) {
+		if (rrv == -1) 
+		    nss_MD_unix_map_read_error(errno);
+		else 
+		    PORT_SetError(PR_IO_ERROR);
+		IOError(rv, "wrapping-read");
+		rv = PR_FALSE;
+	    }
 	}
-	UnlockSidCacheLock(cache->keyCacheLock);
+#else /* XP_WIN32 */
+	/* Use memory mapped I/O and just memcpy() the data */
+	CopyMemory(&SIDCacheData[offset], wswk, sizeof *wswk);
+#endif /* XP_WIN32 */
     }
+    RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, offset, sizeof *wswk);
+    unlock_cache();
     return rv;
 }
 
-#else  /* MAC version or other platform */
+
+#endif /* NADA_VERISON */
+#else
 
 #include "seccomon.h"
 #include "cert.h"
 #include "ssl.h"
 #include "sslimpl.h"
 
 SECStatus
 SSL_ConfigServerSessionIDCache(	int      maxCacheEntries, 
-				PRUint32 ssl2_timeout,
+				PRUint32 timeout,
 			       	PRUint32 ssl3_timeout, 
 			  const char *   directory)
 {
-    PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigServerSessionIDCache)");    
+    PR_ASSERT(!"SSL servers are not supported on the platform. (SSL_ConfigServerSessionIDCache)");    
     return SECFailure;
 }
 
 SECStatus
 SSL_ConfigMPServerSIDCache(	int      maxCacheEntries, 
-				PRUint32 ssl2_timeout,
+				PRUint32 timeout,
 			       	PRUint32 ssl3_timeout, 
 		          const char *   directory)
 {
-    PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigMPServerSIDCache)");    
+    PR_ASSERT(!"SSL servers are not supported on the platform. (SSL_ConfigMPServerSIDCache)");    
     return SECFailure;
 }
 
 SECStatus
 SSL_InheritMPServerSIDCache(const char * envString)
 {
-    PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_InheritMPServerSIDCache)");    
+    PR_ASSERT(!"SSL servers are not supported on the platform. (SSL_InheritMPServerSIDCache)");    
     return SECFailure;
 }
 
 PRBool
 ssl_GetWrappingKey( PRInt32                   symWrapMechIndex,
                     SSL3KEAType               exchKeyType, 
 		    SSLWrappedSymWrappingKey *wswk)
 {
     PRBool rv = PR_FALSE;
-    PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_GetWrappingKey)");    
+    PR_ASSERT(!"SSL servers are not supported on the platform. (ssl_GetWrappingKey)");    
     return rv;
 }
 
 /* This is a kind of test-and-set.  The caller passes in the new value it wants
  * to set.  This code tests the wrapped sym key entry in the file on disk.  
  * If it is uninitialized, this function writes the caller's value into 
  * the disk entry, and returns false.  
  * Otherwise, it overwrites the caller's wswk with the value obtained from 
  * the disk, and returns PR_TRUE.  
- * This is all done while holding the locks/mutexes necessary to make 
+ * This is all done while holding the locks/semaphores necessary to make 
  * the operation atomic.
  */
 PRBool
 ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
 {
     PRBool        rv = PR_FALSE;
-    PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_SetWrappingKey)");
+    PR_ASSERT(!"SSL servers are not supported on the platform. (ssl_SetWrappingKey)");
     return rv;
 }
 
 #endif /* XP_UNIX || XP_WIN32 */
--- a/security/nss/lib/util/mac_rand.c
+++ b/security/nss/lib/util/mac_rand.c
@@ -39,16 +39,17 @@
 #include "mcom_db.h"
 #ifdef XP_MAC
 #include <Events.h>
 #include <OSUtils.h>
 #include <QDOffscreen.h>
 #include <PPCToolbox.h>
 #include <Processes.h>
 #include <LowMem.h>
+#include <Scrap.h>
 
 /* Static prototypes */
 static size_t CopyLowBits(void *dst, size_t dstlen, void *src, size_t srclen);
 void FE_ReadScreen();
 
 static size_t CopyLowBits(void *dst, size_t dstlen, void *src, size_t srclen)
 {
     union endianness {
@@ -68,18 +69,19 @@ static size_t CopyLowBits(void *dst, siz
         /* little-endian case */
         memcpy(dst, src, dstlen);
     }
     return dstlen;
 }
 
 size_t RNG_GetNoise(void *buf, size_t maxbytes)
 {
-    uint32 c = TickCount();
-    return CopyLowBits(buf, maxbytes,  &c, sizeof(c));
+    UnsignedWide microTickCount;
+    Microseconds(&microTickCount);
+    return CopyLowBits(buf, maxbytes,  &microTickCount, sizeof(microTickCount));
 }
 
 void RNG_FileForRNG(char *filename)
 {   
     unsigned char buffer[BUFSIZ];
     size_t bytes;
 #ifdef notdef /*sigh*/
     XP_File file;
@@ -120,24 +122,26 @@ void RNG_SystemInfoForRNG()
 	    RNG_RandomUpdate(&sec, bytes);
     }
 /* User specific variables */
 	{
 		MachineLocation loc;
 		ReadLocation(&loc);
 		RNG_RandomUpdate( &loc, sizeof(loc));
 	}
+#if !TARGET_CARBON
 /* User name */
 	{
 		unsigned long userRef;
 		Str32 userName;
 		GetDefaultUser(&userRef, userName);
 		RNG_RandomUpdate( &userRef, sizeof(userRef));
 		RNG_RandomUpdate( userName, sizeof(userName));
 	}
+#endif
 /* Mouse location */
 	{
 		Point mouseLoc;
 		GetMouse(&mouseLoc);
 		RNG_RandomUpdate( &mouseLoc, sizeof(mouseLoc));
 	}
 /* Keyboard time threshold */
 	{
@@ -150,21 +154,23 @@ void RNG_SystemInfoForRNG()
 		keyLast = LMGetKbdLast();
 		RNG_RandomUpdate( &keyLast, sizeof(keyLast));
 	}
 /* Volume */
 	{
 		UInt8 volume = LMGetSdVolume();
 		RNG_RandomUpdate( &volume, sizeof(volume));
 	}
+#if !TARGET_CARBON
 /* Current directory */
 	{
 		SInt32 dir = LMGetCurDirStore();
 		RNG_RandomUpdate( &dir, sizeof(dir));
 	}
+#endif
 /* Process information about all the processes in the machine */
 	{
 		ProcessSerialNumber 	process;
 		ProcessInfoRec pi;
 	
 		process.highLongOfPSN = process.lowLongOfPSN  = kNoProcess;
 		
 		while (GetNextProcess(&process) == noErr)
@@ -174,56 +180,85 @@ void RNG_SystemInfoForRNG()
 			pi.processName = NULL;
 			pi.processAppSpec = &fileSpec;
 			GetProcessInformation(&process, &pi);
 			RNG_RandomUpdate( &pi, sizeof(pi));
 			RNG_RandomUpdate( &fileSpec, sizeof(fileSpec));
 		}
 	}
 	
+#if !TARGET_CARBON
 /* Heap */
 	{
 		THz zone = LMGetTheZone();
 		RNG_RandomUpdate( &zone, sizeof(zone));
 	}
+#endif
 	
 /* Screen */
 	{
-		GDHandle h = LMGetMainDevice();		/* GDHandle is **GDevice */
+		GDHandle h = GetMainDevice();		/* GDHandle is **GDevice */
 		RNG_RandomUpdate( *h, sizeof(GDevice));
 	}
+
+#if !TARGET_CARBON
 /* Scrap size */
 	{
 		SInt32 scrapSize = LMGetScrapSize();
 		RNG_RandomUpdate( &scrapSize, sizeof(scrapSize));
 	}
 /* Scrap count */
 	{
 		SInt16 scrapCount = LMGetScrapCount();
 		RNG_RandomUpdate( &scrapCount, sizeof(scrapCount));
 	}
+#else
+	{
+	    ScrapRef scrap;
+        if (GetCurrentScrap(&scrap) == noErr) {
+            UInt32 flavorCount;
+            if (GetScrapFlavorCount(scrap, &flavorCount) == noErr) {
+                ScrapFlavorInfo* flavorInfo = (ScrapFlavorInfo*) malloc(flavorCount * sizeof(ScrapFlavorInfo));
+                if (flavorInfo != NULL) {
+                    if (GetScrapFlavorInfoList(scrap, &flavorCount, flavorInfo) == noErr) {
+                        UInt32 i;
+                        RNG_RandomUpdate(&flavorCount, sizeof(flavorCount));
+                        for (i = 0; i < flavorCount; ++i) {
+                            Size flavorSize;
+                            if (GetScrapFlavorSize(scrap, flavorInfo[i].flavorType, &flavorSize) == noErr)
+                                RNG_RandomUpdate(&flavorSize, sizeof(flavorSize));
+                        }
+                    }
+                    free(flavorInfo);
+                }
+            }
+        }
+    }
+#endif
 /*  File stuff, last modified, etc. */
 	{
 		HParamBlockRec			pb;
 		GetVolParmsInfoBuffer	volInfo;
 		pb.ioParam.ioVRefNum = 0;
 		pb.ioParam.ioNamePtr = nil;
 		pb.ioParam.ioBuffer = (Ptr) &volInfo;
 		pb.ioParam.ioReqCount = sizeof(volInfo);
 		PBHGetVolParmsSync(&pb);
 		RNG_RandomUpdate( &volInfo, sizeof(volInfo));
 	}
+#if !TARGET_CARBON
 /* Event queue */
 	{
 		EvQElPtr		eventQ;
 		for (eventQ = (EvQElPtr) LMGetEventQueue()->qHead; 
 				eventQ; 
 				eventQ = (EvQElPtr)eventQ->qLink)
 			RNG_RandomUpdate( &eventQ->evtQWhat, sizeof(EventRecord));
 	}
+#endif
 	FE_ReadScreen();
 	RNG_FileForRNG(NULL);
 }
 
 void FE_ReadScreen()
 {
 	UInt16				coords[4];
 	PixMapHandle 		pmap;
--- a/security/nss/manifest.mn
+++ b/security/nss/manifest.mn
@@ -28,17 +28,17 @@
 # replace them with the notice and other provisions required by
 # the GPL.  If you do not delete the provisions above, a recipient
 # may use your version of this file under either the MPL or the
 # GPL.
 #
 CORE_DEPTH = ..
 DEPTH      = ..
 
-IMPORTS =	nspr20/v4.1.1 \
+IMPORTS =	nspr20/v4.1.2 \
 		dbm/DBM_1_55_RTM \
 		$(NULL)
 
 RELEASE = security
 
 DIRS = lib cmd
 
 
--- a/security/nss/tests/ssl/sslauth.txt
+++ b/security/nss/tests/ssl/sslauth.txt
@@ -5,17 +5,17 @@
 #  return  server     client                         Test Case name
 #   value  params     params
 #  ------  ------     ------                         ---------------
      0       -r       -w_nss                 TLS Request don't require client auth (client does not provide auth)
      0       -r  -w_bogus_-n_TestUser     TLS Request don't require client auth (bad password)
      0       -r   -w_nss_-n_TestUser      TLS Request don't require client auth (client auth)
      0     -r_-r       -w_nss                TLS Require client auth (client does not provide auth)
 # this one should fail
-     2     -r_-r -w_bogus_-n_TestUser     TLS Require client auth (bad password)
+    254    -r_-r -w_bogus_-n_TestUser     TLS Require client auth (bad password)
      0     -r_-r  -w_nss_-n_TestUser_      TLS Require client auth (client auth)
      0       -r       -T_-w_nss             SSL3 Request don't require client auth (client does not provide auth)
      0       -r  -T_-n_TestUser_-w_bogus SSL3 Request don't require client auth (bad password)
      0       -r   -T_-n_TestUser_-w_nss  SSL3 Request don't require client auth (client auth)
      0     -r_-r       -T_-w_nss            SSL3 Require client auth (client does not provide auth)
 # this one should fail
-     2     -r_-r -T_-n_TestUser_-w_bogus SSL3 Require client auth (bad password)
+    254    -r_-r -T_-n_TestUser_-w_bogus SSL3 Require client auth (bad password)
      0     -r_-r  -T_-n_TestUser_-w_nss  SSL3 Require client auth (client auth)