Home | History | Annotate | Download | only in ssl
      1 /* This file implements the SERVER Session ID cache.
      2  * NOTE:  The contents of this file are NOT used by the client.
      3  *
      4  * This Source Code Form is subject to the terms of the Mozilla Public
      5  * License, v. 2.0. If a copy of the MPL was not distributed with this
      6  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      7 
      8 /* Note: ssl_FreeSID() in sslnonce.c gets used for both client and server
      9  * cache sids!
     10  *
     11  * About record locking among different server processes:
     12  *
     13  * All processes that are part of the same conceptual server (serving on
     14  * the same address and port) MUST share a common SSL session cache.
     15  * This code makes the content of the shared cache accessible to all
     16  * processes on the same "server".  This code works on Unix and Win32 only.
     17  *
     18  * We use NSPR anonymous shared memory and move data to & from shared memory.
     19  * We must do explicit locking of the records for all reads and writes.
     20  * The set of Cache entries are divided up into "sets" of 128 entries.
     21  * Each set is protected by a lock.  There may be one or more sets protected
     22  * by each lock.  That is, locks to sets are 1:N.
     23  * There is one lock for the entire cert cache.
     24  * There is one lock for the set of wrapped sym wrap keys.
     25  *
     26  * The anonymous shared memory is laid out as if it were declared like this:
     27  *
     28  * struct {
     29  *     cacheDescriptor          desc;
     30  *     sidCacheLock             sidCacheLocks[ numSIDCacheLocks];
     31  *     sidCacheLock             keyCacheLock;
     32  *     sidCacheLock             certCacheLock;
     33  *     sidCacheSet              sidCacheSets[ numSIDCacheSets ];
     34  *     sidCacheEntry            sidCacheData[ numSIDCacheEntries];
     35  *     certCacheEntry           certCacheData[numCertCacheEntries];
     36  *     SSLWrappedSymWrappingKey keyCacheData[kt_kea_size][SSL_NUM_WRAP_MECHS];
     37  *     PRUint8                  keyNameSuffix[SESS_TICKET_KEY_VAR_NAME_LEN]
     38  *     encKeyCacheEntry         ticketEncKey; // Wrapped in non-bypass mode
     39  *     encKeyCacheEntry         ticketMacKey; // Wrapped in non-bypass mode
     40  *     PRBool                   ticketKeysValid;
     41  *     sidCacheLock             srvNameCacheLock;
     42  *     srvNameCacheEntry        srvNameData[ numSrvNameCacheEntries ];
     43  * } cacheMemCacheData;
     44  */
     45 #include "seccomon.h"
     46 
     47 #if defined(XP_UNIX) || defined(XP_WIN32) || defined (XP_OS2) || defined(XP_BEOS)
     48 
     49 #include "cert.h"
     50 #include "ssl.h"
     51 #include "sslimpl.h"
     52 #include "sslproto.h"
     53 #include "pk11func.h"
     54 #include "base64.h"
     55 #include "keyhi.h"
     56 #ifdef NO_PKCS11_BYPASS
     57 #include "blapit.h"
     58 #include "sechash.h"
     59 #else
     60 #include "blapi.h"
     61 #endif
     62 
     63 #include <stdio.h>
     64 
     65 #if defined(XP_UNIX) || defined(XP_BEOS)
     66 
     67 #include <syslog.h>
     68 #include <fcntl.h>
     69 #include <unistd.h>
     70 #include <errno.h>
     71 #include <signal.h>
     72 #include "unix_err.h"
     73 
     74 #else
     75 
     76 #ifdef XP_WIN32
     77 #include <wtypes.h>
     78 #include "win32err.h"
     79 #endif
     80 
     81 #endif
     82 #include <sys/types.h>
     83 
     84 #define SET_ERROR_CODE /* reminder */
     85 
     86 #include "nspr.h"
     87 #include "sslmutex.h"
     88 
     89 /*
     90 ** Format of a cache entry in the shared memory.
     91 */
     92 struct sidCacheEntryStr {
     93 /* 16 */    PRIPv6Addr  addr;	/* client's IP address */
     94 /*  4 */    PRUint32    creationTime;
     95 /*  4 */    PRUint32    lastAccessTime;
     96 /*  4 */    PRUint32    expirationTime;
     97 /*  2 */    PRUint16	version;
     98 /*  1 */    PRUint8	valid;
     99 /*  1 */    PRUint8     sessionIDLength;
    100 /* 32 */    PRUint8     sessionID[SSL3_SESSIONID_BYTES];
    101 /*  2 */    PRUint16    authAlgorithm;
    102 /*  2 */    PRUint16    authKeyBits;
    103 /*  2 */    PRUint16    keaType;
    104 /*  2 */    PRUint16    keaKeyBits;
    105 /* 72  - common header total */
    106 
    107     union {
    108 	struct {
    109 /* 64 */    PRUint8	masterKey[SSL_MAX_MASTER_KEY_BYTES];
    110 /* 32 */    PRUint8	cipherArg[SSL_MAX_CYPHER_ARG_BYTES];
    111 
    112 /*  1 */    PRUint8	cipherType;
    113 /*  1 */    PRUint8	masterKeyLen;
    114 /*  1 */    PRUint8	keyBits;
    115 /*  1 */    PRUint8	secretKeyBits;
    116 /*  1 */    PRUint8	cipherArgLen;
    117 /*101 */} ssl2;
    118 
    119 	struct {
    120 /*  2 */    ssl3CipherSuite  cipherSuite;
    121 /*  2 */    PRUint16    compression; 	/* SSLCompressionMethod */
    122 
    123 /* 52 */    ssl3SidKeys keys;	/* keys, wrapped as needed. */
    124 
    125 /*  4 */    PRUint32    masterWrapMech;
    126 /*  4 */    SSL3KEAType exchKeyType;
    127 /*  4 */    PRInt32     certIndex;
    128 /*  4 */    PRInt32     srvNameIndex;
    129 /* 32 */    PRUint8     srvNameHash[SHA256_LENGTH]; /* SHA256 name hash */
    130 /*104 */} ssl3;
    131 /* force sizeof(sidCacheEntry) to be a multiple of cache line size */
    132         struct {
    133 /*120 */    PRUint8     filler[120]; /* 72+120==192, a multiple of 16 */
    134 	} forceSize;
    135     } u;
    136 };
    137 typedef struct sidCacheEntryStr sidCacheEntry;
    138 
    139 /* The length of this struct is supposed to be a power of 2, e.g. 4KB */
    140 struct certCacheEntryStr {
    141     PRUint16    certLength;				/*    2 */
    142     PRUint16    sessionIDLength;			/*    2 */
    143     PRUint8 	sessionID[SSL3_SESSIONID_BYTES];	/*   32 */
    144     PRUint8 	cert[SSL_MAX_CACHED_CERT_LEN];		/* 4060 */
    145 };						/* total   4096 */
    146 typedef struct certCacheEntryStr certCacheEntry;
    147 
    148 struct sidCacheLockStr {
    149     PRUint32	timeStamp;
    150     sslMutex	mutex;
    151     sslPID	pid;
    152 };
    153 typedef struct sidCacheLockStr sidCacheLock;
    154 
    155 struct sidCacheSetStr {
    156     PRIntn	next;
    157 };
    158 typedef struct sidCacheSetStr sidCacheSet;
    159 
    160 struct encKeyCacheEntryStr {
    161     PRUint8	bytes[512];
    162     PRInt32	length;
    163 };
    164 typedef struct encKeyCacheEntryStr encKeyCacheEntry;
    165 
    166 #define SSL_MAX_DNS_HOST_NAME  1024
    167 
    168 struct srvNameCacheEntryStr {
    169     PRUint16    type;                                   /*    2 */
    170     PRUint16    nameLen;                                /*    2 */
    171     PRUint8	name[SSL_MAX_DNS_HOST_NAME + 12];       /* 1034 */
    172     PRUint8 	nameHash[SHA256_LENGTH];                /*   32 */
    173                                                         /* 1072 */
    174 };
    175 typedef struct srvNameCacheEntryStr srvNameCacheEntry;
    176 
    177 
    178 struct cacheDescStr {
    179 
    180     PRUint32            cacheMemSize;
    181 
    182     PRUint32		numSIDCacheLocks;
    183     PRUint32		numSIDCacheSets;
    184     PRUint32		numSIDCacheSetsPerLock;
    185 
    186     PRUint32            numSIDCacheEntries;
    187     PRUint32            sidCacheSize;
    188 
    189     PRUint32            numCertCacheEntries;
    190     PRUint32            certCacheSize;
    191 
    192     PRUint32            numKeyCacheEntries;
    193     PRUint32            keyCacheSize;
    194 
    195     PRUint32            numSrvNameCacheEntries;
    196     PRUint32            srvNameCacheSize;
    197 
    198     PRUint32		ssl2Timeout;
    199     PRUint32		ssl3Timeout;
    200 
    201     PRUint32            numSIDCacheLocksInitialized;
    202 
    203     /* These values are volatile, and are accessed through sharedCache-> */
    204     PRUint32		nextCertCacheEntry;	/* certCacheLock protects */
    205     PRBool      	stopPolling;
    206     PRBool		everInherited;
    207 
    208     /* The private copies of these values are pointers into shared mem */
    209     /* The copies of these values in shared memory are merely offsets */
    210     sidCacheLock    *          sidCacheLocks;
    211     sidCacheLock    *          keyCacheLock;
    212     sidCacheLock    *          certCacheLock;
    213     sidCacheLock    *          srvNameCacheLock;
    214     sidCacheSet     *          sidCacheSets;
    215     sidCacheEntry   *          sidCacheData;
    216     certCacheEntry  *          certCacheData;
    217     SSLWrappedSymWrappingKey * keyCacheData;
    218     PRUint8         *          ticketKeyNameSuffix;
    219     encKeyCacheEntry         * ticketEncKey;
    220     encKeyCacheEntry         * ticketMacKey;
    221     PRUint32        *          ticketKeysValid;
    222     srvNameCacheEntry *        srvNameCacheData;
    223 
    224     /* Only the private copies of these pointers are valid */
    225     char *                     cacheMem;
    226     struct cacheDescStr *      sharedCache;  /* shared copy of this struct */
    227     PRFileMap *                cacheMemMap;
    228     PRThread  *                poller;
    229     PRUint32                   mutexTimeout;
    230     PRBool                     shared;
    231 };
    232 typedef struct cacheDescStr cacheDesc;
    233 
    234 static cacheDesc globalCache;
    235 
    236 static const char envVarName[] = { SSL_ENV_VAR_NAME };
    237 
    238 static PRBool isMultiProcess  = PR_FALSE;
    239 
    240 
    241 #define DEF_SID_CACHE_ENTRIES  10000
    242 #define DEF_CERT_CACHE_ENTRIES 250
    243 #define MIN_CERT_CACHE_ENTRIES 125 /* the effective size in old releases. */
    244 #define DEF_KEY_CACHE_ENTRIES  250
    245 #define DEF_NAME_CACHE_ENTRIES  1000
    246 
    247 #define SID_CACHE_ENTRIES_PER_SET  128
    248 #define SID_ALIGNMENT          16
    249 
    250 #define DEF_SSL2_TIMEOUT	100   /* seconds */
    251 #define MAX_SSL2_TIMEOUT	100   /* seconds */
    252 #define MIN_SSL2_TIMEOUT	  5   /* seconds */
    253 
    254 #define DEF_SSL3_TIMEOUT      86400L  /* 24 hours */
    255 #define MAX_SSL3_TIMEOUT      86400L  /* 24 hours */
    256 #define MIN_SSL3_TIMEOUT          5   /* seconds  */
    257 
    258 #if defined(AIX) || defined(LINUX) || defined(NETBSD) || defined(OPENBSD)
    259 #define MAX_SID_CACHE_LOCKS 8	/* two FDs per lock */
    260 #elif defined(OSF1)
    261 #define MAX_SID_CACHE_LOCKS 16	/* one FD per lock */
    262 #else
    263 #define MAX_SID_CACHE_LOCKS 256
    264 #endif
    265 
    266 #define SID_HOWMANY(val, size) (((val) + ((size) - 1)) / (size))
    267 #define SID_ROUNDUP(val, size) ((size) * SID_HOWMANY((val), (size)))
    268 
    269 
    270 static sslPID myPid;
    271 static PRUint32  ssl_max_sid_cache_locks = MAX_SID_CACHE_LOCKS;
    272 
    273 /* forward static function declarations */
    274 static PRUint32 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s,
    275                          unsigned nl);
    276 static SECStatus LaunchLockPoller(cacheDesc *cache);
    277 static SECStatus StopLockPoller(cacheDesc *cache);
    278 
    279 
    280 struct inheritanceStr {
    281     PRUint32 cacheMemSize;
    282     PRUint32 fmStrLen;
    283 };
    284 
    285 typedef struct inheritanceStr inheritance;
    286 
    287 #if defined(_WIN32) || defined(XP_OS2)
    288 
    289 #define DEFAULT_CACHE_DIRECTORY "\\temp"
    290 
    291 #endif /* _win32 */
    292 
    293 #if defined(XP_UNIX) || defined(XP_BEOS)
    294 
    295 #define DEFAULT_CACHE_DIRECTORY "/tmp"
    296 
    297 #endif /* XP_UNIX || XP_BEOS */
    298 
    299 
    300 /************************************************************************/
    301 
    302 static PRUint32
    303 LockSidCacheLock(sidCacheLock *lock, PRUint32 now)
    304 {
    305     SECStatus      rv      = sslMutex_Lock(&lock->mutex);
    306     if (rv != SECSuccess)
    307     	return 0;
    308     if (!now)
    309 	now  = ssl_Time();
    310     lock->timeStamp = now;
    311     lock->pid       = myPid;
    312     return now;
    313 }
    314 
    315 static SECStatus
    316 UnlockSidCacheLock(sidCacheLock *lock)
    317 {
    318     SECStatus      rv;
    319 
    320     lock->pid = 0;
    321     rv        = sslMutex_Unlock(&lock->mutex);
    322     return rv;
    323 }
    324 
    325 /* returns the value of ssl_Time on success, zero on failure. */
    326 static PRUint32
    327 LockSet(cacheDesc *cache, PRUint32 set, PRUint32 now)
    328 {
    329     PRUint32       lockNum = set % cache->numSIDCacheLocks;
    330     sidCacheLock * lock    = cache->sidCacheLocks + lockNum;
    331 
    332     return LockSidCacheLock(lock, now);
    333 }
    334 
    335 static SECStatus
    336 UnlockSet(cacheDesc *cache, PRUint32 set)
    337 {
    338     PRUint32       lockNum = set % cache->numSIDCacheLocks;
    339     sidCacheLock * lock    = cache->sidCacheLocks + lockNum;
    340 
    341     return UnlockSidCacheLock(lock);
    342 }
    343 
    344 /************************************************************************/
    345 
    346 
    347 /* Put a certificate in the cache.  Update the cert index in the sce.
    348 */
    349 static PRUint32
    350 CacheCert(cacheDesc * cache, CERTCertificate *cert, sidCacheEntry *sce)
    351 {
    352     PRUint32        now;
    353     certCacheEntry  cce;
    354 
    355     if ((cert->derCert.len > SSL_MAX_CACHED_CERT_LEN) ||
    356         (cert->derCert.len <= 0) ||
    357 	(cert->derCert.data == NULL)) {
    358 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
    359 	return 0;
    360     }
    361 
    362     cce.sessionIDLength = sce->sessionIDLength;
    363     PORT_Memcpy(cce.sessionID, sce->sessionID, cce.sessionIDLength);
    364 
    365     cce.certLength = cert->derCert.len;
    366     PORT_Memcpy(cce.cert, cert->derCert.data, cce.certLength);
    367 
    368     /* get lock on cert cache */
    369     now = LockSidCacheLock(cache->certCacheLock, 0);
    370     if (now) {
    371 
    372 	/* Find where to place the next cert cache entry. */
    373 	cacheDesc * sharedCache = cache->sharedCache;
    374 	PRUint32    ndx         = sharedCache->nextCertCacheEntry;
    375 
    376 	/* write the entry */
    377 	cache->certCacheData[ndx] = cce;
    378 
    379 	/* remember where we put it. */
    380 	sce->u.ssl3.certIndex = ndx;
    381 
    382 	/* update the "next" cache entry index */
    383 	sharedCache->nextCertCacheEntry =
    384 					(ndx + 1) % cache->numCertCacheEntries;
    385 
    386 	UnlockSidCacheLock(cache->certCacheLock);
    387     }
    388     return now;
    389 
    390 }
    391 
    392 /* Server configuration hash tables need to account the SECITEM.type
    393  * field as well. These functions accomplish that. */
    394 static PLHashNumber
    395 Get32BitNameHash(const SECItem *name)
    396 {
    397     PLHashNumber rv = SECITEM_Hash(name);
    398 
    399     PRUint8 *rvc = (PRUint8 *)&rv;
    400     rvc[ name->len % sizeof(rv) ] ^= name->type;
    401 
    402     return rv;
    403 }
    404 
    405 /* Put a name in the cache.  Update the cert index in the sce.
    406 */
    407 static PRUint32
    408 CacheSrvName(cacheDesc * cache, SECItem *name, sidCacheEntry *sce)
    409 {
    410     PRUint32           now;
    411     PRUint32           ndx;
    412     srvNameCacheEntry  snce;
    413 
    414     if (!name || name->len <= 0 ||
    415         name->len > SSL_MAX_DNS_HOST_NAME) {
    416 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
    417 	return 0;
    418     }
    419 
    420     snce.type = name->type;
    421     snce.nameLen = name->len;
    422     PORT_Memcpy(snce.name, name->data, snce.nameLen);
    423 #ifdef NO_PKCS11_BYPASS
    424     HASH_HashBuf(HASH_AlgSHA256, snce.nameHash, name->data, name->len);
    425 #else
    426     SHA256_HashBuf(snce.nameHash, (unsigned char*)name->data,
    427                    name->len);
    428 #endif
    429     /* get index of the next name */
    430     ndx = Get32BitNameHash(name);
    431     /* get lock on cert cache */
    432     now = LockSidCacheLock(cache->srvNameCacheLock, 0);
    433     if (now) {
    434         if (cache->numSrvNameCacheEntries > 0) {
    435             /* Fit the index into array */
    436             ndx %= cache->numSrvNameCacheEntries;
    437             /* write the entry */
    438             cache->srvNameCacheData[ndx] = snce;
    439             /* remember where we put it. */
    440             sce->u.ssl3.srvNameIndex = ndx;
    441             /* Copy hash into sid hash */
    442             PORT_Memcpy(sce->u.ssl3.srvNameHash, snce.nameHash, SHA256_LENGTH);
    443         }
    444 	UnlockSidCacheLock(cache->srvNameCacheLock);
    445     }
    446     return now;
    447 }
    448 
    449 /*
    450 ** Convert local SID to shared memory one
    451 */
    452 static void
    453 ConvertFromSID(sidCacheEntry *to, sslSessionID *from)
    454 {
    455     to->valid   = 1;
    456     to->version = from->version;
    457     to->addr    = from->addr;
    458     to->creationTime    = from->creationTime;
    459     to->lastAccessTime  = from->lastAccessTime;
    460     to->expirationTime  = from->expirationTime;
    461     to->authAlgorithm	= from->authAlgorithm;
    462     to->authKeyBits	= from->authKeyBits;
    463     to->keaType		= from->keaType;
    464     to->keaKeyBits	= from->keaKeyBits;
    465 
    466     if (from->version < SSL_LIBRARY_VERSION_3_0) {
    467 	if ((from->u.ssl2.masterKey.len > SSL_MAX_MASTER_KEY_BYTES) ||
    468 	    (from->u.ssl2.cipherArg.len > SSL_MAX_CYPHER_ARG_BYTES)) {
    469 	    SSL_DBG(("%d: SSL: masterKeyLen=%d cipherArgLen=%d",
    470 		     myPid, from->u.ssl2.masterKey.len,
    471 		     from->u.ssl2.cipherArg.len));
    472 	    to->valid = 0;
    473 	    return;
    474 	}
    475 
    476 	to->u.ssl2.cipherType    = from->u.ssl2.cipherType;
    477 	to->u.ssl2.masterKeyLen  = from->u.ssl2.masterKey.len;
    478 	to->u.ssl2.cipherArgLen  = from->u.ssl2.cipherArg.len;
    479 	to->u.ssl2.keyBits       = from->u.ssl2.keyBits;
    480 	to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits;
    481 	to->sessionIDLength      = SSL2_SESSIONID_BYTES;
    482 	PORT_Memcpy(to->sessionID, from->u.ssl2.sessionID, SSL2_SESSIONID_BYTES);
    483 	PORT_Memcpy(to->u.ssl2.masterKey, from->u.ssl2.masterKey.data,
    484 		  from->u.ssl2.masterKey.len);
    485 	PORT_Memcpy(to->u.ssl2.cipherArg, from->u.ssl2.cipherArg.data,
    486 		  from->u.ssl2.cipherArg.len);
    487 #ifdef DEBUG
    488 	PORT_Memset(to->u.ssl2.masterKey+from->u.ssl2.masterKey.len, 0,
    489 		  sizeof(to->u.ssl2.masterKey) - from->u.ssl2.masterKey.len);
    490 	PORT_Memset(to->u.ssl2.cipherArg+from->u.ssl2.cipherArg.len, 0,
    491 		  sizeof(to->u.ssl2.cipherArg) - from->u.ssl2.cipherArg.len);
    492 #endif
    493 	SSL_TRC(8, ("%d: SSL: ConvertSID: masterKeyLen=%d cipherArgLen=%d "
    494 		    "time=%d addr=0x%08x%08x%08x%08x cipherType=%d", myPid,
    495 		    to->u.ssl2.masterKeyLen, to->u.ssl2.cipherArgLen,
    496 		    to->creationTime, to->addr.pr_s6_addr32[0],
    497 		    to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2],
    498 		    to->addr.pr_s6_addr32[3], to->u.ssl2.cipherType));
    499     } else {
    500 	/* This is an SSL v3 session */
    501 
    502 	to->u.ssl3.cipherSuite      = from->u.ssl3.cipherSuite;
    503 	to->u.ssl3.compression      = (PRUint16)from->u.ssl3.compression;
    504 	to->u.ssl3.keys             = from->u.ssl3.keys;
    505 	to->u.ssl3.masterWrapMech   = from->u.ssl3.masterWrapMech;
    506 	to->u.ssl3.exchKeyType      = from->u.ssl3.exchKeyType;
    507 	to->sessionIDLength         = from->u.ssl3.sessionIDLength;
    508 	to->u.ssl3.certIndex        = -1;
    509 	to->u.ssl3.srvNameIndex     = -1;
    510 
    511 	PORT_Memcpy(to->sessionID, from->u.ssl3.sessionID,
    512 		    to->sessionIDLength);
    513 
    514 	SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x "
    515 	            "cipherSuite=%d",
    516 		    myPid, to->creationTime, to->addr.pr_s6_addr32[0],
    517 		    to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2],
    518 		    to->addr.pr_s6_addr32[3], to->u.ssl3.cipherSuite));
    519     }
    520 }
    521 
    522 /*
    523 ** Convert shared memory cache-entry to local memory based one
    524 ** This is only called from ServerSessionIDLookup().
    525 ** Caller must hold cache lock when calling this.
    526 */
    527 static sslSessionID *
    528 ConvertToSID(sidCacheEntry *    from,
    529              certCacheEntry *   pcce,
    530              srvNameCacheEntry *psnce,
    531              CERTCertDBHandle * dbHandle)
    532 {
    533     sslSessionID *to;
    534     PRUint16 version = from->version;
    535 
    536     to = PORT_ZNew(sslSessionID);
    537     if (!to) {
    538 	return 0;
    539     }
    540 
    541     if (version < SSL_LIBRARY_VERSION_3_0) {
    542 	/* This is an SSL v2 session */
    543 	to->u.ssl2.masterKey.data =
    544 	    (unsigned char*) PORT_Alloc(from->u.ssl2.masterKeyLen);
    545 	if (!to->u.ssl2.masterKey.data) {
    546 	    goto loser;
    547 	}
    548 	if (from->u.ssl2.cipherArgLen) {
    549 	    to->u.ssl2.cipherArg.data =
    550 	    	(unsigned char*)PORT_Alloc(from->u.ssl2.cipherArgLen);
    551 	    if (!to->u.ssl2.cipherArg.data) {
    552 		goto loser;
    553 	    }
    554 	    PORT_Memcpy(to->u.ssl2.cipherArg.data, from->u.ssl2.cipherArg,
    555 		        from->u.ssl2.cipherArgLen);
    556 	}
    557 
    558 	to->u.ssl2.cipherType    = from->u.ssl2.cipherType;
    559 	to->u.ssl2.masterKey.len = from->u.ssl2.masterKeyLen;
    560 	to->u.ssl2.cipherArg.len = from->u.ssl2.cipherArgLen;
    561 	to->u.ssl2.keyBits       = from->u.ssl2.keyBits;
    562 	to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits;
    563 /*	to->sessionIDLength      = SSL2_SESSIONID_BYTES; */
    564 	PORT_Memcpy(to->u.ssl2.sessionID, from->sessionID, SSL2_SESSIONID_BYTES);
    565 	PORT_Memcpy(to->u.ssl2.masterKey.data, from->u.ssl2.masterKey,
    566 		    from->u.ssl2.masterKeyLen);
    567 
    568 	SSL_TRC(8, ("%d: SSL: ConvertToSID: masterKeyLen=%d cipherArgLen=%d "
    569 		    "time=%d addr=0x%08x%08x%08x%08x cipherType=%d",
    570 		    myPid, to->u.ssl2.masterKey.len,
    571 		    to->u.ssl2.cipherArg.len, to->creationTime,
    572 		    to->addr.pr_s6_addr32[0], to->addr.pr_s6_addr32[1],
    573 		    to->addr.pr_s6_addr32[2], to->addr.pr_s6_addr32[3],
    574 		    to->u.ssl2.cipherType));
    575     } else {
    576 	/* This is an SSL v3 session */
    577 
    578 	to->u.ssl3.sessionIDLength  = from->sessionIDLength;
    579 	to->u.ssl3.cipherSuite      = from->u.ssl3.cipherSuite;
    580 	to->u.ssl3.compression      = (SSLCompressionMethod)from->u.ssl3.compression;
    581 	to->u.ssl3.keys             = from->u.ssl3.keys;
    582 	to->u.ssl3.masterWrapMech   = from->u.ssl3.masterWrapMech;
    583 	to->u.ssl3.exchKeyType      = from->u.ssl3.exchKeyType;
    584 	if (from->u.ssl3.srvNameIndex != -1 && psnce) {
    585             SECItem name;
    586             SECStatus rv;
    587             name.type                   = psnce->type;
    588             name.len                    = psnce->nameLen;
    589             name.data                   = psnce->name;
    590             rv = SECITEM_CopyItem(NULL, &to->u.ssl3.srvName, &name);
    591             if (rv != SECSuccess) {
    592                 goto loser;
    593             }
    594         }
    595 
    596 	PORT_Memcpy(to->u.ssl3.sessionID, from->sessionID, from->sessionIDLength);
    597 
    598 	/* the portions of the SID that are only restored on the client
    599 	 * are set to invalid values on the server.
    600 	 */
    601 	to->u.ssl3.clientWriteKey   = NULL;
    602 	to->u.ssl3.serverWriteKey   = NULL;
    603 
    604 	to->urlSvrName              = NULL;
    605 
    606 	to->u.ssl3.masterModuleID   = (SECMODModuleID)-1; /* invalid value */
    607 	to->u.ssl3.masterSlotID     = (CK_SLOT_ID)-1;     /* invalid value */
    608 	to->u.ssl3.masterWrapIndex  = 0;
    609 	to->u.ssl3.masterWrapSeries = 0;
    610 	to->u.ssl3.masterValid      = PR_FALSE;
    611 
    612 	to->u.ssl3.clAuthModuleID   = (SECMODModuleID)-1; /* invalid value */
    613 	to->u.ssl3.clAuthSlotID     = (CK_SLOT_ID)-1;     /* invalid value */
    614 	to->u.ssl3.clAuthSeries     = 0;
    615 	to->u.ssl3.clAuthValid      = PR_FALSE;
    616 
    617 	if (from->u.ssl3.certIndex != -1 && pcce) {
    618 	    SECItem          derCert;
    619 
    620 	    derCert.len  = pcce->certLength;
    621 	    derCert.data = pcce->cert;
    622 
    623 	    to->peerCert = CERT_NewTempCertificate(dbHandle, &derCert, NULL,
    624 					           PR_FALSE, PR_TRUE);
    625 	    if (to->peerCert == NULL)
    626 		goto loser;
    627 	}
    628     }
    629 
    630     to->version         = from->version;
    631     to->creationTime    = from->creationTime;
    632     to->lastAccessTime  = from->lastAccessTime;
    633     to->expirationTime  = from->expirationTime;
    634     to->cached          = in_server_cache;
    635     to->addr            = from->addr;
    636     to->references      = 1;
    637     to->authAlgorithm	= from->authAlgorithm;
    638     to->authKeyBits	= from->authKeyBits;
    639     to->keaType		= from->keaType;
    640     to->keaKeyBits	= from->keaKeyBits;
    641 
    642     return to;
    643 
    644   loser:
    645     if (to) {
    646 	if (version < SSL_LIBRARY_VERSION_3_0) {
    647 	    if (to->u.ssl2.masterKey.data)
    648 		PORT_Free(to->u.ssl2.masterKey.data);
    649 	    if (to->u.ssl2.cipherArg.data)
    650 		PORT_Free(to->u.ssl2.cipherArg.data);
    651 	} else {
    652             SECITEM_FreeItem(&to->u.ssl3.srvName, PR_FALSE);
    653         }
    654 	PORT_Free(to);
    655     }
    656     return NULL;
    657 }
    658 
    659 
    660 
    661 /*
    662 ** Perform some mumbo jumbo on the ip-address and the session-id value to
    663 ** compute a hash value.
    664 */
    665 static PRUint32
    666 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, unsigned nl)
    667 {
    668     PRUint32 rv;
    669     PRUint32 x[8];
    670 
    671     memset(x, 0, sizeof x);
    672     if (nl > sizeof x)
    673     	nl = sizeof x;
    674     memcpy(x, s, nl);
    675 
    676     rv = (addr->pr_s6_addr32[0] ^ addr->pr_s6_addr32[1] ^
    677 	  addr->pr_s6_addr32[2] ^ addr->pr_s6_addr32[3] ^
    678           x[0] ^ x[1] ^ x[2] ^ x[3] ^ x[4] ^ x[5] ^ x[6] ^ x[7])
    679 	  % cache->numSIDCacheSets;
    680     return rv;
    681 }
    682 
    683 
    684 
    685 /*
    686 ** Look something up in the cache. This will invalidate old entries
    687 ** in the process. Caller has locked the cache set!
    688 ** Returns PR_TRUE if found a valid match.  PR_FALSE otherwise.
    689 */
    690 static sidCacheEntry *
    691 FindSID(cacheDesc *cache, PRUint32 setNum, PRUint32 now,
    692         const PRIPv6Addr *addr, unsigned char *sessionID,
    693 	unsigned sessionIDLength)
    694 {
    695     PRUint32      ndx   = cache->sidCacheSets[setNum].next;
    696     int           i;
    697 
    698     sidCacheEntry * set = cache->sidCacheData +
    699     			 (setNum * SID_CACHE_ENTRIES_PER_SET);
    700 
    701     for (i = SID_CACHE_ENTRIES_PER_SET; i > 0; --i) {
    702 	sidCacheEntry * sce;
    703 
    704 	ndx  = (ndx - 1) % SID_CACHE_ENTRIES_PER_SET;
    705 	sce = set + ndx;
    706 
    707 	if (!sce->valid)
    708 	    continue;
    709 
    710 	if (now > sce->expirationTime) {
    711 	    /* SessionID has timed out. Invalidate the entry. */
    712 	    SSL_TRC(7, ("%d: timed out sid entry addr=%08x%08x%08x%08x now=%x "
    713 			"time+=%x",
    714 			myPid, sce->addr.pr_s6_addr32[0],
    715 			sce->addr.pr_s6_addr32[1], sce->addr.pr_s6_addr32[2],
    716 			sce->addr.pr_s6_addr32[3], now,
    717 			sce->expirationTime ));
    718 	    sce->valid = 0;
    719 	    continue;
    720 	}
    721 
    722 	/*
    723 	** Next, examine specific session-id/addr data to see if the cache
    724 	** entry matches our addr+session-id value
    725 	*/
    726 	if (sessionIDLength == sce->sessionIDLength      &&
    727 	    !memcmp(&sce->addr, addr, sizeof(PRIPv6Addr)) &&
    728 	    !memcmp(sce->sessionID, sessionID, sessionIDLength)) {
    729 	    /* Found it */
    730 	    return sce;
    731 	}
    732     }
    733 
    734     PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND);
    735     return NULL;
    736 }
    737 
    738 /************************************************************************/
    739 
    740 /* This is the primary function for finding entries in the server's sid cache.
    741  * Although it is static, this function is called via the global function
    742  * pointer ssl_sid_lookup.
    743  */
    744 static sslSessionID *
    745 ServerSessionIDLookup(const PRIPv6Addr *addr,
    746 			unsigned char *sessionID,
    747 			unsigned int   sessionIDLength,
    748                         CERTCertDBHandle * dbHandle)
    749 {
    750     sslSessionID *  sid      = 0;
    751     sidCacheEntry * psce;
    752     certCacheEntry *pcce     = 0;
    753     srvNameCacheEntry *psnce = 0;
    754     cacheDesc *     cache    = &globalCache;
    755     PRUint32        now;
    756     PRUint32        set;
    757     PRInt32         cndx;
    758     sidCacheEntry   sce;
    759     certCacheEntry  cce;
    760     srvNameCacheEntry snce;
    761 
    762     set = SIDindex(cache, addr, sessionID, sessionIDLength);
    763     now = LockSet(cache, set, 0);
    764     if (!now)
    765     	return NULL;
    766 
    767     psce = FindSID(cache, set, now, addr, sessionID, sessionIDLength);
    768     if (psce) {
    769 	if (psce->version >= SSL_LIBRARY_VERSION_3_0) {
    770 	    if ((cndx = psce->u.ssl3.certIndex) != -1) {
    771 
    772                 PRUint32 gotLock = LockSidCacheLock(cache->certCacheLock, now);
    773                 if (gotLock) {
    774                     pcce = &cache->certCacheData[cndx];
    775 
    776                     /* See if the cert's session ID matches the sce cache. */
    777                     if ((pcce->sessionIDLength == psce->sessionIDLength) &&
    778                         !PORT_Memcmp(pcce->sessionID, psce->sessionID,
    779                                      pcce->sessionIDLength)) {
    780                         cce = *pcce;
    781                     } else {
    782                         /* The cert doesen't match the SID cache entry,
    783                         ** so invalidate the SID cache entry.
    784                         */
    785                         psce->valid = 0;
    786                         psce = 0;
    787                         pcce = 0;
    788                     }
    789                     UnlockSidCacheLock(cache->certCacheLock);
    790                 } else {
    791                     /* what the ??.  Didn't get the cert cache lock.
    792                     ** Don't invalidate the SID cache entry, but don't find it.
    793                     */
    794                     PORT_Assert(!("Didn't get cert Cache Lock!"));
    795                     psce = 0;
    796                     pcce = 0;
    797                 }
    798             }
    799             if (psce && ((cndx = psce->u.ssl3.srvNameIndex) != -1)) {
    800                 PRUint32 gotLock = LockSidCacheLock(cache->srvNameCacheLock,
    801                                                     now);
    802                 if (gotLock) {
    803                     psnce = &cache->srvNameCacheData[cndx];
    804 
    805                     if (!PORT_Memcmp(psnce->nameHash, psce->u.ssl3.srvNameHash,
    806                                      SHA256_LENGTH)) {
    807                         snce = *psnce;
    808                     } else {
    809                         /* The name doesen't match the SID cache entry,
    810                         ** so invalidate the SID cache entry.
    811                         */
    812                         psce->valid = 0;
    813                         psce = 0;
    814                         psnce = 0;
    815                     }
    816                     UnlockSidCacheLock(cache->srvNameCacheLock);
    817                 } else {
    818                     /* what the ??.  Didn't get the cert cache lock.
    819                     ** Don't invalidate the SID cache entry, but don't find it.
    820                     */
    821                     PORT_Assert(!("Didn't get name Cache Lock!"));
    822                     psce = 0;
    823                     psnce = 0;
    824                 }
    825 
    826             }
    827         }
    828 	if (psce) {
    829 	    psce->lastAccessTime = now;
    830 	    sce = *psce;	/* grab a copy while holding the lock */
    831     	}
    832     }
    833     UnlockSet(cache, set);
    834     if (psce) {
    835 	/* sce conains a copy of the cache entry.
    836 	** Convert shared memory format to local format
    837 	*/
    838 	sid = ConvertToSID(&sce, pcce ? &cce : 0, psnce ? &snce : 0, dbHandle);
    839     }
    840     return sid;
    841 }
    842 
    843 /*
    844 ** Place a sid into the cache, if it isn't already there.
    845 */
    846 static void
    847 ServerSessionIDCache(sslSessionID *sid)
    848 {
    849     sidCacheEntry sce;
    850     PRUint32      now     = 0;
    851     PRUint16      version = sid->version;
    852     cacheDesc *   cache   = &globalCache;
    853 
    854     if ((version >= SSL_LIBRARY_VERSION_3_0) &&
    855 	(sid->u.ssl3.sessionIDLength == 0)) {
    856 	return;
    857     }
    858 
    859     if (sid->cached == never_cached || sid->cached == invalid_cache) {
    860 	PRUint32 set;
    861 
    862 	PORT_Assert(sid->creationTime != 0);
    863 	if (!sid->creationTime)
    864 	    sid->lastAccessTime = sid->creationTime = ssl_Time();
    865 	if (version < SSL_LIBRARY_VERSION_3_0) {
    866 	    /* override caller's expiration time, which uses client timeout
    867 	     * duration, not server timeout duration.
    868 	     */
    869 	    sid->expirationTime = sid->creationTime + cache->ssl2Timeout;
    870 	    SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
    871 			"cipher=%d", myPid, sid->cached,
    872 			sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
    873 			sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
    874 			sid->creationTime, sid->u.ssl2.cipherType));
    875 	    PRINT_BUF(8, (0, "sessionID:", sid->u.ssl2.sessionID,
    876 			  SSL2_SESSIONID_BYTES));
    877 	    PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data,
    878 			  sid->u.ssl2.masterKey.len));
    879 	    PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data,
    880 			  sid->u.ssl2.cipherArg.len));
    881 
    882 	} else {
    883 	    /* override caller's expiration time, which uses client timeout
    884 	     * duration, not server timeout duration.
    885 	     */
    886 	    sid->expirationTime = sid->creationTime + cache->ssl3Timeout;
    887 	    SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
    888 			"cipherSuite=%d", myPid, sid->cached,
    889 			sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
    890 			sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
    891 			sid->creationTime, sid->u.ssl3.cipherSuite));
    892 	    PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID,
    893 			  sid->u.ssl3.sessionIDLength));
    894 	}
    895 
    896 	ConvertFromSID(&sce, sid);
    897 
    898 	if (version >= SSL_LIBRARY_VERSION_3_0) {
    899             SECItem *name = &sid->u.ssl3.srvName;
    900             if (name->len && name->data) {
    901                 now = CacheSrvName(cache, name, &sce);
    902             }
    903             if (sid->peerCert != NULL) {
    904                 now = CacheCert(cache, sid->peerCert, &sce);
    905             }
    906 	}
    907 
    908 	set = SIDindex(cache, &sce.addr, sce.sessionID, sce.sessionIDLength);
    909 	now = LockSet(cache, set, now);
    910 	if (now) {
    911 	    PRUint32  next = cache->sidCacheSets[set].next;
    912 	    PRUint32  ndx  = set * SID_CACHE_ENTRIES_PER_SET + next;
    913 
    914 	    /* Write out new cache entry */
    915 	    cache->sidCacheData[ndx] = sce;
    916 
    917 	    cache->sidCacheSets[set].next =
    918 	    				(next + 1) % SID_CACHE_ENTRIES_PER_SET;
    919 
    920 	    UnlockSet(cache, set);
    921 	    sid->cached = in_server_cache;
    922 	}
    923     }
    924 }
    925 
    926 /*
    927 ** Although this is static, it is called from ssl via global function pointer
    928 **	ssl_sid_uncache.  This invalidates the referenced cache entry.
    929 */
    930 static void
    931 ServerSessionIDUncache(sslSessionID *sid)
    932 {
    933     cacheDesc *    cache   = &globalCache;
    934     PRUint8 *      sessionID;
    935     unsigned int   sessionIDLength;
    936     PRErrorCode    err;
    937     PRUint32       set;
    938     PRUint32       now;
    939     sidCacheEntry *psce;
    940 
    941     if (sid == NULL)
    942     	return;
    943 
    944     /* Uncaching a SID should never change the error code.
    945     ** So save it here and restore it before exiting.
    946     */
    947     err = PR_GetError();
    948 
    949     if (sid->version < SSL_LIBRARY_VERSION_3_0) {
    950 	sessionID       = sid->u.ssl2.sessionID;
    951 	sessionIDLength = SSL2_SESSIONID_BYTES;
    952 	SSL_TRC(8, ("%d: SSL: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
    953 		    "cipher=%d", myPid, sid->cached,
    954 		    sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
    955 		    sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
    956 		    sid->creationTime, sid->u.ssl2.cipherType));
    957 	PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength));
    958 	PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data,
    959 		      sid->u.ssl2.masterKey.len));
    960 	PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data,
    961 		      sid->u.ssl2.cipherArg.len));
    962     } else {
    963 	sessionID       = sid->u.ssl3.sessionID;
    964 	sessionIDLength = sid->u.ssl3.sessionIDLength;
    965 	SSL_TRC(8, ("%d: SSL3: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
    966 		    "cipherSuite=%d", myPid, sid->cached,
    967 		    sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
    968 		    sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
    969 		    sid->creationTime, sid->u.ssl3.cipherSuite));
    970 	PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength));
    971     }
    972     set = SIDindex(cache, &sid->addr, sessionID, sessionIDLength);
    973     now = LockSet(cache, set, 0);
    974     if (now) {
    975 	psce = FindSID(cache, set, now, &sid->addr, sessionID, sessionIDLength);
    976 	if (psce) {
    977 	    psce->valid = 0;
    978 	}
    979 	UnlockSet(cache, set);
    980     }
    981     sid->cached = invalid_cache;
    982     PORT_SetError(err);
    983 }
    984 
    985 #ifdef XP_OS2
    986 
    987 #define INCL_DOSPROCESS
    988 #include <os2.h>
    989 
    990 long gettid(void)
    991 {
    992     PTIB ptib;
    993     PPIB ppib;
    994     DosGetInfoBlocks(&ptib, &ppib);
    995     return ((long)ptib->tib_ordinal); /* thread id */
    996 }
    997 #endif
    998 
    999 static void
   1000 CloseCache(cacheDesc *cache)
   1001 {
   1002     int locks_initialized = cache->numSIDCacheLocksInitialized;
   1003 
   1004     if (cache->cacheMem) {
   1005 	if (cache->sharedCache) {
   1006 	    sidCacheLock *pLock = cache->sidCacheLocks;
   1007 	    for (; locks_initialized > 0; --locks_initialized, ++pLock ) {
   1008 		/* If everInherited is true, this shared cache was (and may
   1009 		** still be) in use by multiple processes.  We do not wish to
   1010 		** destroy the mutexes while they are still in use, but we do
   1011 		** want to free mutex resources associated with this process.
   1012 		*/
   1013 		sslMutex_Destroy(&pLock->mutex,
   1014 				 cache->sharedCache->everInherited);
   1015 	    }
   1016 	}
   1017 	if (cache->shared) {
   1018 	    PR_MemUnmap(cache->cacheMem, cache->cacheMemSize);
   1019 	} else {
   1020 	    PORT_Free(cache->cacheMem);
   1021 	}
   1022 	cache->cacheMem = NULL;
   1023     }
   1024     if (cache->cacheMemMap) {
   1025 	PR_CloseFileMap(cache->cacheMemMap);
   1026 	cache->cacheMemMap = NULL;
   1027     }
   1028     memset(cache, 0, sizeof *cache);
   1029 }
   1030 
   1031 static SECStatus
   1032 InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries,
   1033           int maxSrvNameCacheEntries, PRUint32 ssl2_timeout,
   1034           PRUint32 ssl3_timeout, const char *directory, PRBool shared)
   1035 {
   1036     ptrdiff_t     ptr;
   1037     sidCacheLock *pLock;
   1038     char *        cacheMem;
   1039     PRFileMap *   cacheMemMap;
   1040     char *        cfn = NULL;	/* cache file name */
   1041     int           locks_initialized = 0;
   1042     int           locks_to_initialize = 0;
   1043     PRUint32      init_time;
   1044 
   1045     if ( (!cache) || (maxCacheEntries < 0) || (!directory) ) {
   1046         PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1047         return SECFailure;
   1048     }
   1049 
   1050     if (cache->cacheMem) {
   1051 	/* Already done */
   1052 	return SECSuccess;
   1053     }
   1054 
   1055     /* make sure loser can clean up properly */
   1056     cache->shared = shared;
   1057     cache->cacheMem    = cacheMem    = NULL;
   1058     cache->cacheMemMap = cacheMemMap = NULL;
   1059     cache->sharedCache = (cacheDesc *)0;
   1060 
   1061     cache->numSIDCacheLocksInitialized = 0;
   1062     cache->nextCertCacheEntry = 0;
   1063     cache->stopPolling = PR_FALSE;
   1064     cache->everInherited = PR_FALSE;
   1065     cache->poller = NULL;
   1066     cache->mutexTimeout = 0;
   1067 
   1068     cache->numSIDCacheEntries = maxCacheEntries ? maxCacheEntries
   1069                                                 : DEF_SID_CACHE_ENTRIES;
   1070     cache->numSIDCacheSets    =
   1071     	SID_HOWMANY(cache->numSIDCacheEntries, SID_CACHE_ENTRIES_PER_SET);
   1072 
   1073     cache->numSIDCacheEntries =
   1074     	cache->numSIDCacheSets * SID_CACHE_ENTRIES_PER_SET;
   1075 
   1076     cache->numSIDCacheLocks   =
   1077     	PR_MIN(cache->numSIDCacheSets, ssl_max_sid_cache_locks);
   1078 
   1079     cache->numSIDCacheSetsPerLock =
   1080     	SID_HOWMANY(cache->numSIDCacheSets, cache->numSIDCacheLocks);
   1081 
   1082     cache->numCertCacheEntries = (maxCertCacheEntries > 0) ?
   1083                                              maxCertCacheEntries : 0;
   1084     cache->numSrvNameCacheEntries = (maxSrvNameCacheEntries >= 0) ?
   1085                                              maxSrvNameCacheEntries : DEF_NAME_CACHE_ENTRIES;
   1086 
   1087     /* compute size of shared memory, and offsets of all pointers */
   1088     ptr = 0;
   1089     cache->cacheMem     = (char *)ptr;
   1090     ptr += SID_ROUNDUP(sizeof(cacheDesc), SID_ALIGNMENT);
   1091 
   1092     cache->sidCacheLocks = (sidCacheLock *)ptr;
   1093     cache->keyCacheLock  = cache->sidCacheLocks + cache->numSIDCacheLocks;
   1094     cache->certCacheLock = cache->keyCacheLock  + 1;
   1095     cache->srvNameCacheLock = cache->certCacheLock  + 1;
   1096     ptr = (ptrdiff_t)(cache->srvNameCacheLock + 1);
   1097     ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
   1098 
   1099     cache->sidCacheSets  = (sidCacheSet *)ptr;
   1100     ptr = (ptrdiff_t)(cache->sidCacheSets + cache->numSIDCacheSets);
   1101     ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
   1102 
   1103     cache->sidCacheData  = (sidCacheEntry *)ptr;
   1104     ptr = (ptrdiff_t)(cache->sidCacheData + cache->numSIDCacheEntries);
   1105     ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
   1106 
   1107     cache->certCacheData = (certCacheEntry *)ptr;
   1108     cache->sidCacheSize  =
   1109     	(char *)cache->certCacheData - (char *)cache->sidCacheData;
   1110 
   1111     if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES) {
   1112         /* This is really a poor way to computer this! */
   1113         cache->numCertCacheEntries = cache->sidCacheSize / sizeof(certCacheEntry);
   1114         if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES)
   1115     	cache->numCertCacheEntries = MIN_CERT_CACHE_ENTRIES;
   1116     }
   1117     ptr = (ptrdiff_t)(cache->certCacheData + cache->numCertCacheEntries);
   1118     ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
   1119 
   1120     cache->keyCacheData  = (SSLWrappedSymWrappingKey *)ptr;
   1121     cache->certCacheSize =
   1122     	(char *)cache->keyCacheData - (char *)cache->certCacheData;
   1123 
   1124     cache->numKeyCacheEntries = kt_kea_size * SSL_NUM_WRAP_MECHS;
   1125     ptr = (ptrdiff_t)(cache->keyCacheData + cache->numKeyCacheEntries);
   1126     ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
   1127 
   1128     cache->keyCacheSize  = (char *)ptr - (char *)cache->keyCacheData;
   1129 
   1130     cache->ticketKeyNameSuffix = (PRUint8 *)ptr;
   1131     ptr = (ptrdiff_t)(cache->ticketKeyNameSuffix +
   1132 	SESS_TICKET_KEY_VAR_NAME_LEN);
   1133     ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
   1134 
   1135     cache->ticketEncKey = (encKeyCacheEntry *)ptr;
   1136     ptr = (ptrdiff_t)(cache->ticketEncKey + 1);
   1137     ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
   1138 
   1139     cache->ticketMacKey = (encKeyCacheEntry *)ptr;
   1140     ptr = (ptrdiff_t)(cache->ticketMacKey + 1);
   1141     ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
   1142 
   1143     cache->ticketKeysValid = (PRUint32 *)ptr;
   1144     ptr = (ptrdiff_t)(cache->ticketKeysValid + 1);
   1145     ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
   1146 
   1147     cache->srvNameCacheData = (srvNameCacheEntry *)ptr;
   1148     cache->srvNameCacheSize =
   1149         cache->numSrvNameCacheEntries * sizeof(srvNameCacheEntry);
   1150     ptr = (ptrdiff_t)(cache->srvNameCacheData + cache->numSrvNameCacheEntries);
   1151     ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
   1152 
   1153     cache->cacheMemSize = ptr;
   1154 
   1155     if (ssl2_timeout) {
   1156 	if (ssl2_timeout > MAX_SSL2_TIMEOUT) {
   1157 	    ssl2_timeout = MAX_SSL2_TIMEOUT;
   1158 	}
   1159 	if (ssl2_timeout < MIN_SSL2_TIMEOUT) {
   1160 	    ssl2_timeout = MIN_SSL2_TIMEOUT;
   1161 	}
   1162 	cache->ssl2Timeout = ssl2_timeout;
   1163     } else {
   1164 	cache->ssl2Timeout = DEF_SSL2_TIMEOUT;
   1165     }
   1166 
   1167     if (ssl3_timeout) {
   1168 	if (ssl3_timeout > MAX_SSL3_TIMEOUT) {
   1169 	    ssl3_timeout = MAX_SSL3_TIMEOUT;
   1170 	}
   1171 	if (ssl3_timeout < MIN_SSL3_TIMEOUT) {
   1172 	    ssl3_timeout = MIN_SSL3_TIMEOUT;
   1173 	}
   1174 	cache->ssl3Timeout = ssl3_timeout;
   1175     } else {
   1176 	cache->ssl3Timeout = DEF_SSL3_TIMEOUT;
   1177     }
   1178 
   1179     if (shared) {
   1180 	/* Create file names */
   1181 #if defined(XP_UNIX) || defined(XP_BEOS)
   1182 	/* there's some confusion here about whether PR_OpenAnonFileMap wants
   1183 	** a directory name or a file name for its first argument.
   1184 	cfn = PR_smprintf("%s/.sslsvrcache.%d", directory, myPid);
   1185 	*/
   1186 	cfn = PR_smprintf("%s", directory);
   1187 #elif defined(XP_WIN32)
   1188 	cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid,
   1189 			    GetCurrentThreadId());
   1190 #elif defined(XP_OS2)
   1191 	cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid,
   1192 			    gettid());
   1193 #else
   1194 #error "Don't know how to create file name for this platform!"
   1195 #endif
   1196 	if (!cfn) {
   1197 	    goto loser;
   1198 	}
   1199 
   1200 	/* Create cache */
   1201 	cacheMemMap = PR_OpenAnonFileMap(cfn, cache->cacheMemSize,
   1202 					 PR_PROT_READWRITE);
   1203 
   1204 	PR_smprintf_free(cfn);
   1205 	if(!cacheMemMap) {
   1206 	    goto loser;
   1207 	}
   1208 
   1209         cacheMem = PR_MemMap(cacheMemMap, 0, cache->cacheMemSize);
   1210     } else {
   1211         cacheMem = PORT_Alloc(cache->cacheMemSize);
   1212     }
   1213 
   1214     if (! cacheMem) {
   1215         goto loser;
   1216     }
   1217 
   1218     /* Initialize shared memory. This may not be necessary on all platforms */
   1219     memset(cacheMem, 0, cache->cacheMemSize);
   1220 
   1221     /* Copy cache descriptor header into shared memory */
   1222     memcpy(cacheMem, cache, sizeof *cache);
   1223 
   1224     /* save private copies of these values */
   1225     cache->cacheMemMap = cacheMemMap;
   1226     cache->cacheMem    = cacheMem;
   1227     cache->sharedCache = (cacheDesc *)cacheMem;
   1228 
   1229     /* Fix pointers in our private copy of cache descriptor to point to
   1230     ** spaces in shared memory
   1231     */
   1232     ptr = (ptrdiff_t)cache->cacheMem;
   1233     *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
   1234     *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
   1235     *(ptrdiff_t *)(&cache->certCacheLock) += ptr;
   1236     *(ptrdiff_t *)(&cache->srvNameCacheLock) += ptr;
   1237     *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr;
   1238     *(ptrdiff_t *)(&cache->sidCacheData ) += ptr;
   1239     *(ptrdiff_t *)(&cache->certCacheData) += ptr;
   1240     *(ptrdiff_t *)(&cache->keyCacheData ) += ptr;
   1241     *(ptrdiff_t *)(&cache->ticketKeyNameSuffix) += ptr;
   1242     *(ptrdiff_t *)(&cache->ticketEncKey ) += ptr;
   1243     *(ptrdiff_t *)(&cache->ticketMacKey ) += ptr;
   1244     *(ptrdiff_t *)(&cache->ticketKeysValid) += ptr;
   1245     *(ptrdiff_t *)(&cache->srvNameCacheData) += ptr;
   1246 
   1247     /* initialize the locks */
   1248     init_time = ssl_Time();
   1249     pLock = cache->sidCacheLocks;
   1250     for (locks_to_initialize = cache->numSIDCacheLocks + 3;
   1251          locks_initialized < locks_to_initialize;
   1252 	 ++locks_initialized, ++pLock ) {
   1253 
   1254 	SECStatus err = sslMutex_Init(&pLock->mutex, shared);
   1255 	if (err) {
   1256 	    cache->numSIDCacheLocksInitialized = locks_initialized;
   1257 	    goto loser;
   1258 	}
   1259         pLock->timeStamp = init_time;
   1260 	pLock->pid       = 0;
   1261     }
   1262     cache->numSIDCacheLocksInitialized = locks_initialized;
   1263 
   1264     return SECSuccess;
   1265 
   1266 loser:
   1267     CloseCache(cache);
   1268     return SECFailure;
   1269 }
   1270 
   1271 PRUint32
   1272 SSL_GetMaxServerCacheLocks(void)
   1273 {
   1274     return ssl_max_sid_cache_locks + 2;
   1275     /* The extra two are the cert cache lock and the key cache lock. */
   1276 }
   1277 
   1278 SECStatus
   1279 SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
   1280 {
   1281     /* Minimum is 1 sid cache lock, 1 cert cache lock and 1 key cache lock.
   1282     ** We'd like to test for a maximum value, but not all platforms' header
   1283     ** files provide a symbol or function or other means of determining
   1284     ** the maximum, other than trial and error.
   1285     */
   1286     if (maxLocks < 3) {
   1287 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1288 	return SECFailure;
   1289     }
   1290     ssl_max_sid_cache_locks = maxLocks - 2;
   1291     /* The extra two are the cert cache lock and the key cache lock. */
   1292     return SECSuccess;
   1293 }
   1294 
   1295 static SECStatus
   1296 ssl_ConfigServerSessionIDCacheInstanceWithOpt(cacheDesc *cache,
   1297                                               PRUint32 ssl2_timeout,
   1298                                               PRUint32 ssl3_timeout,
   1299                                               const char *   directory,
   1300                                               PRBool shared,
   1301                                               int      maxCacheEntries,
   1302                                               int      maxCertCacheEntries,
   1303                                               int      maxSrvNameCacheEntries)
   1304 {
   1305     SECStatus rv;
   1306 
   1307     PORT_Assert(sizeof(sidCacheEntry) == 192);
   1308     PORT_Assert(sizeof(certCacheEntry) == 4096);
   1309     PORT_Assert(sizeof(srvNameCacheEntry) == 1072);
   1310 
   1311     rv = ssl_Init();
   1312     if (rv != SECSuccess) {
   1313 	return rv;
   1314     }
   1315 
   1316     myPid = SSL_GETPID();
   1317     if (!directory) {
   1318 	directory = DEFAULT_CACHE_DIRECTORY;
   1319     }
   1320     rv = InitCache(cache, maxCacheEntries, maxCertCacheEntries,
   1321                    maxSrvNameCacheEntries, ssl2_timeout, ssl3_timeout,
   1322                    directory, shared);
   1323     if (rv) {
   1324 	SET_ERROR_CODE
   1325     	return SECFailure;
   1326     }
   1327 
   1328     ssl_sid_lookup  = ServerSessionIDLookup;
   1329     ssl_sid_cache   = ServerSessionIDCache;
   1330     ssl_sid_uncache = ServerSessionIDUncache;
   1331     return SECSuccess;
   1332 }
   1333 
   1334 SECStatus
   1335 SSL_ConfigServerSessionIDCacheInstance(	cacheDesc *cache,
   1336                                 int      maxCacheEntries,
   1337                                 PRUint32 ssl2_timeout,
   1338                                 PRUint32 ssl3_timeout,
   1339                                 const char *   directory, PRBool shared)
   1340 {
   1341     return ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache,
   1342                                                          ssl2_timeout,
   1343                                                          ssl3_timeout,
   1344                                                          directory,
   1345                                                          shared,
   1346                                                          maxCacheEntries,
   1347                                                          -1, -1);
   1348 }
   1349 
   1350 SECStatus
   1351 SSL_ConfigServerSessionIDCache(	int      maxCacheEntries,
   1352 				PRUint32 ssl2_timeout,
   1353 			       	PRUint32 ssl3_timeout,
   1354 			  const char *   directory)
   1355 {
   1356     ssl_InitSessionCacheLocks();
   1357     return SSL_ConfigServerSessionIDCacheInstance(&globalCache,
   1358     		maxCacheEntries, ssl2_timeout, ssl3_timeout, directory, PR_FALSE);
   1359 }
   1360 
   1361 SECStatus
   1362 SSL_ShutdownServerSessionIDCacheInstance(cacheDesc *cache)
   1363 {
   1364     CloseCache(cache);
   1365     return SECSuccess;
   1366 }
   1367 
   1368 SECStatus
   1369 SSL_ShutdownServerSessionIDCache(void)
   1370 {
   1371 #if defined(XP_UNIX) || defined(XP_BEOS)
   1372     /* Stop the thread that polls cache for expired locks on Unix */
   1373     StopLockPoller(&globalCache);
   1374 #endif
   1375     SSL3_ShutdownServerCache();
   1376     return SSL_ShutdownServerSessionIDCacheInstance(&globalCache);
   1377 }
   1378 
   1379 /* Use this function, instead of SSL_ConfigServerSessionIDCache,
   1380  * if the cache will be shared by multiple processes.
   1381  */
   1382 static SECStatus
   1383 ssl_ConfigMPServerSIDCacheWithOpt(      PRUint32 ssl2_timeout,
   1384                                         PRUint32 ssl3_timeout,
   1385                                         const char *   directory,
   1386                                         int maxCacheEntries,
   1387                                         int maxCertCacheEntries,
   1388                                         int maxSrvNameCacheEntries)
   1389 {
   1390     char *	envValue;
   1391     char *	inhValue;
   1392     cacheDesc * cache         = &globalCache;
   1393     PRUint32    fmStrLen;
   1394     SECStatus 	result;
   1395     PRStatus 	prStatus;
   1396     SECStatus	putEnvFailed;
   1397     inheritance inherit;
   1398     char        fmString[PR_FILEMAP_STRING_BUFSIZE];
   1399 
   1400     isMultiProcess = PR_TRUE;
   1401     result = ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache,
   1402                   ssl2_timeout, ssl3_timeout, directory, PR_TRUE,
   1403         maxCacheEntries, maxCacheEntries, maxSrvNameCacheEntries);
   1404     if (result != SECSuccess)
   1405         return result;
   1406 
   1407     prStatus = PR_ExportFileMapAsString(cache->cacheMemMap,
   1408                                         sizeof fmString, fmString);
   1409     if ((prStatus != PR_SUCCESS) || !(fmStrLen = strlen(fmString))) {
   1410 	SET_ERROR_CODE
   1411 	return SECFailure;
   1412     }
   1413 
   1414     inherit.cacheMemSize	= cache->cacheMemSize;
   1415     inherit.fmStrLen            = fmStrLen;
   1416 
   1417     inhValue = BTOA_DataToAscii((unsigned char *)&inherit, sizeof inherit);
   1418     if (!inhValue || !strlen(inhValue)) {
   1419 	SET_ERROR_CODE
   1420 	return SECFailure;
   1421     }
   1422     envValue = PR_smprintf("%s,%s", inhValue, fmString);
   1423     if (!envValue || !strlen(envValue)) {
   1424 	SET_ERROR_CODE
   1425 	return SECFailure;
   1426     }
   1427     PORT_Free(inhValue);
   1428 
   1429     putEnvFailed = (SECStatus)NSS_PutEnv(envVarName, envValue);
   1430     PR_smprintf_free(envValue);
   1431     if (putEnvFailed) {
   1432         SET_ERROR_CODE
   1433         result = SECFailure;
   1434     }
   1435 
   1436 #if defined(XP_UNIX) || defined(XP_BEOS)
   1437     /* Launch thread to poll cache for expired locks on Unix */
   1438     LaunchLockPoller(cache);
   1439 #endif
   1440     return result;
   1441 }
   1442 
   1443 /* Use this function, instead of SSL_ConfigServerSessionIDCache,
   1444  * if the cache will be shared by multiple processes.
   1445  */
   1446 SECStatus
   1447 SSL_ConfigMPServerSIDCache(	int      maxCacheEntries,
   1448 				PRUint32 ssl2_timeout,
   1449 			       	PRUint32 ssl3_timeout,
   1450 		          const char *   directory)
   1451 {
   1452     return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout,
   1453                                              ssl3_timeout,
   1454                                              directory,
   1455                                              maxCacheEntries,
   1456                                              -1, -1);
   1457 }
   1458 
   1459 SECStatus
   1460 SSL_ConfigServerSessionIDCacheWithOpt(
   1461 				PRUint32 ssl2_timeout,
   1462 			       	PRUint32 ssl3_timeout,
   1463                                 const char *   directory,
   1464                                 int maxCacheEntries,
   1465                                 int maxCertCacheEntries,
   1466                                 int maxSrvNameCacheEntries,
   1467                                 PRBool enableMPCache)
   1468 {
   1469     if (!enableMPCache) {
   1470         ssl_InitSessionCacheLocks();
   1471         return ssl_ConfigServerSessionIDCacheInstanceWithOpt(&globalCache,
   1472            ssl2_timeout, ssl3_timeout, directory, PR_FALSE,
   1473            maxCacheEntries, maxCertCacheEntries, maxSrvNameCacheEntries);
   1474     } else {
   1475         return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout, ssl3_timeout,
   1476                 directory, maxCacheEntries, maxCertCacheEntries,
   1477                                                  maxSrvNameCacheEntries);
   1478     }
   1479 }
   1480 
   1481 SECStatus
   1482 SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString)
   1483 {
   1484     unsigned char * decoString = NULL;
   1485     char *          fmString   = NULL;
   1486     char *          myEnvString = NULL;
   1487     unsigned int    decoLen;
   1488     ptrdiff_t       ptr;
   1489     inheritance     inherit;
   1490     cacheDesc       my;
   1491 #ifdef WINNT
   1492     sidCacheLock* newLocks;
   1493     int           locks_initialized = 0;
   1494     int           locks_to_initialize = 0;
   1495 #endif
   1496     SECStatus     status = ssl_Init();
   1497 
   1498     if (status != SECSuccess) {
   1499 	return status;
   1500     }
   1501 
   1502     myPid = SSL_GETPID();
   1503 
   1504     /* If this child was created by fork(), and not by exec() on unix,
   1505     ** then isMultiProcess will already be set.
   1506     ** If not, we'll set it below.
   1507     */
   1508     if (isMultiProcess) {
   1509 	if (cache && cache->sharedCache) {
   1510 	    cache->sharedCache->everInherited = PR_TRUE;
   1511 	}
   1512     	return SECSuccess;	/* already done. */
   1513     }
   1514 
   1515     ssl_InitSessionCacheLocks();
   1516 
   1517     ssl_sid_lookup  = ServerSessionIDLookup;
   1518     ssl_sid_cache   = ServerSessionIDCache;
   1519     ssl_sid_uncache = ServerSessionIDUncache;
   1520 
   1521     if (!envString) {
   1522     	envString  = getenv(envVarName);
   1523 	if (!envString) {
   1524 	    SET_ERROR_CODE
   1525 	    return SECFailure;
   1526 	}
   1527     }
   1528     myEnvString = PORT_Strdup(envString);
   1529     if (!myEnvString)
   1530 	return SECFailure;
   1531     fmString = strchr(myEnvString, ',');
   1532     if (!fmString)
   1533     	goto loser;
   1534     *fmString++ = 0;
   1535 
   1536     decoString = ATOB_AsciiToData(myEnvString, &decoLen);
   1537     if (!decoString) {
   1538     	SET_ERROR_CODE
   1539 	goto loser;
   1540     }
   1541     if (decoLen != sizeof inherit) {
   1542     	SET_ERROR_CODE
   1543     	goto loser;
   1544     }
   1545 
   1546     PORT_Memcpy(&inherit, decoString, sizeof inherit);
   1547 
   1548     if (strlen(fmString)  != inherit.fmStrLen ) {
   1549     	goto loser;
   1550     }
   1551 
   1552     memset(cache, 0, sizeof *cache);
   1553     cache->cacheMemSize	= inherit.cacheMemSize;
   1554 
   1555     /* Create cache */
   1556     cache->cacheMemMap = PR_ImportFileMapFromString(fmString);
   1557     if(! cache->cacheMemMap) {
   1558 	goto loser;
   1559     }
   1560     cache->cacheMem = PR_MemMap(cache->cacheMemMap, 0, cache->cacheMemSize);
   1561     if (! cache->cacheMem) {
   1562 	goto loser;
   1563     }
   1564     cache->sharedCache   = (cacheDesc *)cache->cacheMem;
   1565 
   1566     if (cache->sharedCache->cacheMemSize != cache->cacheMemSize) {
   1567 	SET_ERROR_CODE
   1568     	goto loser;
   1569     }
   1570 
   1571     /* We're now going to overwrite the local cache instance with the
   1572     ** shared copy of the cache struct, then update several values in
   1573     ** the local cache using the values for cache->cacheMemMap and
   1574     ** cache->cacheMem computed just above.  So, we copy cache into
   1575     ** the automatic variable "my", to preserve the variables while
   1576     ** cache is overwritten.
   1577     */
   1578     my = *cache;  /* save values computed above. */
   1579     memcpy(cache, cache->sharedCache, sizeof *cache); /* overwrite */
   1580 
   1581     /* Fix pointers in our private copy of cache descriptor to point to
   1582     ** spaces in shared memory, whose address is now in "my".
   1583     */
   1584     ptr = (ptrdiff_t)my.cacheMem;
   1585     *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
   1586     *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
   1587     *(ptrdiff_t *)(&cache->certCacheLock) += ptr;
   1588     *(ptrdiff_t *)(&cache->srvNameCacheLock) += ptr;
   1589     *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr;
   1590     *(ptrdiff_t *)(&cache->sidCacheData ) += ptr;
   1591     *(ptrdiff_t *)(&cache->certCacheData) += ptr;
   1592     *(ptrdiff_t *)(&cache->keyCacheData ) += ptr;
   1593     *(ptrdiff_t *)(&cache->ticketKeyNameSuffix) += ptr;
   1594     *(ptrdiff_t *)(&cache->ticketEncKey ) += ptr;
   1595     *(ptrdiff_t *)(&cache->ticketMacKey ) += ptr;
   1596     *(ptrdiff_t *)(&cache->ticketKeysValid) += ptr;
   1597     *(ptrdiff_t *)(&cache->srvNameCacheData) += ptr;
   1598 
   1599     cache->cacheMemMap = my.cacheMemMap;
   1600     cache->cacheMem    = my.cacheMem;
   1601     cache->sharedCache = (cacheDesc *)cache->cacheMem;
   1602 
   1603 #ifdef WINNT
   1604     /*  On Windows NT we need to "fix" the sidCacheLocks here to support fibers
   1605     **  When NT fibers are used in a multi-process server, a second level of
   1606     **  locking is needed to prevent a deadlock, in case a fiber acquires the
   1607     **  cross-process mutex, yields, and another fiber is later scheduled on
   1608     **  the same native thread and tries to acquire the cross-process mutex.
   1609     **  We do this by using a PRLock in the sslMutex. However, it is stored in
   1610     **  shared memory as part of sidCacheLocks, and we don't want to overwrite
   1611     **  the PRLock of the parent process. So we need to make new, private
   1612     **  copies of sidCacheLocks before modifying the sslMutex with our own
   1613     **  PRLock
   1614     */
   1615 
   1616     /* note from jpierre : this should be free'd in child processes when
   1617     ** a function is added to delete the SSL session cache in the future.
   1618     */
   1619     locks_to_initialize = cache->numSIDCacheLocks + 3;
   1620     newLocks = PORT_NewArray(sidCacheLock, locks_to_initialize);
   1621     if (!newLocks)
   1622     	goto loser;
   1623     /* copy the old locks */
   1624     memcpy(newLocks, cache->sidCacheLocks,
   1625            locks_to_initialize * sizeof(sidCacheLock));
   1626     cache->sidCacheLocks = newLocks;
   1627     /* fix the locks */
   1628     for (; locks_initialized < locks_to_initialize; ++locks_initialized) {
   1629         /* now, make a local PRLock in this sslMutex for this child process */
   1630 	SECStatus err;
   1631         err = sslMutex_2LevelInit(&newLocks[locks_initialized].mutex);
   1632 	if (err != SECSuccess) {
   1633 	    cache->numSIDCacheLocksInitialized = locks_initialized;
   1634 	    goto loser;
   1635     	}
   1636     }
   1637     cache->numSIDCacheLocksInitialized = locks_initialized;
   1638 
   1639     /* also fix the key and cert cache which use the last 2 lock entries */
   1640     cache->keyCacheLock  = cache->sidCacheLocks + cache->numSIDCacheLocks;
   1641     cache->certCacheLock = cache->keyCacheLock  + 1;
   1642     cache->srvNameCacheLock = cache->certCacheLock  + 1;
   1643 #endif
   1644 
   1645     PORT_Free(myEnvString);
   1646     PORT_Free(decoString);
   1647 
   1648     /* mark that we have inherited this. */
   1649     cache->sharedCache->everInherited = PR_TRUE;
   1650     isMultiProcess = PR_TRUE;
   1651 
   1652     return SECSuccess;
   1653 
   1654 loser:
   1655     PORT_Free(myEnvString);
   1656     if (decoString)
   1657 	PORT_Free(decoString);
   1658     CloseCache(cache);
   1659     return SECFailure;
   1660 }
   1661 
   1662 SECStatus
   1663 SSL_InheritMPServerSIDCache(const char * envString)
   1664 {
   1665     return SSL_InheritMPServerSIDCacheInstance(&globalCache, envString);
   1666 }
   1667 
   1668 #if defined(XP_UNIX) || defined(XP_BEOS)
   1669 
   1670 #define SID_LOCK_EXPIRATION_TIMEOUT  30 /* seconds */
   1671 
   1672 static void
   1673 LockPoller(void * arg)
   1674 {
   1675     cacheDesc *    cache         = (cacheDesc *)arg;
   1676     cacheDesc *    sharedCache   = cache->sharedCache;
   1677     sidCacheLock * pLock;
   1678     PRIntervalTime timeout;
   1679     PRUint32       now;
   1680     PRUint32       then;
   1681     int            locks_polled  = 0;
   1682     int            locks_to_poll = cache->numSIDCacheLocks + 2;
   1683     PRUint32       expiration    = cache->mutexTimeout;
   1684 
   1685     timeout = PR_SecondsToInterval(expiration);
   1686     while(!sharedCache->stopPolling) {
   1687     	PR_Sleep(timeout);
   1688 	if (sharedCache->stopPolling)
   1689 	    break;
   1690 
   1691 	now   = ssl_Time();
   1692 	then  = now - expiration;
   1693 	for (pLock = cache->sidCacheLocks, locks_polled = 0;
   1694 	     locks_to_poll > locks_polled && !sharedCache->stopPolling;
   1695 	     ++locks_polled, ++pLock ) {
   1696 	    pid_t pid;
   1697 
   1698 	    if (pLock->timeStamp   < then &&
   1699 	        pLock->timeStamp   != 0 &&
   1700 		(pid = pLock->pid) != 0) {
   1701 
   1702 	    	/* maybe we should try the lock? */
   1703 		int result = kill(pid, 0);
   1704 		if (result < 0 && errno == ESRCH) {
   1705 		    SECStatus rv;
   1706 		    /* No process exists by that pid any more.
   1707 		    ** Treat this mutex as abandoned.
   1708 		    */
   1709 		    pLock->timeStamp = now;
   1710 		    pLock->pid       = 0;
   1711 		    rv = sslMutex_Unlock(&pLock->mutex);
   1712 		    if (rv != SECSuccess) {
   1713 		    	/* Now what? */
   1714 		    }
   1715 		}
   1716 	    }
   1717 	} /* end of loop over locks */
   1718     } /* end of entire polling loop */
   1719 }
   1720 
   1721 /* Launch thread to poll cache for expired locks */
   1722 static SECStatus
   1723 LaunchLockPoller(cacheDesc *cache)
   1724 {
   1725     const char * timeoutString;
   1726     PRThread *   pollerThread;
   1727 
   1728     cache->mutexTimeout = SID_LOCK_EXPIRATION_TIMEOUT;
   1729     timeoutString       = getenv("NSS_SSL_SERVER_CACHE_MUTEX_TIMEOUT");
   1730     if (timeoutString) {
   1731 	long newTime = strtol(timeoutString, 0, 0);
   1732 	if (newTime == 0)
   1733 	    return SECSuccess;  /* application doesn't want poller thread */
   1734 	if (newTime > 0)
   1735 	    cache->mutexTimeout = (PRUint32)newTime;
   1736 	/* if error (newTime < 0) ignore it and use default */
   1737     }
   1738 
   1739     pollerThread =
   1740 	PR_CreateThread(PR_USER_THREAD, LockPoller, cache, PR_PRIORITY_NORMAL,
   1741 	                PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
   1742     if (!pollerThread) {
   1743     	return SECFailure;
   1744     }
   1745     cache->poller = pollerThread;
   1746     return SECSuccess;
   1747 }
   1748 
   1749 /* Stop the thread that polls cache for expired locks */
   1750 static SECStatus
   1751 StopLockPoller(cacheDesc *cache)
   1752 {
   1753     if (!cache->poller) {
   1754 	return SECSuccess;
   1755     }
   1756     cache->sharedCache->stopPolling = PR_TRUE;
   1757     if (PR_Interrupt(cache->poller) != PR_SUCCESS) {
   1758 	return SECFailure;
   1759     }
   1760     if (PR_JoinThread(cache->poller) != PR_SUCCESS) {
   1761 	return SECFailure;
   1762     }
   1763     cache->poller = NULL;
   1764     return SECSuccess;
   1765 }
   1766 #endif
   1767 
   1768 /************************************************************************
   1769  *  Code dealing with shared wrapped symmetric wrapping keys below      *
   1770  ************************************************************************/
   1771 
   1772 /* If now is zero, it implies that the lock is not held, and must be
   1773 ** aquired here.
   1774 */
   1775 static PRBool
   1776 getSvrWrappingKey(PRInt32                symWrapMechIndex,
   1777                SSL3KEAType               exchKeyType,
   1778                SSLWrappedSymWrappingKey *wswk,
   1779 	       cacheDesc *               cache,
   1780 	       PRUint32                  lockTime)
   1781 {
   1782     PRUint32  ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
   1783     SSLWrappedSymWrappingKey * pwswk = cache->keyCacheData + ndx;
   1784     PRUint32  now = 0;
   1785     PRBool    rv  = PR_FALSE;
   1786 
   1787     if (!cache->cacheMem) { /* cache is uninitialized */
   1788 	PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
   1789 	return rv;
   1790     }
   1791     if (!lockTime) {
   1792 	lockTime = now = LockSidCacheLock(cache->keyCacheLock, now);
   1793 	if (!lockTime) {
   1794 	    return rv;
   1795 	}
   1796     }
   1797     if (pwswk->exchKeyType      == exchKeyType &&
   1798 	pwswk->symWrapMechIndex == symWrapMechIndex &&
   1799 	pwswk->wrappedSymKeyLen != 0) {
   1800 	*wswk = *pwswk;
   1801 	rv = PR_TRUE;
   1802     }
   1803     if (now) {
   1804 	UnlockSidCacheLock(cache->keyCacheLock);
   1805     }
   1806     return rv;
   1807 }
   1808 
   1809 PRBool
   1810 ssl_GetWrappingKey( PRInt32                   symWrapMechIndex,
   1811                     SSL3KEAType               exchKeyType,
   1812 		    SSLWrappedSymWrappingKey *wswk)
   1813 {
   1814     PRBool rv;
   1815 
   1816     PORT_Assert( (unsigned)exchKeyType < kt_kea_size);
   1817     PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
   1818     if ((unsigned)exchKeyType < kt_kea_size &&
   1819         (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS) {
   1820 	rv = getSvrWrappingKey(symWrapMechIndex, exchKeyType, wswk,
   1821 	                       &globalCache, 0);
   1822     } else {
   1823     	rv = PR_FALSE;
   1824     }
   1825 
   1826     return rv;
   1827 }
   1828 
   1829 /* Wrap and cache a session ticket key. */
   1830 static PRBool
   1831 WrapTicketKey(SECKEYPublicKey *svrPubKey, PK11SymKey *symKey,
   1832               const char *keyName, encKeyCacheEntry* cacheEntry)
   1833 {
   1834     SECItem wrappedKey = {siBuffer, NULL, 0};
   1835 
   1836     wrappedKey.len = SECKEY_PublicKeyStrength(svrPubKey);
   1837     PORT_Assert(wrappedKey.len <= sizeof(cacheEntry->bytes));
   1838     if (wrappedKey.len > sizeof(cacheEntry->bytes))
   1839 	return PR_FALSE;
   1840     wrappedKey.data = cacheEntry->bytes;
   1841 
   1842     if (PK11_PubWrapSymKey(CKM_RSA_PKCS, svrPubKey, symKey, &wrappedKey)
   1843 	    != SECSuccess) {
   1844 	SSL_DBG(("%d: SSL[%s]: Unable to wrap session ticket %s.",
   1845 		    SSL_GETPID(), "unknown", keyName));
   1846 	return PR_FALSE;
   1847     }
   1848     cacheEntry->length = wrappedKey.len;
   1849     return PR_TRUE;
   1850 }
   1851 
   1852 static PRBool
   1853 GenerateTicketKeys(void *pwArg, unsigned char *keyName, PK11SymKey **aesKey,
   1854                    PK11SymKey **macKey)
   1855 {
   1856     PK11SlotInfo *slot;
   1857     CK_MECHANISM_TYPE mechanismArray[2];
   1858     PK11SymKey *aesKeyTmp = NULL;
   1859     PK11SymKey *macKeyTmp = NULL;
   1860     cacheDesc *cache = &globalCache;
   1861     PRUint8 ticketKeyNameSuffixLocal[SESS_TICKET_KEY_VAR_NAME_LEN];
   1862     PRUint8 *ticketKeyNameSuffix;
   1863 
   1864     if (!cache->cacheMem) {
   1865         /* cache is not initalized. Use stack buffer */
   1866         ticketKeyNameSuffix = ticketKeyNameSuffixLocal;
   1867     } else {
   1868         ticketKeyNameSuffix = cache->ticketKeyNameSuffix;
   1869     }
   1870 
   1871     if (PK11_GenerateRandom(ticketKeyNameSuffix,
   1872 	    SESS_TICKET_KEY_VAR_NAME_LEN) != SECSuccess) {
   1873 	SSL_DBG(("%d: SSL[%s]: Unable to generate random key name bytes.",
   1874 		    SSL_GETPID(), "unknown"));
   1875 	goto loser;
   1876     }
   1877 
   1878     mechanismArray[0] = CKM_AES_CBC;
   1879     mechanismArray[1] = CKM_SHA256_HMAC;
   1880 
   1881     slot = PK11_GetBestSlotMultiple(mechanismArray, 2, pwArg);
   1882     if (slot) {
   1883 	aesKeyTmp = PK11_KeyGen(slot, mechanismArray[0], NULL,
   1884                                 AES_256_KEY_LENGTH, pwArg);
   1885 	macKeyTmp = PK11_KeyGen(slot, mechanismArray[1], NULL,
   1886                                 SHA256_LENGTH, pwArg);
   1887 	PK11_FreeSlot(slot);
   1888     }
   1889 
   1890     if (aesKeyTmp == NULL || macKeyTmp == NULL) {
   1891 	SSL_DBG(("%d: SSL[%s]: Unable to generate session ticket keys.",
   1892 		    SSL_GETPID(), "unknown"));
   1893 	goto loser;
   1894     }
   1895     PORT_Memcpy(keyName, ticketKeyNameSuffix, SESS_TICKET_KEY_VAR_NAME_LEN);
   1896     *aesKey = aesKeyTmp;
   1897     *macKey = macKeyTmp;
   1898     return PR_TRUE;
   1899 
   1900 loser:
   1901     if (aesKeyTmp)
   1902 	PK11_FreeSymKey(aesKeyTmp);
   1903     if (macKeyTmp)
   1904 	PK11_FreeSymKey(macKeyTmp);
   1905     return PR_FALSE;
   1906 }
   1907 
   1908 static PRBool
   1909 GenerateAndWrapTicketKeys(SECKEYPublicKey *svrPubKey, void *pwArg,
   1910                           unsigned char *keyName, PK11SymKey **aesKey,
   1911                           PK11SymKey **macKey)
   1912 {
   1913     PK11SymKey *aesKeyTmp = NULL;
   1914     PK11SymKey *macKeyTmp = NULL;
   1915     cacheDesc *cache = &globalCache;
   1916 
   1917     if (!GenerateTicketKeys(pwArg, keyName, &aesKeyTmp, &macKeyTmp)) {
   1918         goto loser;
   1919     }
   1920 
   1921     if (cache->cacheMem) {
   1922         /* Export the keys to the shared cache in wrapped form. */
   1923         if (!WrapTicketKey(svrPubKey, aesKeyTmp, "enc key", cache->ticketEncKey))
   1924             goto loser;
   1925         if (!WrapTicketKey(svrPubKey, macKeyTmp, "mac key", cache->ticketMacKey))
   1926             goto loser;
   1927     }
   1928     *aesKey = aesKeyTmp;
   1929     *macKey = macKeyTmp;
   1930     return PR_TRUE;
   1931 
   1932 loser:
   1933     if (aesKeyTmp)
   1934 	PK11_FreeSymKey(aesKeyTmp);
   1935     if (macKeyTmp)
   1936 	PK11_FreeSymKey(macKeyTmp);
   1937     return PR_FALSE;
   1938 }
   1939 
   1940 static PRBool
   1941 UnwrapCachedTicketKeys(SECKEYPrivateKey *svrPrivKey, unsigned char *keyName,
   1942                        PK11SymKey **aesKey, PK11SymKey **macKey)
   1943 {
   1944     SECItem wrappedKey = {siBuffer, NULL, 0};
   1945     PK11SymKey *aesKeyTmp = NULL;
   1946     PK11SymKey *macKeyTmp = NULL;
   1947     cacheDesc *cache = &globalCache;
   1948 
   1949     wrappedKey.data = cache->ticketEncKey->bytes;
   1950     wrappedKey.len = cache->ticketEncKey->length;
   1951     PORT_Assert(wrappedKey.len <= sizeof(cache->ticketEncKey->bytes));
   1952     aesKeyTmp = PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey,
   1953 	CKM_AES_CBC, CKA_DECRYPT, 0);
   1954 
   1955     wrappedKey.data = cache->ticketMacKey->bytes;
   1956     wrappedKey.len = cache->ticketMacKey->length;
   1957     PORT_Assert(wrappedKey.len <= sizeof(cache->ticketMacKey->bytes));
   1958     macKeyTmp = PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey,
   1959 	CKM_SHA256_HMAC, CKA_SIGN, 0);
   1960 
   1961     if (aesKeyTmp == NULL || macKeyTmp == NULL) {
   1962 	SSL_DBG(("%d: SSL[%s]: Unable to unwrap session ticket keys.",
   1963 		    SSL_GETPID(), "unknown"));
   1964 	goto loser;
   1965     }
   1966     SSL_DBG(("%d: SSL[%s]: Successfully unwrapped session ticket keys.",
   1967 		SSL_GETPID(), "unknown"));
   1968 
   1969     PORT_Memcpy(keyName, cache->ticketKeyNameSuffix,
   1970 	SESS_TICKET_KEY_VAR_NAME_LEN);
   1971     *aesKey = aesKeyTmp;
   1972     *macKey = macKeyTmp;
   1973     return PR_TRUE;
   1974 
   1975 loser:
   1976     if (aesKeyTmp)
   1977 	PK11_FreeSymKey(aesKeyTmp);
   1978     if (macKeyTmp)
   1979 	PK11_FreeSymKey(macKeyTmp);
   1980     return PR_FALSE;
   1981 }
   1982 
   1983 PRBool
   1984 ssl_GetSessionTicketKeysPKCS11(SECKEYPrivateKey *svrPrivKey,
   1985                                SECKEYPublicKey *svrPubKey, void *pwArg,
   1986                                unsigned char *keyName, PK11SymKey **aesKey,
   1987                                PK11SymKey **macKey)
   1988 {
   1989     PRUint32 now = 0;
   1990     PRBool rv = PR_FALSE;
   1991     PRBool keysGenerated = PR_FALSE;
   1992     cacheDesc *cache = &globalCache;
   1993 
   1994     if (!cache->cacheMem) {
   1995         /* cache is uninitialized. Generate keys and return them
   1996          * without caching. */
   1997         return GenerateTicketKeys(pwArg, keyName, aesKey, macKey);
   1998     }
   1999 
   2000     now = LockSidCacheLock(cache->keyCacheLock, now);
   2001     if (!now)
   2002 	return rv;
   2003 
   2004     if (!*(cache->ticketKeysValid)) {
   2005 	/* Keys do not exist, create them. */
   2006 	if (!GenerateAndWrapTicketKeys(svrPubKey, pwArg, keyName,
   2007 		aesKey, macKey))
   2008 	    goto loser;
   2009 	keysGenerated = PR_TRUE;
   2010 	*(cache->ticketKeysValid) = 1;
   2011     }
   2012 
   2013     rv = PR_TRUE;
   2014 
   2015  loser:
   2016     UnlockSidCacheLock(cache->keyCacheLock);
   2017     if (rv && !keysGenerated)
   2018 	rv = UnwrapCachedTicketKeys(svrPrivKey, keyName, aesKey, macKey);
   2019     return rv;
   2020 }
   2021 
   2022 PRBool
   2023 ssl_GetSessionTicketKeys(unsigned char *keyName, unsigned char *encKey,
   2024                          unsigned char *macKey)
   2025 {
   2026     PRBool rv = PR_FALSE;
   2027     PRUint32 now = 0;
   2028     cacheDesc *cache = &globalCache;
   2029     PRUint8 ticketMacKey[SHA256_LENGTH], ticketEncKey[AES_256_KEY_LENGTH];
   2030     PRUint8 ticketKeyNameSuffixLocal[SESS_TICKET_KEY_VAR_NAME_LEN];
   2031     PRUint8 *ticketMacKeyPtr, *ticketEncKeyPtr, *ticketKeyNameSuffix;
   2032     PRBool cacheIsEnabled = PR_TRUE;
   2033 
   2034     if (!cache->cacheMem) { /* cache is uninitialized */
   2035         cacheIsEnabled = PR_FALSE;
   2036         ticketKeyNameSuffix = ticketKeyNameSuffixLocal;
   2037         ticketEncKeyPtr = ticketEncKey;
   2038         ticketMacKeyPtr = ticketMacKey;
   2039     } else {
   2040         /* these values have constant memory locations in the cache.
   2041          * Ok to reference them without holding the lock. */
   2042         ticketKeyNameSuffix = cache->ticketKeyNameSuffix;
   2043         ticketEncKeyPtr = cache->ticketEncKey->bytes;
   2044         ticketMacKeyPtr = cache->ticketMacKey->bytes;
   2045     }
   2046 
   2047     if (cacheIsEnabled) {
   2048         /* Grab lock if initialized. */
   2049         now = LockSidCacheLock(cache->keyCacheLock, now);
   2050         if (!now)
   2051             return rv;
   2052     }
   2053     /* Going to regenerate keys on every call if cache was not
   2054      * initialized. */
   2055     if (!cacheIsEnabled || !*(cache->ticketKeysValid)) {
   2056 	if (PK11_GenerateRandom(ticketKeyNameSuffix,
   2057 		SESS_TICKET_KEY_VAR_NAME_LEN) != SECSuccess)
   2058 	    goto loser;
   2059 	if (PK11_GenerateRandom(ticketEncKeyPtr,
   2060                                 AES_256_KEY_LENGTH) != SECSuccess)
   2061 	    goto loser;
   2062 	if (PK11_GenerateRandom(ticketMacKeyPtr,
   2063                                 SHA256_LENGTH) != SECSuccess)
   2064 	    goto loser;
   2065         if (cacheIsEnabled) {
   2066             *(cache->ticketKeysValid) = 1;
   2067         }
   2068     }
   2069 
   2070     rv = PR_TRUE;
   2071 
   2072  loser:
   2073     if (cacheIsEnabled) {
   2074         UnlockSidCacheLock(cache->keyCacheLock);
   2075     }
   2076     if (rv) {
   2077 	PORT_Memcpy(keyName, ticketKeyNameSuffix,
   2078                     SESS_TICKET_KEY_VAR_NAME_LEN);
   2079 	PORT_Memcpy(encKey, ticketEncKeyPtr, AES_256_KEY_LENGTH);
   2080 	PORT_Memcpy(macKey, ticketMacKeyPtr, SHA256_LENGTH);
   2081     }
   2082     return rv;
   2083 }
   2084 
   2085 /* The caller passes in the new value it wants
   2086  * to set.  This code tests the wrapped sym key entry in the shared memory.
   2087  * If it is uninitialized, this function writes the caller's value into
   2088  * the disk entry, and returns false.
   2089  * Otherwise, it overwrites the caller's wswk with the value obtained from
   2090  * the disk, and returns PR_TRUE.
   2091  * This is all done while holding the locks/mutexes necessary to make
   2092  * the operation atomic.
   2093  */
   2094 PRBool
   2095 ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
   2096 {
   2097     cacheDesc *   cache            = &globalCache;
   2098     PRBool        rv               = PR_FALSE;
   2099     SSL3KEAType   exchKeyType      = wswk->exchKeyType;
   2100                                 /* type of keys used to wrap SymWrapKey*/
   2101     PRInt32       symWrapMechIndex = wswk->symWrapMechIndex;
   2102     PRUint32      ndx;
   2103     PRUint32      now = 0;
   2104     SSLWrappedSymWrappingKey myWswk;
   2105 
   2106     if (!cache->cacheMem) { /* cache is uninitialized */
   2107 	PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
   2108 	return 0;
   2109     }
   2110 
   2111     PORT_Assert( (unsigned)exchKeyType < kt_kea_size);
   2112     if ((unsigned)exchKeyType >= kt_kea_size)
   2113     	return 0;
   2114 
   2115     PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
   2116     if ((unsigned)symWrapMechIndex >=  SSL_NUM_WRAP_MECHS)
   2117     	return 0;
   2118 
   2119     ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
   2120     PORT_Memset(&myWswk, 0, sizeof myWswk);	/* eliminate UMRs. */
   2121 
   2122     now = LockSidCacheLock(cache->keyCacheLock, now);
   2123     if (now) {
   2124 	rv = getSvrWrappingKey(wswk->symWrapMechIndex, wswk->exchKeyType,
   2125 	                       &myWswk, cache, now);
   2126 	if (rv) {
   2127 	    /* we found it on disk, copy it out to the caller. */
   2128 	    PORT_Memcpy(wswk, &myWswk, sizeof *wswk);
   2129 	} else {
   2130 	    /* Wasn't on disk, and we're still holding the lock, so write it. */
   2131 	    cache->keyCacheData[ndx] = *wswk;
   2132 	}
   2133 	UnlockSidCacheLock(cache->keyCacheLock);
   2134     }
   2135     return rv;
   2136 }
   2137 
   2138 #else  /* MAC version or other platform */
   2139 
   2140 #include "seccomon.h"
   2141 #include "cert.h"
   2142 #include "ssl.h"
   2143 #include "sslimpl.h"
   2144 
   2145 SECStatus
   2146 SSL_ConfigServerSessionIDCache(	int      maxCacheEntries,
   2147 				PRUint32 ssl2_timeout,
   2148 			       	PRUint32 ssl3_timeout,
   2149 			  const char *   directory)
   2150 {
   2151     PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigServerSessionIDCache)");
   2152     return SECFailure;
   2153 }
   2154 
   2155 SECStatus
   2156 SSL_ConfigMPServerSIDCache(	int      maxCacheEntries,
   2157 				PRUint32 ssl2_timeout,
   2158 			       	PRUint32 ssl3_timeout,
   2159 		          const char *   directory)
   2160 {
   2161     PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigMPServerSIDCache)");
   2162     return SECFailure;
   2163 }
   2164 
   2165 SECStatus
   2166 SSL_InheritMPServerSIDCache(const char * envString)
   2167 {
   2168     PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_InheritMPServerSIDCache)");
   2169     return SECFailure;
   2170 }
   2171 
   2172 PRBool
   2173 ssl_GetWrappingKey( PRInt32                   symWrapMechIndex,
   2174                     SSL3KEAType               exchKeyType,
   2175 		    SSLWrappedSymWrappingKey *wswk)
   2176 {
   2177     PRBool rv = PR_FALSE;
   2178     PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_GetWrappingKey)");
   2179     return rv;
   2180 }
   2181 
   2182 /* This is a kind of test-and-set.  The caller passes in the new value it wants
   2183  * to set.  This code tests the wrapped sym key entry in the shared memory.
   2184  * If it is uninitialized, this function writes the caller's value into
   2185  * the disk entry, and returns false.
   2186  * Otherwise, it overwrites the caller's wswk with the value obtained from
   2187  * the disk, and returns PR_TRUE.
   2188  * This is all done while holding the locks/mutexes necessary to make
   2189  * the operation atomic.
   2190  */
   2191 PRBool
   2192 ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
   2193 {
   2194     PRBool        rv = PR_FALSE;
   2195     PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_SetWrappingKey)");
   2196     return rv;
   2197 }
   2198 
   2199 PRUint32
   2200 SSL_GetMaxServerCacheLocks(void)
   2201 {
   2202     PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_GetMaxServerCacheLocks)");
   2203     return -1;
   2204 }
   2205 
   2206 SECStatus
   2207 SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
   2208 {
   2209     PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_SetMaxServerCacheLocks)");
   2210     return SECFailure;
   2211 }
   2212 
   2213 #endif /* XP_UNIX || XP_WIN32 */
   2214