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.
345 lines
8.4 KiB
345 lines
8.4 KiB
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 2002
|
|
|
|
Module Name:
|
|
|
|
sidcache.cxx
|
|
|
|
Abstract:
|
|
|
|
This contains the SID_CACHE definition and wrappers to access the per process
|
|
SIDCache.
|
|
|
|
Author:
|
|
|
|
Maurice Flanagan (mauricf) June 27, 2002
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include <precomp.hxx>
|
|
#include <sidcache.hxx>
|
|
|
|
|
|
SID_CACHE *SIDCache = NULL;
|
|
|
|
RPC_STATUS
|
|
QuerySIDCache(
|
|
IN RPC_CHAR *ServerPrincipalName,
|
|
OUT PSID *Sid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This wraps access to our global SIDCache object.
|
|
|
|
Arguments, either:
|
|
|
|
ServerPrincipalName - the server principal name to be translated to
|
|
a SID
|
|
|
|
Sid - On output contains a pointer to the allocated SID. On success (RPC_S_OK) this will be
|
|
NULL if the SPN was not found in our cache. Undefined on failure.
|
|
Pointer must be freed with delete.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK or RPC_S_* error
|
|
|
|
--*/
|
|
{
|
|
ASSERT(ServerPrincipalName != NULL);
|
|
ASSERT(Sid != NULL);
|
|
|
|
if (SIDCache == NULL)
|
|
{
|
|
return RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
|
|
return SIDCache->Query(ServerPrincipalName, Sid);
|
|
}
|
|
|
|
RPC_STATUS
|
|
AddToSIDCache(
|
|
IN RPC_CHAR *ServerPrincipalName,
|
|
IN PSID Sid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This wraps access to our global SIDCache object.
|
|
|
|
Arguments, either:
|
|
|
|
ServerPrincipalName - The server principal name which we want to add to our cache.
|
|
|
|
Sid - The SID associated with this server principal name.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK or RPC_S_* error
|
|
|
|
--*/
|
|
{
|
|
ASSERT(ServerPrincipalName != NULL);
|
|
ASSERT(Sid != NULL);
|
|
|
|
if (SIDCache == NULL)
|
|
{
|
|
return RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
|
|
return SIDCache->Add(ServerPrincipalName, Sid);
|
|
}
|
|
|
|
RPC_STATUS
|
|
RemoveFromSIDCache(
|
|
IN RPC_CHAR *ServerPrincipalName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This wraps access to our global SIDCache object.
|
|
|
|
Arguments, either:
|
|
|
|
ServerPrincipalName - The server principal name which we want to remove from our cache
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK or RPC_S_* error
|
|
|
|
--*/
|
|
{
|
|
if (SIDCache == NULL)
|
|
{
|
|
return RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
|
|
return SIDCache->Remove(ServerPrincipalName);
|
|
}
|
|
|
|
RPC_STATUS
|
|
SID_CACHE::Query (
|
|
IN RPC_CHAR *ServerPrincipalName,
|
|
OUT PSID *Sid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This checks the chache for a matching ServerPrincipalName and if found it returns the SID.
|
|
The goal of the cache is to maintain the last N (N is currently 4) most recently accessed entries.
|
|
We must loop through the entire cache and increment the Age of every entry. If there is a matching
|
|
entry (a hit) then we start the age over again at zero. Every SPN in the cache is unique in the cache.
|
|
|
|
Arguments, either:
|
|
|
|
ServerPrincipalName - The server principal name which we want to lookup in our cache
|
|
|
|
Sid - Filled in with the value found in the cache, or NULL if not found. Undefined on error return.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK or RPC_S_OUT_OF_MEMORY
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD idx;
|
|
BOOL fFound = FALSE;
|
|
*Sid = NULL;
|
|
|
|
CacheMutex.Request();
|
|
for (idx = 0; idx < CacheSize; idx++)
|
|
{
|
|
if (Cache[idx].SPN != NULL)
|
|
{
|
|
if ((!fFound) && (RpcpStringCompare(ServerPrincipalName, Cache[idx].SPN) == 0))
|
|
{
|
|
ASSERT(Cache[idx].SID != NULL);
|
|
Cache[idx].Age = 0;
|
|
fFound = TRUE;
|
|
*Sid = DuplicateSID(Cache[idx].SID);
|
|
if (*Sid == NULL)
|
|
{
|
|
CacheMutex.Clear();
|
|
return RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Cache[idx].Age++;
|
|
}
|
|
}
|
|
}
|
|
|
|
CacheMutex.Clear();
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
RPC_STATUS
|
|
SID_CACHE::Add (
|
|
IN RPC_CHAR *ServerPrincipalName,
|
|
IN PSID Sid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This adds an entry to the cache for this SPN and sets this SID.
|
|
We only have four slots, first we check if this SPN has an entry, if so we free the existing SID
|
|
and add the new one in its place. Next we check for an empty slot, if so we use it. Lastly we
|
|
find the first oldest slot and use that (freeing the existing SPN and SID).
|
|
|
|
Arguments, either:
|
|
|
|
ServerPrincipalName - The server principal name which we want to add to our cache, we
|
|
make a copy of it.
|
|
|
|
|
|
Sid - The SID to associate with this SPN, we make a copy of this (DuplicateSID)
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK or RPC_S_* error
|
|
|
|
--*/
|
|
|
|
{
|
|
RPC_STATUS Status = RPC_S_OK;
|
|
DWORD idx = 0;
|
|
DWORD IdxToUse = -1;
|
|
DWORD OldestIdx = -1, OldestAge;
|
|
DWORD EmptyIdx = -1;
|
|
|
|
|
|
// What slot to use, in order:
|
|
|
|
// Slot with same SPN
|
|
// Empty slot
|
|
// Oldest slot
|
|
|
|
CacheMutex.Request();
|
|
for (idx = 0; idx < CacheSize; idx++)
|
|
{
|
|
// Is this SPN already in the cache?
|
|
if (Cache[idx].SPN != NULL)
|
|
{
|
|
if (RpcpStringCompare(ServerPrincipalName, Cache[idx].SPN) == 0)
|
|
{
|
|
if (!EqualSid(Sid, Cache[idx].SID))
|
|
{
|
|
delete [] Cache[idx].SID;
|
|
Cache[idx].SID = DuplicateSID(Sid);
|
|
if (Cache[idx].SID == NULL)
|
|
{
|
|
delete [] Cache[idx].SPN;
|
|
Cache[idx].SPN = NULL;
|
|
CacheMutex.Clear();
|
|
return RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
Cache[idx].Age = 0;
|
|
CacheMutex.Clear();
|
|
return RPC_S_OK;
|
|
}
|
|
}
|
|
|
|
if (EmptyIdx == -1)
|
|
{
|
|
if (Cache[idx].SPN == NULL)
|
|
{
|
|
// remember this empty slot
|
|
EmptyIdx = idx;
|
|
}
|
|
else
|
|
{
|
|
if (OldestIdx == -1)
|
|
{
|
|
OldestAge = Cache[idx].Age;
|
|
OldestIdx = idx;
|
|
}
|
|
else if (OldestAge < Cache[idx].Age)
|
|
{
|
|
OldestAge = Cache[idx].Age;
|
|
OldestIdx = idx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// We have either the oldest or an empty slot
|
|
if (EmptyIdx == -1)
|
|
{
|
|
delete [] Cache[OldestIdx].SPN;
|
|
delete [] Cache[OldestIdx].SID;
|
|
Cache[OldestIdx].SPN = NULL;
|
|
Cache[OldestIdx].SID = NULL;
|
|
IdxToUse = OldestIdx;
|
|
}
|
|
else
|
|
{
|
|
IdxToUse = EmptyIdx;
|
|
}
|
|
|
|
ASSERT(IdxToUse != -1);
|
|
|
|
Cache[IdxToUse].Age = 0;
|
|
Cache[IdxToUse].SPN = new RPC_CHAR [RpcpStringLength(ServerPrincipalName) +1];
|
|
if (Cache[IdxToUse].SPN == NULL)
|
|
{
|
|
CacheMutex.Clear();
|
|
return RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
RpcpStringNCopy(Cache[IdxToUse].SPN, ServerPrincipalName, RpcpStringLength(ServerPrincipalName) +1);
|
|
Cache[IdxToUse].SID = DuplicateSID(Sid);
|
|
if (Cache[IdxToUse].SID == NULL)
|
|
{
|
|
delete [] Cache[IdxToUse].SPN;
|
|
Cache[IdxToUse].SPN = NULL;
|
|
CacheMutex.Clear();
|
|
return RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
|
|
CacheMutex.Clear();
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
RPC_STATUS
|
|
SID_CACHE::Remove (
|
|
IN RPC_CHAR *ServerPrincipalName
|
|
)
|
|
{
|
|
DWORD idx;
|
|
|
|
if (ServerPrincipalName == NULL)
|
|
return RPC_S_OK;
|
|
|
|
CacheMutex.Request();
|
|
for (idx = 0; idx < CacheSize; idx++)
|
|
{
|
|
if (Cache[idx].SPN != NULL)
|
|
{
|
|
if (RpcpStringCompare(ServerPrincipalName, Cache[idx].SPN) == 0)
|
|
{
|
|
ASSERT(Cache[idx].SID != NULL);
|
|
delete [] Cache[idx].SPN;
|
|
delete [] Cache[idx].SID;
|
|
Cache[idx].SPN = NULL;
|
|
Cache[idx].SID = NULL;
|
|
Cache[idx].Age = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
CacheMutex.Clear();
|
|
return RPC_S_OK;
|
|
}
|