~ubuntu-branches/ubuntu/lucid/seamonkey/lucid-security

« back to all changes in this revision

Viewing changes to security/nss-fips/lib/ssl/sslsnce.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabien Tassin
  • Date: 2008-07-29 21:29:02 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20080729212902-spm9kpvchp9udwbw
Tags: 1.1.11+nobinonly-0ubuntu1
* New security upstream release: 1.1.11 (LP: #218534)
  Fixes USN-602-1, USN-619-1, USN-623-1 and USN-629-1
* Refresh diverged patch:
  - update debian/patches/80_security_build.patch
* Fix FTBFS with missing -lfontconfig
  - add debian/patches/11_fix_ftbfs_with_fontconfig.patch
  - update debian/patches/series
* Build with default gcc (hardy: 4.2, intrepid: 4.3)
  - update debian/rules
  - update debian/control

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.36.2.2 2006/07/17 22:15:10 alexei.volkov.bugs%sun.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
 * } cacheMemCacheData;
 
71
 */
 
72
#include "nssrenam.h"
 
73
#include "seccomon.h"
 
74
 
 
75
#if (defined(XP_UNIX) || defined(XP_WIN32) || defined (XP_OS2) || defined(XP_BEOS)) && !defined(_WIN32_WCE)
 
76
 
 
77
#include "cert.h"
 
78
#include "ssl.h"
 
79
#include "sslimpl.h"
 
80
#include "sslproto.h"
 
81
#include "pk11func.h"
 
82
#include "base64.h"
 
83
 
 
84
#include <stdio.h>
 
85
 
 
86
#if defined(XP_UNIX) || defined(XP_BEOS)
 
87
 
 
88
#include <syslog.h>
 
89
#include <fcntl.h>
 
90
#include <unistd.h>
 
91
#include <errno.h>
 
92
#include <signal.h>
 
93
#include "unix_err.h"
 
94
 
 
95
#else
 
96
 
 
97
#ifdef XP_WIN32
 
98
#include <wtypes.h>
 
99
#include "win32err.h"
 
100
#endif
 
101
 
 
102
#endif 
 
103
#include <sys/types.h>
 
104
 
 
105
#define SET_ERROR_CODE /* reminder */
 
106
 
 
107
#include "nspr.h"
 
108
#include "nsslocks.h"
 
109
#include "sslmutex.h"
 
110
 
 
111
#ifdef XP_OS2_VACPP
 
112
#pragma pack(1)
 
113
#endif
 
114
 
 
115
/*
 
116
** Format of a cache entry in the shared memory.
 
117
*/ 
 
118
struct sidCacheEntryStr {
 
119
/* 16 */    PRIPv6Addr  addr;   /* client's IP address */
 
120
/*  4 */    PRUint32    creationTime;
 
121
/*  4 */    PRUint32    lastAccessTime; 
 
122
/*  4 */    PRUint32    expirationTime;
 
123
/*  2 */    PRUint16    version;
 
124
/*  1 */    PRUint8     valid;
 
125
/*  1 */    PRUint8     sessionIDLength;
 
126
/* 32 */    PRUint8     sessionID[SSL3_SESSIONID_BYTES];
 
127
/*  2 */    PRUint16    authAlgorithm;
 
128
/*  2 */    PRUint16    authKeyBits;
 
129
/*  2 */    PRUint16    keaType;
 
130
/*  2 */    PRUint16    keaKeyBits;
 
131
/* 72  - common header total */
 
132
 
 
133
    union {
 
134
        struct {
 
135
/* 64 */    PRUint8     masterKey[SSL_MAX_MASTER_KEY_BYTES];
 
136
/* 32 */    PRUint8     cipherArg[SSL_MAX_CYPHER_ARG_BYTES];
 
137
 
 
138
/*  1 */    PRUint8     cipherType;
 
139
/*  1 */    PRUint8     masterKeyLen;
 
140
/*  1 */    PRUint8     keyBits;
 
141
/*  1 */    PRUint8     secretKeyBits;
 
142
/*  1 */    PRUint8     cipherArgLen;
 
143
/*101 */} ssl2;
 
144
 
 
145
        struct {
 
146
/*  2 */    ssl3CipherSuite  cipherSuite;
 
147
/*  2 */    PRUint16    compression;    /* SSL3CompressionMethod */
 
148
 
 
149
/*100 */    ssl3SidKeys keys;   /* keys and ivs, wrapped as needed. */
 
150
 
 
151
/*  4 */    PRUint32    masterWrapMech; 
 
152
/*  4 */    SSL3KEAType exchKeyType;
 
153
/*  4 */    PRInt32     certIndex;
 
154
/*116 */} ssl3;
 
155
#if defined(LINUX)                      /* XXX Why only on Linux ? */
 
156
        struct {
 
157
            PRUint8     filler[144];    /* XXX why this number ? */
 
158
        } forceSize;
 
159
#endif
 
160
    } u;
 
161
};
 
162
typedef struct sidCacheEntryStr sidCacheEntry;
 
163
 
 
164
/* The length of this struct is supposed to be a power of 2, e.g. 4KB */
 
165
struct certCacheEntryStr {
 
166
    PRUint16    certLength;                             /*    2 */
 
167
    PRUint16    sessionIDLength;                        /*    2 */
 
168
    PRUint8     sessionID[SSL3_SESSIONID_BYTES];        /*   32 */
 
169
    PRUint8     cert[SSL_MAX_CACHED_CERT_LEN];          /* 4060 */
 
170
};                                              /* total   4096 */
 
171
typedef struct certCacheEntryStr certCacheEntry;
 
172
 
 
173
struct sidCacheLockStr {
 
174
    PRUint32    timeStamp;
 
175
    sslMutex    mutex;
 
176
    sslPID      pid;
 
177
};
 
178
typedef struct sidCacheLockStr sidCacheLock;
 
179
 
 
180
struct sidCacheSetStr {
 
181
    PRIntn      next;
 
182
};
 
183
typedef struct sidCacheSetStr sidCacheSet;
 
184
 
 
185
struct cacheDescStr {
 
186
 
 
187
    PRUint32            cacheMemSize;
 
188
 
 
189
    PRUint32            numSIDCacheLocks;
 
190
    PRUint32            numSIDCacheSets;
 
191
    PRUint32            numSIDCacheSetsPerLock;
 
192
 
 
193
    PRUint32            numSIDCacheEntries; 
 
194
    PRUint32            sidCacheSize;
 
195
 
 
196
    PRUint32            numCertCacheEntries;
 
197
    PRUint32            certCacheSize;
 
198
 
 
199
    PRUint32            numKeyCacheEntries;
 
200
    PRUint32            keyCacheSize;
 
201
 
 
202
    PRUint32            ssl2Timeout;
 
203
    PRUint32            ssl3Timeout;
 
204
 
 
205
    PRUint32            numSIDCacheLocksInitialized;
 
206
 
 
207
    /* These values are volatile, and are accessed through sharedCache-> */
 
208
    PRUint32            nextCertCacheEntry;     /* certCacheLock protects */
 
209
    PRBool              stopPolling;
 
210
    PRBool              everInherited;
 
211
 
 
212
    /* The private copies of these values are pointers into shared mem */
 
213
    /* The copies of these values in shared memory are merely offsets */
 
214
    sidCacheLock    *          sidCacheLocks;
 
215
    sidCacheLock    *          keyCacheLock;
 
216
    sidCacheLock    *          certCacheLock;
 
217
    sidCacheSet     *          sidCacheSets;
 
218
    sidCacheEntry   *          sidCacheData;
 
219
    certCacheEntry  *          certCacheData;
 
220
    SSLWrappedSymWrappingKey * keyCacheData;
 
221
 
 
222
    /* Only the private copies of these pointers are valid */
 
223
    char *                     cacheMem;
 
224
    struct cacheDescStr *      sharedCache;  /* shared copy of this struct */
 
225
    PRFileMap *                cacheMemMap;
 
226
    PRThread  *                poller;
 
227
    PRBool                     shared;
 
228
};
 
229
typedef struct cacheDescStr cacheDesc;
 
230
 
 
231
static cacheDesc globalCache;
 
232
 
 
233
static const char envVarName[] = { SSL_ENV_VAR_NAME };
 
234
 
 
235
static PRBool isMultiProcess  = PR_FALSE;
 
236
 
 
237
 
 
238
#define DEF_SID_CACHE_ENTRIES  10000
 
239
#define DEF_CERT_CACHE_ENTRIES 250
 
240
#define MIN_CERT_CACHE_ENTRIES 125 /* the effective size in old releases. */
 
241
#define DEF_KEY_CACHE_ENTRIES  250
 
242
 
 
243
#define SID_CACHE_ENTRIES_PER_SET  128
 
244
#define SID_ALIGNMENT          16
 
245
 
 
246
#define DEF_SSL2_TIMEOUT        100   /* seconds */
 
247
#define MAX_SSL2_TIMEOUT        100   /* seconds */
 
248
#define MIN_SSL2_TIMEOUT          5   /* seconds */
 
249
 
 
250
#define DEF_SSL3_TIMEOUT      86400L  /* 24 hours */
 
251
#define MAX_SSL3_TIMEOUT      86400L  /* 24 hours */
 
252
#define MIN_SSL3_TIMEOUT          5   /* seconds  */
 
253
 
 
254
#if defined(AIX) || defined(LINUX) || defined(VMS)
 
255
#define MAX_SID_CACHE_LOCKS 8   /* two FDs per lock */
 
256
#elif defined(OSF1)
 
257
#define MAX_SID_CACHE_LOCKS 16  /* one FD per lock */
 
258
#else
 
259
#define MAX_SID_CACHE_LOCKS 256
 
260
#endif
 
