diff options
Diffstat (limited to 'security/nss')
-rw-r--r-- | security/nss/lib/ssl/manifest.mn | 1 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslcon.c | 18 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslimpl.h | 9 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslsecur.c | 2 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslsnce.c | 2071 |
5 files changed, 814 insertions, 1287 deletions
diff --git a/security/nss/lib/ssl/manifest.mn b/security/nss/lib/ssl/manifest.mn index e76c516f1..038cff4d5 100644 --- a/security/nss/lib/ssl/manifest.mn +++ b/security/nss/lib/ssl/manifest.mn @@ -60,6 +60,7 @@ CSRCS = \ sslenum.c \ sslerr.c \ sslgathr.c \ + sslmutex.c \ sslnonce.c \ sslreveal.c \ sslsecur.c \ diff --git a/security/nss/lib/ssl/sslcon.c b/security/nss/lib/ssl/sslcon.c index 70253c379..181b03e59 100644 --- a/security/nss/lib/ssl/sslcon.c +++ b/security/nss/lib/ssl/sslcon.c @@ -2531,7 +2531,7 @@ ssl2_HandleMessage(sslSocket *ss) goto bad_peer; } - if (gs->recordLen - 1 != SSL_SESSIONID_BYTES) { + if (gs->recordLen - 1 != SSL2_SESSIONID_BYTES) { SSL_DBG(("%d: SSL[%d]: bad server-finished message, len=%d", SSL_GETPID(), ss->fd, gs->recordLen)); goto bad_peer; @@ -3366,7 +3366,7 @@ ssl2_HandleClientHelloMessage(sslSocket *ss) sslSecurityInfo *sec; sslConnectInfo *ci; sslGather *gs; - sslSessionID *sid = NULL; + sslSessionID *sid; PRUint8 *msg; PRUint8 *data; PRUint8 *cs; @@ -3375,7 +3375,6 @@ ssl2_HandleClientHelloMessage(sslSocket *ss) PRUint8 *challenge; unsigned int challengeLen; SECStatus rv; - int hit; int csLen; int sendLen; int sdLen; @@ -3383,6 +3382,11 @@ ssl2_HandleClientHelloMessage(sslSocket *ss) int pid; int sent; int gotXmitBufLock = 0; +#if defined(SOLARIS) && defined(i386) + volatile PRUint8 hit; +#else + int hit; +#endif PRUint8 csImpl[sizeof implementedCipherSuites]; PORT_Assert( ssl_Have1stHandshakeLock(ss) ); @@ -3508,14 +3512,14 @@ ssl2_HandleClientHelloMessage(sslSocket *ss) /* Examine message and see if session-id is good */ ci->elements = 0; - if (ss->noCache) { - sid = NULL; - } else if (sdLen) { + if (sdLen > 0 && !ss->noCache) { SSL_TRC(7, ("%d: SSL[%d]: server, lookup client session-id for 0x%08x%08x%08x%08x", SSL_GETPID(), ss->fd, ci->peer.pr_s6_addr32[0], ci->peer.pr_s6_addr32[1], ci->peer.pr_s6_addr32[2], ci->peer.pr_s6_addr32[3])); sid = (*ssl_sid_lookup)(&ci->peer, sd, sdLen, ss->dbHandle); + } else { + sid = NULL; } if (sid) { /* Got a good session-id. Short cut! */ @@ -3545,7 +3549,7 @@ ssl2_HandleClientHelloMessage(sslSocket *ss) /* Invent a session-id */ ci->sid = sid; - PK11_GenerateRandom(sid->u.ssl2.sessionID+2, SSL_SESSIONID_BYTES-2); + PK11_GenerateRandom(sid->u.ssl2.sessionID+2, SSL2_SESSIONID_BYTES-2); pid = SSL_GETPID(); sid->u.ssl2.sessionID[0] = MSB(pid); diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h index 98beb5097..6925af0fe 100644 --- a/security/nss/lib/ssl/sslimpl.h +++ b/security/nss/lib/ssl/sslimpl.h @@ -113,7 +113,7 @@ typedef enum { SSLAppOpRead = 0, #define SSL_MIN_MASTER_KEY_BYTES 5 #define SSL_MAX_MASTER_KEY_BYTES 64 -#define SSL_SESSIONID_BYTES 16 +#define SSL2_SESSIONID_BYTES 16 #define SSL3_SESSIONID_BYTES 32 #define SSL_MIN_CHALLENGE_BYTES 16 @@ -711,7 +711,7 @@ struct sslSessionIDStr { union { struct { /* the V2 code depends upon the size of sessionID. */ - unsigned char sessionID[SSL_SESSIONID_BYTES]; + unsigned char sessionID[SSL2_SESSIONID_BYTES]; /* Stuff used to recreate key and read/write cipher objects */ SECItem masterKey; @@ -1247,8 +1247,11 @@ void ssl_Trace(const char *format, ...); SEC_END_PROTOS -#ifdef XP_UNIX +#if defined(XP_UNIX) #define SSL_GETPID() getpid() +#elif defined(WIN32) +/* #define SSL_GETPID() GetCurrentProcessId() */ +#define SSL_GETPID() _getpid() #else #define SSL_GETPID() 0 #endif diff --git a/security/nss/lib/ssl/sslsecur.c b/security/nss/lib/ssl/sslsecur.c index 14b0047c5..306838a41 100644 --- a/security/nss/lib/ssl/sslsecur.c +++ b/security/nss/lib/ssl/sslsecur.c @@ -1239,7 +1239,7 @@ SSL_GetSessionID(PRFileDesc *fd) sid = ss->sec->ci.sid; item = (SECItem *)PORT_Alloc(sizeof(SECItem)); if (sid->version < SSL_LIBRARY_VERSION_3_0) { - item->len = SSL_SESSIONID_BYTES; + item->len = SSL2_SESSIONID_BYTES; item->data = (unsigned char*)PORT_Alloc(item->len); PORT_Memcpy(item->data, sid->u.ssl2.sessionID, item->len); } else { diff --git a/security/nss/lib/ssl/sslsnce.c b/security/nss/lib/ssl/sslsnce.c index 28a2f3812..64346db64 100644 --- a/security/nss/lib/ssl/sslsnce.c +++ b/security/nss/lib/ssl/sslsnce.c @@ -43,42 +43,33 @@ * All processes that are part of the same conceptual server (serving on * the same address and port) MUST share a common SSL session cache. * This code makes the content of the shared cache accessible to all - * processes on the same "server". This code works on Unix and Win32 only, - * and is platform specific. + * processes on the same "server". This code works on Unix and Win32 only. * - * Unix: Multiple processes share a single (inherited) FD for a disk - * file all share one single file position. If one lseeks, the position for - * all processes is changed. Since the set of platforms we support do not - * all share portable lseek-and-read or lseek-and-write functions, a global - * lock must be used to make the lseek call and the subsequent read or write - * call be one atomic operation. It is no longer necessary for cache element - * sizes to be a power of 2, or a multiple of a sector size. + * We use NSPR anonymous shared memory and move data to & from shared memory. + * We must do explicit locking of the records for all reads and writes. + * The set of Cache entries are divided up into "sets" of 128 entries. + * Each set is protected by a lock. There may be one or more sets protected + * by each lock. That is, locks to sets are 1:N. + * There is one lock for the entire cert cache. + * There is one lock for the set of wrapped sym wrap keys. * - * For Win32, where (a) disk I/O is not atomic, and (b) we use memory-mapped - * files and move data to & from memory instead of calling read or write, - * we must do explicit locking of the records for all reads and writes. - * We have just one lock, for the entire file, using an NT semaphore. - * We avoid blocking on "local threads" since it's bad to block on a local - * thread - If NSPR offered portable semaphores, it would handle this itself. + * The anonymous shared memory is laid out as if it were declared like this: * - * Since this file has to do lots of platform specific I/O, the system - * dependent error codes need to be mapped back into NSPR error codes. - * Since NSPR's error mapping functions are private, the code is necessarily - * duplicated in libSSL. - * - * Note, now that NSPR provides portable anonymous shared memory, for all - * platforms except Mac, the implementation below should be replaced with - * one that uses anonymous shared memory ASAP. This will eliminate most - * platform dependent code in this file, and improve performance big time. - * - * Now that NSPR offers portable cross-process locking (semaphores) on Unix - * and Win32, semaphores should be used here for all platforms. + * struct { + * cacheDescriptor desc; + * sidCacheLock sidCacheLocks[ numSIDCacheLocks]; + * sidCacheLock keyCacheLock; + * sidCacheLock certCacheLock; + * sidCacheSet sidCacheSets[ numSIDCacheSets ]; + * sidCacheEntry sidCacheData[ numSIDCacheEntries]; + * certCacheEntry certCacheData[numCertCacheEntries]; + * SSLWrappedSymWrappingKey keyCacheData[kt_kea_size][SSL_NUM_WRAP_MECHS]; + * } sharedMemCacheData; */ #include "nssrenam.h" #include "seccomon.h" #if defined(XP_UNIX) || defined(XP_WIN32) -#ifndef NADA_VERISON #include "cert.h" #include "ssl.h" @@ -95,12 +86,10 @@ #include <fcntl.h> #include <unistd.h> #include <errno.h> +#include <signal.h> #include "unix_err.h" #else /* XP_WIN32 */ -#ifdef MC_HTTPD -#include <ereport.h> -#endif /* MC_HTTPD */ #include <wtypes.h> #include "win32err.h" #endif /* XP_WIN32 */ @@ -110,615 +99,294 @@ #include "nspr.h" #include "nsslocks.h" - -static PZLock *cacheLock; - -/* -** The server session-id cache uses a simple flat cache. The cache is -** sized during initialization. We hash the ip-address + session-id value -** into an index into the cache and do the lookup. No buckets, nothing -** fancy. -*/ - -static PRBool isMultiProcess = PR_FALSE; - -static PRUint32 numSIDCacheEntries = 10000; -static PRUint32 sidCacheFileSize; -static PRUint32 sidCacheWrapOffset; - -static PRUint32 numCertCacheEntries = 250; -static PRUint32 certCacheFileSize; - -#define MIN_CERT_CACHE_ENTRIES 125 /* the effective size in old releases. */ - +#include "sslmutex.h" /* -** Format of a cache entry. +** Format of a cache entry in the shared memory. */ -typedef struct SIDCacheEntryStr SIDCacheEntry; -struct SIDCacheEntryStr { - PRIPv6Addr addr; - PRUint32 time; +struct sidCacheEntryStr { +/* 16 */ PRIPv6Addr addr; /* client's IP address */ +/* 4 */ PRUint32 time; /* expiration time of this entry */ +/* 2 */ PRUint16 version; +/* 1 */ PRUint8 valid; +/* 1 */ PRUint8 sessionIDLength; +/* 32 */ PRUint8 sessionID[SSL3_SESSIONID_BYTES]; +/* 56 - common header total */ union { struct { - /* This is gross. We have to have version and valid in both arms - * of the union for alignment reasons. This probably won't work - * on a 64-bit machine. XXXX - */ -/* 2 */ uint16 version; -/* 1 */ unsigned char valid; -/* 1 */ unsigned char cipherType; - -/* 16 */ unsigned char sessionID[SSL_SESSIONID_BYTES]; -/* 64 */ unsigned char masterKey[SSL_MAX_MASTER_KEY_BYTES]; -/* 32 */ unsigned char cipherArg[SSL_MAX_CYPHER_ARG_BYTES]; +/* 64 */ PRUint8 masterKey[SSL_MAX_MASTER_KEY_BYTES]; +/* 32 */ PRUint8 cipherArg[SSL_MAX_CYPHER_ARG_BYTES]; -/* 1 */ unsigned char masterKeyLen; -/* 1 */ unsigned char keyBits; - -/* 1 */ unsigned char secretKeyBits; -/* 1 */ unsigned char cipherArgLen; -/*120 */} ssl2; +/* 1 */ PRUint8 cipherType; +/* 1 */ PRUint8 masterKeyLen; +/* 1 */ PRUint8 keyBits; +/* 1 */ PRUint8 secretKeyBits; +/* 1 */ PRUint8 cipherArgLen; +/*101 */} ssl2; struct { -/* 2 */ uint16 version; -/* 1 */ unsigned char valid; -/* 1 */ uint8 sessionIDLength; +/* 2 */ ssl3CipherSuite cipherSuite; +/* 2 */ PRUint16 compression; /* SSL3CompressionMethod */ -/* 32 */ unsigned char sessionID[SSL3_SESSIONID_BYTES]; +/*122 */ ssl3SidKeys keys; /* keys and ivs, wrapped as needed. */ +/* 1 */ PRUint8 hasFortezza; +/* 1 */ PRUint8 resumable; -/* 2 */ ssl3CipherSuite cipherSuite; -/* 2 */ uint16 compression; /* SSL3CompressionMethod */ - -/*122 */ ssl3SidKeys keys; /* keys and ivs, wrapped as needed. */ -/* 4 */ PRUint32 masterWrapMech; -/* 4 */ SSL3KEAType exchKeyType; - -/* 2 */ int16 certIndex; -/* 1 */ uint8 hasFortezza; -/* 1 */ uint8 resumable; - } ssl3; - /* We can't make this struct fit in 128 bytes - * so, force the struct size up to the next power of two. - */ +/* 4 */ PRUint32 masterWrapMech; +/* 4 */ SSL3KEAType exchKeyType; +/* 4 */ PRInt32 certIndex; +/*140 */} ssl3; +#if defined(LINUX) struct { - unsigned char filler[256 - sizeof(PRIPv6Addr) - sizeof(PRUint32)]; - } force256; + PRUint8 filler[144]; + } forceSize; +#endif } u; }; +typedef struct sidCacheEntryStr sidCacheEntry; -typedef struct CertCacheEntryStr CertCacheEntry; - /* The length of this struct is supposed to be a power of 2, e.g. 4KB */ -struct CertCacheEntryStr { - uint16 certLength; /* 2 */ - uint16 sessionIDLength; /* 2 */ - unsigned char sessionID[SSL3_SESSIONID_BYTES]; /* 32 */ - unsigned char cert[SSL_MAX_CACHED_CERT_LEN]; /* 4060 */ +struct certCacheEntryStr { + PRUint16 certLength; /* 2 */ + PRUint16 sessionIDLength; /* 2 */ + PRUint8 sessionID[SSL3_SESSIONID_BYTES]; /* 32 */ + PRUint8 cert[SSL_MAX_CACHED_CERT_LEN]; /* 4060 */ }; /* total 4096 */ +typedef struct certCacheEntryStr certCacheEntry; +struct sidCacheLockStr { + PRUint32 timeStamp; + sslMutex mutex; + sslPID pid; +}; +typedef struct sidCacheLockStr sidCacheLock; -static void IOError(int rv, char *type); -static PRUint32 Offset(const PRIPv6Addr *addr, unsigned char *s, unsigned nl); -static void Invalidate(SIDCacheEntry *sce); -/************************************************************************/ +struct sidCacheSetStr { + PRIntn next; +}; +typedef struct sidCacheSetStr sidCacheSet; -static const char envVarName[] = { SSL_ENV_VAR_NAME }; +struct cacheDescStr { -#ifdef _WIN32 + PRUint32 sharedMemSize; -struct winInheritanceStr { - PRUint32 numSIDCacheEntries; - PRUint32 sidCacheFileSize; - PRUint32 sidCacheWrapOffset; - PRUint32 numCertCacheEntries; - PRUint32 certCacheFileSize; - - DWORD parentProcessID; - HANDLE parentProcessHandle; - HANDLE SIDCacheFDMAP; - HANDLE certCacheFDMAP; - HANDLE svrCacheSem; -}; -typedef struct winInheritanceStr winInheritance; + PRUint32 numSIDCacheLocks; + PRUint32 numSIDCacheSets; + PRUint32 numSIDCacheSetsPerLock; -static HANDLE svrCacheSem = INVALID_HANDLE_VALUE; + PRUint32 numSIDCacheEntries; + PRUint32 sidCacheSize; -static char * SIDCacheData = NULL; -static HANDLE SIDCacheFD = INVALID_HANDLE_VALUE; -static HANDLE SIDCacheFDMAP = INVALID_HANDLE_VALUE; + PRUint32 numCertCacheEntries; + PRUint32 certCacheSize; -static char * certCacheData = NULL; -static HANDLE certCacheFD = INVALID_HANDLE_VALUE; -static HANDLE certCacheFDMAP = INVALID_HANDLE_VALUE; + PRUint32 numKeyCacheEntries; + PRUint32 keyCacheSize; -static PRUint32 myPid; + PRUint32 ssl2Timeout; + PRUint32 ssl3Timeout; -/* The presence of the TRUE element in this struct makes the semaphore - * inheritable. The NULL means use process's default security descriptor. - */ -static SECURITY_ATTRIBUTES semaphoreAttributes = - { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; + /* These values are volatile, and are accessed through sharedCache-> */ + PRUint32 nextCertCacheEntry; /* certCacheLock protects */ + PRBool stopPolling; -static SECURITY_ATTRIBUTES sidCacheFDMapAttributes = - { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; + /* The private copies of these values are pointers into shared mem */ + /* The copies of these values in shared memory are merely offsets */ + sidCacheLock * sidCacheLocks; + sidCacheLock * keyCacheLock; + sidCacheLock * certCacheLock; + sidCacheSet * sidCacheSets; + sidCacheEntry * sidCacheData; + certCacheEntry * certCacheData; + SSLWrappedSymWrappingKey * keyCacheData; -static SECURITY_ATTRIBUTES certCacheFDMapAttributes = - { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; + /* Only the private copies of these pointers are valid */ + char * sharedMem; + struct cacheDescStr * sharedCache; /* shared copy of this struct */ + PRFileMap * cacheMemMap; + PRThread * poller; +}; +typedef struct cacheDescStr cacheDesc; -#define DEFAULT_CACHE_DIRECTORY "\\temp" +static cacheDesc globalCache; -static SECStatus -createServerCacheSemaphore(void) -{ - PR_ASSERT(svrCacheSem == INVALID_HANDLE_VALUE); - - /* inheritable, starts signalled, 1 signal max, no file name. */ - svrCacheSem = CreateSemaphore(&semaphoreAttributes, 1, 1, NULL); - if (svrCacheSem == NULL) { - svrCacheSem = INVALID_HANDLE_VALUE; - /* We could get the error code, but what could be do with it ? */ - nss_MD_win32_map_default_error(GetLastError()); - return SECFailure; - } - return SECSuccess; -} +static const char envVarName[] = { SSL_ENV_VAR_NAME }; -static SECStatus -_getServerCacheSemaphore(void) -{ - DWORD event; - DWORD lastError; - SECStatus rv; +static PRBool isMultiProcess = PR_FALSE; - PR_ASSERT(svrCacheSem != INVALID_HANDLE_VALUE); - if (svrCacheSem == INVALID_HANDLE_VALUE && - SECSuccess != createServerCacheSemaphore()) { - return SECFailure; /* what else ? */ - } - event = WaitForSingleObject(svrCacheSem, INFINITE); - switch (event) { - case WAIT_OBJECT_0: - case WAIT_ABANDONED: - rv = SECSuccess; - break; - - case WAIT_TIMEOUT: - case WAIT_IO_COMPLETION: - default: /* should never happen. nothing we can do. */ - PR_ASSERT(("WaitForSingleObject returned invalid value.", 0)); - /* fall thru */ - - case WAIT_FAILED: /* failure returns this */ - rv = SECFailure; - lastError = GetLastError(); /* for debugging */ - nss_MD_win32_map_default_error(lastError); - break; - } - return rv; -} -static void -_doGetServerCacheSemaphore(void * arg) -{ - SECStatus * rv = (SECStatus *)arg; - *rv = _getServerCacheSemaphore(); -} +#define DEF_SID_CACHE_ENTRIES 10000 +#define DEF_CERT_CACHE_ENTRIES 250 +#define MIN_CERT_CACHE_ENTRIES 125 /* the effective size in old releases. */ +#define DEF_KEY_CACHE_ENTRIES 250 -static SECStatus -getServerCacheSemaphore(void) -{ - PRThread * selectThread; - PRThread * me = PR_GetCurrentThread(); - PRThreadScope scope = PR_GetThreadScope(me); - SECStatus rv = SECFailure; +#define SID_CACHE_ENTRIES_PER_SET 128 +#define SID_ALIGNMENT 16 - if (scope == PR_GLOBAL_THREAD) { - rv = _getServerCacheSemaphore(); - } else { - selectThread = PR_CreateThread(PR_USER_THREAD, - _doGetServerCacheSemaphore, &rv, - PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, - PR_JOINABLE_THREAD, 0); - if (selectThread != NULL) { - /* rv will be set by _doGetServerCacheSemaphore() */ - PR_JoinThread(selectThread); - } - } - return rv; -} +#define DEF_SSL2_TIMEOUT 100 /* seconds */ +#define MAX_SSL2_TIMEOUT 100 /* seconds */ +#define MIN_SSL2_TIMEOUT 5 /* seconds */ -static SECStatus -releaseServerCacheSemaphore(void) -{ - BOOL success = FALSE; +#define DEF_SSL3_TIMEOUT 86400L /* 24 hours */ +#define MAX_SSL3_TIMEOUT 86400L /* 24 hours */ +#define MIN_SSL3_TIMEOUT 5 /* seconds */ - PR_ASSERT(svrCacheSem != INVALID_HANDLE_VALUE); - if (svrCacheSem != INVALID_HANDLE_VALUE) { - /* Add 1, don't want previous value. */ - success = ReleaseSemaphore(svrCacheSem, 1, NULL); - } - if (!success) { - nss_MD_win32_map_default_error(GetLastError()); - return SECFailure; - } - return SECSuccess; -} +#if defined(AIX) || defined(LINUX) +#define MAX_SID_CACHE_LOCKS 8 +#else +#define MAX_SID_CACHE_LOCKS 256 +#endif -static void -destroyServerCacheSemaphore(void) -{ - PR_ASSERT(svrCacheSem != INVALID_HANDLE_VALUE); - if (svrCacheSem != INVALID_HANDLE_VALUE) { - CloseHandle(svrCacheSem); - /* ignore error */ - svrCacheSem = INVALID_HANDLE_VALUE; - } -} +#define SID_HOWMANY(val, size) (((val) + ((size) - 1)) / (size)) +#define SID_ROUNDUP(val, size) ((size) * SID_HOWMANY((val), (size))) -#define GET_SERVER_CACHE_READ_LOCK(fd, offset, size) \ - if (isMultiProcess) getServerCacheSemaphore(); -#define GET_SERVER_CACHE_WRITE_LOCK(fd, offset, size) \ - if (isMultiProcess) getServerCacheSemaphore(); +static sslPID myPid; -#define RELEASE_SERVER_CACHE_LOCK(fd, offset, size) \ - if (isMultiProcess) releaseServerCacheSemaphore(); +/* forward static function declarations */ +static void IOError(int rv, char *type); +static PRUint32 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, unsigned nl); +static SECStatus LaunchLockPoller(cacheDesc *cache); -#endif /* _win32 */ -/************************************************************************/ -#ifdef XP_UNIX -static int SIDCacheFD = -1; -static int certCacheFD = -1; -static pid_t myPid; +struct inheritanceStr { + PRUint32 sharedMemSize; + PRUint16 fmStrLen; +}; -struct unixInheritanceStr { - PRUint32 numSIDCacheEntries; - PRUint32 sidCacheFileSize; - PRUint32 sidCacheWrapOffset; - PRUint32 numCertCacheEntries; - PRUint32 certCacheFileSize; +typedef struct inheritanceStr inheritance; - PRInt32 SIDCacheFD; - PRInt32 certCacheFD; -}; +#ifdef _WIN32 + +#define DEFAULT_CACHE_DIRECTORY "\\temp" -typedef struct unixInheritanceStr unixInheritance; +#endif /* _win32 */ +#ifdef XP_UNIX #define DEFAULT_CACHE_DIRECTORY "/tmp" -#ifdef TRACE -static void -fcntlFailed(struct flock *lock) -{ - fprintf(stderr, - "fcntl failed, errno = %d, PR_GetError = %d, lock.l_type = %d\n", - errno, PR_GetError(), lock->l_type); - fflush(stderr); -} -#define FCNTL_FAILED(lock) fcntlFailed(lock) -#else -#define FCNTL_FAILED(lock) -#endif +#endif /* XP_UNIX */ -/* NOTES: Because there are no atomic seek-and-read and seek-and-write -** functions that are supported on all our UNIX platforms, we need -** to prevent all simultaeous seek-and-read operations. For that reason, -** we use mutually exclusive (write) locks for read and write operations, -** and use them all at the same offset (zero). -*/ -static SECStatus -_getServerCacheLock(int fd, short type, PRUint32 offset, PRUint32 size) + +/************************************************************************/ + +static void +IOError(int rv, char *type) { - int result; - struct flock lock; - - memset(&lock, 0, sizeof lock); - lock.l_type = /* type */ F_WRLCK; - lock.l_whence = SEEK_SET; /* absolute file offsets. */ - lock.l_start = 0; - lock.l_len = 128; - -#ifdef TRACE - if (ssl_trace) { - fprintf(stderr, "%d: %s lock, offset %8x, size %4d\n", myPid, - (type == F_RDLCK) ? "read " : "write", offset, size); - fflush(stderr); - } -#endif - result = fcntl(fd, F_SETLKW, &lock); - if (result == -1) { - nss_MD_unix_map_default_error(errno); - FCNTL_FAILED(&lock); - return SECFailure; - } -#ifdef TRACE - if (ssl_trace) { - fprintf(stderr, "%d: got lock, offset %8x, size %4d\n", - myPid, offset, size); - fflush(stderr); - } -#endif - return SECSuccess; +#ifdef XP_UNIX + syslog(LOG_ALERT, + "SSL: %s error with session-id cache, pid=%d, rv=%d, error='%m'", + type, myPid, rv); +#else /* XP_WIN32 */ + /* wish win32 had something like syslog() */ +#endif /* XP_UNIX */ } -typedef struct sslLockArgsStr { - PRUint32 offset; - PRUint32 size; - PRErrorCode err; - SECStatus rv; - int fd; - short type; -} sslLockArgs; - -static void -_doGetServerCacheLock(void * arg) +static PRUint32 +LockSidCacheLock(sidCacheLock *lock, PRUint32 now) { - sslLockArgs * args = (sslLockArgs *)arg; - args->rv = _getServerCacheLock(args->fd, args->type, args->offset, - args->size ); - if (args->rv != SECSuccess) { - args->err = PR_GetError(); - } + SECStatus rv = sslMutex_Lock(&lock->mutex); + if (rv != SECSuccess) + return 0; + if (!now) + now = ssl_Time(); + lock->timeStamp = now; + lock->pid = myPid; + return now; } static SECStatus -getServerCacheLock(int fd, short type, PRUint32 offset, PRUint32 size) +UnlockSidCacheLock(sidCacheLock *lock) { - PRThread * selectThread; - PRThread * me = PR_GetCurrentThread(); - PRThreadScope scope = PR_GetThreadScope(me); - SECStatus rv = SECFailure; - - if (scope == PR_GLOBAL_THREAD) { - rv = _getServerCacheLock(fd, type, offset, size); - } else { - /* Ib some platforms, one thread cannot read local/automatic - ** variables from another thread's stack. So, get this space - ** from the heap, not the stack. - */ - sslLockArgs * args = PORT_New(sslLockArgs); - - if (!args) - return rv; + SECStatus rv; - args->offset = offset; - args->size = size; - args->rv = SECFailure; - args->fd = fd; - args->type = type; - selectThread = PR_CreateThread(PR_USER_THREAD, - _doGetServerCacheLock, args, - PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, - PR_JOINABLE_THREAD, 0); - if (selectThread != NULL) { - /* rv will be set by _doGetServerCacheLock() */ - PR_JoinThread(selectThread); - rv = args->rv; - if (rv != SECSuccess) { - PORT_SetError(args->err); - } - } - PORT_Free(args); - } + lock->pid = 0; + rv = sslMutex_Unlock(&lock->mutex); return rv; } -static SECStatus -releaseServerCacheLock(int fd, PRUint32 offset, PRUint32 size) +/* returns the value of ssl_Time on success, zero on failure. */ +static PRUint32 +LockSet(cacheDesc *cache, PRUint32 set, PRUint32 now) { - int result; - struct flock lock; - - memset(&lock, 0, sizeof lock); - lock.l_type = F_UNLCK; - lock.l_whence = SEEK_SET; /* absolute file offsets. */ - lock.l_start = 0; - lock.l_len = 128; - -#ifdef TRACE - if (ssl_trace) { - fprintf(stderr, "%d: unlock, offset %8x, size %4d\n", - myPid, offset, size); - fflush(stderr); - } -#endif - result = fcntl(fd, F_SETLK, &lock); - if (result == -1) { - nss_MD_unix_map_default_error(errno); - FCNTL_FAILED(&lock); - return SECFailure; - } - return SECSuccess; -} - - -/* these defines take the arguments needed to do record locking, - * however the present implementation does only file locking. - */ - -#define GET_SERVER_CACHE_READ_LOCK( fd, offset, size) \ - if (isMultiProcess) getServerCacheLock(fd, F_RDLCK, offset, size); + PRUint32 lockNum = set % cache->numSIDCacheLocks; + sidCacheLock * lock = cache->sidCacheLocks + lockNum; -#define GET_SERVER_CACHE_WRITE_LOCK(fd, offset, size) \ - if (isMultiProcess) getServerCacheLock(fd, F_WRLCK, offset, size); - -#define RELEASE_SERVER_CACHE_LOCK( fd, offset, size) \ - if (isMultiProcess) releaseServerCacheLock(fd, offset, size); + return LockSidCacheLock(lock, now); +} -/* -** Zero a file out to nb bytes -*/ -static SECStatus -ZeroFile(int fd, int nb) +static SECStatus +UnlockSet(cacheDesc *cache, PRUint32 set) { - off_t off; - int amount, rv; - char buf[16384]; - - PORT_Memset(buf, 0, sizeof(buf)); - off = lseek(fd, 0, SEEK_SET); - if (off != 0) { - if (off == -1) - nss_MD_unix_map_lseek_error(errno); - else - PORT_SetError(PR_FILE_SEEK_ERROR); - return SECFailure; - } + PRUint32 lockNum = set % cache->numSIDCacheLocks; + sidCacheLock * lock = cache->sidCacheLocks + lockNum; - while (nb > 0) { - amount = (nb > sizeof buf) ? sizeof buf : nb; - rv = write(fd, buf, amount); - if (rv <= 0) { - if (!rv) - PORT_SetError(PR_IO_ERROR); - else - nss_MD_unix_map_write_error(errno); - IOError(rv, "zero-write"); - return SECFailure; - } - nb -= rv; - } - return SECSuccess; + return UnlockSidCacheLock(lock); } -#endif /* XP_UNIX */ - - /************************************************************************/ -/* -** Reconstitute a cert from the cache -** This is only called from ConvertToSID(). -** Caller must hold the cache lock before calling this. + +/* Put a certificate in the cache. Update the cert index in the sce. */ -static CERTCertificate * -GetCertFromCache(SIDCacheEntry *sce, CERTCertDBHandle *dbHandle) +static PRUint32 +CacheCert(cacheDesc * cache, CERTCertificate *cert, sidCacheEntry *sce) { - CERTCertificate *cert; - PRUint32 offset; - int rv; -#ifdef XP_UNIX - off_t off; -#endif - SECItem derCert; - CertCacheEntry cce; + PRUint32 now; + certCacheEntry cce; - offset = (PRUint32)sce->u.ssl3.certIndex * sizeof(CertCacheEntry); - GET_SERVER_CACHE_READ_LOCK(certCacheFD, offset, sizeof(CertCacheEntry)); -#ifdef XP_UNIX - off = lseek(certCacheFD, offset, SEEK_SET); - rv = -1; - if (off != offset) { - if (off == -1) - nss_MD_unix_map_lseek_error(errno); - else - PORT_SetError(PR_FILE_SEEK_ERROR); - } else { - rv = read(certCacheFD, &cce, sizeof(CertCacheEntry)); - if (rv != sizeof(CertCacheEntry)) { - if (rv == -1) - nss_MD_unix_map_read_error(errno); - else - PORT_SetError(PR_IO_ERROR); - } - } -#else /* XP_WIN32 */ - /* Use memory mapped I/O and just memcpy() the data */ - CopyMemory(&cce, &certCacheData[offset], sizeof(CertCacheEntry)); - rv = sizeof cce; -#endif /* XP_WIN32 */ - RELEASE_SERVER_CACHE_LOCK(certCacheFD, offset, sizeof(CertCacheEntry)) - - if (rv != sizeof(CertCacheEntry)) { - IOError(rv, "read"); /* error set above */ - return NULL; + if ((cert->derCert.len > SSL_MAX_CACHED_CERT_LEN) || + (cert->derCert.len <= 0) || + (cert->derCert.data == NULL)) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return 0; } - /* See if the session ID matches with that in the sce cache. */ - if((cce.sessionIDLength != sce->u.ssl3.sessionIDLength) || - PORT_Memcmp(cce.sessionID, sce->u.ssl3.sessionID, cce.sessionIDLength)) { - /* this is a cache miss, not an error */ - PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND); - return NULL; - } + cce.sessionIDLength = sce->sessionIDLength; + PORT_Memcpy(cce.sessionID, sce->sessionID, cce.sessionIDLength); - derCert.len = cce.certLength; - derCert.data = cce.cert; + cce.certLength = cert->derCert.len; + PORT_Memcpy(cce.cert, cert->derCert.data, cce.certLength); - cert = CERT_NewTempCertificate(dbHandle, &derCert, NULL, - PR_FALSE, PR_TRUE); + /* get lock on cert cache */ + now = LockSidCacheLock(cache->certCacheLock, 0); + if (now) { - return cert; -} + /* Find where to place the next cert cache entry. */ + cacheDesc * sharedCache = cache->sharedCache; + PRUint32 ndx = sharedCache->nextCertCacheEntry; -/* Put a certificate in the cache. We assume that the certIndex in -** sid is valid. -*/ -static void -CacheCert(CERTCertificate *cert, SIDCacheEntry *sce) -{ - PRUint32 offset; - CertCacheEntry cce; -#ifdef XP_UNIX - off_t off; - int rv; -#endif + /* write the entry */ + cache->certCacheData[ndx] = cce; - offset = (PRUint32)sce->u.ssl3.certIndex * sizeof(CertCacheEntry); - if (cert->derCert.len > SSL_MAX_CACHED_CERT_LEN) - return; - - cce.sessionIDLength = sce->u.ssl3.sessionIDLength; - PORT_Memcpy(cce.sessionID, sce->u.ssl3.sessionID, cce.sessionIDLength); + /* remember where we put it. */ + sce->u.ssl3.certIndex = ndx; - cce.certLength = cert->derCert.len; - PORT_Memcpy(cce.cert, cert->derCert.data, cce.certLength); + /* update the "next" cache entry index */ + sharedCache->nextCertCacheEntry = + (ndx + 1) % cache->numCertCacheEntries; - GET_SERVER_CACHE_WRITE_LOCK(certCacheFD, offset, sizeof cce); -#ifdef XP_UNIX - off = lseek(certCacheFD, offset, SEEK_SET); - if (off != offset) { - if (off == -1) - nss_MD_unix_map_lseek_error(errno); - else - PORT_SetError(PR_FILE_SEEK_ERROR); - } else { - rv = write(certCacheFD, &cce, sizeof cce); - if (rv != sizeof(CertCacheEntry)) { - if (rv == -1) - nss_MD_unix_map_write_error(errno); - else - PORT_SetError(PR_IO_ERROR); - IOError(rv, "cert-write"); - Invalidate(sce); - } + UnlockSidCacheLock(cache->certCacheLock); } -#else /* WIN32 */ - /* Use memory mapped I/O and just memcpy() the data */ - CopyMemory(&certCacheData[offset], &cce, sizeof cce); -#endif /* XP_UNIX */ + return now; - RELEASE_SERVER_CACHE_LOCK(certCacheFD, offset, sizeof cce); - return; } /* ** Convert memory based SID to file based one */ static void -ConvertFromSID(SIDCacheEntry *to, sslSessionID *from) +ConvertFromSID(sidCacheEntry *to, sslSessionID *from) { - to->u.ssl2.valid = 1; - to->u.ssl2.version = from->version; - to->addr = from->addr; - to->time = from->time; + to->valid = 1; + to->version = from->version; + to->addr = from->addr; + to->time = from->time; if (from->version < SSL_LIBRARY_VERSION_3_0) { if ((from->u.ssl2.masterKey.len > SSL_MAX_MASTER_KEY_BYTES) || @@ -726,7 +394,7 @@ ConvertFromSID(SIDCacheEntry *to, sslSessionID *from) SSL_DBG(("%d: SSL: masterKeyLen=%d cipherArgLen=%d", myPid, from->u.ssl2.masterKey.len, from->u.ssl2.cipherArg.len)); - to->u.ssl2.valid = 0; + to->valid = 0; return; } @@ -735,8 +403,8 @@ ConvertFromSID(SIDCacheEntry *to, sslSessionID *from) to->u.ssl2.cipherArgLen = from->u.ssl2.cipherArg.len; to->u.ssl2.keyBits = from->u.ssl2.keyBits; to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits; - PORT_Memcpy(to->u.ssl2.sessionID, from->u.ssl2.sessionID, - sizeof(to->u.ssl2.sessionID)); + to->sessionIDLength = SSL2_SESSIONID_BYTES; + PORT_Memcpy(to->sessionID, from->u.ssl2.sessionID, SSL2_SESSIONID_BYTES); PORT_Memcpy(to->u.ssl2.masterKey, from->u.ssl2.masterKey.data, from->u.ssl2.masterKey.len); PORT_Memcpy(to->u.ssl2.cipherArg, from->u.ssl2.cipherArg.data, @@ -750,13 +418,12 @@ ConvertFromSID(SIDCacheEntry *to, sslSessionID *from) SSL_TRC(8, ("%d: SSL: ConvertSID: masterKeyLen=%d cipherArgLen=%d " "time=%d addr=0x%08x%08x%08x%08x cipherType=%d", myPid, to->u.ssl2.masterKeyLen, to->u.ssl2.cipherArgLen, - to->time, to->addr.pr_s6_addr32[0], + to->time, to->addr.pr_s6_addr32[0], to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2], to->addr.pr_s6_addr32[3], to->u.ssl2.cipherType)); } else { /* This is an SSL v3 session */ - to->u.ssl3.sessionIDLength = from->u.ssl3.sessionIDLength; to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite; to->u.ssl3.compression = (uint16)from->u.ssl3.compression; to->u.ssl3.resumable = from->u.ssl3.resumable; @@ -764,12 +431,14 @@ ConvertFromSID(SIDCacheEntry *to, sslSessionID *from) to->u.ssl3.keys = from->u.ssl3.keys; to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech; to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType; + to->sessionIDLength = from->u.ssl3.sessionIDLength; + to->u.ssl3.certIndex = -1; - PORT_Memcpy(to->u.ssl3.sessionID, - from->u.ssl3.sessionID, - from->u.ssl3.sessionIDLength); + PORT_Memcpy(to->sessionID, from->u.ssl3.sessionID, + to->sessionIDLength); - SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x cipherSuite=%d", + SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x " + "cipherSuite=%d", myPid, to->time, to->addr.pr_s6_addr32[0], to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2], to->addr.pr_s6_addr32[3], to->u.ssl3.cipherSuite)); @@ -782,10 +451,11 @@ ConvertFromSID(SIDCacheEntry *to, sslSessionID *from) ** Caller must hold cache lock when calling this. */ static sslSessionID * -ConvertToSID(SIDCacheEntry *from, CERTCertDBHandle * dbHandle) +ConvertToSID(sidCacheEntry *from, certCacheEntry *pcce, + CERTCertDBHandle * dbHandle) { sslSessionID *to; - uint16 version = from->u.ssl2.version; + uint16 version = from->version; to = (sslSessionID*) PORT_ZAlloc(sizeof(sslSessionID)); if (!to) { @@ -800,13 +470,13 @@ ConvertToSID(SIDCacheEntry *from, CERTCertDBHandle * dbHandle) goto loser; } if (from->u.ssl2.cipherArgLen) { - to->u.ssl2.cipherArg.data = (unsigned char*) - PORT_Alloc(from->u.ssl2.cipherArgLen); + to->u.ssl2.cipherArg.data = + (unsigned char*)PORT_Alloc(from->u.ssl2.cipherArgLen); if (!to->u.ssl2.cipherArg.data) { goto loser; } PORT_Memcpy(to->u.ssl2.cipherArg.data, from->u.ssl2.cipherArg, - from->u.ssl2.cipherArgLen); + from->u.ssl2.cipherArgLen); } to->u.ssl2.cipherType = from->u.ssl2.cipherType; @@ -814,22 +484,22 @@ ConvertToSID(SIDCacheEntry *from, CERTCertDBHandle * dbHandle) to->u.ssl2.cipherArg.len = from->u.ssl2.cipherArgLen; to->u.ssl2.keyBits = from->u.ssl2.keyBits; to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits; - PORT_Memcpy(to->u.ssl2.sessionID, from->u.ssl2.sessionID, - sizeof from->u.ssl2.sessionID); +/* to->sessionIDLength = SSL2_SESSIONID_BYTES; */ + PORT_Memcpy(to->u.ssl2.sessionID, from->sessionID, SSL2_SESSIONID_BYTES); PORT_Memcpy(to->u.ssl2.masterKey.data, from->u.ssl2.masterKey, - from->u.ssl2.masterKeyLen); + from->u.ssl2.masterKeyLen); SSL_TRC(8, ("%d: SSL: ConvertToSID: masterKeyLen=%d cipherArgLen=%d " "time=%d addr=0x%08x%08x%08x%08x cipherType=%d", myPid, to->u.ssl2.masterKey.len, - to->u.ssl2.cipherArg.len, to->time, + to->u.ssl2.cipherArg.len, to->time, to->addr.pr_s6_addr32[0], to->addr.pr_s6_addr32[1], - to->addr.pr_s6_addr32[2], to->addr.pr_s6_addr32[3], + to->addr.pr_s6_addr32[2], to->addr.pr_s6_addr32[3], to->u.ssl2.cipherType)); } else { /* This is an SSL v3 session */ - to->u.ssl3.sessionIDLength = from->u.ssl3.sessionIDLength; + to->u.ssl3.sessionIDLength = from->sessionIDLength; to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite; to->u.ssl3.compression = (SSL3CompressionMethod)from->u.ssl3.compression; to->u.ssl3.resumable = from->u.ssl3.resumable; @@ -838,9 +508,7 @@ ConvertToSID(SIDCacheEntry *from, CERTCertDBHandle * dbHandle) to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech; to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType; - PORT_Memcpy(to->u.ssl3.sessionID, - from->u.ssl3.sessionID, - from->u.ssl3.sessionIDLength); + PORT_Memcpy(to->u.ssl3.sessionID, from->sessionID, from->sessionIDLength); /* the portions of the SID that are only restored on the client * are set to invalid values on the server. @@ -863,15 +531,21 @@ ConvertToSID(SIDCacheEntry *from, CERTCertDBHandle * dbHandle) to->u.ssl3.clientWriteSaveLen = 0; - if (from->u.ssl3.certIndex != -1) { - to->peerCert = GetCertFromCache(from, dbHandle); + if (from->u.ssl3.certIndex != -1 && pcce) { + SECItem derCert; + + derCert.len = pcce->certLength; + derCert.data = pcce->cert; + + to->peerCert = CERT_NewTempCertificate(dbHandle, &derCert, NULL, + PR_FALSE, PR_TRUE); if (to->peerCert == NULL) goto loser; } } - to->version = from->u.ssl2.version; - to->time = from->time; + to->version = from->version; + to->time = from->time; /* XXX ??? is expiration time */ to->cached = in_server_cache; to->addr = from->addr; to->references = 1; @@ -879,7 +553,6 @@ ConvertToSID(SIDCacheEntry *from, CERTCertDBHandle * dbHandle) return to; loser: - Invalidate(from); if (to) { if (version < SSL_LIBRARY_VERSION_3_0) { if (to->u.ssl2.masterKey.data) @@ -893,210 +566,82 @@ ConvertToSID(SIDCacheEntry *from, CERTCertDBHandle * dbHandle) } -/* Invalidate a SID cache entry. - * Called from CacheCert, ConvertToSid, and ServerSessionIDUncache. - */ -static void -Invalidate(SIDCacheEntry *sce) -{ - PRUint32 offset; -#ifdef XP_UNIX - off_t off; - int rv; -#endif - - if (sce == NULL) return; - - if (sce->u.ssl2.version < SSL_LIBRARY_VERSION_3_0) { - offset = Offset(&sce->addr, sce->u.ssl2.sessionID, - sizeof sce->u.ssl2.sessionID); - } else { - offset = Offset(&sce->addr, sce->u.ssl3.sessionID, - sce->u.ssl3.sessionIDLength); - } - - sce->u.ssl2.valid = 0; - SSL_TRC(7, ("%d: SSL: uncaching session-id at offset %ld", - myPid, offset)); - - GET_SERVER_CACHE_WRITE_LOCK(SIDCacheFD, offset, sizeof *sce); - -#ifdef XP_UNIX - off = lseek(SIDCacheFD, offset, SEEK_SET); - if (off != offset) { - if (off == -1) - nss_MD_unix_map_lseek_error(errno); - else - PORT_SetError(PR_FILE_SEEK_ERROR); - } else { - rv = write(SIDCacheFD, sce, sizeof *sce); - if (rv != sizeof *sce) { - if (rv == -1) - nss_MD_unix_map_write_error(errno); - else - PORT_SetError(PR_IO_ERROR); - IOError(rv, "invalidate-write"); - } - } -#else /* WIN32 */ - /* Use memory mapped I/O and just memcpy() the data */ - CopyMemory(&SIDCacheData[offset], sce, sizeof *sce); -#endif /* XP_UNIX */ - - RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, offset, sizeof *sce); -} - - -static void -IOError(int rv, char *type) -{ -#ifdef XP_UNIX - syslog(LOG_ALERT, - "SSL: %s error with session-id cache, pid=%d, rv=%d, error='%m'", - type, myPid, rv); -#else /* XP_WIN32 */ -#ifdef MC_HTTPD - ereport(LOG_FAILURE, "%s error with session-id cache rv=%d\n",type, rv); -#endif /* MC_HTTPD */ -#endif /* XP_UNIX */ -} - -static void -lock_cache(void) -{ - PZ_Lock(cacheLock); -} - -static void -unlock_cache(void) -{ - PZ_Unlock(cacheLock); -} /* ** Perform some mumbo jumbo on the ip-address and the session-id value to ** compute a hash value. */ static PRUint32 -Offset(const PRIPv6Addr *addr, unsigned char *s, unsigned nl) +SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, unsigned nl) { PRUint32 rv; + PRUint32 x[8]; + + memset(x, 0, sizeof x); + if (nl > sizeof x) + nl = sizeof x; + memcpy(x, s, nl); - rv = addr->pr_s6_addr32[3] ^ (((PRUint32)s[0] << 24) | ((PRUint32)s[1] << 16) - | (s[2] << 8) | s[nl-1]); - return (rv % numSIDCacheEntries) * sizeof(SIDCacheEntry); + rv = (addr->pr_s6_addr32[0] ^ addr->pr_s6_addr32[1] ^ + addr->pr_s6_addr32[2] ^ addr->pr_s6_addr32[3] ^ + x[0] ^ x[1] ^ x[2] ^ x[3] ^ x[4] ^ x[5] ^ x[6] ^ x[7]) + % cache->numSIDCacheSets; + return rv; } /* ** Look something up in the cache. This will invalidate old entries -** in the process. Caller has locked the cache! +** in the process. Caller has locked the cache set! ** Returns PR_TRUE if found a valid match. PR_FALSE otherwise. */ -static PRBool -FindSID(const PRIPv6Addr *addr, unsigned char *sessionID, - unsigned sessionIDLength, SIDCacheEntry *sce) +static sidCacheEntry * +FindSID(cacheDesc *cache, PRUint32 setNum, PRUint32 now, + const PRIPv6Addr *addr, unsigned char *sessionID, + unsigned sessionIDLength) { - PRUint32 offset; - PRUint32 now; - int rv; -#ifdef XP_UNIX - off_t off; -#endif - - /* Read in cache entry after hashing ip address and session-id value */ - offset = Offset(addr, sessionID, sessionIDLength); - now = ssl_Time(); - GET_SERVER_CACHE_READ_LOCK(SIDCacheFD, offset, sizeof *sce); -#ifdef XP_UNIX - off = lseek(SIDCacheFD, offset, SEEK_SET); - rv = -1; - if (off != offset) { - if (off == -1) - nss_MD_unix_map_lseek_error(errno); - else - PORT_SetError(PR_FILE_SEEK_ERROR); - } else { - rv = read(SIDCacheFD, sce, sizeof *sce); - if (rv != sizeof *sce) { - if (rv == -1) - nss_MD_unix_map_read_error(errno); - else - PORT_SetError(PR_IO_ERROR); - } - } -#else /* XP_WIN32 */ - /* Use memory mapped I/O and just memcpy() the data */ - CopyMemory(sce, &SIDCacheData[offset], sizeof *sce); - rv = sizeof *sce; -#endif /* XP_WIN32 */ - RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, offset, sizeof *sce); - - if (rv != sizeof *sce) { - IOError(rv, "server sid cache read"); - return PR_FALSE; - } - - if (!sce->u.ssl2.valid) { - /* Entry is not valid */ - PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND); - return PR_FALSE; - } + PRUint32 ndx = cache->sidCacheSets[setNum].next; + int i; + + sidCacheEntry * set = cache->sidCacheData + + (setNum * SID_CACHE_ENTRIES_PER_SET); + + for (i = SID_CACHE_ENTRIES_PER_SET; i > 0; --i) { + sidCacheEntry * sce; + + ndx = (ndx - 1) % SID_CACHE_ENTRIES_PER_SET; + sce = set + ndx; + + if (!sce->valid) + continue; + + if (now > sce->time) { + /* SessionID has timed out. Invalidate the entry. */ + SSL_TRC(7, ("%d: timed out sid entry addr=%08x%08x%08x%08x now=%x " + "time+=%x", + myPid, sce->addr.pr_s6_addr32[0], + sce->addr.pr_s6_addr32[1], sce->addr.pr_s6_addr32[2], + sce->addr.pr_s6_addr32[3], now, + sce->time + ssl_sid_timeout)); + sce->valid = 0; + continue; + } - if (((sce->u.ssl2.version < SSL_LIBRARY_VERSION_3_0) && - (now > sce->time + ssl_sid_timeout)) || - ((sce->u.ssl2.version >= SSL_LIBRARY_VERSION_3_0) && - (now > sce->time + ssl3_sid_timeout))) { - /* SessionID has timed out. Invalidate the entry. */ - SSL_TRC(7, ("%d: timed out sid entry addr=%08x%08x%08x%08x now=%x time+=%x", - myPid, sce->addr.pr_s6_addr32[0], - sce->addr.pr_s6_addr32[1], sce->addr.pr_s6_addr32[2], - sce->addr.pr_s6_addr32[3], now, - sce->time + ssl_sid_timeout)); - sce->u.ssl2.valid = 0; - - GET_SERVER_CACHE_WRITE_LOCK(SIDCacheFD, offset, sizeof *sce); -#ifdef XP_UNIX - off = lseek(SIDCacheFD, offset, SEEK_SET); - rv = -1; - if (off != offset) { - if (off == -1) - nss_MD_unix_map_lseek_error(errno); - else - PORT_SetError(PR_IO_ERROR); - } else { - rv = write(SIDCacheFD, sce, sizeof *sce); - if (rv != sizeof *sce) { - if (rv == -1) - nss_MD_unix_map_write_error(errno); - else - PORT_SetError(PR_IO_ERROR); - IOError(rv, "timeout-write"); - } + /* + ** Next, examine specific session-id/addr data to see if the cache + ** entry matches our addr+session-id value + */ + if (sessionIDLength == sce->sessionIDLength && + !memcmp(&sce->addr, addr, sizeof(PRIPv6Addr)) && + !memcmp(sce->sessionID, sessionID, sessionIDLength)) { + /* Found it */ + return sce; } -#else /* WIN32 */ - /* Use memory mapped I/O and just memcpy() the data */ - CopyMemory(&SIDCacheData[offset], sce, sizeof *sce); - rv = sizeof *sce; -#endif /* XP_UNIX */ - RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, offset, sizeof *sce); - if (rv == sizeof *sce) - PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND); - return PR_FALSE; } - /* - ** Finally, examine specific session-id/addr data to see if the cache - ** entry matches our addr+session-id value - */ - if (!memcmp(&sce->addr, addr, sizeof(PRIPv6Addr)) && - (PORT_Memcmp(sce->u.ssl2.sessionID, sessionID, sessionIDLength) == 0)) { - /* Found it */ - return PR_TRUE; - } PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND); - return PR_FALSE; + return NULL; } /************************************************************************/ @@ -1106,40 +651,82 @@ FindSID(const PRIPv6Addr *addr, unsigned char *sessionID, * pointer ssl_sid_lookup. */ static sslSessionID * -ServerSessionIDLookup( const PRIPv6Addr *addr, +ServerSessionIDLookup(const PRIPv6Addr *addr, unsigned char *sessionID, unsigned int sessionIDLength, CERTCertDBHandle * dbHandle) { - SIDCacheEntry sce; - sslSessionID *sid; - - sid = 0; - lock_cache(); - if (FindSID(addr, sessionID, sessionIDLength, &sce)) { - /* Found it. Convert file format to internal format */ - sid = ConvertToSID(&sce, dbHandle); + sslSessionID * sid = 0; + sidCacheEntry * psce; + certCacheEntry *pcce = 0; + cacheDesc * cache = &globalCache; + PRUint32 now; + PRUint32 set; + PRInt32 cndx; + sidCacheEntry sce; + certCacheEntry cce; + + set = SIDindex(cache, addr, sessionID, sessionIDLength); + now = LockSet(cache, set, 0); + if (!now) + return NULL; + + psce = FindSID(cache, set, now, addr, sessionID, sessionIDLength); + if (psce) { + if (psce->version >= SSL_LIBRARY_VERSION_3_0 && + (cndx = psce->u.ssl3.certIndex) != -1) { + + PRUint32 gotLock = LockSidCacheLock(cache->certCacheLock, now); + if (gotLock) { + pcce = &cache->certCacheData[cndx]; + + /* See if the cert's session ID matches the sce cache. */ + if ((pcce->sessionIDLength == psce->sessionIDLength) && + !PORT_Memcmp(pcce->sessionID, psce->sessionID, + pcce->sessionIDLength)) { + cce = *pcce; + } else { + /* The cert doesen't match the SID cache entry, + ** so invalidate the SID cache entry. + */ + psce->valid = 0; + psce = 0; + pcce = 0; + } + UnlockSidCacheLock(cache->certCacheLock); + } else { + /* what the ??. Didn't get the cert cache lock. + ** Don't invalidate the SID cache entry, but don't find it. + */ + PORT_Assert(!("Didn't get cert Cache Lock!")); + psce = 0; + pcce = 0; + } + } + if (psce) { + sce = *psce; /* grab a copy while holding the lock */ + } + } + UnlockSet(cache, set); + if (psce) { + /* sce conains a copy of the cache entry. + ** Convert file format to internal format + */ + sid = ConvertToSID(&sce, pcce ? &cce : 0, dbHandle); } - unlock_cache(); return sid; } /* -** Place an sid into the cache, if it isn't already there. Note that if -** some other server process has replaced a session-id cache entry that has -** the same cache index as this sid, then all is ok. Somebody has to lose -** when this condition occurs, so it might as well be this sid. +** Place a sid into the cache, if it isn't already there. */ static void ServerSessionIDCache(sslSessionID *sid) { - SIDCacheEntry sce; - PRUint32 offset; -#ifdef XP_UNIX - off_t off; - int rv; -#endif - uint16 version = sid->version; + sidCacheEntry sce; + PRUint32 now = 0; + uint16 version = sid->version; + cacheDesc * cache = &globalCache; if ((version >= SSL_LIBRARY_VERSION_3_0) && (sid->u.ssl3.sessionIDLength == 0)) { @@ -1147,384 +734,319 @@ ServerSessionIDCache(sslSessionID *sid) } if (sid->cached == never_cached || sid->cached == invalid_cache) { - lock_cache(); + PRUint32 set; - sid->time = ssl_Time(); if (version < SSL_LIBRARY_VERSION_3_0) { + sid->time = ssl_Time() + ssl_sid_timeout; SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x " - "cipher=%d", myPid, sid->cached, + "cipher=%d", myPid, sid->cached, sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1], sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], sid->time, sid->u.ssl2.cipherType)); PRINT_BUF(8, (0, "sessionID:", sid->u.ssl2.sessionID, - sizeof(sid->u.ssl2.sessionID))); + SSL2_SESSIONID_BYTES)); PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data, sid->u.ssl2.masterKey.len)); PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data, sid->u.ssl2.cipherArg.len)); - /* Write out new cache entry */ - offset = Offset(&sid->addr, sid->u.ssl2.sessionID, - sizeof(sid->u.ssl2.sessionID)); } else { + sid->time = ssl_Time() + ssl3_sid_timeout; SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x " - "cipherSuite=%d", myPid, sid->cached, + "cipherSuite=%d", myPid, sid->cached, sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1], - sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], + sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], sid->time, sid->u.ssl3.cipherSuite)); PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength)); - - offset = Offset(&sid->addr, sid->u.ssl3.sessionID, - sid->u.ssl3.sessionIDLength); - } ConvertFromSID(&sce, sid); - if (version >= SSL_LIBRARY_VERSION_3_0) { - if (sid->peerCert == NULL) { - sce.u.ssl3.certIndex = -1; - } else { - sce.u.ssl3.certIndex = (int16) - ((offset / sizeof(SIDCacheEntry)) % numCertCacheEntries); - } - } - - GET_SERVER_CACHE_WRITE_LOCK(SIDCacheFD, offset, sizeof sce); -#ifdef XP_UNIX - off = lseek(SIDCacheFD, offset, SEEK_SET); - if (off != offset) { - if (off == -1) - nss_MD_unix_map_lseek_error(errno); - else - PORT_SetError(PR_IO_ERROR); - } else { - rv = write(SIDCacheFD, &sce, sizeof sce); - if (rv != sizeof(sce)) { - if (rv == -1) - nss_MD_unix_map_write_error(errno); - else - PORT_SetError(PR_IO_ERROR); - IOError(rv, "update-write"); - } - } -#else /* WIN32 */ - CopyMemory(&SIDCacheData[offset], &sce, sizeof sce); -#endif /* XP_UNIX */ - RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, offset, sizeof sce); if ((version >= SSL_LIBRARY_VERSION_3_0) && (sid->peerCert != NULL)) { - CacheCert(sid->peerCert, &sce); + now = CacheCert(cache, sid->peerCert, &sce); } - sid->cached = in_server_cache; - unlock_cache(); + set = SIDindex(cache, &sce.addr, sce.sessionID, sce.sessionIDLength); + now = LockSet(cache, set, now); + if (now) { + PRUint32 next = cache->sidCacheSets[set].next; + PRUint32 ndx = set * SID_CACHE_ENTRIES_PER_SET + next; + + /* Write out new cache entry */ + cache->sidCacheData[ndx] = sce; + + cache->sidCacheSets[set].next = + (next + 1) % SID_CACHE_ENTRIES_PER_SET; + + UnlockSet(cache, set); + sid->cached = in_server_cache; + } } } +/* +** Although this is static, it is called from ssl via global function pointer +** ssl_sid_uncache. This invalidates the referenced cache entry. +*/ static void ServerSessionIDUncache(sslSessionID *sid) { - SIDCacheEntry sce; - PRErrorCode err; - int rv; - - if (sid == NULL) return; + cacheDesc * cache = &globalCache; + PRUint8 * sessionID; + unsigned int sessionIDLength; + PRErrorCode err; + PRUint32 set; + PRUint32 now; + sidCacheEntry *psce; + + if (sid == NULL) + return; /* Uncaching a SID should never change the error code. ** So save it here and restore it before exiting. */ err = PR_GetError(); - lock_cache(); + if (sid->version < SSL_LIBRARY_VERSION_3_0) { + sessionID = sid->u.ssl2.sessionID; + sessionIDLength = SSL2_SESSIONID_BYTES; SSL_TRC(8, ("%d: SSL: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x " - "cipher=%d", myPid, sid->cached, + "cipher=%d", myPid, sid->cached, sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1], - sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], + sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], sid->time, sid->u.ssl2.cipherType)); - PRINT_BUF(8, (0, "sessionID:", sid->u.ssl2.sessionID, - sizeof(sid->u.ssl2.sessionID))); + PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength)); PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data, sid->u.ssl2.masterKey.len)); PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data, sid->u.ssl2.cipherArg.len)); - rv = FindSID(&sid->addr, sid->u.ssl2.sessionID, - sizeof(sid->u.ssl2.sessionID), &sce); } else { + sessionID = sid->u.ssl3.sessionID; + sessionIDLength = sid->u.ssl3.sessionIDLength; SSL_TRC(8, ("%d: SSL3: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x " - "cipherSuite=%d", myPid, sid->cached, + "cipherSuite=%d", myPid, sid->cached, sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1], - sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], + sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], sid->time, sid->u.ssl3.cipherSuite)); - PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID, - sid->u.ssl3.sessionIDLength)); - rv = FindSID(&sid->addr, sid->u.ssl3.sessionID, - sid->u.ssl3.sessionIDLength, &sce); - } - - if (rv) { - Invalidate(&sce); + PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength)); + } + set = SIDindex(cache, &sid->addr, sessionID, sessionIDLength); + now = LockSet(cache, set, 0); + if (now) { + psce = FindSID(cache, set, now, &sid->addr, sessionID, sessionIDLength); + if (psce) { + psce->valid = 0; + } + UnlockSet(cache, set); } sid->cached = invalid_cache; - unlock_cache(); PORT_SetError(err); } static SECStatus -InitSessionIDCache(int maxCacheEntries, PRUint32 timeout, - PRUint32 ssl3_timeout, const char *directory) +InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout, + PRUint32 ssl3_timeout, const char *directory) { - char *cfn; -#ifdef XP_UNIX - int rv; - if (SIDCacheFD >= 0) { + ptrdiff_t ptr; + sidCacheLock *pLock; + char * sharedMem; + PRFileMap * cacheMemMap; + char * cfn = NULL; /* cache file name */ + int locks_initialized = 0; + int locks_to_initialize = 0; + PRUint32 init_time; + + if (cache->sharedMem) { /* Already done */ return SECSuccess; } -#else /* WIN32 */ - if(SIDCacheFDMAP != INVALID_HANDLE_VALUE) { - /* Already done */ - return SECSuccess; - } -#endif /* XP_UNIX */ + cache->numSIDCacheEntries = maxCacheEntries ? maxCacheEntries + : DEF_SID_CACHE_ENTRIES; + cache->numSIDCacheSets = + SID_HOWMANY(cache->numSIDCacheEntries, SID_CACHE_ENTRIES_PER_SET); - if (maxCacheEntries) { - numSIDCacheEntries = maxCacheEntries; - } - sidCacheWrapOffset = numSIDCacheEntries * sizeof(SIDCacheEntry); - sidCacheFileSize = sidCacheWrapOffset + - (kt_kea_size * SSL_NUM_WRAP_MECHS * sizeof(SSLWrappedSymWrappingKey)); + cache->numSIDCacheEntries = + cache->numSIDCacheSets * SID_CACHE_ENTRIES_PER_SET; - /* Create file names */ - cfn = (char*) PORT_Alloc(PORT_Strlen(directory) + 100); - if (!cfn) { - return SECFailure; - } -#ifdef XP_UNIX - sprintf(cfn, "%s/.sslsidc.%d", directory, getpid()); -#else /* XP_WIN32 */ - sprintf(cfn, "%s\\ssl.sidc.%d.%d", directory, - GetCurrentProcessId(), GetCurrentThreadId()); -#endif /* XP_WIN32 */ + cache->numSIDCacheLocks = + PR_MIN(cache->numSIDCacheSets, MAX_SID_CACHE_LOCKS); - /* Create session-id cache file */ -#ifdef XP_UNIX - do { - (void) unlink(cfn); - SIDCacheFD = open(cfn, O_EXCL|O_CREAT|O_RDWR, 0600); - } while (SIDCacheFD < 0 && errno == EEXIST); - if (SIDCacheFD < 0) { - nss_MD_unix_map_open_error(errno); - IOError(SIDCacheFD, "create"); - goto loser; - } - rv = unlink(cfn); - if (rv < 0) { - nss_MD_unix_map_unlink_error(errno); - IOError(rv, "unlink"); - goto loser; - } -#else /* WIN32 */ - SIDCacheFDMAP = - CreateFileMapping(INVALID_HANDLE_VALUE, /* allocate in swap file */ - &sidCacheFDMapAttributes, /* inheritable. */ - PAGE_READWRITE, - 0, /* size, high word. */ - sidCacheFileSize, /* size, low word. */ - NULL); /* no map name in FS */ - if(! SIDCacheFDMAP) { - nss_MD_win32_map_default_error(GetLastError()); - goto loser; - } - SIDCacheData = (char *)MapViewOfFile(SIDCacheFDMAP, - FILE_MAP_ALL_ACCESS, /* R/W */ - 0, 0, /* offset */ - sidCacheFileSize); /* size */ - if (! SIDCacheData) { - nss_MD_win32_map_default_error(GetLastError()); - goto loser; - } -#endif /* XP_UNIX */ + cache->numSIDCacheSetsPerLock = + SID_HOWMANY(cache->numSIDCacheSets, cache->numSIDCacheLocks); - if (!cacheLock) - nss_InitLock(&cacheLock, nssILockCache); - if (!cacheLock) { - SET_ERROR_CODE - goto loser; - } -#ifdef _WIN32 - if (isMultiProcess && (SECSuccess != createServerCacheSemaphore())) { - SET_ERROR_CODE - goto loser; - } -#endif + /* compute size of shared memory, and offsets of all pointers */ + ptr = 0; + cache->sharedMem = (char *)ptr; + ptr += SID_ROUNDUP(sizeof(cacheDesc), SID_ALIGNMENT); + + cache->sidCacheLocks = (sidCacheLock *)ptr; + cache->keyCacheLock = cache->sidCacheLocks + cache->numSIDCacheLocks; + cache->certCacheLock = cache->keyCacheLock + 1; + ptr = (ptrdiff_t)(cache->certCacheLock + 1); + ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); + + cache->sidCacheSets = (sidCacheSet *)ptr; + ptr = (ptrdiff_t)(cache->sidCacheSets + cache->numSIDCacheSets); + ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); + + cache->sidCacheData = (sidCacheEntry *)ptr; + ptr = (ptrdiff_t)(cache->sidCacheData + cache->numSIDCacheEntries); + ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); + + cache->certCacheData = (certCacheEntry *)ptr; + cache->sidCacheSize = + (char *)cache->certCacheData - (char *)cache->sidCacheData; + + /* This is really a poor way to computer this! */ + cache->numCertCacheEntries = cache->sidCacheSize / sizeof(certCacheEntry); + if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES) + cache->numCertCacheEntries = MIN_CERT_CACHE_ENTRIES; + ptr = (ptrdiff_t)(cache->certCacheData + cache->numCertCacheEntries); + ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); - if (timeout) { - if (timeout > 100) { - timeout = 100; + cache->keyCacheData = (SSLWrappedSymWrappingKey *)ptr; + cache->certCacheSize = + (char *)cache->keyCacheData - (char *)cache->certCacheData; + + cache->numKeyCacheEntries = kt_kea_size * SSL_NUM_WRAP_MECHS; + ptr = (ptrdiff_t)(cache->keyCacheData + cache->numKeyCacheEntries); + ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); + + cache->sharedMemSize = ptr; + + cache->keyCacheSize = (char *)ptr - (char *)cache->keyCacheData; + + if (ssl2_timeout) { + if (ssl2_timeout > MAX_SSL2_TIMEOUT) { + ssl2_timeout = MAX_SSL2_TIMEOUT; } - if (timeout < 5) { - timeout = 5; + if (ssl2_timeout < MIN_SSL2_TIMEOUT) { + ssl2_timeout = MIN_SSL2_TIMEOUT; } - ssl_sid_timeout = timeout; + cache->ssl2Timeout = ssl2_timeout; + } else { + cache->ssl2Timeout = DEF_SSL2_TIMEOUT; } if (ssl3_timeout) { - if (ssl3_timeout > 86400L) { - ssl3_timeout = 86400L; + if (ssl3_timeout > MAX_SSL3_TIMEOUT) { + ssl3_timeout = MAX_SSL3_TIMEOUT; } - if (ssl3_timeout < 5) { - ssl3_timeout = 5; + if (ssl3_timeout < MIN_SSL3_TIMEOUT) { + ssl3_timeout = MIN_SSL3_TIMEOUT; } - ssl3_sid_timeout = ssl3_timeout; - } - - GET_SERVER_CACHE_WRITE_LOCK(SIDCacheFD, 0, sidCacheFileSize); -#ifdef XP_UNIX - /* Initialize the files */ - if (ZeroFile(SIDCacheFD, sidCacheFileSize)) { - /* Bummer */ - close(SIDCacheFD); - SIDCacheFD = -1; - goto loser; - } -#else /* XP_WIN32 */ - ZeroMemory(SIDCacheData, sidCacheFileSize); -#endif /* XP_UNIX */ - RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, 0, sidCacheFileSize); - PORT_Free(cfn); - return SECSuccess; - - loser: -#ifdef _WIN32 - if (svrCacheSem) - destroyServerCacheSemaphore(); -#endif - if (cacheLock) { - PZ_DestroyLock(cacheLock); - cacheLock = NULL; - } - PORT_Free(cfn); - return SECFailure; -} - -static SECStatus -InitCertCache(const char *directory) -{ - char *cfn; -#ifdef XP_UNIX - int rv; - if (certCacheFD >= 0) { - /* Already done */ - return SECSuccess; - } -#else /* WIN32 */ - if(certCacheFDMAP != INVALID_HANDLE_VALUE) { - /* Already done */ - return SECSuccess; + cache->ssl3Timeout = ssl3_timeout; + } else { + cache->ssl3Timeout = DEF_SSL3_TIMEOUT; } -#endif /* XP_UNIX */ - - numCertCacheEntries = sidCacheFileSize / sizeof(CertCacheEntry); - if (numCertCacheEntries < MIN_CERT_CACHE_ENTRIES) - numCertCacheEntries = MIN_CERT_CACHE_ENTRIES; - certCacheFileSize = numCertCacheEntries * sizeof(CertCacheEntry); /* Create file names */ - cfn = (char*) PORT_Alloc(PORT_Strlen(directory) + 100); - if (!cfn) { - return SECFailure; - } #ifdef XP_UNIX - sprintf(cfn, "%s/.sslcertc.%d", directory, getpid()); + /* there's some confusion here about whether PR_OpenAnonFileMap wants + ** a directory name or a file name for its first argument. + cfn = PR_smprintf("%s/.sslsvrcache.%d", directory, myPid); + */ + cfn = PR_smprintf("%s", directory); #else /* XP_WIN32 */ - sprintf(cfn, "%s\\ssl.certc.%d.%d", directory, - GetCurrentProcessId(), GetCurrentThreadId()); + cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid, + GetCurrentThreadId()); #endif /* XP_WIN32 */ - - /* Create certificate cache file */ -#ifdef XP_UNIX - do { - (void) unlink(cfn); - certCacheFD = open(cfn, O_EXCL|O_CREAT|O_RDWR, 0600); - } while (certCacheFD < 0 && errno == EEXIST); - if (certCacheFD < 0) { - nss_MD_unix_map_open_error(errno); - IOError(certCacheFD, "create"); - goto loser; - } - rv = unlink(cfn); - if (rv < 0) { - nss_MD_unix_map_unlink_error(errno); - IOError(rv, "unlink"); + if (!cfn) { goto loser; } -#else /* WIN32 */ - certCacheFDMAP = - CreateFileMapping(INVALID_HANDLE_VALUE, /* allocate in swap file */ - &certCacheFDMapAttributes, /* inheritable. */ - PAGE_READWRITE, - 0, /* size, high word. */ - certCacheFileSize, /* size, low word. */ - NULL); /* no map name in FS */ - if (! certCacheFDMAP) { - nss_MD_win32_map_default_error(GetLastError()); + + /* Create cache */ + cacheMemMap = PR_OpenAnonFileMap(cfn, cache->sharedMemSize, + PR_PROT_READWRITE); + PR_smprintf_free(cfn); + if(! cacheMemMap) { goto loser; } - certCacheData = (char *) MapViewOfFile(certCacheFDMAP, - FILE_MAP_ALL_ACCESS, /* R/W */ - 0, 0, /* offset */ - certCacheFileSize); /* size */ - if (! certCacheData) { - nss_MD_win32_map_default_error(GetLastError()); + sharedMem = PR_MemMap(cacheMemMap, 0, cache->sharedMemSize); + if (! sharedMem) { goto loser; } -#endif /* XP_UNIX */ -/* GET_SERVER_CACHE_WRITE_LOCK(certCacheFD, 0, certCacheFileSize); */ -#ifdef XP_UNIX - /* Initialize the files */ - if (ZeroFile(certCacheFD, certCacheFileSize)) { - /* Bummer */ - close(certCacheFD); - certCacheFD = -1; - goto loser; + /* Initialize shared memory. This may not be necessary on all platforms */ + memset(sharedMem, 0, cache->sharedMemSize); + + /* Copy cache descriptor header into shared memory */ + memcpy(sharedMem, cache, sizeof *cache); + + /* save private copies of these values */ + cache->cacheMemMap = cacheMemMap; + cache->sharedMem = sharedMem; + cache->sharedCache = (cacheDesc *)sharedMem; + + /* Fix pointers in our private copy of cache descriptor to point to + ** spaces in shared memory + */ + ptr = (ptrdiff_t)cache->sharedMem; + *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr; + *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr; + *(ptrdiff_t *)(&cache->certCacheLock) += ptr; + *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr; + *(ptrdiff_t *)(&cache->sidCacheData ) += ptr; + *(ptrdiff_t *)(&cache->certCacheData) += ptr; + *(ptrdiff_t *)(&cache->keyCacheData ) += ptr; + + /* initialize the locks */ + init_time = ssl_Time(); + pLock = cache->sidCacheLocks; + for (locks_to_initialize = cache->numSIDCacheLocks + 2; + locks_initialized < locks_to_initialize; + ++locks_initialized, ++pLock ) { + + SECStatus err = sslMutex_Init(&pLock->mutex, isMultiProcess); + if (err) + goto loser; + pLock->timeStamp = init_time; + pLock->pid = 0; } -#else /* XP_WIN32 */ - ZeroMemory(certCacheData, certCacheFileSize); -#endif /* XP_UNIX */ -/* RELEASE_SERVER_CACHE_LOCK(certCacheFD, 0, certCacheFileSize); */ - PORT_Free(cfn); + return SECSuccess; - loser: - PORT_Free(cfn); +loser: + if (cache->cacheMemMap) { + if (cache->sharedMem) { + if (locks_initialized > 0) { + pLock = cache->sidCacheLocks; + for (; locks_initialized > 0; --locks_initialized, ++pLock ) { + sslMutex_Destroy(&pLock->mutex); + } + } + PR_MemUnmap(cache->sharedMem, cache->sharedMemSize); + cache->sharedMem = NULL; + } + PR_CloseFileMap(cache->cacheMemMap); + cache->cacheMemMap = NULL; + } return SECFailure; } + SECStatus -SSL_ConfigServerSessionIDCache( int maxCacheEntries, - PRUint32 timeout, +SSL_ConfigServerSessionIDCacheInstance( cacheDesc *cache, + int maxCacheEntries, + PRUint32 ssl2_timeout, PRUint32 ssl3_timeout, const char * directory) { SECStatus rv; - PORT_Assert(sizeof(SIDCacheEntry) == 256); - PORT_Assert(sizeof(CertCacheEntry) == 4096); +/* printf("sizeof(sidCacheEntry) == %u\n", sizeof(sidCacheEntry)); */ + PORT_Assert(sizeof(sidCacheEntry) % 8 == 0); + PORT_Assert(sizeof(certCacheEntry) == 4096); myPid = SSL_GETPID(); if (!directory) { directory = DEFAULT_CACHE_DIRECTORY; } - rv = InitSessionIDCache(maxCacheEntries, timeout, ssl3_timeout, directory); - if (rv) { - SET_ERROR_CODE - return SECFailure; - } - rv = InitCertCache(directory); + rv = InitCache(cache, maxCacheEntries, ssl2_timeout, ssl3_timeout, + directory); if (rv) { SET_ERROR_CODE return SECFailure; @@ -1536,87 +1058,93 @@ SSL_ConfigServerSessionIDCache( int maxCacheEntries, return SECSuccess; } +SECStatus +SSL_ConfigServerSessionIDCache( int maxCacheEntries, + PRUint32 ssl2_timeout, + PRUint32 ssl3_timeout, + const char * directory) +{ + return SSL_ConfigServerSessionIDCacheInstance(&globalCache, + maxCacheEntries, ssl2_timeout, ssl3_timeout, directory); +} + /* Use this function, instead of SSL_ConfigServerSessionIDCache, * if the cache will be shared by multiple processes. */ SECStatus SSL_ConfigMPServerSIDCache( int maxCacheEntries, - PRUint32 timeout, + PRUint32 ssl2_timeout, PRUint32 ssl3_timeout, const char * directory) { char * envValue; + char * inhValue; + cacheDesc * cache = &globalCache; + PRUint32 fmStrLen; SECStatus result; + PRStatus prStatus; SECStatus putEnvFailed; + inheritance inherit; + char fmString[PR_FILEMAP_STRING_BUFSIZE]; isMultiProcess = PR_TRUE; - result = SSL_ConfigServerSessionIDCache(maxCacheEntries, timeout, - ssl3_timeout, directory); - if (result == SECSuccess) { -#ifdef _WIN32 - winInheritance winherit; - - winherit.numSIDCacheEntries = numSIDCacheEntries; - winherit.sidCacheFileSize = sidCacheFileSize; - winherit.sidCacheWrapOffset = sidCacheWrapOffset; - winherit.numCertCacheEntries = numCertCacheEntries; - winherit.certCacheFileSize = certCacheFileSize; - winherit.SIDCacheFDMAP = SIDCacheFDMAP; - winherit.certCacheFDMAP = certCacheFDMAP; - winherit.svrCacheSem = svrCacheSem; - winherit.parentProcessID = GetCurrentProcessId(); - winherit.parentProcessHandle = - OpenProcess(PROCESS_DUP_HANDLE, TRUE, winherit.parentProcessID); - if (winherit.parentProcessHandle == NULL) { - SET_ERROR_CODE - return SECFailure; - } - envValue = BTOA_DataToAscii((unsigned char *)&winherit, - sizeof winherit); - if (!envValue) { - SET_ERROR_CODE - return SECFailure; - } -#else - unixInheritance uinherit; - - uinherit.numSIDCacheEntries = numSIDCacheEntries; - uinherit.sidCacheFileSize = sidCacheFileSize; - uinherit.sidCacheWrapOffset = sidCacheWrapOffset; - uinherit.numCertCacheEntries = numCertCacheEntries; - uinherit.certCacheFileSize = certCacheFileSize; - uinherit.SIDCacheFD = SIDCacheFD; - uinherit.certCacheFD = certCacheFD; - - envValue = BTOA_DataToAscii((unsigned char *)&uinherit, - sizeof uinherit); - if (!envValue) { - SET_ERROR_CODE - return SECFailure; - } -#endif + result = SSL_ConfigServerSessionIDCacheInstance(cache, maxCacheEntries, + ssl2_timeout, ssl3_timeout, directory); + if (result != SECSuccess) + return result; + + prStatus = PR_ExportFileMapAsString(cache->cacheMemMap, + sizeof fmString, fmString); + if ((prStatus != PR_SUCCESS) || !(fmStrLen = strlen(fmString))) { + SET_ERROR_CODE + return SECFailure; } + + inherit.sharedMemSize = cache->sharedMemSize; + inherit.fmStrLen = fmStrLen; + + inhValue = BTOA_DataToAscii((unsigned char *)&inherit, sizeof inherit); + if (!inhValue || !strlen(inhValue)) { + SET_ERROR_CODE + return SECFailure; + } + envValue = PR_smprintf("%s,%s", inhValue, fmString); + if (!envValue || !strlen(envValue)) { + SET_ERROR_CODE + return SECFailure; + } + PORT_Free(inhValue); + putEnvFailed = (SECStatus)NSS_PutEnv(envVarName, envValue); - PORT_Free(envValue); + PR_smprintf_free(envValue); if (putEnvFailed) { SET_ERROR_CODE result = SECFailure; } + +#if !defined(WIN32) + /* Launch thread to poll cache for expired locks */ + LaunchLockPoller(cache); +#endif return result; } SECStatus -SSL_InheritMPServerSIDCache(const char * envString) +SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString) { unsigned char * decoString = NULL; + char * fmString = NULL; unsigned int decoLen; -#ifdef _WIN32 - winInheritance inherit; -#else - unixInheritance inherit; -#endif + ptrdiff_t ptr; + inheritance inherit; + cacheDesc my; myPid = SSL_GETPID(); + + /* If this child was created by fork(), and not by exec() on unix, + ** then isMultiProcess will already be set. + ** If not, we'll set it below. + */ if (isMultiProcess) return SECSuccess; /* already done. */ @@ -1631,11 +1159,18 @@ SSL_InheritMPServerSIDCache(const char * envString) return SECFailure; } } + envString = PORT_Strdup(envString); + if (!envString) + return SECFailure; + fmString = strchr(envString, ','); + if (!fmString) + goto loser; + *fmString++ = 0; decoString = ATOB_AsciiToData(envString, &decoLen); if (!decoString) { SET_ERROR_CODE - return SECFailure; + goto loser; } if (decoLen != sizeof inherit) { SET_ERROR_CODE @@ -1643,152 +1178,166 @@ SSL_InheritMPServerSIDCache(const char * envString) } PORT_Memcpy(&inherit, decoString, sizeof inherit); - PORT_Free(decoString); - - numSIDCacheEntries = inherit.numSIDCacheEntries; - sidCacheFileSize = inherit.sidCacheFileSize; - sidCacheWrapOffset = inherit.sidCacheWrapOffset; - numCertCacheEntries = inherit.numCertCacheEntries; - certCacheFileSize = inherit.certCacheFileSize; - -#ifdef _WIN32 - SIDCacheFDMAP = inherit.SIDCacheFDMAP; - certCacheFDMAP = inherit.certCacheFDMAP; - svrCacheSem = inherit.svrCacheSem; - -#if 0 - /* call DuplicateHandle ?? */ - inherit.parentProcessID; - inherit.parentProcessHandle; -#endif - if(!SIDCacheFDMAP) { - SET_ERROR_CODE - goto loser; - } - SIDCacheData = (char *)MapViewOfFile(SIDCacheFDMAP, - FILE_MAP_ALL_ACCESS, /* R/W */ - 0, 0, /* offset */ - sidCacheFileSize); /* size */ - if(!SIDCacheData) { - nss_MD_win32_map_default_error(GetLastError()); + if (strlen(fmString) != inherit.fmStrLen ) { goto loser; } - if(!certCacheFDMAP) { - SET_ERROR_CODE - goto loser; + memset(&my, 0, sizeof my); + my.sharedMemSize = inherit.sharedMemSize; + + /* Create cache */ + my.cacheMemMap = PR_ImportFileMapFromString(fmString); + if(! my.cacheMemMap) { + goto loser; } - certCacheData = (char *) MapViewOfFile(certCacheFDMAP, - FILE_MAP_ALL_ACCESS, /* R/W */ - 0, 0, /* offset */ - certCacheFileSize); /* size */ - if(!certCacheData) { - nss_MD_win32_map_default_error(GetLastError()); - goto loser; + my.sharedMem = PR_MemMap(my.cacheMemMap, 0, my.sharedMemSize); + if (! my.sharedMem) { + goto loser; } + my.sharedCache = (cacheDesc *)my.sharedMem; -#else /* must be unix */ - SIDCacheFD = inherit.SIDCacheFD; - certCacheFD = inherit.certCacheFD; - if (SIDCacheFD < 0 || certCacheFD < 0) { - SET_ERROR_CODE + if (my.sharedCache->sharedMemSize != my.sharedMemSize) { + SET_ERROR_CODE goto loser; } -#endif - if (!cacheLock) { - nss_InitLock(&cacheLock, nssILockCache); - if (!cacheLock) - goto loser; - } + memcpy(cache, my.sharedCache, sizeof *cache); + cache->cacheMemMap = my.cacheMemMap; + cache->sharedMem = my.sharedMem; + cache->sharedCache = my.sharedCache; + + /* Fix pointers in our private copy of cache descriptor to point to + ** spaces in shared memory + */ + ptr = (ptrdiff_t)cache->sharedMem; + *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr; + *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr; + *(ptrdiff_t *)(&cache->certCacheLock) += ptr; + *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr; + *(ptrdiff_t *)(&cache->sidCacheData ) += ptr; + *(ptrdiff_t *)(&cache->certCacheData) += ptr; + *(ptrdiff_t *)(&cache->keyCacheData ) += ptr; + + PORT_Free(decoString); isMultiProcess = PR_TRUE; return SECSuccess; loser: if (decoString) PORT_Free(decoString); -#if _WIN32 - if (SIDCacheFDMAP) { - CloseHandle(SIDCacheFDMAP); - SIDCacheFDMAP = NULL; - } - if (certCacheFDMAP) { - CloseHandle(certCacheFDMAP); - certCacheFDMAP = NULL; - } -#else - if (SIDCacheFD >= 0) { - close(SIDCacheFD); - SIDCacheFD = -1; - } - if (certCacheFD >= 0) { - close(certCacheFD); - certCacheFD = -1; - } -#endif return SECFailure; } +SECStatus +SSL_InheritMPServerSIDCache(const char * envString) +{ + return SSL_InheritMPServerSIDCacheInstance(&globalCache, envString); +} + +#if !defined(WIN32) + +#define SID_LOCK_EXPIRATION_TIMEOUT 30 /* seconds */ + +static void +LockPoller(void * arg) +{ + cacheDesc * cache = (cacheDesc *)arg; + cacheDesc * sharedCache = cache->sharedCache; + sidCacheLock * pLock; + PRIntervalTime timeout; + PRUint32 now; + PRUint32 then; + int locks_polled = 0; + int locks_to_poll = cache->numSIDCacheLocks + 2; + + timeout = PR_SecondsToInterval(SID_LOCK_EXPIRATION_TIMEOUT); + while(!sharedCache->stopPolling) { + PR_Sleep(timeout); + if (sharedCache->stopPolling) + break; + + now = ssl_Time(); + then = now - SID_LOCK_EXPIRATION_TIMEOUT; + for (pLock = cache->sidCacheLocks, locks_polled = 0; + locks_to_poll > locks_polled && !sharedCache->stopPolling; + ++locks_polled, ++pLock ) { + pid_t pid; + + if (pLock->timeStamp < then && + pLock->timeStamp != 0 && + (pid = pLock->pid) != 0) { + + /* maybe we should try the lock? */ + int result = kill(pid, 0); + if (result < 0 && errno == ESRCH) { + SECStatus rv; + /* No process exists by that pid any more. + ** Treat this mutex as abandoned. + */ + pLock->timeStamp = now; + pLock->pid = 0; + rv = sslMutex_Unlock(&pLock->mutex); + if (rv != SECSuccess) { + /* Now what? */ + } + } + } + } /* end of loop over locks */ + } /* end of entire polling loop */ +} + +/* Launch thread to poll cache for expired locks */ +static SECStatus +LaunchLockPoller(cacheDesc *cache) +{ + PRThread * pollerThread; + + pollerThread = + PR_CreateThread(PR_USER_THREAD, LockPoller, cache, PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); + if (!pollerThread) { + return SECFailure; + } + cache->poller = pollerThread; + return SECSuccess; +} +#endif + /************************************************************************ * Code dealing with shared wrapped symmetric wrapping keys below * ************************************************************************/ - +/* If now is zero, it implies that the lock is not held, and must be +** aquired here. +*/ static PRBool -getWrappingKey(PRInt32 symWrapMechIndex, +getSvrWrappingKey(PRInt32 symWrapMechIndex, SSL3KEAType exchKeyType, SSLWrappedSymWrappingKey *wswk, - PRBool grabSharedLock) + cacheDesc * cache, + PRUint32 lockTime) { - PRUint32 offset = sidCacheWrapOffset + - ((exchKeyType * SSL_NUM_WRAP_MECHS + symWrapMechIndex) * - sizeof(SSLWrappedSymWrappingKey)); - PRBool rv = PR_TRUE; -#ifdef XP_UNIX - off_t lrv; - ssize_t rrv; -#endif - - if (grabSharedLock) { - GET_SERVER_CACHE_READ_LOCK(SIDCacheFD, offset, sizeof *wswk); - } - -#ifdef XP_UNIX - lrv = lseek(SIDCacheFD, offset, SEEK_SET); - if (lrv != offset) { - if (lrv == -1) - nss_MD_unix_map_lseek_error(errno); - else - PORT_SetError(PR_IO_ERROR); - IOError(rv, "wrapping-read"); - rv = PR_FALSE; - } else { - rrv = read(SIDCacheFD, wswk, sizeof *wswk); - if (rrv != sizeof *wswk) { - if (rrv == -1) - nss_MD_unix_map_read_error(errno); - else - PORT_SetError(PR_IO_ERROR); - IOError(rv, "wrapping-read"); - rv = PR_FALSE; + PRUint32 ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex; + SSLWrappedSymWrappingKey * pwswk = cache->keyCacheData + ndx; + PRUint32 now = 0; + PRBool rv = PR_FALSE; + + if (!lockTime) { + lockTime = now = LockSidCacheLock(cache->keyCacheLock, now); + if (!lockTime) { + return rv; } } -#else /* XP_WIN32 */ - /* Use memory mapped I/O and just memcpy() the data */ - CopyMemory(wswk, &SIDCacheData[offset], sizeof *wswk); -#endif /* XP_WIN32 */ - if (grabSharedLock) { - RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, offset, sizeof *wswk); + if (pwswk->exchKeyType == exchKeyType && + pwswk->symWrapMechIndex == symWrapMechIndex && + pwswk->wrappedSymKeyLen != 0) { + *wswk = *pwswk; + rv = PR_TRUE; } - if (rv) { - if (wswk->exchKeyType != exchKeyType || - wswk->symWrapMechIndex != symWrapMechIndex || - wswk->wrappedSymKeyLen == 0) { - memset(wswk, 0, sizeof *wswk); - rv = PR_FALSE; - } + if (now) { + UnlockSidCacheLock(cache->keyCacheLock); } return rv; } @@ -1800,17 +1349,16 @@ ssl_GetWrappingKey( PRInt32 symWrapMechIndex, { PRBool rv; - lock_cache(); - PORT_Assert( (unsigned)exchKeyType < kt_kea_size); PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS); if ((unsigned)exchKeyType < kt_kea_size && (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS) { - rv = getWrappingKey(symWrapMechIndex, exchKeyType, wswk, PR_TRUE); + rv = getSvrWrappingKey(symWrapMechIndex, exchKeyType, wswk, + &globalCache, 0); } else { rv = PR_FALSE; } - unlock_cache(); + return rv; } @@ -1820,17 +1368,19 @@ ssl_GetWrappingKey( PRInt32 symWrapMechIndex, * the disk entry, and returns false. * Otherwise, it overwrites the caller's wswk with the value obtained from * the disk, and returns PR_TRUE. - * This is all done while holding the locks/semaphores necessary to make + * This is all done while holding the locks/mutexes necessary to make * the operation atomic. */ PRBool ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk) { - PRBool rv; + cacheDesc * cache = &globalCache; + PRBool rv = PR_FALSE; SSL3KEAType exchKeyType = wswk->exchKeyType; /* type of keys used to wrap SymWrapKey*/ PRInt32 symWrapMechIndex = wswk->symWrapMechIndex; - PRUint32 offset; + PRUint32 ndx; + PRUint32 now = 0; SSLWrappedSymWrappingKey myWswk; PORT_Assert( (unsigned)exchKeyType < kt_kea_size); @@ -1841,57 +1391,26 @@ ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk) if ((unsigned)symWrapMechIndex >= SSL_NUM_WRAP_MECHS) return 0; - offset = sidCacheWrapOffset + - ((exchKeyType * SSL_NUM_WRAP_MECHS + symWrapMechIndex) * - sizeof(SSLWrappedSymWrappingKey)); + ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex; PORT_Memset(&myWswk, 0, sizeof myWswk); /* eliminate UMRs. */ - lock_cache(); - GET_SERVER_CACHE_WRITE_LOCK(SIDCacheFD, offset, sizeof *wswk); - rv = getWrappingKey(wswk->symWrapMechIndex, wswk->exchKeyType, &myWswk, - PR_FALSE); - if (rv) { - /* we found it on disk, copy it out to the caller. */ - PORT_Memcpy(wswk, &myWswk, sizeof *wswk); - } else { - /* Wasn't on disk, and we're still holding the lock, so write it. */ - -#ifdef XP_UNIX - off_t lrv; - ssize_t rrv; - - lrv = lseek(SIDCacheFD, offset, SEEK_SET); - if (lrv != offset) { - if (lrv == -1) - nss_MD_unix_map_lseek_error(errno); - else - PORT_SetError(PR_IO_ERROR); - IOError(rv, "wrapping-read"); - rv = PR_FALSE; + now = LockSidCacheLock(cache->keyCacheLock, now); + if (now) { + rv = getSvrWrappingKey(wswk->symWrapMechIndex, wswk->exchKeyType, + &myWswk, cache, now); + if (rv) { + /* we found it on disk, copy it out to the caller. */ + PORT_Memcpy(wswk, &myWswk, sizeof *wswk); } else { - rrv = write(SIDCacheFD, wswk, sizeof *wswk); - if (rrv != sizeof *wswk) { - if (rrv == -1) - nss_MD_unix_map_read_error(errno); - else - PORT_SetError(PR_IO_ERROR); - IOError(rv, "wrapping-read"); - rv = PR_FALSE; - } + /* Wasn't on disk, and we're still holding the lock, so write it. */ + cache->keyCacheData[ndx] = *wswk; } -#else /* XP_WIN32 */ - /* Use memory mapped I/O and just memcpy() the data */ - CopyMemory(&SIDCacheData[offset], wswk, sizeof *wswk); -#endif /* XP_WIN32 */ + UnlockSidCacheLock(cache->keyCacheLock); } - RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, offset, sizeof *wswk); - unlock_cache(); return rv; } - -#endif /* NADA_VERISON */ -#else +#else /* MAC version or other platform */ #include "seccomon.h" #include "cert.h" @@ -1900,28 +1419,28 @@ ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk) SECStatus SSL_ConfigServerSessionIDCache( int maxCacheEntries, - PRUint32 timeout, + PRUint32 ssl2_timeout, PRUint32 ssl3_timeout, const char * directory) { - PR_ASSERT(!"SSL servers are not supported on the platform. (SSL_ConfigServerSessionIDCache)"); + PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigServerSessionIDCache)"); return SECFailure; } SECStatus SSL_ConfigMPServerSIDCache( int maxCacheEntries, - PRUint32 timeout, + PRUint32 ssl2_timeout, PRUint32 ssl3_timeout, const char * directory) { - PR_ASSERT(!"SSL servers are not supported on the platform. (SSL_ConfigMPServerSIDCache)"); + PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigMPServerSIDCache)"); return SECFailure; } SECStatus SSL_InheritMPServerSIDCache(const char * envString) { - PR_ASSERT(!"SSL servers are not supported on the platform. (SSL_InheritMPServerSIDCache)"); + PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_InheritMPServerSIDCache)"); return SECFailure; } @@ -1931,7 +1450,7 @@ ssl_GetWrappingKey( PRInt32 symWrapMechIndex, SSLWrappedSymWrappingKey *wswk) { PRBool rv = PR_FALSE; - PR_ASSERT(!"SSL servers are not supported on the platform. (ssl_GetWrappingKey)"); + PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_GetWrappingKey)"); return rv; } @@ -1941,14 +1460,14 @@ ssl_GetWrappingKey( PRInt32 symWrapMechIndex, * the disk entry, and returns false. * Otherwise, it overwrites the caller's wswk with the value obtained from * the disk, and returns PR_TRUE. - * This is all done while holding the locks/semaphores necessary to make + * This is all done while holding the locks/mutexes necessary to make * the operation atomic. */ PRBool ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk) { PRBool rv = PR_FALSE; - PR_ASSERT(!"SSL servers are not supported on the platform. (ssl_SetWrappingKey)"); + PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_SetWrappingKey)"); return rv; } |