PageRenderTime 137ms CodeModel.GetById 21ms app.highlight 103ms RepoModel.GetById 1ms app.codeStats 1ms

/security/nss/lib/ssl/sslsnce.c

http://github.com/zpao/v8monkey
C | 2237 lines | 1644 code | 300 blank | 293 comment | 251 complexity | c8d7083e0dee098ee8b81b13690e85e3 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/* This file implements the SERVER Session ID cache. 
   2 * NOTE:  The contents of this file are NOT used by the client.
   3 *
   4 * ***** BEGIN LICENSE BLOCK *****
   5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
   6 *
   7 * The contents of this file are subject to the Mozilla Public License Version
   8 * 1.1 (the "License"); you may not use this file except in compliance with
   9 * the License. You may obtain a copy of the License at
  10 * http://www.mozilla.org/MPL/
  11 *
  12 * Software distributed under the License is distributed on an "AS IS" basis,
  13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  14 * for the specific language governing rights and limitations under the
  15 * License.
  16 *
  17 * The Original Code is the Netscape security libraries.
  18 *
  19 * The Initial Developer of the Original Code is
  20 * Netscape Communications Corporation.
  21 * Portions created by the Initial Developer are Copyright (C) 1994-2000
  22 * the Initial Developer. All Rights Reserved.
  23 *
  24 * Contributor(s):
  25 *
  26 * Alternatively, the contents of this file may be used under the terms of
  27 * either the GNU General Public License Version 2 or later (the "GPL"), or
  28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  29 * in which case the provisions of the GPL or the LGPL are applicable instead
  30 * of those above. If you wish to allow use of your version of this file only
  31 * under the terms of either the GPL or the LGPL, and not to allow others to
  32 * use your version of this file under the terms of the MPL, indicate your
  33 * decision by deleting the provisions above and replace them with the notice
  34 * and other provisions required by the GPL or the LGPL. If you do not delete
  35 * the provisions above, a recipient may use your version of this file under
  36 * the terms of any one of the MPL, the GPL or the LGPL.
  37 *
  38 * ***** END LICENSE BLOCK ***** */
  39/* $Id: sslsnce.c,v 1.59 2011/10/22 16:45:40 emaldona%redhat.com Exp $ */
  40
  41/* Note: ssl_FreeSID() in sslnonce.c gets used for both client and server 
  42 * cache sids!
  43 *
  44 * About record locking among different server processes:
  45 *
  46 * All processes that are part of the same conceptual server (serving on 
  47 * the same address and port) MUST share a common SSL session cache. 
  48 * This code makes the content of the shared cache accessible to all
  49 * processes on the same "server".  This code works on Unix and Win32 only.
  50 *
  51 * We use NSPR anonymous shared memory and move data to & from shared memory.
  52 * We must do explicit locking of the records for all reads and writes.
  53 * The set of Cache entries are divided up into "sets" of 128 entries. 
  54 * Each set is protected by a lock.  There may be one or more sets protected
  55 * by each lock.  That is, locks to sets are 1:N.
  56 * There is one lock for the entire cert cache.
  57 * There is one lock for the set of wrapped sym wrap keys.
  58 *
  59 * The anonymous shared memory is laid out as if it were declared like this:
  60 *
  61 * struct {
  62 *     cacheDescriptor          desc;
  63 *     sidCacheLock             sidCacheLocks[ numSIDCacheLocks];
  64 *     sidCacheLock             keyCacheLock;
  65 *     sidCacheLock             certCacheLock;
  66 *     sidCacheSet              sidCacheSets[ numSIDCacheSets ];
  67 *     sidCacheEntry            sidCacheData[ numSIDCacheEntries];
  68 *     certCacheEntry           certCacheData[numCertCacheEntries];
  69 *     SSLWrappedSymWrappingKey keyCacheData[kt_kea_size][SSL_NUM_WRAP_MECHS];
  70 *     uint8                    keyNameSuffix[SESS_TICKET_KEY_VAR_NAME_LEN]
  71 *     encKeyCacheEntry         ticketEncKey; // Wrapped in non-bypass mode
  72 *     encKeyCacheEntry         ticketMacKey; // Wrapped in non-bypass mode
  73 *     PRBool                   ticketKeysValid;
  74 *     sidCacheLock             srvNameCacheLock;
  75 *     srvNameCacheEntry        srvNameData[ numSrvNameCacheEntries ];
  76 * } cacheMemCacheData;
  77 */
  78#include "seccomon.h"
  79
  80#if defined(XP_UNIX) || defined(XP_WIN32) || defined (XP_OS2) || defined(XP_BEOS)
  81
  82#include "cert.h"
  83#include "ssl.h"
  84#include "sslimpl.h"
  85#include "sslproto.h"
  86#include "pk11func.h"
  87#include "base64.h"
  88#include "keyhi.h"
  89#include "blapi.h"
  90
  91#include <stdio.h>
  92
  93#if defined(XP_UNIX) || defined(XP_BEOS)
  94
  95#include <syslog.h>
  96#include <fcntl.h>
  97#include <unistd.h>
  98#include <errno.h>
  99#include <signal.h>
 100#include "unix_err.h"
 101
 102#else
 103
 104#ifdef XP_WIN32
 105#include <wtypes.h>
 106#include "win32err.h"
 107#endif
 108
 109#endif 
 110#include <sys/types.h>
 111
 112#define SET_ERROR_CODE /* reminder */
 113
 114#include "nspr.h"
 115#include "sslmutex.h"
 116
 117/*
 118** Format of a cache entry in the shared memory.
 119*/ 
 120struct sidCacheEntryStr {
 121/* 16 */    PRIPv6Addr  addr;	/* client's IP address */
 122/*  4 */    PRUint32    creationTime;
 123/*  4 */    PRUint32    lastAccessTime;	
 124/*  4 */    PRUint32    expirationTime;
 125/*  2 */    PRUint16	version;
 126/*  1 */    PRUint8	valid;
 127/*  1 */    PRUint8     sessionIDLength;
 128/* 32 */    PRUint8     sessionID[SSL3_SESSIONID_BYTES];
 129/*  2 */    PRUint16    authAlgorithm;
 130/*  2 */    PRUint16    authKeyBits;
 131/*  2 */    PRUint16    keaType;
 132/*  2 */    PRUint16    keaKeyBits;
 133/* 72  - common header total */
 134
 135    union {
 136	struct {
 137/* 64 */    PRUint8	masterKey[SSL_MAX_MASTER_KEY_BYTES];
 138/* 32 */    PRUint8	cipherArg[SSL_MAX_CYPHER_ARG_BYTES];
 139
 140/*  1 */    PRUint8	cipherType;
 141/*  1 */    PRUint8	masterKeyLen;
 142/*  1 */    PRUint8	keyBits;
 143/*  1 */    PRUint8	secretKeyBits;
 144/*  1 */    PRUint8	cipherArgLen;
 145/*101 */} ssl2;
 146
 147	struct {
 148/*  2 */    ssl3CipherSuite  cipherSuite;
 149/*  2 */    PRUint16    compression; 	/* SSLCompressionMethod */
 150
 151/*100 */    ssl3SidKeys keys;	/* keys and ivs, wrapped as needed. */
 152
 153/*  4 */    PRUint32    masterWrapMech; 
 154/*  4 */    SSL3KEAType exchKeyType;
 155/*  4 */    PRInt32     certIndex;
 156/*  4 */    PRInt32     srvNameIndex;
 157/* 32 */    PRUint8     srvNameHash[SHA256_LENGTH]; /* SHA256 name hash */
 158/*152 */} ssl3;
 159/* force sizeof(sidCacheEntry) to be a multiple of cache line size */
 160        struct {
 161/*152 */    PRUint8     filler[120]; /* 72+152==224, a multiple of 16 */
 162	} forceSize;
 163    } u;
 164};
 165typedef struct sidCacheEntryStr sidCacheEntry;
 166
 167/* The length of this struct is supposed to be a power of 2, e.g. 4KB */
 168struct certCacheEntryStr {
 169    PRUint16    certLength;				/*    2 */
 170    PRUint16    sessionIDLength;			/*    2 */
 171    PRUint8 	sessionID[SSL3_SESSIONID_BYTES];	/*   32 */
 172    PRUint8 	cert[SSL_MAX_CACHED_CERT_LEN];		/* 4060 */
 173};						/* total   4096 */
 174typedef struct certCacheEntryStr certCacheEntry;
 175
 176struct sidCacheLockStr {
 177    PRUint32	timeStamp;
 178    sslMutex	mutex;
 179    sslPID	pid;
 180};
 181typedef struct sidCacheLockStr sidCacheLock;
 182
 183struct sidCacheSetStr {
 184    PRIntn	next;
 185};
 186typedef struct sidCacheSetStr sidCacheSet;
 187
 188struct encKeyCacheEntryStr {
 189    PRUint8	bytes[512];
 190    PRInt32	length;
 191};
 192typedef struct encKeyCacheEntryStr encKeyCacheEntry;
 193
 194#define SSL_MAX_DNS_HOST_NAME  1024
 195
 196struct srvNameCacheEntryStr {
 197    PRUint16    type;                                   /*    2 */
 198    PRUint16    nameLen;                                /*    2 */
 199    PRUint8	name[SSL_MAX_DNS_HOST_NAME + 12];       /* 1034 */
 200    PRUint8 	nameHash[SHA256_LENGTH];                /*   32 */
 201                                                        /* 1072 */
 202};
 203typedef struct srvNameCacheEntryStr srvNameCacheEntry;
 204
 205
 206struct cacheDescStr {
 207
 208    PRUint32            cacheMemSize;
 209
 210    PRUint32		numSIDCacheLocks;
 211    PRUint32		numSIDCacheSets;
 212    PRUint32		numSIDCacheSetsPerLock;
 213
 214    PRUint32            numSIDCacheEntries; 
 215    PRUint32            sidCacheSize;
 216
 217    PRUint32            numCertCacheEntries;
 218    PRUint32            certCacheSize;
 219
 220    PRUint32            numKeyCacheEntries;
 221    PRUint32            keyCacheSize;
 222
 223    PRUint32            numSrvNameCacheEntries;
 224    PRUint32            srvNameCacheSize;
 225
 226    PRUint32		ssl2Timeout;
 227    PRUint32		ssl3Timeout;
 228
 229    PRUint32            numSIDCacheLocksInitialized;
 230
 231    /* These values are volatile, and are accessed through sharedCache-> */
 232    PRUint32		nextCertCacheEntry;	/* certCacheLock protects */
 233    PRBool      	stopPolling;
 234    PRBool		everInherited;
 235
 236    /* The private copies of these values are pointers into shared mem */
 237    /* The copies of these values in shared memory are merely offsets */
 238    sidCacheLock    *          sidCacheLocks;
 239    sidCacheLock    *          keyCacheLock;
 240    sidCacheLock    *          certCacheLock;
 241    sidCacheLock    *          srvNameCacheLock;
 242    sidCacheSet     *          sidCacheSets;
 243    sidCacheEntry   *          sidCacheData;
 244    certCacheEntry  *          certCacheData;
 245    SSLWrappedSymWrappingKey * keyCacheData;
 246    uint8           *          ticketKeyNameSuffix;
 247    encKeyCacheEntry         * ticketEncKey;
 248    encKeyCacheEntry         * ticketMacKey;
 249    PRUint32        *          ticketKeysValid;
 250    srvNameCacheEntry *        srvNameCacheData;
 251
 252    /* Only the private copies of these pointers are valid */
 253    char *                     cacheMem;
 254    struct cacheDescStr *      sharedCache;  /* shared copy of this struct */
 255    PRFileMap *                cacheMemMap;
 256    PRThread  *                poller;
 257    PRUint32                   mutexTimeout;
 258    PRBool                     shared;
 259};
 260typedef struct cacheDescStr cacheDesc;
 261
 262static cacheDesc globalCache;
 263
 264static const char envVarName[] = { SSL_ENV_VAR_NAME };
 265
 266static PRBool isMultiProcess  = PR_FALSE;
 267
 268
 269#define DEF_SID_CACHE_ENTRIES  10000
 270#define DEF_CERT_CACHE_ENTRIES 250
 271#define MIN_CERT_CACHE_ENTRIES 125 /* the effective size in old releases. */
 272#define DEF_KEY_CACHE_ENTRIES  250
 273#define DEF_NAME_CACHE_ENTRIES  1000
 274
 275#define SID_CACHE_ENTRIES_PER_SET  128
 276#define SID_ALIGNMENT          16
 277
 278#define DEF_SSL2_TIMEOUT	100   /* seconds */
 279#define MAX_SSL2_TIMEOUT	100   /* seconds */
 280#define MIN_SSL2_TIMEOUT	  5   /* seconds */
 281
 282#define DEF_SSL3_TIMEOUT      86400L  /* 24 hours */
 283#define MAX_SSL3_TIMEOUT      86400L  /* 24 hours */
 284#define MIN_SSL3_TIMEOUT          5   /* seconds  */
 285
 286#if defined(AIX) || defined(LINUX) || defined(NETBSD) || defined(OPENBSD)
 287#define MAX_SID_CACHE_LOCKS 8	/* two FDs per lock */
 288#elif defined(OSF1)
 289#define MAX_SID_CACHE_LOCKS 16	/* one FD per lock */
 290#else
 291#define MAX_SID_CACHE_LOCKS 256
 292#endif
 293
 294#define SID_HOWMANY(val, size) (((val) + ((size) - 1)) / (size))
 295#define SID_ROUNDUP(val, size) ((size) * SID_HOWMANY((val), (size)))
 296
 297
 298static sslPID myPid;
 299static PRUint32  ssl_max_sid_cache_locks = MAX_SID_CACHE_LOCKS;
 300
 301/* forward static function declarations */
 302static PRUint32 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, 
 303                         unsigned nl);
 304static SECStatus LaunchLockPoller(cacheDesc *cache);
 305static SECStatus StopLockPoller(cacheDesc *cache);
 306
 307
 308struct inheritanceStr {
 309    PRUint32 cacheMemSize;
 310    PRUint32 fmStrLen;
 311};
 312
 313typedef struct inheritanceStr inheritance;
 314
 315#if defined(_WIN32) || defined(XP_OS2)
 316
 317#define DEFAULT_CACHE_DIRECTORY "\\temp"
 318
 319#endif /* _win32 */
 320
 321#if defined(XP_UNIX) || defined(XP_BEOS)
 322
 323#define DEFAULT_CACHE_DIRECTORY "/tmp"
 324
 325#endif /* XP_UNIX || XP_BEOS */
 326
 327
 328/************************************************************************/
 329
 330static PRUint32
 331LockSidCacheLock(sidCacheLock *lock, PRUint32 now)
 332{
 333    SECStatus      rv      = sslMutex_Lock(&lock->mutex);
 334    if (rv != SECSuccess)
 335    	return 0;
 336    if (!now)
 337	now  = ssl_Time();
 338    lock->timeStamp = now;
 339    lock->pid       = myPid;
 340    return now;
 341}
 342
 343static SECStatus
 344UnlockSidCacheLock(sidCacheLock *lock)
 345{
 346    SECStatus      rv;
 347
 348    lock->pid = 0;
 349    rv        = sslMutex_Unlock(&lock->mutex);
 350    return rv;
 351}
 352
 353/* returns the value of ssl_Time on success, zero on failure. */
 354static PRUint32
 355LockSet(cacheDesc *cache, PRUint32 set, PRUint32 now)
 356{
 357    PRUint32       lockNum = set % cache->numSIDCacheLocks;
 358    sidCacheLock * lock    = cache->sidCacheLocks + lockNum;
 359
 360    return LockSidCacheLock(lock, now);
 361}
 362
 363static SECStatus
 364UnlockSet(cacheDesc *cache, PRUint32 set)
 365{
 366    PRUint32       lockNum = set % cache->numSIDCacheLocks;
 367    sidCacheLock * lock    = cache->sidCacheLocks + lockNum;
 368
 369    return UnlockSidCacheLock(lock);
 370}
 371
 372/************************************************************************/
 373
 374
 375/* Put a certificate in the cache.  Update the cert index in the sce.
 376*/
 377static PRUint32
 378CacheCert(cacheDesc * cache, CERTCertificate *cert, sidCacheEntry *sce)
 379{
 380    PRUint32        now;
 381    certCacheEntry  cce;
 382
 383    if ((cert->derCert.len > SSL_MAX_CACHED_CERT_LEN) ||
 384        (cert->derCert.len <= 0) ||
 385	(cert->derCert.data == NULL)) {
 386	PORT_SetError(SEC_ERROR_INVALID_ARGS);
 387	return 0;
 388    }
 389
 390    cce.sessionIDLength = sce->sessionIDLength;
 391    PORT_Memcpy(cce.sessionID, sce->sessionID, cce.sessionIDLength);
 392
 393    cce.certLength = cert->derCert.len;
 394    PORT_Memcpy(cce.cert, cert->derCert.data, cce.certLength);
 395
 396    /* get lock on cert cache */
 397    now = LockSidCacheLock(cache->certCacheLock, 0);
 398    if (now) {
 399
 400	/* Find where to place the next cert cache entry. */
 401	cacheDesc * sharedCache = cache->sharedCache;
 402	PRUint32    ndx         = sharedCache->nextCertCacheEntry;
 403
 404	/* write the entry */
 405	cache->certCacheData[ndx] = cce;
 406
 407	/* remember where we put it. */
 408	sce->u.ssl3.certIndex = ndx;
 409
 410	/* update the "next" cache entry index */
 411	sharedCache->nextCertCacheEntry = 
 412					(ndx + 1) % cache->numCertCacheEntries;
 413
 414	UnlockSidCacheLock(cache->certCacheLock);
 415    }
 416    return now;
 417
 418}
 419
 420/* Server configuration hash tables need to account the SECITEM.type
 421 * field as well. These functions accomplish that. */
 422static PLHashNumber
 423Get32BitNameHash(const SECItem *name)
 424{
 425    PLHashNumber rv = SECITEM_Hash(name);
 426    
 427    PRUint8 *rvc = (PRUint8 *)&rv;
 428    rvc[ name->len % sizeof(rv) ] ^= name->type;
 429
 430    return rv;
 431}
 432
 433/* Put a name in the cache.  Update the cert index in the sce.
 434*/
 435static PRUint32
 436CacheSrvName(cacheDesc * cache, SECItem *name, sidCacheEntry *sce)
 437{
 438    PRUint32           now;
 439    PRUint32           ndx;
 440    srvNameCacheEntry  snce;
 441
 442    if (!name || name->len <= 0 ||
 443        name->len > SSL_MAX_DNS_HOST_NAME) {
 444	PORT_SetError(SEC_ERROR_INVALID_ARGS);
 445	return 0;
 446    }
 447
 448    snce.type = name->type;
 449    snce.nameLen = name->len;
 450    PORT_Memcpy(snce.name, name->data, snce.nameLen);
 451    SHA256_HashBuf(snce.nameHash, (unsigned char*)name->data,
 452                   name->len);
 453    /* get index of the next name */
 454    ndx = Get32BitNameHash(name);
 455    /* get lock on cert cache */
 456    now = LockSidCacheLock(cache->srvNameCacheLock, 0);
 457    if (now) {
 458        if (cache->numSrvNameCacheEntries > 0) {
 459            /* Fit the index into array */
 460            ndx %= cache->numSrvNameCacheEntries;
 461            /* write the entry */
 462            cache->srvNameCacheData[ndx] = snce;
 463            /* remember where we put it. */
 464            sce->u.ssl3.srvNameIndex = ndx;
 465            /* Copy hash into sid hash */
 466            PORT_Memcpy(sce->u.ssl3.srvNameHash, snce.nameHash, SHA256_LENGTH);
 467        }
 468	UnlockSidCacheLock(cache->srvNameCacheLock);
 469    }
 470    return now;
 471}
 472
 473/*
 474** Convert local SID to shared memory one
 475*/
 476static void 
 477ConvertFromSID(sidCacheEntry *to, sslSessionID *from)
 478{
 479    to->valid   = 1;
 480    to->version = from->version;
 481    to->addr    = from->addr;
 482    to->creationTime    = from->creationTime;
 483    to->lastAccessTime  = from->lastAccessTime;
 484    to->expirationTime  = from->expirationTime;
 485    to->authAlgorithm	= from->authAlgorithm;
 486    to->authKeyBits	= from->authKeyBits;
 487    to->keaType		= from->keaType;
 488    to->keaKeyBits	= from->keaKeyBits;
 489
 490    if (from->version < SSL_LIBRARY_VERSION_3_0) {
 491	if ((from->u.ssl2.masterKey.len > SSL_MAX_MASTER_KEY_BYTES) ||
 492	    (from->u.ssl2.cipherArg.len > SSL_MAX_CYPHER_ARG_BYTES)) {
 493	    SSL_DBG(("%d: SSL: masterKeyLen=%d cipherArgLen=%d",
 494		     myPid, from->u.ssl2.masterKey.len,
 495		     from->u.ssl2.cipherArg.len));
 496	    to->valid = 0;
 497	    return;
 498	}
 499
 500	to->u.ssl2.cipherType    = from->u.ssl2.cipherType;
 501	to->u.ssl2.masterKeyLen  = from->u.ssl2.masterKey.len;
 502	to->u.ssl2.cipherArgLen  = from->u.ssl2.cipherArg.len;
 503	to->u.ssl2.keyBits       = from->u.ssl2.keyBits;
 504	to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits;
 505	to->sessionIDLength      = SSL2_SESSIONID_BYTES;
 506	PORT_Memcpy(to->sessionID, from->u.ssl2.sessionID, SSL2_SESSIONID_BYTES);
 507	PORT_Memcpy(to->u.ssl2.masterKey, from->u.ssl2.masterKey.data,
 508		  from->u.ssl2.masterKey.len);
 509	PORT_Memcpy(to->u.ssl2.cipherArg, from->u.ssl2.cipherArg.data,
 510		  from->u.ssl2.cipherArg.len);
 511#ifdef DEBUG
 512	PORT_Memset(to->u.ssl2.masterKey+from->u.ssl2.masterKey.len, 0,
 513		  sizeof(to->u.ssl2.masterKey) - from->u.ssl2.masterKey.len);
 514	PORT_Memset(to->u.ssl2.cipherArg+from->u.ssl2.cipherArg.len, 0,
 515		  sizeof(to->u.ssl2.cipherArg) - from->u.ssl2.cipherArg.len);
 516#endif
 517	SSL_TRC(8, ("%d: SSL: ConvertSID: masterKeyLen=%d cipherArgLen=%d "
 518		    "time=%d addr=0x%08x%08x%08x%08x cipherType=%d", myPid,
 519		    to->u.ssl2.masterKeyLen, to->u.ssl2.cipherArgLen,
 520		    to->creationTime, to->addr.pr_s6_addr32[0],
 521		    to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2],
 522		    to->addr.pr_s6_addr32[3], to->u.ssl2.cipherType));
 523    } else {
 524	/* This is an SSL v3 session */
 525
 526	to->u.ssl3.cipherSuite      = from->u.ssl3.cipherSuite;
 527	to->u.ssl3.compression      = (uint16)from->u.ssl3.compression;
 528	to->u.ssl3.keys             = from->u.ssl3.keys;
 529	to->u.ssl3.masterWrapMech   = from->u.ssl3.masterWrapMech;
 530	to->u.ssl3.exchKeyType      = from->u.ssl3.exchKeyType;
 531	to->sessionIDLength         = from->u.ssl3.sessionIDLength;
 532	to->u.ssl3.certIndex        = -1;
 533	to->u.ssl3.srvNameIndex     = -1;
 534
 535	PORT_Memcpy(to->sessionID, from->u.ssl3.sessionID,
 536		    to->sessionIDLength);
 537
 538	SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x "
 539	            "cipherSuite=%d",
 540		    myPid, to->creationTime, to->addr.pr_s6_addr32[0],
 541		    to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2],
 542		    to->addr.pr_s6_addr32[3], to->u.ssl3.cipherSuite));
 543    }
 544}
 545
 546/*
 547** Convert shared memory cache-entry to local memory based one
 548** This is only called from ServerSessionIDLookup().
 549** Caller must hold cache lock when calling this.
 550*/
 551static sslSessionID *
 552ConvertToSID(sidCacheEntry *    from,
 553             certCacheEntry *   pcce,
 554             srvNameCacheEntry *psnce,
 555             CERTCertDBHandle * dbHandle)
 556{
 557    sslSessionID *to;
 558    uint16 version = from->version;
 559
 560    to = (sslSessionID*) PORT_ZAlloc(sizeof(sslSessionID));
 561    if (!to) {
 562	return 0;
 563    }
 564
 565    if (version < SSL_LIBRARY_VERSION_3_0) {
 566	/* This is an SSL v2 session */
 567	to->u.ssl2.masterKey.data =
 568	    (unsigned char*) PORT_Alloc(from->u.ssl2.masterKeyLen);
 569	if (!to->u.ssl2.masterKey.data) {
 570	    goto loser;
 571	}
 572	if (from->u.ssl2.cipherArgLen) {
 573	    to->u.ssl2.cipherArg.data = 
 574	    	(unsigned char*)PORT_Alloc(from->u.ssl2.cipherArgLen);
 575	    if (!to->u.ssl2.cipherArg.data) {
 576		goto loser;
 577	    }
 578	    PORT_Memcpy(to->u.ssl2.cipherArg.data, from->u.ssl2.cipherArg,
 579		        from->u.ssl2.cipherArgLen);
 580	}
 581
 582	to->u.ssl2.cipherType    = from->u.ssl2.cipherType;
 583	to->u.ssl2.masterKey.len = from->u.ssl2.masterKeyLen;
 584	to->u.ssl2.cipherArg.len = from->u.ssl2.cipherArgLen;
 585	to->u.ssl2.keyBits       = from->u.ssl2.keyBits;
 586	to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits;
 587/*	to->sessionIDLength      = SSL2_SESSIONID_BYTES; */
 588	PORT_Memcpy(to->u.ssl2.sessionID, from->sessionID, SSL2_SESSIONID_BYTES);
 589	PORT_Memcpy(to->u.ssl2.masterKey.data, from->u.ssl2.masterKey,
 590		    from->u.ssl2.masterKeyLen);
 591
 592	SSL_TRC(8, ("%d: SSL: ConvertToSID: masterKeyLen=%d cipherArgLen=%d "
 593		    "time=%d addr=0x%08x%08x%08x%08x cipherType=%d",
 594		    myPid, to->u.ssl2.masterKey.len,
 595		    to->u.ssl2.cipherArg.len, to->creationTime,
 596		    to->addr.pr_s6_addr32[0], to->addr.pr_s6_addr32[1],
 597		    to->addr.pr_s6_addr32[2], to->addr.pr_s6_addr32[3],
 598		    to->u.ssl2.cipherType));
 599    } else {
 600	/* This is an SSL v3 session */
 601
 602	to->u.ssl3.sessionIDLength  = from->sessionIDLength;
 603	to->u.ssl3.cipherSuite      = from->u.ssl3.cipherSuite;
 604	to->u.ssl3.compression      = (SSLCompressionMethod)from->u.ssl3.compression;
 605	to->u.ssl3.keys             = from->u.ssl3.keys;
 606	to->u.ssl3.masterWrapMech   = from->u.ssl3.masterWrapMech;
 607	to->u.ssl3.exchKeyType      = from->u.ssl3.exchKeyType;
 608	if (from->u.ssl3.srvNameIndex != -1 && psnce) {
 609            SECItem name;
 610            SECStatus rv;
 611            name.type                   = psnce->type;
 612            name.len                    = psnce->nameLen;
 613            name.data                   = psnce->name;
 614            rv = SECITEM_CopyItem(NULL, &to->u.ssl3.srvName, &name);
 615            if (rv != SECSuccess) {
 616                goto loser;
 617            }
 618        }
 619
 620	PORT_Memcpy(to->u.ssl3.sessionID, from->sessionID, from->sessionIDLength);
 621
 622	/* the portions of the SID that are only restored on the client
 623	 * are set to invalid values on the server.
 624	 */
 625	to->u.ssl3.clientWriteKey   = NULL;
 626	to->u.ssl3.serverWriteKey   = NULL;
 627
 628	to->urlSvrName              = NULL;
 629
 630	to->u.ssl3.masterModuleID   = (SECMODModuleID)-1; /* invalid value */
 631	to->u.ssl3.masterSlotID     = (CK_SLOT_ID)-1;     /* invalid value */
 632	to->u.ssl3.masterWrapIndex  = 0;
 633	to->u.ssl3.masterWrapSeries = 0;
 634	to->u.ssl3.masterValid      = PR_FALSE;
 635
 636	to->u.ssl3.clAuthModuleID   = (SECMODModuleID)-1; /* invalid value */
 637	to->u.ssl3.clAuthSlotID     = (CK_SLOT_ID)-1;     /* invalid value */
 638	to->u.ssl3.clAuthSeries     = 0;
 639	to->u.ssl3.clAuthValid      = PR_FALSE;
 640
 641	if (from->u.ssl3.certIndex != -1 && pcce) {
 642	    SECItem          derCert;
 643
 644	    derCert.len  = pcce->certLength;
 645	    derCert.data = pcce->cert;
 646
 647	    to->peerCert = CERT_NewTempCertificate(dbHandle, &derCert, NULL,
 648					           PR_FALSE, PR_TRUE);
 649	    if (to->peerCert == NULL)
 650		goto loser;
 651	}
 652    }
 653
 654    to->version         = from->version;
 655    to->creationTime    = from->creationTime;
 656    to->lastAccessTime  = from->lastAccessTime;
 657    to->expirationTime  = from->expirationTime;
 658    to->cached          = in_server_cache;
 659    to->addr            = from->addr;
 660    to->references      = 1;
 661    to->authAlgorithm	= from->authAlgorithm;
 662    to->authKeyBits	= from->authKeyBits;
 663    to->keaType		= from->keaType;
 664    to->keaKeyBits	= from->keaKeyBits;
 665    
 666    return to;
 667
 668  loser:
 669    if (to) {
 670	if (version < SSL_LIBRARY_VERSION_3_0) {
 671	    if (to->u.ssl2.masterKey.data)
 672		PORT_Free(to->u.ssl2.masterKey.data);
 673	    if (to->u.ssl2.cipherArg.data)
 674		PORT_Free(to->u.ssl2.cipherArg.data);
 675	} else {
 676            SECITEM_FreeItem(&to->u.ssl3.srvName, PR_FALSE);
 677        }
 678	PORT_Free(to);
 679    }
 680    return NULL;
 681}
 682
 683
 684
 685/*
 686** Perform some mumbo jumbo on the ip-address and the session-id value to
 687** compute a hash value.
 688*/
 689static PRUint32 
 690SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, unsigned nl)
 691{
 692    PRUint32 rv;
 693    PRUint32 x[8];
 694
 695    memset(x, 0, sizeof x);
 696    if (nl > sizeof x)
 697    	nl = sizeof x;
 698    memcpy(x, s, nl);
 699
 700    rv = (addr->pr_s6_addr32[0] ^ addr->pr_s6_addr32[1] ^
 701	  addr->pr_s6_addr32[2] ^ addr->pr_s6_addr32[3] ^
 702          x[0] ^ x[1] ^ x[2] ^ x[3] ^ x[4] ^ x[5] ^ x[6] ^ x[7])
 703	  % cache->numSIDCacheSets;
 704    return rv;
 705}
 706
 707
 708
 709/*
 710** Look something up in the cache. This will invalidate old entries
 711** in the process. Caller has locked the cache set!
 712** Returns PR_TRUE if found a valid match.  PR_FALSE otherwise.
 713*/
 714static sidCacheEntry *
 715FindSID(cacheDesc *cache, PRUint32 setNum, PRUint32 now,
 716        const PRIPv6Addr *addr, unsigned char *sessionID,
 717	unsigned sessionIDLength)
 718{
 719    PRUint32      ndx   = cache->sidCacheSets[setNum].next;
 720    int           i;
 721
 722    sidCacheEntry * set = cache->sidCacheData + 
 723    			 (setNum * SID_CACHE_ENTRIES_PER_SET);
 724
 725    for (i = SID_CACHE_ENTRIES_PER_SET; i > 0; --i) {
 726	sidCacheEntry * sce;
 727
 728	ndx  = (ndx - 1) % SID_CACHE_ENTRIES_PER_SET;
 729	sce = set + ndx;
 730
 731	if (!sce->valid)
 732	    continue;
 733
 734	if (now > sce->expirationTime) {
 735	    /* SessionID has timed out. Invalidate the entry. */
 736	    SSL_TRC(7, ("%d: timed out sid entry addr=%08x%08x%08x%08x now=%x "
 737			"time+=%x",
 738			myPid, sce->addr.pr_s6_addr32[0],
 739			sce->addr.pr_s6_addr32[1], sce->addr.pr_s6_addr32[2],
 740			sce->addr.pr_s6_addr32[3], now,
 741			sce->expirationTime ));
 742	    sce->valid = 0;
 743	    continue;
 744	}
 745
 746	/*
 747	** Next, examine specific session-id/addr data to see if the cache
 748	** entry matches our addr+session-id value
 749	*/
 750	if (sessionIDLength == sce->sessionIDLength      &&
 751	    !memcmp(&sce->addr, addr, sizeof(PRIPv6Addr)) &&
 752	    !memcmp(sce->sessionID, sessionID, sessionIDLength)) {
 753	    /* Found it */
 754	    return sce;
 755	}
 756    }
 757
 758    PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND);
 759    return NULL;
 760}
 761
 762/************************************************************************/
 763
 764/* This is the primary function for finding entries in the server's sid cache.
 765 * Although it is static, this function is called via the global function 
 766 * pointer ssl_sid_lookup.
 767 */
 768static sslSessionID *
 769ServerSessionIDLookup(const PRIPv6Addr *addr,
 770			unsigned char *sessionID,
 771			unsigned int   sessionIDLength,
 772                        CERTCertDBHandle * dbHandle)
 773{
 774    sslSessionID *  sid      = 0;
 775    sidCacheEntry * psce;
 776    certCacheEntry *pcce     = 0;
 777    srvNameCacheEntry *psnce = 0;
 778    cacheDesc *     cache    = &globalCache;
 779    PRUint32        now;
 780    PRUint32        set;
 781    PRInt32         cndx;
 782    sidCacheEntry   sce;
 783    certCacheEntry  cce;
 784    srvNameCacheEntry snce;
 785
 786    set = SIDindex(cache, addr, sessionID, sessionIDLength);
 787    now = LockSet(cache, set, 0);
 788    if (!now)
 789    	return NULL;
 790
 791    psce = FindSID(cache, set, now, addr, sessionID, sessionIDLength);
 792    if (psce) {
 793	if (psce->version >= SSL_LIBRARY_VERSION_3_0) {
 794	    if ((cndx = psce->u.ssl3.certIndex) != -1) {
 795                
 796                PRUint32 gotLock = LockSidCacheLock(cache->certCacheLock, now);
 797                if (gotLock) {
 798                    pcce = &cache->certCacheData[cndx];
 799                    
 800                    /* See if the cert's session ID matches the sce cache. */
 801                    if ((pcce->sessionIDLength == psce->sessionIDLength) &&
 802                        !PORT_Memcmp(pcce->sessionID, psce->sessionID, 
 803                                     pcce->sessionIDLength)) {
 804                        cce = *pcce;
 805                    } else {
 806                        /* The cert doesen't match the SID cache entry, 
 807                        ** so invalidate the SID cache entry. 
 808                        */
 809                        psce->valid = 0;
 810                        psce = 0;
 811                        pcce = 0;
 812                    }
 813                    UnlockSidCacheLock(cache->certCacheLock);
 814                } else {
 815                    /* what the ??.  Didn't get the cert cache lock.
 816                    ** Don't invalidate the SID cache entry, but don't find it.
 817                    */
 818                    PORT_Assert(!("Didn't get cert Cache Lock!"));
 819                    psce = 0;
 820                    pcce = 0;
 821                }
 822            }
 823            if (psce && ((cndx = psce->u.ssl3.srvNameIndex) != -1)) {
 824                PRUint32 gotLock = LockSidCacheLock(cache->srvNameCacheLock,
 825                                                    now);
 826                if (gotLock) {
 827                    psnce = &cache->srvNameCacheData[cndx];
 828                    
 829                    if (!PORT_Memcmp(psnce->nameHash, psce->u.ssl3.srvNameHash, 
 830                                     SHA256_LENGTH)) {
 831                        snce = *psnce;
 832                    } else {
 833                        /* The name doesen't match the SID cache entry, 
 834                        ** so invalidate the SID cache entry. 
 835                        */
 836                        psce->valid = 0;
 837                        psce = 0;
 838                        psnce = 0;
 839                    }
 840                    UnlockSidCacheLock(cache->srvNameCacheLock);
 841                } else {
 842                    /* what the ??.  Didn't get the cert cache lock.
 843                    ** Don't invalidate the SID cache entry, but don't find it.
 844                    */
 845                    PORT_Assert(!("Didn't get name Cache Lock!"));
 846                    psce = 0;
 847                    psnce = 0;
 848                }
 849                
 850            }
 851        }
 852	if (psce) {
 853	    psce->lastAccessTime = now;
 854	    sce = *psce;	/* grab a copy while holding the lock */
 855    	}
 856    }
 857    UnlockSet(cache, set);
 858    if (psce) {
 859	/* sce conains a copy of the cache entry.
 860	** Convert shared memory format to local format 
 861	*/
 862	sid = ConvertToSID(&sce, pcce ? &cce : 0, psnce ? &snce : 0, dbHandle);
 863    }
 864    return sid;
 865}
 866
 867/*
 868** Place a sid into the cache, if it isn't already there. 
 869*/
 870static void 
 871ServerSessionIDCache(sslSessionID *sid)
 872{
 873    sidCacheEntry sce;
 874    PRUint32      now     = 0;
 875    uint16        version = sid->version;
 876    cacheDesc *   cache   = &globalCache;
 877
 878    if ((version >= SSL_LIBRARY_VERSION_3_0) &&
 879	(sid->u.ssl3.sessionIDLength == 0)) {
 880	return;
 881    }
 882
 883    if (sid->cached == never_cached || sid->cached == invalid_cache) {
 884	PRUint32 set;
 885
 886	PORT_Assert(sid->creationTime != 0);
 887	if (!sid->creationTime)
 888	    sid->lastAccessTime = sid->creationTime = ssl_Time();
 889	if (version < SSL_LIBRARY_VERSION_3_0) {
 890	    /* override caller's expiration time, which uses client timeout
 891	     * duration, not server timeout duration.
 892	     */
 893	    sid->expirationTime = sid->creationTime + cache->ssl2Timeout;
 894	    SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
 895			"cipher=%d", myPid, sid->cached,
 896			sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
 897			sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
 898			sid->creationTime, sid->u.ssl2.cipherType));
 899	    PRINT_BUF(8, (0, "sessionID:", sid->u.ssl2.sessionID,
 900			  SSL2_SESSIONID_BYTES));
 901	    PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data,
 902			  sid->u.ssl2.masterKey.len));
 903	    PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data,
 904			  sid->u.ssl2.cipherArg.len));
 905
 906	} else {
 907	    /* override caller's expiration time, which uses client timeout
 908	     * duration, not server timeout duration.
 909	     */
 910	    sid->expirationTime = sid->creationTime + cache->ssl3Timeout;
 911	    SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
 912			"cipherSuite=%d", myPid, sid->cached,
 913			sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
 914			sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
 915			sid->creationTime, sid->u.ssl3.cipherSuite));
 916	    PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID,
 917			  sid->u.ssl3.sessionIDLength));
 918	}
 919
 920	ConvertFromSID(&sce, sid);
 921
 922	if (version >= SSL_LIBRARY_VERSION_3_0) {
 923            SECItem *name = &sid->u.ssl3.srvName;
 924            if (name->len && name->data) {
 925                now = CacheSrvName(cache, name, &sce);
 926            }
 927            if (sid->peerCert != NULL) {
 928                now = CacheCert(cache, sid->peerCert, &sce);
 929            }
 930	}
 931
 932	set = SIDindex(cache, &sce.addr, sce.sessionID, sce.sessionIDLength);
 933	now = LockSet(cache, set, now);
 934	if (now) {
 935	    PRUint32  next = cache->sidCacheSets[set].next;
 936	    PRUint32  ndx  = set * SID_CACHE_ENTRIES_PER_SET + next;
 937
 938	    /* Write out new cache entry */
 939	    cache->sidCacheData[ndx] = sce;
 940
 941	    cache->sidCacheSets[set].next = 
 942	    				(next + 1) % SID_CACHE_ENTRIES_PER_SET;
 943
 944	    UnlockSet(cache, set);
 945	    sid->cached = in_server_cache;
 946	}
 947    }
 948}
 949
 950/*
 951** Although this is static, it is called from ssl via global function pointer
 952**	ssl_sid_uncache.  This invalidates the referenced cache entry.
 953*/
 954static void 
 955ServerSessionIDUncache(sslSessionID *sid)
 956{
 957    cacheDesc *    cache   = &globalCache;
 958    PRUint8 *      sessionID;
 959    unsigned int   sessionIDLength;
 960    PRErrorCode    err;
 961    PRUint32       set;
 962    PRUint32       now;
 963    sidCacheEntry *psce;
 964
 965    if (sid == NULL) 
 966    	return;
 967    
 968    /* Uncaching a SID should never change the error code. 
 969    ** So save it here and restore it before exiting.
 970    */
 971    err = PR_GetError();
 972
 973    if (sid->version < SSL_LIBRARY_VERSION_3_0) {
 974	sessionID       = sid->u.ssl2.sessionID;
 975	sessionIDLength = SSL2_SESSIONID_BYTES;
 976	SSL_TRC(8, ("%d: SSL: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
 977		    "cipher=%d", myPid, sid->cached,
 978		    sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
 979		    sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
 980		    sid->creationTime, sid->u.ssl2.cipherType));
 981	PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength));
 982	PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data,
 983		      sid->u.ssl2.masterKey.len));
 984	PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data,
 985		      sid->u.ssl2.cipherArg.len));
 986    } else {
 987	sessionID       = sid->u.ssl3.sessionID;
 988	sessionIDLength = sid->u.ssl3.sessionIDLength;
 989	SSL_TRC(8, ("%d: SSL3: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
 990		    "cipherSuite=%d", myPid, sid->cached,
 991		    sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
 992		    sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
 993		    sid->creationTime, sid->u.ssl3.cipherSuite));
 994	PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength));
 995    }
 996    set = SIDindex(cache, &sid->addr, sessionID, sessionIDLength);
 997    now = LockSet(cache, set, 0);
 998    if (now) {
 999	psce = FindSID(cache, set, now, &sid->addr, sessionID, sessionIDLength);
1000	if (psce) {
1001	    psce->valid = 0;
1002	}
1003	UnlockSet(cache, set);
1004    }
1005    sid->cached = invalid_cache;
1006    PORT_SetError(err);
1007}
1008
1009#ifdef XP_OS2
1010
1011#define INCL_DOSPROCESS
1012#include <os2.h>
1013
1014long gettid(void)
1015{
1016    PTIB ptib;
1017    PPIB ppib;
1018    DosGetInfoBlocks(&ptib, &ppib);
1019    return ((long)ptib->tib_ordinal); /* thread id */
1020}
1021#endif
1022
1023static void
1024CloseCache(cacheDesc *cache)
1025{
1026    int locks_initialized = cache->numSIDCacheLocksInitialized;
1027
1028    if (cache->cacheMem) {
1029	if (cache->sharedCache) {
1030	    sidCacheLock *pLock = cache->sidCacheLocks;
1031	    for (; locks_initialized > 0; --locks_initialized, ++pLock ) {
1032		/* If everInherited is true, this shared cache was (and may
1033		** still be) in use by multiple processes.  We do not wish to
1034		** destroy the mutexes while they are still in use, but we do
1035		** want to free mutex resources associated with this process.
1036		*/
1037		sslMutex_Destroy(&pLock->mutex,
1038				 cache->sharedCache->everInherited);
1039	    }
1040	}
1041	if (cache->shared) {
1042	    PR_MemUnmap(cache->cacheMem, cache->cacheMemSize);
1043	} else {
1044	    PORT_Free(cache->cacheMem);
1045	}
1046	cache->cacheMem = NULL;
1047    }
1048    if (cache->cacheMemMap) {
1049	PR_CloseFileMap(cache->cacheMemMap);
1050	cache->cacheMemMap = NULL;
1051    }
1052    memset(cache, 0, sizeof *cache);
1053}
1054
1055static SECStatus
1056InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries,
1057          int maxSrvNameCacheEntries, PRUint32 ssl2_timeout, 
1058          PRUint32 ssl3_timeout, const char *directory, PRBool shared)
1059{
1060    ptrdiff_t     ptr;
1061    sidCacheLock *pLock;
1062    char *        cacheMem;
1063    PRFileMap *   cacheMemMap;
1064    char *        cfn = NULL;	/* cache file name */
1065    int           locks_initialized = 0;
1066    int           locks_to_initialize = 0;
1067    PRUint32      init_time;
1068
1069    if ( (!cache) || (maxCacheEntries < 0) || (!directory) ) {
1070        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1071        return SECFailure;
1072    }
1073
1074    if (cache->cacheMem) {
1075	/* Already done */
1076	return SECSuccess;
1077    }
1078
1079    /* make sure loser can clean up properly */
1080    cache->shared = shared;
1081    cache->cacheMem    = cacheMem    = NULL;
1082    cache->cacheMemMap = cacheMemMap = NULL;
1083    cache->sharedCache = (cacheDesc *)0;
1084
1085    cache->numSIDCacheLocksInitialized = 0;
1086    cache->nextCertCacheEntry = 0;
1087    cache->stopPolling = PR_FALSE;
1088    cache->everInherited = PR_FALSE;
1089    cache->poller = NULL;
1090    cache->mutexTimeout = 0;
1091
1092    cache->numSIDCacheEntries = maxCacheEntries ? maxCacheEntries 
1093                                                : DEF_SID_CACHE_ENTRIES;
1094    cache->numSIDCacheSets    = 
1095    	SID_HOWMANY(cache->numSIDCacheEntries, SID_CACHE_ENTRIES_PER_SET);
1096
1097    cache->numSIDCacheEntries = 
1098    	cache->numSIDCacheSets * SID_CACHE_ENTRIES_PER_SET;
1099
1100    cache->numSIDCacheLocks   = 
1101    	PR_MIN(cache->numSIDCacheSets, ssl_max_sid_cache_locks);
1102
1103    cache->numSIDCacheSetsPerLock = 
1104    	SID_HOWMANY(cache->numSIDCacheSets, cache->numSIDCacheLocks);
1105
1106    cache->numCertCacheEntries = (maxCertCacheEntries > 0) ?
1107                                             maxCertCacheEntries : 0;
1108    cache->numSrvNameCacheEntries = (maxSrvNameCacheEntries >= 0) ?
1109                                             maxSrvNameCacheEntries : DEF_NAME_CACHE_ENTRIES;
1110
1111    /* compute size of shared memory, and offsets of all pointers */
1112    ptr = 0;
1113    cache->cacheMem     = (char *)ptr;
1114    ptr += SID_ROUNDUP(sizeof(cacheDesc), SID_ALIGNMENT);
1115
1116    cache->sidCacheLocks = (sidCacheLock *)ptr;
1117    cache->keyCacheLock  = cache->sidCacheLocks + cache->numSIDCacheLocks;
1118    cache->certCacheLock = cache->keyCacheLock  + 1;
1119    cache->srvNameCacheLock = cache->certCacheLock  + 1;
1120    ptr = (ptrdiff_t)(cache->srvNameCacheLock + 1);
1121    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1122
1123    cache->sidCacheSets  = (sidCacheSet *)ptr;
1124    ptr = (ptrdiff_t)(cache->sidCacheSets + cache->numSIDCacheSets);
1125    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1126
1127    cache->sidCacheData  = (sidCacheEntry *)ptr;
1128    ptr = (ptrdiff_t)(cache->sidCacheData + cache->numSIDCacheEntries);
1129    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1130
1131    cache->certCacheData = (certCacheEntry *)ptr;
1132    cache->sidCacheSize  = 
1133    	(char *)cache->certCacheData - (char *)cache->sidCacheData;
1134
1135    if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES) {
1136        /* This is really a poor way to computer this! */
1137        cache->numCertCacheEntries = cache->sidCacheSize / sizeof(certCacheEntry);
1138        if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES)
1139    	cache->numCertCacheEntries = MIN_CERT_CACHE_ENTRIES;
1140    }
1141    ptr = (ptrdiff_t)(cache->certCacheData + cache->numCertCacheEntries);
1142    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1143
1144    cache->keyCacheData  = (SSLWrappedSymWrappingKey *)ptr;
1145    cache->certCacheSize = 
1146    	(char *)cache->keyCacheData - (char *)cache->certCacheData;
1147
1148    cache->numKeyCacheEntries = kt_kea_size * SSL_NUM_WRAP_MECHS;
1149    ptr = (ptrdiff_t)(cache->keyCacheData + cache->numKeyCacheEntries);
1150    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1151
1152    cache->keyCacheSize  = (char *)ptr - (char *)cache->keyCacheData;
1153
1154    cache->ticketKeyNameSuffix = (uint8 *)ptr;
1155    ptr = (ptrdiff_t)(cache->ticketKeyNameSuffix +
1156	SESS_TICKET_KEY_VAR_NAME_LEN);
1157    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1158
1159    cache->ticketEncKey = (encKeyCacheEntry *)ptr;
1160    ptr = (ptrdiff_t)(cache->ticketEncKey + 1);
1161    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1162
1163    cache->ticketMacKey = (encKeyCacheEntry *)ptr;
1164    ptr = (ptrdiff_t)(cache->ticketMacKey + 1);
1165    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1166
1167    cache->ticketKeysValid = (PRUint32 *)ptr;
1168    ptr = (ptrdiff_t)(cache->ticketKeysValid + 1);
1169    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1170
1171    cache->srvNameCacheData = (srvNameCacheEntry *)ptr;
1172    cache->srvNameCacheSize =
1173        cache->numSrvNameCacheEntries * sizeof(srvNameCacheEntry);
1174    ptr = (ptrdiff_t)(cache->srvNameCacheData + cache->numSrvNameCacheEntries);
1175    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1176
1177    cache->cacheMemSize = ptr;
1178
1179    if (ssl2_timeout) {   
1180	if (ssl2_timeout > MAX_SSL2_TIMEOUT) {
1181	    ssl2_timeout = MAX_SSL2_TIMEOUT;
1182	}
1183	if (ssl2_timeout < MIN_SSL2_TIMEOUT) {
1184	    ssl2_timeout = MIN_SSL2_TIMEOUT;
1185	}
1186	cache->ssl2Timeout = ssl2_timeout;
1187    } else {
1188	cache->ssl2Timeout = DEF_SSL2_TIMEOUT;
1189    }
1190
1191    if (ssl3_timeout) {   
1192	if (ssl3_timeout > MAX_SSL3_TIMEOUT) {
1193	    ssl3_timeout = MAX_SSL3_TIMEOUT;
1194	}
1195	if (ssl3_timeout < MIN_SSL3_TIMEOUT) {
1196	    ssl3_timeout = MIN_SSL3_TIMEOUT;
1197	}
1198	cache->ssl3Timeout = ssl3_timeout;
1199    } else {
1200	cache->ssl3Timeout = DEF_SSL3_TIMEOUT;
1201    }
1202
1203    if (shared) {
1204	/* Create file names */
1205#if defined(XP_UNIX) || defined(XP_BEOS)
1206	/* there's some confusion here about whether PR_OpenAnonFileMap wants
1207	** a directory name or a file name for its first argument.
1208	cfn = PR_smprintf("%s/.sslsvrcache.%d", directory, myPid);
1209	*/
1210	cfn = PR_smprintf("%s", directory);
1211#elif defined(XP_WIN32)
1212	cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid, 
1213			    GetCurrentThreadId());
1214#elif defined(XP_OS2)
1215	cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid, 
1216			    gettid());
1217#else
1218#error "Don't know how to create file name for this platform!"
1219#endif
1220	if (!cfn) {
1221	    goto loser;
1222	}
1223
1224	/* Create cache */
1225	cacheMemMap = PR_OpenAnonFileMap(cfn, cache->cacheMemSize, 
1226					 PR_PROT_READWRITE);
1227
1228	PR_smprintf_free(cfn);
1229	if(!cacheMemMap) {
1230	    goto loser;
1231	}
1232
1233        cacheMem = PR_MemMap(cacheMemMap, 0, cache->cacheMemSize);
1234    } else {
1235        cacheMem = PORT_Alloc(cache->cacheMemSize);
1236    }
1237    
1238    if (! cacheMem) {
1239        goto loser;
1240    }
1241
1242    /* Initialize shared memory. This may not be necessary on all platforms */
1243    memset(cacheMem, 0, cache->cacheMemSize);
1244
1245    /* Copy cache descriptor header into shared memory */
1246    memcpy(cacheMem, cache, sizeof *cache);
1247
1248    /* save private copies of these values */
1249    cache->cacheMemMap = cacheMemMap;
1250    cache->cacheMem    = cacheMem;
1251    cache->sharedCache = (cacheDesc *)cacheMem;
1252
1253    /* Fix pointers in our private copy of cache descriptor to point to 
1254    ** spaces in shared memory 
1255    */
1256    ptr = (ptrdiff_t)cache->cacheMem;
1257    *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
1258    *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
1259    *(ptrdiff_t *)(&cache->certCacheLock) += ptr;
1260    *(ptrdiff_t *)(&cache->srvNameCacheLock) += ptr;
1261    *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr;
1262    *(ptrdiff_t *)(&cache->sidCacheData ) += ptr;
1263    *(ptrdiff_t *)(&cache->certCacheData) += ptr;
1264    *(ptrdiff_t *)(&cache->keyCacheData ) += ptr;
1265    *(ptrdiff_t *)(&cache->ticketKeyNameSuffix) += ptr;
1266    *(ptrdiff_t *)(&cache->ticketEncKey ) += ptr;
1267    *(ptrdiff_t *)(&cache->ticketMacKey ) += ptr;
1268    *(ptrdiff_t *)(&cache->ticketKeysValid) += ptr;
1269    *(ptrdiff_t *)(&cache->srvNameCacheData) += ptr;
1270
1271    /* initialize the locks */
1272    init_time = ssl_Time();
1273    pLock = cache->sidCacheLocks;
1274    for (locks_to_initialize = cache->numSIDCacheLocks + 3;
1275         locks_initialized < locks_to_initialize; 
1276	 ++locks_initialized, ++pLock ) {
1277
1278	SECStatus err = sslMutex_Init(&pLock->mutex, shared);
1279	if (err) {
1280	    cache->numSIDCacheLocksInitialized = locks_initialized;
1281	    goto loser;
1282	}
1283        pLock->timeStamp = init_time;
1284	pLock->pid       = 0;
1285    }
1286    cache->numSIDCacheLocksInitialized = locks_initialized;
1287
1288    return SECSuccess;
1289
1290loser:
1291    CloseCache(cache);
1292    return SECFailure;
1293}
1294
1295PRUint32
1296SSL_GetMaxServerCacheLocks(void)
1297{
1298    return ssl_max_sid_cache_locks + 2;
1299    /* The extra two are the cert cache lock and the key cache lock. */
1300}
1301
1302SECStatus
1303SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
1304{
1305    /* Minimum is 1 sid cache lock, 1 cert cache lock and 1 key cache lock.
1306    ** We'd like to test for a maximum value, but not all platforms' header
1307    ** files provide a symbol or function or other means of determining
1308    ** the maximum, other than trial and error.
1309    */
1310    if (maxLocks < 3) {
1311	PORT_SetError(SEC_ERROR_INVALID_ARGS);
1312	return SECFailure;
1313    }
1314    ssl_max_sid_cache_locks = maxLocks - 2;
1315    /* The extra two are the cert cache lock and the key cache lock. */
1316    return SECSuccess;
1317}
1318
1319static SECStatus
1320ssl_ConfigServerSessionIDCacheInstanceWithOpt(cacheDesc *cache,
1321                                              PRUint32 ssl2_timeout,
1322                                              PRUint32 ssl3_timeout, 
1323                                              const char *   directory,
1324                                              PRBool shared,
1325                                              int      maxCacheEntries, 
1326                                              int      maxCertCacheEntries,
1327                                              int      maxSrvNameCacheEntries)
1328{
1329    SECStatus rv;
1330
1331    PORT_Assert(sizeof(sidCacheEntry) == 224);
1332    PORT_Assert(sizeof(certCacheEntry) == 4096);
1333    PORT_Assert(sizeof(srvNameCacheEntry) == 1072);
1334
1335    rv = ssl_Init();
1336    if (rv != SECSuccess) {
1337	return rv;
1338    }
1339
1340    myPid = SSL_GETPID();
1341    if (!directory) {
1342	directory = DEFAULT_CACHE_DIRECTORY;
1343    }
1344    rv = InitCache(cache, maxCacheEntries, maxCertCacheEntries,
1345                   maxSrvNameCacheEntries, ssl2_timeout, ssl3_timeout, 
1346                   directory, shared);
1347    if (rv) {
1348	SET_ERROR_CODE
1349    	return SECFailure;
1350    }
1351
1352    ssl_sid_lookup  = ServerSessionIDLookup;
1353    ssl_sid_cache   = ServerSessionIDCache;
1354    ssl_sid_uncache = ServerSessionIDUncache;
1355    return SECSuccess;
1356}
1357
1358SECStatus
1359SSL_ConfigServerSessionIDCacheInstance(	cacheDesc *cache,
1360                                int      maxCacheEntries, 
1361                                PRUint32 ssl2_timeout,
1362                                PRUint32 ssl3_timeout, 
1363                                const char *   directory, PRBool shared)
1364{
1365    return ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache,
1366                                                         ssl2_timeout,
1367                                                         ssl3_timeout,
1368                                                         directory,
1369                                                         shared,
1370                                                         maxCacheEntries, 
1371                                                         -1, -1);
1372}
1373
1374SECStatus
1375SSL_ConfigServerSessionIDCache(	int      maxCacheEntries, 
1376				PRUint32 ssl2_timeout,
1377			       	PRUint32 ssl3_timeout, 
1378			  const char *   directory)
1379{
1380    ssl_InitSessionCacheLocks(PR_FALSE);
1381    return SSL_ConfigServerSessionIDCacheInstance(&globalCache, 
1382    		maxCacheEntries, ssl2_timeout, ssl3_timeout, directory, PR_FALSE);
1383}
1384
1385SECStatus
1386SSL_ShutdownServerSessionIDCacheInstance(cacheDesc *cache)
1387{
1388    CloseCache(cache);
1389    return SECSuccess;
1390}
1391
1392SECStatus
1393SSL_ShutdownServerSessionIDCache(void)
1394{
1395#if defined(XP_UNIX) || defined(XP_BEOS)
1396    /* Stop the thread that polls cache for expired locks on Unix */
1397    StopLockPoller(&globalCache);
1398#endif
1399    SSL3_ShutdownServerCache();
1400    return SSL_ShutdownServerSessionIDCacheInstance(&globalCache);
1401}
1402
1403/* Use this function, instead of SSL_ConfigServerSessionIDCache,
1404 * if the cache will be shared by multiple processes.
1405 */
1406static SECStatus
1407ssl_ConfigMPServerSIDCacheWithOpt(      PRUint32 ssl2_timeout,
1408                                        PRUint32 ssl3_timeout, 
1409                                        const char *   directory,
1410                                        int maxCacheEntries,
1411                                        int maxCertCacheEntries,
1412                                        int maxSrvNameCacheEntries)
1413{
1414    char *	envValue;
1415    char *	inhValue;
1416    cacheDesc * cache         = &globalCache;
1417    PRUint32    fmStrLen;
1418    SECStatus 	result;
1419    PRStatus 	prStatus;
1420    SECStatus	putEnvFailed;
1421    inheritance inherit;
1422    char        fmString[PR_FILEMAP_STRING_BUFSIZE];
1423
1424    isMultiProcess = PR_TRUE;
1425    result = ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache,
1426                  ssl2_timeout, ssl3_timeout, directory, PR_TRUE,
1427        maxCacheEntries, maxCacheEntries, maxSrvNameCacheEntries);
1428    if (result != SECSuccess) 
1429        return result;
1430
1431    prStatus = PR_ExportFileMapAsString(cache->cacheMemMap, 
1432                                        sizeof fmString, fmString);
1433    if ((prStatus != PR_SUCCESS) || !(fmStrLen = strlen(fmString))) {
1434	SET_ERROR_CODE
1435	return SECFailure;
1436    }
1437
1438    inherit.cacheMemSize	= cache->cacheMemSize;
1439    inherit.fmStrLen            = fmStrLen;
1440
1441    inhValue = BTOA_DataToAscii((unsigned char *)&inherit, sizeof inherit);
1442    if (!inhValue || !strlen(inhValue)) {
1443	SET_ERROR_CODE
1444	return SECFailure;
1445    }
1446    envValue = PR_smprintf("%s,%s", inhValue, fmString);
1447    if (!envValue || !strlen(envValue)) {
1448	SET_ERROR_CODE
1449	return SECFailure;
1450    }
1451    PORT_Free(inhValue);
1452
1453    putEnvFailed = (SECStatus)NSS_PutEnv(envVarName, envValue);
1454    PR_smprintf_free(envValue);
1455    if (putEnvFailed) {
1456        SET_ERROR_CODE
1457        result = SECFailure;
1458    }
1459
1460#if defined(XP_UNIX) || defined(XP_BEOS)
1461    /* Launch thread to poll cache for expired locks on Unix */
1462    LaunchLockPoller(cache);
1463#endif
1464    return result;
1465}
1466
1467/* Use this function, instead of SSL_ConfigServerSessionIDCache,
1468 * if the cache will be shared by multiple processes.
1469 */
1470SECStatus
1471SSL_ConfigMPServerSIDCache(	int      maxCacheEntries, 
1472				PRUint32 ssl2_timeout,
1473			       	PRUint32 ssl3_timeout, 
1474		          const char *   directory)
1475{
1476    return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout,
1477                                             ssl3_timeout,
1478                                             directory,
1479                                             maxCacheEntries,
1480                                             -1, -1);
1481}
1482
1483SECStatus
1484SSL_ConfigServerSessionIDCacheWithOpt(
1485				PRUint32 ssl2_timeout,
1486			       	PRUint32 ssl3_timeout, 
1487                                const char *   directory,
1488                                int maxCacheEntries,
1489                                int maxCertCacheEntries,
1490                                int maxSrvNameCacheEntries,
1491                                PRBool enableMPCache)
1492{
1493    if (!enableMPCache) {
1494        ssl_InitSessionCacheLocks(PR_FALSE);
1495        return ssl_ConfigServerSessionIDCacheInstanceWithOpt(&globalCache, 
1496           ssl2_timeout, ssl3_timeout, directory, PR_FALSE,
1497           maxCacheEntries, maxCertCacheEntries, maxSrvNameCacheEntries);
1498    } else {
1499        return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout, ssl3_timeout,
1500                directory, maxCacheEntries, maxCertCacheEntries,
1501                                                 maxSrvNameCacheEntries);
1502    }
1503}
1504
1505SECStatus
1506SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString)
1507{
1508    unsigned char * decoString = NULL;
1509    char *          fmString   = NULL;
1510    char *          myEnvString = NULL;
1511    unsigned int    decoLen;
1512    ptrdiff_t       ptr;
1513    inheritance     inherit;
1514    cacheDesc       my

Large files files are truncated, but you can click here to view the full file