261
 
 
262
#define SID_HOWMANY(val, size) (((val) + ((size) - 1)) / (size))
 
263
#define SID_ROUNDUP(val, size) ((size) * SID_HOWMANY((val), (size)))
 
264
 
 
265
 
 
266
static sslPID myPid;
 
267
static PRUint32  ssl_max_sid_cache_locks = MAX_SID_CACHE_LOCKS;
 
268
 
 
269
/* forward static function declarations */
 
270
static PRUint32 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, 
 
271
                         unsigned nl);
 
272
static SECStatus LaunchLockPoller(cacheDesc *cache);
 
273
 
 
274
 
 
275
struct inheritanceStr {
 
276
    PRUint32 cacheMemSize;
 
277
    PRUint32 fmStrLen;
 
278
};
 
279
 
 
280
typedef struct inheritanceStr inheritance;
 
281
 
 
282
#if defined(_WIN32) || defined(XP_OS2)
 
283
 
 
284
#define DEFAULT_CACHE_DIRECTORY "\\temp"
 
285
 
 
286
#endif /* _win32 */
 
287
 
 
288
#if defined(XP_UNIX) || defined(XP_BEOS)
 
289
 
 
290
#define DEFAULT_CACHE_DIRECTORY "/tmp"
 
291
 
 
292
#endif /* XP_UNIX || XP_BEOS */
 
293
 
 
294
 
 
295
/************************************************************************/
 
296
 
 
297
static PRUint32
 
298
LockSidCacheLock(sidCacheLock *lock, PRUint32 now)
 
299
{
 
300
    SECStatus      rv      = sslMutex_Lock(&lock->mutex);
 
301
    if (rv != SECSuccess)
 
302
        return 0;
 
303
    if (!now)
 
304
        now  = ssl_Time();
 
305
    lock->timeStamp = now;
 
306
    lock->pid       = myPid;
 
307
    return now;
 
308
}
 
309
 
 
310
static SECStatus
 
311
UnlockSidCacheLock(sidCacheLock *lock)
 
312
{
 
313
    SECStatus      rv;
 
314
 
 
315
    lock->pid = 0;
 
316
    rv        = sslMutex_Unlock(&lock->mutex);
 
317
    return rv;
 
318
}
 
319
 
 
320
/* returns the value of ssl_Time on success, zero on failure. */
 
321
static PRUint32
 
322
LockSet(cacheDesc *cache, PRUint32 set, PRUint32 now)
 
323
{
 
324
    PRUint32       lockNum = set % cache->numSIDCacheLocks;
 
325
    sidCacheLock * lock    = cache->sidCacheLocks + lockNum;
 
326
 
 
327
    return LockSidCacheLock(lock, now);
 
328
}
 
329
 
 
330
static SECStatus
 
331
UnlockSet(cacheDesc *cache, PRUint32 set)
 
332
{
 
333
    PRUint32       lockNum = set % cache->numSIDCacheLocks;
 
334
    sidCacheLock * lock    = cache->sidCacheLocks + lockNum;
 
335
 
 
336
    return UnlockSidCacheLock(lock);
 
337
}
 
338
 
 
339
/************************************************************************/
 
340
 
 
341
 
 
342
/* Put a certificate in the cache.  Update the cert index in the sce.
 
343
*/
 
344
static PRUint32
 
345
CacheCert(cacheDesc * cache, CERTCertificate *cert, sidCacheEntry *sce)
 
346
{
 
347
    PRUint32        now;
 
348
    certCacheEntry  cce;
 
349
 
 
350
    if ((cert->derCert.len > SSL_MAX_CACHED_CERT_LEN) ||
 
351
        (cert->derCert.len <= 0) ||
 
352
        (cert->derCert.data == NULL)) {
 
353
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
 
354
        return 0;
 
355
    }
 
356
 
 
357
    cce.sessionIDLength = sce->sessionIDLength;
 
358
    PORT_Memcpy(cce.sessionID, sce->sessionID, cce.sessionIDLength);
 
359
 
 
360
    cce.certLength = cert->derCert.len;
 
361
    PORT_Memcpy(cce.cert, cert->derCert.data, cce.certLength);
 
362
 
 
363
    /* get lock on cert cache */
 
364
    now = LockSidCacheLock(cache->certCacheLock, 0);
 
365
    if (now) {
 
366
 
 
367
        /* Find where to place the next cert cache entry. */
 
368
        cacheDesc * sharedCache = cache->sharedCache;
 
369
        PRUint32    ndx         = sharedCache->nextCertCacheEntry;
 
370
 
 
371
        /* write the entry */
 
372
        cache->certCacheData[ndx] = cce;
 
373
 
 
374
        /* remember where we put it. */
 
375
        sce->u.ssl3.certIndex = ndx;
 
376
 
 
377
        /* update the "next" cache entry index */
 
378
        sharedCache->nextCertCacheEntry = 
 
379
                                        (ndx + 1) % cache->numCertCacheEntries;
 
380
 
 
381
        UnlockSidCacheLock(cache->certCacheLock);
 
382
    }
 
383
    return now;
 
384
 
 
385
}
 
386
 
 
387
/*
 
388
** Convert local SID to shared memory one
 
389
*/
 
390
static void 
 
391
ConvertFromSID(sidCacheEntry *to, sslSessionID *from)
 
392
{
 
393
    to->valid   = 1;
 
394
    to->version = from->version;
 
395
    to->addr    = from->addr;
 
396
    to->creationTime    = from->creationTime;
 
397
    to->lastAccessTime  = from->lastAccessTime;
 
398
    to->expirationTime  = from->expirationTime;
 
399
    to->authAlgorithm   = from->authAlgorithm;
 
400
    to->authKeyBits     = from->authKeyBits;
 
401
    to->keaType         = from->keaType;
 
402
    to->keaKeyBits      = from->keaKeyBits;
 
403
 
 
404
    if (from->version < SSL_LIBRARY_VERSION_3_0) {
 
405
        if ((from->u.ssl2.masterKey.len > SSL_MAX_MASTER_KEY_BYTES) ||
 
406
            (from->u.ssl2.cipherArg.len > SSL_MAX_CYPHER_ARG_BYTES)) {
 
407
            SSL_DBG(("%d: SSL: masterKeyLen=%d cipherArgLen=%d",
 
408
                     myPid, from->u.ssl2.masterKey.len,
 
409
                     from->u.ssl2.cipherArg.len));
 
410
            to->valid = 0;
 
411
            return;
 
412
        }
 
413
 
 
414
        to->u.ssl2.cipherType    = from->u.ssl2.cipherType;
 
415
        to->u.ssl2.masterKeyLen  = from->u.ssl2.masterKey.len;
 
416
        to->u.ssl2.cipherArgLen  = from->u.ssl2.cipherArg.len;
 
417
        to->u.ssl2.keyBits       = from->u.ssl2.keyBits;
 
418
        to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits;
 
419
        to->sessionIDLength      = SSL2_SESSIONID_BYTES;
 
420
        PORT_Memcpy(to->sessionID, from->u.ssl2.sessionID, SSL2_SESSIONID_BYTES);
 
421
        PORT_Memcpy(to->u.ssl2.masterKey, from->u.ssl2.masterKey.data,
 
422
                  from->u.ssl2.masterKey.len);
 
423
        PORT_Memcpy(to->u.ssl2.cipherArg, from->u.ssl2.cipherArg.data,
 
424
                  from->u.ssl2.cipherArg.len);
 
425
#ifdef DEBUG
 
426
        PORT_Memset(to->u.ssl2.masterKey+from->u.ssl2.masterKey.len, 0,
 
427
                  sizeof(to->u.ssl2.masterKey) - from->u.ssl2.masterKey.len);
 
428
        PORT_Memset(to->u.ssl2.cipherArg+from->u.ssl2.cipherArg.len, 0,
 
429
                  sizeof(to->u.ssl2.cipherArg) - from->u.ssl2.cipherArg.len);
 
430
#endif
 
431
        SSL_TRC(8, ("%d: SSL: ConvertSID: masterKeyLen=%d cipherArgLen=%d "
 
432
                    "time=%d addr=0x%08x%08x%08x%08x cipherType=%d", myPid,
 
433
                    to->u.ssl2.masterKeyLen, to->u.ssl2.cipherArgLen,
 
434
                    to->creationTime, to->addr.pr_s6_addr32[0],
 
435
                    to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2],
 
436
                    to->addr.pr_s6_addr32[3], to->u.ssl2.cipherType));
 
437
    } else {
 
438
        /* This is an SSL v3 session */
 
439
 
 
440
        to->u.ssl3.cipherSuite      = from->u.ssl3.cipherSuite;
 
441
        to->u.ssl3.compression      = (uint16)from->u.ssl3.compression;
 
442
        to->u.ssl3.keys             = from->u.ssl3.keys;
 
443
        to->u.ssl3.masterWrapMech   = from->u.ssl3.masterWrapMech;
 
444
        to->u.ssl3.exchKeyType      = from->u.ssl3.exchKeyType;
 
445
        to->sessionIDLength         = from->u.ssl3.sessionIDLength;
 
446
        to->u.ssl3.certIndex        = -1;
 
447
 
 
448
        PORT_Memcpy(to->sessionID, from->u.ssl3.sessionID,
 
449
                    to->sessionIDLength);
 
450
 
 
451
        SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x "
 
452
                    "cipherSuite=%d",
 
453
                    myPid, to->creationTime, to->addr.pr_s6_addr32[0],
 
454
                    to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2],
 
455
                    to->addr.pr_s6_addr32[3], to->u.ssl3.cipherSuite));
 
456
    }
 
457
}
 
458
 
 
459
/*
 
460
** Convert shared memory cache-entry to local memory based one
 
461
** This is only called from ServerSessionIDLookup().
 
462
** Caller must hold cache lock when calling this.
 
463
*/
 
