Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

405 lines
8.9 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2001.
//
// File: mapcache.c
//
// Contents: Routines to manage a cache that holds issuer names we've
// recently processed via many-to-one certificate mapping.
// This is a negative cache, so only issuers that have failed
// mapping are stored in the cache.
//
// The purpose of this cache is to avoid attempting to map
// the same issuers over and over again. This is especially
// important now that the many-to-one mapper walks up the
// certificate chain, attempting to map each CA as it goes.
//
// This code is active on DC machines only.
//
// Functions:
//
// History: 04-12-2001 jbanes Created
//
//----------------------------------------------------------------------------
#include "spbase.h"
#include <mapper.h>
ISSUER_CACHE IssuerCache;
SP_STATUS
SPInitIssuerCache(void)
{
DWORD i;
NTSTATUS Status;
memset(&IssuerCache, 0, sizeof(IssuerCache));
IssuerCache.dwLifespan = ISSUER_CACHE_LIFESPAN;
IssuerCache.dwCacheSize = ISSUER_CACHE_SIZE;
IssuerCache.dwMaximumEntries = ISSUER_CACHE_SIZE;
InitializeListHead(&IssuerCache.EntryList);
__try {
RtlInitializeResource(&IssuerCache.Lock);
} __except(EXCEPTION_EXECUTE_HANDLER)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto cleanup;
}
IssuerCache.LockInitialized = TRUE;
IssuerCache.Cache = (PLIST_ENTRY)SPExternalAlloc(IssuerCache.dwCacheSize * sizeof(LIST_ENTRY));
if(IssuerCache.Cache == NULL)
{
Status = SP_LOG_RESULT(STATUS_NO_MEMORY);
goto cleanup;
}
for(i = 0; i < IssuerCache.dwCacheSize; i++)
{
InitializeListHead(&IssuerCache.Cache[i]);
}
Status = STATUS_SUCCESS;
cleanup:
if(!NT_SUCCESS(Status))
{
SPShutdownIssuerCache();
}
return Status;
}
void
SPShutdownIssuerCache(void)
{
ISSUER_CACHE_ENTRY *pItem;
PLIST_ENTRY pList;
if(IssuerCache.LockInitialized)
{
RtlAcquireResourceExclusive(&IssuerCache.Lock, TRUE);
}
if(IssuerCache.Cache != NULL)
{
pList = IssuerCache.EntryList.Flink;
while(pList != &IssuerCache.EntryList)
{
pItem = CONTAINING_RECORD(pList, ISSUER_CACHE_ENTRY, EntryList.Flink);
pList = pList->Flink;
SPDeleteIssuerEntry(pItem);
}
SPExternalFree(IssuerCache.Cache);
}
if(IssuerCache.LockInitialized)
{
RtlDeleteResource(&IssuerCache.Lock);
IssuerCache.LockInitialized = FALSE;
}
}
void
SPPurgeIssuerCache(void)
{
ISSUER_CACHE_ENTRY *pItem;
PLIST_ENTRY pList;
if(!IssuerCache.LockInitialized)
{
return;
}
if(IssuerCache.dwUsedEntries == 0)
{
return;
}
RtlAcquireResourceExclusive(&IssuerCache.Lock, TRUE);
pList = IssuerCache.EntryList.Flink;
while(pList != &IssuerCache.EntryList)
{
pItem = CONTAINING_RECORD(pList, ISSUER_CACHE_ENTRY, EntryList.Flink);
pList = pList->Flink;
RemoveEntryList(&pItem->IndexEntryList);
RemoveEntryList(&pItem->EntryList);
IssuerCache.dwUsedEntries--;
SPDeleteIssuerEntry(pItem);
}
RtlReleaseResource(&IssuerCache.Lock);
}
void
SPDeleteIssuerEntry(
ISSUER_CACHE_ENTRY *pItem)
{
if(pItem == NULL)
{
return;
}
if(pItem->pbIssuer)
{
LogDistinguishedName(DEB_TRACE, "Delete from cache: %s\n", pItem->pbIssuer, pItem->cbIssuer);
SPExternalFree(pItem->pbIssuer);
}
SPExternalFree(pItem);
}
DWORD
ComputeIssuerCacheIndex(
PBYTE pbIssuer,
DWORD cbIssuer)
{
ULONG Index = 0;
ULONG i;
if(pbIssuer == NULL)
{
Index = 0;
}
else
{
for(i = 0; i < cbIssuer; i++)
{
Index += (pbIssuer[i] ^ 0x55);
}
Index %= IssuerCache.dwCacheSize;
}
return Index;
}
BOOL
SPFindIssuerInCache(
PBYTE pbIssuer,
DWORD cbIssuer)
{
DWORD Index;
DWORD timeNow;
ISSUER_CACHE_ENTRY *pItem;
PLIST_ENTRY pList;
BOOL fFound = FALSE;
if(pbIssuer == NULL || cbIssuer == 0)
{
return FALSE;
}
if(!IssuerCache.LockInitialized)
{
return FALSE;
}
//
// Compute the cache index.
//
Index = ComputeIssuerCacheIndex(pbIssuer, cbIssuer);
Index %= IssuerCache.dwCacheSize;
//
// Search through the cache entries at the computed index.
//
timeNow = GetTickCount();
RtlAcquireResourceShared(&IssuerCache.Lock, TRUE);
pList = IssuerCache.Cache[Index].Flink;
while(pList != &IssuerCache.Cache[Index])
{
pItem = CONTAINING_RECORD(pList, ISSUER_CACHE_ENTRY, IndexEntryList.Flink);
pList = pList->Flink ;
// Has this item expired?
if(HasTimeElapsed(pItem->CreationTime, timeNow, IssuerCache.dwLifespan))
{
continue;
}
// Does the issuer name match?
if(cbIssuer != pItem->cbIssuer)
{
continue;
}
if(memcmp(pbIssuer, pItem->pbIssuer, cbIssuer) != 0)
{
continue;
}
// Found item in cache!!
fFound = TRUE;
break;
}
RtlReleaseResource(&IssuerCache.Lock);
return fFound;
}
void
SPExpireIssuerCacheElements(void)
{
ISSUER_CACHE_ENTRY *pItem;
PLIST_ENTRY pList;
BOOL fDeleteEntry;
DWORD timeNow;
if(!IssuerCache.LockInitialized)
{
return;
}
if(IssuerCache.dwUsedEntries == 0)
{
return;
}
timeNow = GetTickCount();
RtlAcquireResourceExclusive(&IssuerCache.Lock, TRUE);
pList = IssuerCache.EntryList.Flink;
while(pList != &IssuerCache.EntryList)
{
pItem = CONTAINING_RECORD(pList, ISSUER_CACHE_ENTRY, EntryList.Flink);
pList = pList->Flink;
fDeleteEntry = FALSE;
// Mark all expired cache entries as non-resumable.
if(HasTimeElapsed(pItem->CreationTime, timeNow, IssuerCache.dwLifespan))
{
fDeleteEntry = TRUE;
}
// If the cache has gotten too large, then expire elements early. The
// cache elements are sorted by creation time, so the oldest
// entries will be expired first.
if(IssuerCache.dwUsedEntries > IssuerCache.dwMaximumEntries)
{
fDeleteEntry = TRUE;
}
// Remove this entry from the cache.
if(fDeleteEntry)
{
RemoveEntryList(&pItem->IndexEntryList);
RemoveEntryList(&pItem->EntryList);
IssuerCache.dwUsedEntries--;
SPDeleteIssuerEntry(pItem);
}
}
RtlReleaseResource(&IssuerCache.Lock);
}
void
SPAddIssuerToCache(
PBYTE pbIssuer,
DWORD cbIssuer)
{
DWORD Index;
DWORD timeNow;
ISSUER_CACHE_ENTRY *pItem = NULL;
if(pbIssuer == NULL || cbIssuer == 0)
{
return;
}
if(!IssuerCache.LockInitialized)
{
return;
}
//
// Determine if the issuer is already in the cache. This isn't particularly
// thread-safe, so it's possible that the same issuer might sneak into
// the cache multiple times, but that's harmless.
//
if(SPFindIssuerInCache(pbIssuer, cbIssuer))
{
return;
}
//
// Compute the cache index.
//
Index = ComputeIssuerCacheIndex(pbIssuer, cbIssuer);
Index %= IssuerCache.dwCacheSize;
timeNow = GetTickCount();
//
// Allocate a new cache entry.
//
pItem = SPExternalAlloc(sizeof(ISSUER_CACHE_ENTRY));
if(pItem == NULL)
{
SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
return;
}
//
// Fill in the cache internal fields.
//
pItem->pbIssuer = SPExternalAlloc(cbIssuer);
if(pItem->pbIssuer == NULL)
{
SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
SPExternalFree(pItem);
return;
}
pItem->cbIssuer = cbIssuer;
memcpy(pItem->pbIssuer, pbIssuer, cbIssuer);
pItem->CreationTime = timeNow;
//
// Add the new entry to the cache.
//
LogDistinguishedName(DEB_TRACE, "Add to cache: %s\n", pbIssuer, cbIssuer);
RtlAcquireResourceExclusive(&IssuerCache.Lock, TRUE);
InsertTailList(&IssuerCache.Cache[Index], &pItem->IndexEntryList);
InsertTailList(&IssuerCache.EntryList, &pItem->EntryList);
IssuerCache.dwUsedEntries++;
RtlReleaseResource(&IssuerCache.Lock);
}