464
static sslSessionID *
 
465
ConvertToSID(sidCacheEntry *from, certCacheEntry *pcce, 
 
466
             CERTCertDBHandle * dbHandle)
 
467
{
 
468
    sslSessionID *to;
 
469
    uint16 version = from->version;
 
470
 
 
471
    to = (sslSessionID*) PORT_ZAlloc(sizeof(sslSessionID));
 
472
    if (!to) {
 
473
        return 0;
 
474
    }
 
475
 
 
476
    if (version < SSL_LIBRARY_VERSION_3_0) {
 
477
        /* This is an SSL v2 session */
 
478
        to->u.ssl2.masterKey.data =
 
479
            (unsigned char*) PORT_Alloc(from->u.ssl2.masterKeyLen);
 
480
        if (!to->u.ssl2.masterKey.data) {
 
481
            goto loser;
 
482
        }
 
483
        if (from->u.ssl2.cipherArgLen) {
 
484
            to->u.ssl2.cipherArg.data = 
 
485
                (unsigned char*)PORT_Alloc(from->u.ssl2.cipherArgLen);
 
486
            if (!to->u.ssl2.cipherArg.data) {
 
487
                goto loser;
 
488
            }
 
489
            PORT_Memcpy(to->u.ssl2.cipherArg.data, from->u.ssl2.cipherArg,
 
490
                        from->u.ssl2.cipherArgLen);
 
491
        }
 
492
 
 
493
        to->u.ssl2.cipherType    = from->u.ssl2.cipherType;
 
494
        to->u.ssl2.masterKey.len = from->u.ssl2.masterKeyLen;
 
495
        to->u.ssl2.cipherArg.len = from->u.ssl2.cipherArgLen;
 
496
        to->u.ssl2.keyBits       = from->u.ssl2.keyBits;
 
497
        to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits;
 
498
/*      to->sessionIDLength      = SSL2_SESSIONID_BYTES; */
 
499
        PORT_Memcpy(to->u.ssl2.sessionID, from->sessionID, SSL2_SESSIONID_BYTES);
 
500
        PORT_Memcpy(to->u.ssl2.masterKey.data, from->u.ssl2.masterKey,
 
501
                    from->u.ssl2.masterKeyLen);
 
502
 
 
503
        SSL_TRC(8, ("%d: SSL: ConvertToSID: masterKeyLen=%d cipherArgLen=%d "
 
504
                    "time=%d addr=0x%08x%08x%08x%08x cipherType=%d",
 
505
                    myPid, to->u.ssl2.masterKey.len,
 
506
                    to->u.ssl2.cipherArg.len, to->creationTime,
 
507
                    to->addr.pr_s6_addr32[0], to->addr.pr_s6_addr32[1],
 
508
                    to->addr.pr_s6_addr32[2], to->addr.pr_s6_addr32[3],
 
509
                    to->u.ssl2.cipherType));
 
510
    } else {
 
511
        /* This is an SSL v3 session */
 
512
 
 
513
        to->u.ssl3.sessionIDLength  = from->sessionIDLength;
 
514
        to->u.ssl3.cipherSuite      = from->u.ssl3.cipherSuite;
 
515
        to->u.ssl3.compression      = (SSL3CompressionMethod)from->u.ssl3.compression;
 
516
        to->u.ssl3.keys             = from->u.ssl3.keys;
 
517
        to->u.ssl3.masterWrapMech   = from->u.ssl3.masterWrapMech;
 
518
        to->u.ssl3.exchKeyType      = from->u.ssl3.exchKeyType;
 
519
 
 
520
        PORT_Memcpy(to->u.ssl3.sessionID, from->sessionID, from->sessionIDLength);
 
521
 
 
522
        /* the portions of the SID that are only restored on the client
 
523
         * are set to invalid values on the server.
 
524
         */
 
525
        to->u.ssl3.clientWriteKey   = NULL;
 
526
        to->u.ssl3.serverWriteKey   = NULL;
 
527
 
 
528
        to->urlSvrName              = NULL;
 
529
 
 
530
        to->u.ssl3.masterModuleID   = (SECMODModuleID)-1; /* invalid value */
 
531
        to->u.ssl3.masterSlotID     = (CK_SLOT_ID)-1;     /* invalid value */
 
532
        to->u.ssl3.masterWrapIndex  = 0;
 
533
        to->u.ssl3.masterWrapSeries = 0;
 
534
        to->u.ssl3.masterValid      = PR_FALSE;
 
535
 
 
536
        to->u.ssl3.clAuthModuleID   = (SECMODModuleID)-1; /* invalid value */
 
537
        to->u.ssl3.clAuthSlotID     = (CK_SLOT_ID)-1;     /* invalid value */
 
538
        to->u.ssl3.clAuthSeries     = 0;
 
539
        to->u.ssl3.clAuthValid      = PR_FALSE;
 
540
 
 
541
        if (from->u.ssl3.certIndex != -1 && pcce) {
 
542
            SECItem          derCert;
 
543
 
 
544
            derCert.len  = pcce->certLength;
 
545
            derCert.data = pcce->cert;
 
546
 
 
547
            to->peerCert = CERT_NewTempCertificate(dbHandle, &derCert, NULL,
 
548
                                                   PR_FALSE, PR_TRUE);
 
549
            if (to->peerCert == NULL)
 
550
                goto loser;
 
551
        }
 
552
    }
 
553
 
 
554
    to->version         = from->version;
 
555
    to->creationTime    = from->creationTime;
 
556
    to->lastAccessTime  = from->lastAccessTime;
 
557
    to->expirationTime  = from->expirationTime;
 
558
    to->cached          = in_server_cache;
 
559
    to->addr            = from->addr;
 
560
    to->references      = 1;
 
561
    to->authAlgorithm   = from->authAlgorithm;
 
562
    to->authKeyBits     = from->authKeyBits;
 
563
    to->keaType         = from->keaType;
 
564
    to->keaKeyBits      = from->keaKeyBits;
 
565
    
 
566
    return to;
 
567
 
 
568
  loser:
 
569
    if (to) {
 
570
        if (version < SSL_LIBRARY_VERSION_3_0) {
 
571
            if (to->u.ssl2.masterKey.data)
 
572
                PORT_Free(to->u.ssl2.masterKey.data);
 
573
            if (to->u.ssl2.cipherArg.data)
 
574
                PORT_Free(to->u.ssl2.cipherArg.data);
 
575
        }
 
576
        PORT_Free(to);
 
577
    }
 
578
    return NULL;
 
579
}
 
580
 
 
581
 
 
582
 
 
583
/*
 
584
** Perform some mumbo jumbo on the ip-address and the session-id value to
 
585
** compute a hash value.
 
586
*/
 
587
static PRUint32 
 
588
SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, unsigned nl)
 
589
{
 
590
    PRUint32 rv;
 
591
    PRUint32 x[8];
 
592
 
 
593
    memset(x, 0, sizeof x);
 
594
    if (nl > sizeof x)
 
595
        nl = sizeof x;
 
596
    memcpy(x, s, nl);
 
597
 
 
598
    rv = (addr->pr_s6_addr32[0] ^ addr->pr_s6_addr32[1] ^
 
599
          addr->pr_s6_addr32[2] ^ addr->pr_s6_addr32[3] ^
 
600
          x[0] ^ x[1] ^ x[2] ^ x[3] ^ x[4] ^ x[5] ^ x[6] ^ x[7])
 
601
          % cache->numSIDCacheSets;
 
602
    return rv;
 
603
}
 
604
 
 
605
 
 
606
 
 
607
/*
 
608
** Look something up in the cache. This will invalidate old entries
 
609
** in the process. Caller has locked the cache set!
 
610
** Returns PR_TRUE if found a valid match.  PR_FALSE otherwise.
 
611
*/
 
612
static sidCacheEntry *
 
613
FindSID(cacheDesc *cache, PRUint32 setNum, PRUint32 now,
 
614
        const PRIPv6Addr *addr, unsigned char *sessionID,
 
615
        unsigned sessionIDLength)
 
616
{
 
617
    PRUint32      ndx   = cache->sidCacheSets[setNum].next;
 
618
    int           i;
 
619
 
 
620
    sidCacheEntry * set = cache->sidCacheData + 
 
621
                         (setNum * SID_CACHE_ENTRIES_PER_SET);
 
622
 
 
623
    for (i = SID_CACHE_ENTRIES_PER_SET; i > 0; --i) {
 
624
        sidCacheEntry * sce;
 
625
 
 
626
        ndx  = (ndx - 1) % SID_CACHE_ENTRIES_PER_SET;
 
627
        sce = set + ndx;
 
628
 
 
629
        if (!sce->valid)
 
630
            continue;
 
631
 
 
632
        if (now > sce->expirationTime) {
 
633
            /* SessionID has timed out. Invalidate the entry. */
 
634
            SSL_TRC(7, ("%d: timed out sid entry addr=%08x%08x%08x%08x now=%x "
 
635
                        "time+=%x",
 
636
                        myPid, sce->addr.pr_s6_addr32[0],
 
637
                        sce->addr.pr_s6_addr32[1], sce->addr.pr_s6_addr32[2],
 
638
                        sce->addr.pr_s6_addr32[3], now,
 
639
                        sce->expirationTime ));
 
640
            sce->valid = 0;
 
641
            continue;
 
642
        }
 
643
 
 
644
        /*
 
645
        ** Next, examine specific session-id/addr data to see if the cache
 
646
        ** entry matches our addr+session-id value
 
647
        */
 
648
        if (sessionIDLength == sce->sessionIDLength      &&
 
649
            !memcmp(&sce->addr, addr, sizeof(PRIPv6Addr)) &&
 
650
            !memcmp(sce->sessionID, sessionID, sessionIDLength)) {
 
651
            /* Found it */
 
652
            return sce;
 
653
        }
 
654
    }
 
655
 
 
656
    PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND);
 
657
    return NULL;
 
658
}
 
659
 
 
660
/************************************************************************/
 
661
 
 
662
/* This is the primary function for finding entries in the server's sid cache.
 
663
 * Although it is static, this function is called via the global function 
 
664
 * pointer ssl_sid_lookup.
 
665
 */
 
666
static sslSessionID *
 
667
ServerSessionIDLookup(const PRIPv6Addr *addr,
 
668
                        unsigned char *sessionID,
 
669
                        unsigned int   sessionIDLength,
 
670
                        CERTCertDBHandle * dbHandle)
 
671
{
 
672
    sslSessionID *  sid      = 0;
 
673
    sidCacheEntry * psce;
 
674
    certCacheEntry *pcce     = 0;
 
675
    cacheDesc *     cache    = &globalCache;
 
676
    PRUint32        now;
 
677
    PRUint32        set;
 
678
    PRInt32         cndx;
 
679
    sidCacheEntry   sce;
 
680
    certCacheEntry  cce;
 
681
 
 
682
    set = SIDindex(cache, addr, sessionID, sessionIDLength);
 
683
    now = LockSet(cache, set, 0);
 
684
    if (!now)
 
685
        return NULL;
 
686
 
 
687
    psce = FindSID(cache, set, now, addr, sessionID, sessionIDLength);
 
688
    if (psce) {
 
689
        if (psce->version >= SSL_LIBRARY_VERSION_3_0 && 
 
690
            (cndx = psce->u.ssl3.certIndex) != -1) {
 
691
 
 
692
            PRUint32 gotLock = LockSidCacheLock(cache->certCacheLock, now);
 
693
            if (gotLock) {
 
694
                pcce = &cache->certCacheData[cndx];
 
695
 
 
696
                /* See if the cert's session ID matches the sce cache. */
 
697
                if ((pcce->sessionIDLength == psce->sessionIDLength) &&
 
698
                    !PORT_Memcmp(pcce->sessionID, psce->sessionID, 
 
699
                                 pcce->sessionIDLength)) {
 
700
                    cce = *pcce;
 
701
                } else {
 
702
                    /* The cert doesen't match the SID cache entry, 
 
703
                    ** so invalidate the SID cache entry. 
 
704
                    */
 
705
                    psce->valid = 0;
 
706
                    psce = 0;
 
707
                    pcce = 0;
 
708
                }
 
709
                UnlockSidCacheLock(cache->certCacheLock);
 
710
            } else {
 
711
                /* what the ??.  Didn't get the cert cache lock.
 
712
                ** Don't invalidate the SID cache entry, but don't find it.
 
713
                */
 
714
                PORT_Assert(!("Didn't get cert Cache Lock!"));
 
715
                psce = 0;
 
716
                pcce = 0;
 
717
            }
 
718
        }
 
719
        if (psce) {
 
720
            psce->lastAccessTime = now;
 
721
            sce = *psce;        /* grab a copy while holding the lock */
 
722
        }
 
723
    }
 
724
    UnlockSet(cache, set);
 
725
    if (psce) {
 
726
        /* sce conains a copy of the cache entry.
 
727
        ** Convert shared memory format to local format 
 
728
        */
 
729
        sid = ConvertToSID(&sce, pcce ? &cce : 0, dbHandle);
 
730
    }
 
731
    return sid;
 
732
}
 
733
 
 
734
/*
 
735
** Place a sid into the cache, if it isn't already there. 
 
736
*/
 
737
static void 
 
738
ServerSessionIDCache(sslSessionID *sid)
 
739
{
 
740
    sidCacheEntry sce;
 
741
    PRUint32      now     = 0;
 
742
    uint16        version = sid->version;
 
743
    cacheDesc *   cache   = &globalCache;
 
744
 
 
745
    if ((version >= SSL_LIBRARY_VERSION_3_0) &&
 
746
        (sid->u.ssl3.sessionIDLength == 0)) {
 
747
        return;
 
748
    }
 
749
 
 
750
    if (sid->cached == never_cached || sid->cached == invalid_cache) {
 
751
        PRUint32 set;
 
752
 
 
753
        PORT_Assert(sid->creationTime != 0);
 
754
        if (!sid->creationTime)
 
755
            sid->lastAccessTime = sid->creationTime = ssl_Time();
 
756
        if (version < SSL_LIBRARY_VERSION_3_0) {
 
757
            /* override caller's expiration time, which uses client timeout
 
758
             * duration, not server timeout duration.
 
759
             */
 
760
            sid->expirationTime = sid->creationTime + cache->ssl2Timeout;
 
761
            SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
 
762
                        "cipher=%d", myPid, sid->cached,
 
763
                        sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
 
764
                        sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
 
765
                        sid->creationTime, sid->u.ssl2.cipherType));
 
766
            PRINT_BUF(8, (0, "sessionID:", sid->u.ssl2.sessionID,
 
767
                          SSL2_SESSIONID_BYTES));
 
768
            PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data,
 
769
                          sid->u.ssl2.masterKey.len));
 
770
            PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data,
 
771
                          sid->u.ssl2.cipherArg.len));
 
772
 
 
773
        } else {
 
774
            /* override caller's expiration time, which uses client timeout
 
775
             * duration, not server timeout duration.
 
776
             */
 
777
            sid->expirationTime = sid->creationTime + cache->ssl3Timeout;
 
778
            SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
 
779
                        "cipherSuite=%d", myPid, sid->cached,
 
780
                        sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
 
781
                        sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
 
782
                        sid->creationTime, sid->u.ssl3.cipherSuite));
 
783
            PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID,
 
784
                          sid->u.ssl3.sessionIDLength));
 
785
        }
 
786
 
 
787
        ConvertFromSID(&sce, sid);
 
788
 
 
789
        if ((version >= SSL_LIBRARY_VERSION_3_0) && 
 
790
            (sid->peerCert != NULL)) {
 
791
            now = CacheCert(cache, sid->peerCert, &sce);
 
792
        }
 
793
 
 
794
        set = SIDindex(cache, &sce.addr, sce.sessionID, sce.sessionIDLength);
 
795
        now = LockSet(cache, set, now);
 
796
        if (now) {
 
797
            PRUint32  next = cache->sidCacheSets[set].next;
 
798
            PRUint32  ndx  = set * SID_CACHE_ENTRIES_PER_SET + next;
 
799
 
 
800
            /* Write out new cache entry */
 
801
            cache->sidCacheData[ndx] = sce;
 
802
 
 
803
            cache->sidCacheSets[set].next = 
 
804
                                        (next + 1) % SID_CACHE_ENTRIES_PER_SET;
 
805
 
 
806
            UnlockSet(cache, set);
 
807
            sid->cached = in_server_cache;
 
808
        }
 
809
    }
 
810
}
 
811
 
 
812
/*
 
813
** Although this is static, it is called from ssl via global function pointer
 
814
**      ssl_sid_uncache.  This invalidates the referenced cache entry.
 
815
*/
 
816
static void 
 
817
ServerSessionIDUncache(sslSessionID *sid)
 
818
{
 
819
    cacheDesc *    cache   = &globalCache;
 
820
    PRUint8 *      sessionID;
 
821
    unsigned int   sessionIDLength;
 
822
    PRErrorCode    err;
 
823
    PRUint32       set;
 
824
    PRUint32       now;
 
825
    sidCacheEntry *psce;
 
826
 
 
827
    if (sid == NULL) 
 
828
        return;
 
829
    
 
830
    /* Uncaching a SID should never change the error code. 
 
831
    ** So save it here and restore it before exiting.
 
832
    */
 
833
    err = PR_GetError();
 
834
 
 
835
    if (sid->version < SSL_LIBRARY_VERSION_3_0) {
 
836
        sessionID       = sid->u.ssl2.sessionID;
 
837
        sessionIDLength = SSL2_SESSIONID_BYTES;
 
838
        SSL_TRC(8, ("%d: SSL: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
 
839
                    "cipher=%d", myPid, sid->cached,
 
840
                    sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
 
841
                    sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
 
842
                    sid->creationTime, sid->u.ssl2.cipherType));
 
843
        PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength));
 
844
        PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data,
 
845
                      sid->u.ssl2.masterKey.len));
 
846
        PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data,
 
847
                      sid->u.ssl2.cipherArg.len));
 
848
    } else {
 
849
        sessionID       = sid->u.ssl3.sessionID;
 
850
        sessionIDLength = sid->u.ssl3.sessionIDLength;
 
851
        SSL_TRC(8, ("%d: SSL3: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
 
852
                    "cipherSuite=%d", myPid, sid->cached,
 
853
                    sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
 
854
                    sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
 
855
                    sid->creationTime, sid->u.ssl3.cipherSuite));
 
856
        PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength));
 
857
    }
 
858
    set = SIDindex(cache, &sid->addr, sessionID, sessionIDLength);
 
859
    now = LockSet(cache, set, 0);
 
860
    if (now) {
 
861
        psce = FindSID(cache, set, now, &sid->addr, sessionID, sessionIDLength);
 
862
        if (psce) {
 
863
            psce->valid = 0;
 
864
        }
 
865
        UnlockSet(cache, set);
 
866
    }
 
867
    sid->cached = invalid_cache;
 
868
    PORT_SetError(err);
 
869
}
 
870
 
 
871
#ifdef XP_OS2
 
872
 
 
873
#define INCL_DOSPROCESS
 
874
#include <os2.h>
 
875
 
 
876
long gettid(void)
 
877
{
 
878
    PTIB ptib;
 
879
    PPIB ppib;
 
880
    DosGetInfoBlocks(&ptib, &ppib);
 
881
    return ((long)ptib->tib_ordinal); /* thread id */
 
882
}
 
883
#endif
 
884
 
 
885
static void
 
886
CloseCache(cacheDesc *cache)
 
887
{
 
888
    int locks_initialized = cache->numSIDCacheLocksInitialized;
 
889
 
 
890
    if (cache->cacheMem) {
 
891
        /* If everInherited is true, this shared cache was (and may still
 
892
        ** be) in use by multiple processes.  We do not wish to destroy
 
893
        ** the mutexes while they are still in use.  
 
894
        */
 
895
        if (cache->sharedCache &&
 
896
            PR_FALSE == cache->sharedCache->everInherited) {
 
897
            sidCacheLock *pLock = cache->sidCacheLocks;
 
898
            for (; locks_initialized > 0; --locks_initialized, ++pLock ) {
 
899
                sslMutex_Destroy(&pLock->mutex);
 
900
            }
 
901
        }
 
902
        if (cache->shared) {
 
903
            PR_MemUnmap(cache->cacheMem, cache->cacheMemSize);
 
904
        } else {
 
905
            PORT_Free(cache->cacheMem);
 
906
        }
 
907
        cache->cacheMem = NULL;
 
908
    }
 
909
    if (cache->cacheMemMap) {
 
910
        PR_CloseFileMap(cache->cacheMemMap);
 
911
        cache->cacheMemMap = NULL;
 
912
    }
 
913
    memset(cache, 0, sizeof *cache);
 
914
}
 
915
 
 
916
static SECStatus
 
917
InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout, 
 
918
          PRUint32 ssl3_timeout, const char *directory, PRBool shared)
 
919
{
 
920
    ptrdiff_t     ptr;
 
921
    sidCacheLock *pLock;
 
922
    char *        cacheMem;
 
923
    PRFileMap *   cacheMemMap;
 
924
    char *        cfn = NULL;   /* cache file name */
 
925
    int           locks_initialized = 0;
 
926
    int           locks_to_initialize = 0;
 
927
    PRUint32      init_time;
 
928
 
 
929
    if ( (!cache) || (maxCacheEntries < 0) || (!directory) ) {
 
930
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
 
931
        return SECFailure;
 
932
    }
 
933
 
 
934
    if (cache->cacheMem) {
 
935
        /* Already done */
 
936
        return SECSuccess;
 
937
    }
 
938
 
 
939
    /* make sure loser can clean up properly */
 
940
    cache->shared = shared;
 
941
    cache->cacheMem    = cacheMem    = NULL;
 
942
    cache->cacheMemMap = cacheMemMap = NULL;
 
943
    cache->sharedCache = (cacheDesc *)0;
 
944
 
 
945
    cache->numSIDCacheLocksInitialized = 0;
 
946
    cache->nextCertCacheEntry = 0;
 
947
    cache->stopPolling = PR_FALSE;
 
948
    cache->everInherited = PR_FALSE;
 
949
    cache->poller = NULL;
 
950
 
 
951
    cache->numSIDCacheEntries = maxCacheEntries ? maxCacheEntries 
 
952
                                                : DEF_SID_CACHE_ENTRIES;
 
953
    cache->numSIDCacheSets    = 
 
954
        SID_HOWMANY(cache->numSIDCacheEntries, SID_CACHE_ENTRIES_PER_SET);
 
955
 
 
956
    cache->numSIDCacheEntries = 
 
957
        cache->numSIDCacheSets * SID_CACHE_ENTRIES_PER_SET;
 
958
 
 
959
    cache->numSIDCacheLocks   = 
 
960
        PR_MIN(cache->numSIDCacheSets, ssl_max_sid_cache_locks);
 
961
 
 
962
    cache->numSIDCacheSetsPerLock = 
 
963
        SID_HOWMANY(cache->numSIDCacheSets, cache->numSIDCacheLocks);
 
964
 
 
965
    /* compute size of shared memory, and offsets of all pointers */
 
966
    ptr = 0;
 
967
    cache->cacheMem     = (char *)ptr;
 
968
    ptr += SID_ROUNDUP(sizeof(cacheDesc), SID_ALIGNMENT);
 
969
 
 
970
    cache->sidCacheLocks = (sidCacheLock *)ptr;
 
971
    cache->keyCacheLock  = cache->sidCacheLocks + cache->numSIDCacheLocks;
 
972
    cache->certCacheLock = cache->keyCacheLock  + 1;
 
973
    ptr = (ptrdiff_t)(cache->certCacheLock + 1);
 
974
    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
 
975
 
 
976
    cache->sidCacheSets  = (sidCacheSet *)ptr;
 
977
    ptr = (ptrdiff_t)(cache->sidCacheSets + cache->numSIDCacheSets);
 
978
    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
 
979
 
 
980
    cache->sidCacheData  = (sidCacheEntry *)ptr;
 
981
    ptr = (ptrdiff_t)(cache->sidCacheData + cache->numSIDCacheEntries);
 
982
    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
 
983
 
 
984
    cache->certCacheData = (certCacheEntry *)ptr;
 
985
    cache->sidCacheSize  = 
 
986
        (char *)cache->certCacheData - (char *)cache->sidCacheData;
 
987
 
 
988
    /* This is really a poor way to computer this! */
 
989
    cache->numCertCacheEntries = cache->sidCacheSize / sizeof(certCacheEntry);
 
990
    if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES)
 
991
        cache->numCertCacheEntries = MIN_CERT_CACHE_ENTRIES;
 
992
    ptr = (ptrdiff_t)(cache->certCacheData + cache->numCertCacheEntries);
 
993
    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
 
994
 
 
995
    cache->keyCacheData  = (SSLWrappedSymWrappingKey *)ptr;
 
996
    cache->certCacheSize = 
 
997
        (char *)cache->keyCacheData - (char *)cache->certCacheData;
 
998
 
 
999
    cache->numKeyCacheEntries = kt_kea_size * SSL_NUM_WRAP_MECHS;
 
1000
    ptr = (ptrdiff_t)(cache->keyCacheData + cache->numKeyCacheEntries);
 
1001
    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
 
1002
 
 
1003
    cache->cacheMemSize = ptr;
 
1004
 
 
1005
    cache->keyCacheSize  = (char *)ptr - (char *)cache->keyCacheData;
 
1006
 
 
1007
    if (ssl2_timeout) {   
 
1008
        if (ssl2_timeout > MAX_SSL2_TIMEOUT) {
 
1009
            ssl2_timeout = MAX_SSL2_TIMEOUT;
 
1010
        }
 
1011
        if (ssl2_timeout < MIN_SSL2_TIMEOUT) {
 
1012
            ssl2_timeout = MIN_SSL2_TIMEOUT;
 
1013
        }
 
1014
        cache->ssl2Timeout = ssl2_timeout;
 
1015
    } else {
 
1016
        cache->ssl2Timeout = DEF_SSL2_TIMEOUT;
 
1017
    }
 
1018
 
 
1019
    if (ssl3_timeout) {   
 
1020
        if (ssl3_timeout > MAX_SSL3_TIMEOUT) {
 
1021
            ssl3_timeout = MAX_SSL3_TIMEOUT;
 
1022
        }
 
1023
        if (ssl3_timeout < MIN_SSL3_TIMEOUT) {
 
1024
            ssl3_timeout = MIN_SSL3_TIMEOUT;
 
1025
        }
 
1026
        cache->ssl3Timeout = ssl3_timeout;
 
1027
    } else {
 
1028
        cache->ssl3Timeout = DEF_SSL3_TIMEOUT;
 
1029
    }
 
1030
 
 
1031
    if (shared) {
 
1032
        /* Create file names */
 
1033
#if defined(XP_UNIX) || defined(XP_BEOS)
 
1034
        /* there's some confusion here about whether PR_OpenAnonFileMap wants
 
1035
        ** a directory name or a file name for its first argument.
 
1036
        cfn = PR_smprintf("%s/.sslsvrcache.%d", directory, myPid);
 
1037
        */
 
1038
        cfn = PR_smprintf("%s", directory);
 
1039
#elif defined(XP_WIN32)
 
1040
        cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid, 
 
1041
                            GetCurrentThreadId());
 
1042
#elif defined(XP_OS2)
 
1043
        cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid, 
 
1044
                            gettid());
 
1045
#else
 
1046
#error "Don't know how to create file name for this platform!"
 
1047
#endif
 
1048
        if (!cfn) {
 
1049
            goto loser;
 
1050
        }
 
1051
 
 
1052
        /* Create cache */
 
1053
        cacheMemMap = PR_OpenAnonFileMap(cfn, cache->cacheMemSize, 
 
1054
                                         PR_PROT_READWRITE);
 
1055
 
 
1056
        PR_smprintf_free(cfn);
 
1057
        if(!cacheMemMap) {
 
1058
            goto loser;
 
1059
        }
 
1060
 
 
1061
        cacheMem = PR_MemMap(cacheMemMap, 0, cache->cacheMemSize);
 
1062
    } else {
 
1063
        cacheMem = PORT_Alloc(cache->cacheMemSize);
 
1064
    }
 
1065
    
 
1066
    if (! cacheMem) {
 
1067
        goto loser;
 
1068
    }
 
1069
 
 
1070
    /* Initialize shared memory. This may not be necessary on all platforms */
 
1071
    memset(cacheMem, 0, cache->cacheMemSize);
 
1072
 
 
1073
    /* Copy cache descriptor header into shared memory */
 
1074
    memcpy(cacheMem, cache, sizeof *cache);
 
1075
 
 
1076
    /* save private copies of these values */
 
1077
    cache->cacheMemMap = cacheMemMap;
 
1078
    cache->cacheMem    = cacheMem;
 
1079
    cache->sharedCache = (cacheDesc *)cacheMem;
 
1080
 
 
1081
    /* Fix pointers in our private copy of cache descriptor to point to 
 
1082
    ** spaces in shared memory 
 
1083
    */
 
1084
    ptr = (ptrdiff_t)cache->cacheMem;
 
1085
    *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
 
1086
    *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
 
1087
    *(ptrdiff_t *)(&cache->certCacheLock) += ptr;
 
1088
    *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr;
 
1089
    *(ptrdiff_t *)(&cache->sidCacheData ) += ptr;
 
1090
    *(ptrdiff_t *)(&cache->certCacheData) += ptr;
 
1091
    *(ptrdiff_t *)(&cache->keyCacheData ) += ptr;
 
1092
 
 
1093
    /* initialize the locks */
 
1094
    init_time = ssl_Time();
 
1095
    pLock = cache->sidCacheLocks;
 
1096
    for (locks_to_initialize = cache->numSIDCacheLocks + 2;
 
1097
         locks_initialized < locks_to_initialize; 
 
1098
         ++locks_initialized, ++pLock ) {
 
1099
 
 
1100
        SECStatus err = sslMutex_Init(&pLock->mutex, shared);
 
1101
        if (err) {
 
1102
            cache->numSIDCacheLocksInitialized = locks_initialized;
 
1103
            goto loser;
 
1104
        }
 
1105
        pLock->timeStamp = init_time;
 
1106
        pLock->pid       = 0;
 
1107
    }
 
1108
    cache->numSIDCacheLocksInitialized = locks_initialized;
 
1109
 
 
1110
    return SECSuccess;
 
1111
 
 
1112
loser:
 
1113
    CloseCache(cache);
 
1114
    return SECFailure;
 
1115
}
 
1116
 
 
1117
PRUint32
 
1118
SSL_GetMaxServerCacheLocks(void)
 
1119
{
 
1120
    return ssl_max_sid_cache_locks + 2;
 
1121
    /* The extra two are the cert cache lock and the key cache lock. */
 
1122
}
 
1123
 
 
1124
SECStatus
 
1125
SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
 
1126
{
 
1127
    /* Minimum is 1 sid cache lock, 1 cert cache lock and 1 key cache lock.
 
1128
    ** We'd like to test for a maximum value, but not all platforms' header
 
1129
    ** files provide a symbol or function or other means of determining
 
1130
    ** the maximum, other than trial and error.
 
1131
    */
 
1132
    if (maxLocks < 3) {
 
1133
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
 
1134
        return SECFailure;
 
1135
    }
 
1136
    ssl_max_sid_cache_locks = maxLocks - 2;
 
1137
    /* The extra two are the cert cache lock and the key cache lock. */
 
1138
    return SECSuccess;
 
1139
}
 
1140
 
 
1141
SECStatus
 
1142
SSL_ConfigServerSessionIDCacheInstance( cacheDesc *cache,
 
1143
                                int      maxCacheEntries, 
 
1144
                                PRUint32 ssl2_timeout,
 
1145
                                PRUint32 ssl3_timeout, 
 
1146
                          const char *   directory, PRBool shared)
 
1147
{
 
1148
    SECStatus rv;
 
1149
 
 
1150
#if defined(DEBUG_nelsonb)
 
1151
    printf("sizeof(sidCacheEntry) == %u\n", sizeof(sidCacheEntry));
 
1152
#endif
 
1153
#if !(defined(SOLARIS) && defined(i386))
 
1154
#ifndef XP_OS2
 
1155
    PORT_Assert(sizeof(sidCacheEntry) % 8 == 0);
 
1156
#endif
 
1157
#endif
 
1158
    PORT_Assert(sizeof(certCacheEntry) == 4096);
 
1159
 
 
1160
    myPid = SSL_GETPID();
 
1161
    if (!directory) {
 
1162
        directory = DEFAULT_CACHE_DIRECTORY;
 
1163
    }
 
1164
    rv = InitCache(cache, maxCacheEntries, ssl2_timeout, ssl3_timeout, 
 
1165
                   directory, shared);
 
1166
    if (rv) {
 
1167
        SET_ERROR_CODE
 
1168
        return SECFailure;
 
1169
    }
 
1170
 
 
1171
    ssl_sid_lookup  = ServerSessionIDLookup;
 
1172
    ssl_sid_cache   = ServerSessionIDCache;
 
1173
    ssl_sid_uncache = ServerSessionIDUncache;
 
1174
    return SECSuccess;
 
1175
}
 
1176
 
 
1177
SECStatus
 
1178
SSL_ConfigServerSessionIDCache( int      maxCacheEntries, 
 
1179
                                PRUint32 ssl2_timeout,
 
1180
                                PRUint32 ssl3_timeout, 
 
1181
                          const char *   directory)
 
1182
{
 
1183
    ssl_InitClientSessionCacheLock();
 
1184
    ssl_InitSymWrapKeysLock();
 
1185
    return SSL_ConfigServerSessionIDCacheInstance(&globalCache, 
 
1186
                maxCacheEntries, ssl2_timeout, ssl3_timeout, directory, PR_FALSE);
 
1187
}
 
1188
 
 
1189
SECStatus
 
1190
SSL_ShutdownServerSessionIDCacheInstance(cacheDesc *cache)
 
1191
{
 
1192
    CloseCache(cache);
 
1193
    return SECSuccess;
 
1194
}
 
1195
 
 
1196
SECStatus
 
1197
SSL_ShutdownServerSessionIDCache(void)
 
1198
{
 
1199
    SSL3_ShutdownServerCache();
 
1200
    return SSL_ShutdownServerSessionIDCacheInstance(&globalCache);
 
1201
}
 
1202
 
 
1203
/* Use this function, instead of SSL_ConfigServerSessionIDCache,
 
1204
 * if the cache will be shared by multiple processes.
 
1205
 */
 
1206
SECStatus
 
1207
SSL_ConfigMPServerSIDCache(     int      maxCacheEntries, 
 
1208
                                PRUint32 ssl2_timeout,
 
1209
                                PRUint32 ssl3_timeout, 
 
1210
                          const char *   directory)
 
1211
{
 
1212
    char *      envValue;
 
1213
    char *      inhValue;
 
1214
    cacheDesc * cache         = &globalCache;
 
1215
    PRUint32    fmStrLen;
 
1216
    SECStatus   result;
 
1217
    PRStatus    prStatus;
 
1218
    SECStatus   putEnvFailed;
 
1219
    inheritance inherit;
 
1220
    char        fmString[PR_FILEMAP_STRING_BUFSIZE];
 
1221
 
 
1222
    isMultiProcess = PR_TRUE;
 
1223
    result = SSL_ConfigServerSessionIDCacheInstance(cache, maxCacheEntries, 
 
1224
                        ssl2_timeout, ssl3_timeout, directory, PR_TRUE);
 
1225
    if (result != SECSuccess) 
 
1226
        return result;
 
1227
 
 
1228
    prStatus = PR_ExportFileMapAsString(cache->cacheMemMap, 
 
1229
                                        sizeof fmString, fmString);
 
1230
    if ((prStatus != PR_SUCCESS) || !(fmStrLen = strlen(fmString))) {
 
1231
        SET_ERROR_CODE
 
1232
        return SECFailure;
 
1233
    }
 
1234
 
 
1235
    inherit.cacheMemSize        = cache->cacheMemSize;
 
1236
    inherit.fmStrLen            = fmStrLen;
 
1237
 
 
1238
    inhValue = BTOA_DataToAscii((unsigned char *)&inherit, sizeof inherit);
 
1239
    if (!inhValue || !strlen(inhValue)) {
 
1240
        SET_ERROR_CODE
 
1241
        return SECFailure;
 
1242
    }
 
1243
    envValue = PR_smprintf("%s,%s", inhValue, fmString);
 
1244
    if (!envValue || !strlen(envValue)) {
 
1245
        SET_ERROR_CODE
 
1246
        return SECFailure;
 
1247
    }
 
1248
    PORT_Free(inhValue);
 
1249
 
 
1250
    putEnvFailed = (SECStatus)NSS_PutEnv(envVarName, envValue);
 
1251
    PR_smprintf_free(envValue);
 
1252
    if (putEnvFailed) {
 
1253
        SET_ERROR_CODE
 
1254
        result = SECFailure;
 
1255
    }
 
1256
 
 
1257
#if defined(XP_UNIX) || defined(XP_BEOS)
 
1258
    /* Launch thread to poll cache for expired locks on Unix */
 
1259
    LaunchLockPoller(cache);
 
1260
#endif
 
1261
    return result;
 
1262
}
 
1263
 
 
1264
SECStatus
 
1265
SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString)
 
1266
{
 
1267
    unsigned char * decoString = NULL;
 
1268
    char *          fmString   = NULL;
 
1269
    char *          myEnvString = NULL;
 
1270
    unsigned int    decoLen;
 
1271
    ptrdiff_t       ptr;
 
1272
    inheritance     inherit;
 
1273
    cacheDesc       my;
 
1274
#ifdef WINNT
 
1275
    sidCacheLock* newLocks;
 
1276
    int           locks_initialized = 0;
 
1277
    int           locks_to_initialize = 0;
 
1278
#endif
 
1279
 
 
1280
    myPid = SSL_GETPID();
 
1281
 
 
1282
    /* If this child was created by fork(), and not by exec() on unix,
 
1283
    ** then isMultiProcess will already be set.
 
1284
    ** If not, we'll set it below.
 
1285
    */
 
1286
    if (isMultiProcess) {
 
1287
        if (cache && cache->sharedCache) {
 
1288
            cache->sharedCache->everInherited = PR_TRUE;
 
1289
        }
 
1290
        return SECSuccess;      /* already done. */
 
1291
    }
 
1292
 
 
1293
    ssl_InitClientSessionCacheLock();
 
1294
    ssl_InitSymWrapKeysLock();
 
1295
 
 
1296
    ssl_sid_lookup  = ServerSessionIDLookup;
 
1297
    ssl_sid_cache   = ServerSessionIDCache;
 
1298
    ssl_sid_uncache = ServerSessionIDUncache;
 
1299
 
 
1300
    if (!envString) {
 
1301
        envString  = getenv(envVarName);
 
1302
        if (!envString) {
 
1303
            SET_ERROR_CODE
 
1304
            return SECFailure;
 
1305
        }
 
1306
    }
 
1307
    myEnvString = PORT_Strdup(envString);
 
1308
    if (!myEnvString) 
 
1309
        return SECFailure;
 
1310
    fmString = strchr(myEnvString, ',');
 
1311
    if (!fmString) 
 
1312
        goto loser;
 
1313
    *fmString++ = 0;
 
1314
 
 
1315
    decoString = ATOB_AsciiToData(myEnvString, &decoLen);
 
1316
    if (!decoString) {
 
1317
        SET_ERROR_CODE
 
1318
        goto loser;
 
1319
    }
 
1320
    if (decoLen != sizeof inherit) {
 
1321
        SET_ERROR_CODE
 
1322
        goto loser;
 
1323
    }
 
1324
 
 
1325
    PORT_Memcpy(&inherit, decoString, sizeof inherit);
 
1326
 
 
1327
    if (strlen(fmString)  != inherit.fmStrLen ) {
 
1328
        goto loser;
 
1329
    }
 
1330
 
 
1331
    memset(cache, 0, sizeof *cache);
 
1332
    cache->cacheMemSize = inherit.cacheMemSize;
 
1333
 
 
1334
    /* Create cache */
 
1335
    cache->cacheMemMap = PR_ImportFileMapFromString(fmString);
 
1336
    if(! cache->cacheMemMap) {
 
1337
        goto loser;
 
1338
    }
 
1339
    cache->cacheMem = PR_MemMap(cache->cacheMemMap, 0, cache->cacheMemSize);
 
1340
    if (! cache->cacheMem) {
 
1341
        goto loser;
 
1342
    }
 
1343
    cache->sharedCache   = (cacheDesc *)cache->cacheMem;
 
1344
 
 
1345
    if (cache->sharedCache->cacheMemSize != cache->cacheMemSize) {
 
1346
        SET_ERROR_CODE
 
1347
        goto loser;
 
1348
    }
 
1349
 
 
1350
    /* We're now going to overwrite the local cache instance with the 
 
1351
    ** shared copy of the cache struct, then update several values in 
 
1352
    ** the local cache using the values for cache->cacheMemMap and 
 
1353
    ** cache->cacheMem computed just above.  So, we copy cache into 
 
1354
    ** the automatic variable "my", to preserve the variables while
 
1355
    ** cache is overwritten.
 
1356
    */
 
1357
    my = *cache;  /* save values computed above. */
 
1358
    memcpy(cache, cache->sharedCache, sizeof *cache); /* overwrite */
 
1359
 
 
1360
    /* Fix pointers in our private copy of cache descriptor to point to 
 
1361
    ** spaces in shared memory, whose address is now in "my".
 
1362
    */
 
1363
    ptr = (ptrdiff_t)my.cacheMem;
 
1364
    *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
 
1365
    *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
 
1366
    *(ptrdiff_t *)(&cache->certCacheLock) += ptr;
 
1367
    *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr;
 
1368
    *(ptrdiff_t *)(&cache->sidCacheData ) += ptr;
 
1369
    *(ptrdiff_t *)(&cache->certCacheData) += ptr;
 
1370
    *(ptrdiff_t *)(&cache->keyCacheData ) += ptr;
 
1371
 
 
1372
    cache->cacheMemMap = my.cacheMemMap;
 
1373
    cache->cacheMem    = my.cacheMem;
 
1374
    cache->sharedCache = (cacheDesc *)cache->cacheMem;
 
1375
 
 
1376
#ifdef WINNT
 
1377
    /*  On Windows NT we need to "fix" the sidCacheLocks here to support fibers
 
1378
    **  When NT fibers are used in a multi-process server, a second level of
 
1379
    **  locking is needed to prevent a deadlock, in case a fiber acquires the
 
1380
    **  cross-process mutex, yields, and another fiber is later scheduled on
 
1381
    **  the same native thread and tries to acquire the cross-process mutex.
 
1382
    **  We do this by using a PRLock in the sslMutex. However, it is stored in
 
1383
    **  shared memory as part of sidCacheLocks, and we don't want to overwrite
 
1384
    **  the PRLock of the parent process. So we need to make new, private
 
1385
    **  copies of sidCacheLocks before modifying the sslMutex with our own
 
1386
    **  PRLock
 
1387
    */
 
1388
    
 
1389
    /* note from jpierre : this should be free'd in child processes when
 
1390
    ** a function is added to delete the SSL session cache in the future. 
 
1391
    */
 
1392
    locks_to_initialize = cache->numSIDCacheLocks + 2;
 
1393
    newLocks = PORT_NewArray(sidCacheLock, locks_to_initialize);
 
1394
    if (!newLocks)
 
1395
        goto loser;
 
1396
    /* copy the old locks */
 
1397
    memcpy(newLocks, cache->sidCacheLocks, 
 
1398
           locks_to_initialize * sizeof(sidCacheLock));
 
1399
    cache->sidCacheLocks = newLocks;
 
1400
    /* fix the locks */         
 
1401
    for (; locks_initialized < locks_to_initialize; ++locks_initialized) {
 
1402
        /* now, make a local PRLock in this sslMutex for this child process */
 
1403
        SECStatus err;
 
1404
        err = sslMutex_2LevelInit(&newLocks[locks_initialized].mutex);
 
1405
        if (err != SECSuccess) {
 
1406
            cache->numSIDCacheLocksInitialized = locks_initialized;
 
1407
            goto loser;
 
1408
        }
 
1409
    }
 
1410
    cache->numSIDCacheLocksInitialized = locks_initialized;
 
1411
 
 
1412
    /* also fix the key and cert cache which use the last 2 lock entries */
 
1413
    cache->keyCacheLock  = cache->sidCacheLocks + cache->numSIDCacheLocks;
 
1414
    cache->certCacheLock = cache->keyCacheLock  + 1;
 
1415
#endif
 
1416
 
 
1417
    PORT_Free(myEnvString);
 
1418
    PORT_Free(decoString);
 
1419
 
 
1420
    /* mark that we have inherited this. */
 
1421
    cache->sharedCache->everInherited = PR_TRUE;
 
1422
    isMultiProcess = PR_TRUE;
 
1423
 
 
1424
    return SECSuccess;
 
1425
 
 
1426
loser:
 
1427
    PORT_Free(myEnvString);
 
1428
    if (decoString) 
 
1429
        PORT_Free(decoString);
 
1430
    CloseCache(cache);
 
1431
    return SECFailure;
 
1432
}
 
1433
 
 
1434
SECStatus
 
1435
SSL_InheritMPServerSIDCache(const char * envString)
 
1436
{
 
1437
    return SSL_InheritMPServerSIDCacheInstance(&globalCache, envString);
 
1438
}
 
1439
 
 
1440
#if defined(XP_UNIX) || defined(XP_BEOS)
 
1441
 
 
1442
#define SID_LOCK_EXPIRATION_TIMEOUT  30 /* seconds */
 
1443
 
 
1444
static void
 
1445
LockPoller(void * arg)
 
1446
{
 
1447
    cacheDesc *    cache         = (cacheDesc *)arg;
 
1448
    cacheDesc *    sharedCache   = cache->sharedCache;
 
1449
    sidCacheLock * pLock;
 
1450
    const char *   timeoutString;
 
1451
    PRIntervalTime timeout;
 
1452
    PRUint32       now;
 
1453
    PRUint32       then;
 
1454
    int            locks_polled  = 0;
 
1455
    int            locks_to_poll = cache->numSIDCacheLocks + 2;
 
1456
    PRUint32       expiration    = SID_LOCK_EXPIRATION_TIMEOUT;
 
1457
 
 
1458
    timeoutString = getenv("NSS_SSL_SERVER_CACHE_MUTEX_TIMEOUT");
 
1459
    if (timeoutString) {
 
1460
        long newTime = strtol(timeoutString, 0, 0);
 
1461
        if (newTime == 0) 
 
1462
            return;  /* application doesn't want this function */
 
1463
        if (newTime > 0)
 
1464
            expiration = (PRUint32)newTime;
 
1465
        /* if error (newTime < 0) ignore it and use default */
 
1466
    }
 
1467
 
 
1468
    timeout = PR_SecondsToInterval(expiration);
 
1469
    while(!sharedCache->stopPolling) {
 
1470
        PR_Sleep(timeout);
 
1471
        if (sharedCache->stopPolling)
 
1472
            break;
 
1473
 
 
1474
        now   = ssl_Time();
 
1475
        then  = now - expiration;
 
1476
        for (pLock = cache->sidCacheLocks, locks_polled = 0;
 
1477
             locks_to_poll > locks_polled && !sharedCache->stopPolling; 
 
1478
             ++locks_polled, ++pLock ) {
 
1479
            pid_t pid;
 
1480
 
 
1481
            if (pLock->timeStamp   < then && 
 
1482
                pLock->timeStamp   != 0 && 
 
1483
                (pid = pLock->pid) != 0) {
 
1484
 
 
1485
                /* maybe we should try the lock? */
 
1486
                int result = kill(pid, 0);
 
1487
                if (result < 0 && errno == ESRCH) {
 
1488
                    SECStatus rv;
 
1489
                    /* No process exists by that pid any more.
 
1490
                    ** Treat this mutex as abandoned.
 
1491
                    */
 
1492
                    pLock->timeStamp = now;
 
1493
                    pLock->pid       = 0;
 
1494
                    rv = sslMutex_Unlock(&pLock->mutex);
 
1495
                    if (rv != SECSuccess) {
 
1496
                        /* Now what? */
 
1497
                    }
 
1498
                }
 
1499
            }
 
1500
        } /* end of loop over locks */
 
1501
    } /* end of entire polling loop */
 
1502
}
 
1503
 
 
1504
/* Launch thread to poll cache for expired locks */
 
1505
static SECStatus 
 
1506
LaunchLockPoller(cacheDesc *cache)
 
1507
{
 
1508
    PRThread * pollerThread;
 
1509
 
 
1510
    pollerThread = 
 
1511
        PR_CreateThread(PR_USER_THREAD, LockPoller, cache, PR_PRIORITY_NORMAL, 
 
1512
                        PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
 
1513
    if (!pollerThread) {
 
1514
        return SECFailure;
 
1515
    }
 
1516
    cache->poller = pollerThread;
 
1517
    return SECSuccess;
 
1518
}
 
1519
#endif
 
1520
 
 
1521
/************************************************************************
 
1522
 *  Code dealing with shared wrapped symmetric wrapping keys below      *
 
1523
 ************************************************************************/
 
1524
 
 
1525
/* If now is zero, it implies that the lock is not held, and must be 
 
1526
** aquired here.  
 
1527
*/
 
1528
static PRBool
 
1529
getSvrWrappingKey(PRInt32                symWrapMechIndex,
 
1530
               SSL3KEAType               exchKeyType, 
 
1531
               SSLWrappedSymWrappingKey *wswk, 
 
1532
               cacheDesc *               cache,
 
1533
               PRUint32                  lockTime)
 
1534
{
 
1535
    PRUint32  ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
 
1536
    SSLWrappedSymWrappingKey * pwswk = cache->keyCacheData + ndx;
 
1537
    PRUint32  now = 0;
 
1538
    PRBool    rv  = PR_FALSE;
 
1539
 
 
1540
    if (!cache->cacheMem) { /* cache is uninitialized */
 
1541
        PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
 
1542
        return rv;
 
1543
    }
 
1544
    if (!lockTime) {
 
1545
        lockTime = now = LockSidCacheLock(cache->keyCacheLock, now);
 
1546
        if (!lockTime) {
 
1547
            return rv;
 
1548
        }
 
1549
    }
 
1550
    if (pwswk->exchKeyType      == exchKeyType && 
 
1551
        pwswk->symWrapMechIndex == symWrapMechIndex &&
 
1552
        pwswk->wrappedSymKeyLen != 0) {
 
1553
        *wswk = *pwswk;
 
1554
        rv = PR_TRUE;
 
1555
    }
 
1556
    if (now) {
 
1557
        UnlockSidCacheLock(cache->keyCacheLock);
 
1558
    }
 
1559
    return rv;
 
1560
}
 
1561
 
 
1562
PRBool
 
1563
ssl_GetWrappingKey( PRInt32                   symWrapMechIndex,
 
1564
                    SSL3KEAType               exchKeyType, 
 
1565
                    SSLWrappedSymWrappingKey *wswk)
 
1566
{
 
1567
    PRBool rv;
 
1568
 
 
1569
    PORT_Assert( (unsigned)exchKeyType < kt_kea_size);
 
1570
    PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
 
1571
    if ((unsigned)exchKeyType < kt_kea_size &&
 
1572
        (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS) {
 
1573
        rv = getSvrWrappingKey(symWrapMechIndex, exchKeyType, wswk, 
 
1574
                               &globalCache, 0);
 
1575
    } else {
 
1576
        rv = PR_FALSE;
 
1577
    }
 
1578
 
 
1579
    return rv;
 
1580
}
 
1581
 
 
1582
/* The caller passes in the new value it wants
 
1583
 * to set.  This code tests the wrapped sym key entry in the shared memory.
 
1584
 * If it is uninitialized, this function writes the caller's value into 
 
1585
 * the disk entry, and returns false.  
 
1586
 * Otherwise, it overwrites the caller's wswk with the value obtained from 
 
1587
 * the disk, and returns PR_TRUE.  
 
1588
 * This is all done while holding the locks/mutexes necessary to make 
 
1589
 * the operation atomic.
 
1590
 */
 
1591
PRBool
 
1592
ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
 
1593
{
 
1594
    cacheDesc *   cache            = &globalCache;
 
1595
    PRBool        rv               = PR_FALSE;
 
1596
    SSL3KEAType   exchKeyType      = wswk->exchKeyType;   
 
1597
                                /* type of keys used to wrap SymWrapKey*/
 
1598
    PRInt32       symWrapMechIndex = wswk->symWrapMechIndex;
 
1599
    PRUint32      ndx;
 
1600
    PRUint32      now = 0;
 
1601
    SSLWrappedSymWrappingKey myWswk;
 
1602
 
 
1603
    if (!cache->cacheMem) { /* cache is uninitialized */
 
1604
        PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
 
1605
        return 0;
 
1606
    }
 
1607
 
 
1608
    PORT_Assert( (unsigned)exchKeyType < kt_kea_size);
 
1609
    if ((unsigned)exchKeyType >= kt_kea_size)
 
1610
        return 0;
 
1611
 
 
1612
    PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
 
1613
    if ((unsigned)symWrapMechIndex >=  SSL_NUM_WRAP_MECHS)
 
1614
        return 0;
 
1615
 
 
1616
    ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
 
1617
    PORT_Memset(&myWswk, 0, sizeof myWswk);     /* eliminate UMRs. */
 
1618
 
 
1619
    now = LockSidCacheLock(cache->keyCacheLock, now);
 
1620
    if (now) {
 
1621
        rv = getSvrWrappingKey(wswk->symWrapMechIndex, wswk->exchKeyType, 
 
1622
                               &myWswk, cache, now);
 
1623
        if (rv) {
 
1624
            /* we found it on disk, copy it out to the caller. */
 
1625
            PORT_Memcpy(wswk, &myWswk, sizeof *wswk);
 
1626
        } else {
 
1627
            /* Wasn't on disk, and we're still holding the lock, so write it. */
 
1628
            cache->keyCacheData[ndx] = *wswk;
 
1629
        }
 
1630
        UnlockSidCacheLock(cache->keyCacheLock);
 
1631
    }
 
1632
    return rv;
 
1633
}
 
1634
 
 
1635
#else  /* MAC version or other platform */
 
1636
 
 
1637
#include "seccomon.h"
 
1638
#include "cert.h"
 
1639
#include "ssl.h"
 
1640
#include "sslimpl.h"
 
1641
 
 
1642
SECStatus
 
1643
SSL_ConfigServerSessionIDCache( int      maxCacheEntries, 
 
1644
                                PRUint32 ssl2_timeout,
 
1645
                                PRUint32 ssl3_timeout, 
 
1646
                          const char *   directory)
 
1647
{
 
1648
    PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigServerSessionIDCache)");    
 
1649
    return SECFailure;
 
1650
}
 
1651
 
 
1652
SECStatus
 
1653
SSL_ConfigMPServerSIDCache(     int      maxCacheEntries, 
 
1654
                                PRUint32 ssl2_timeout,
 
1655
                                PRUint32 ssl3_timeout, 
 
1656
                          const char *   directory)
 
1657
{
 
1658
    PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigMPServerSIDCache)");    
 
1659
    return SECFailure;
 
1660
}
 
1661
 
 
1662
SECStatus
 
1663
SSL_InheritMPServerSIDCache(const char * envString)
 
1664
{
 
1665
    PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_InheritMPServerSIDCache)");    
 
1666
    return SECFailure;
 
1667
}
 
1668
 
 
1669
PRBool
 
1670
ssl_GetWrappingKey( PRInt32                   symWrapMechIndex,
 
1671
                    SSL3KEAType               exchKeyType, 
 
1672
                    SSLWrappedSymWrappingKey *wswk)
 
1673
{
 
1674
    PRBool rv = PR_FALSE;
 
1675
    PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_GetWrappingKey)");    
 
1676
    return rv;
 
1677
}
 
1678
 
 
1679
/* This is a kind of test-and-set.  The caller passes in the new value it wants
 
1680
 * to set.  This code tests the wrapped sym key entry in the shared memory.
 
1681
 * If it is uninitialized, this function writes the caller's value into 
 
1682
 * the disk entry, and returns false.  
 
1683
 * Otherwise, it overwrites the caller's wswk with the value obtained from 
 
1684
 * the disk, and returns PR_TRUE.  
 
1685
 * This is all done while holding the locks/mutexes necessary to make 
 
1686
 * the operation atomic.
 
1687
 */
 
1688
PRBool
 
1689
ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
 
1690
{
 
1691
    PRBool        rv = PR_FALSE;
 
1692
    PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_SetWrappingKey)");
 
1693
    return rv;
 
1694
}
 
1695
 
 
1696
PRUint32  
 
1697
SSL_GetMaxServerCacheLocks(void)
 
1698
{
 
1699
    PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_GetMaxServerCacheLocks)");
 
1700
    return -1;
 
1701
}
 
1702
 
 
1703
SECStatus 
 
1704
SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
 
1705
{
 
1706
    PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_SetMaxServerCacheLocks)");
 
1707
    return SECFailure;
 
1708
}
 
1709
 
 
1710
#endif /* XP_UNIX || XP_WIN32 */