|
|
//+-------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997 - 1997.
//
// File: sidcache.cxx
//
// Contents: Implementation of the sid/name lookup cache
//
// History: 2-Feb-97 MacM Created
//
//--------------------------------------------------------------------
#include <aclpch.hxx>
#pragma hdrstop
//
// Global name/sid cache
//
PACTRL_NAME_CACHE grgNameCache[ACTRL_NAME_TABLE_SIZE]; PACTRL_NAME_CACHE grgSidCache[ACTRL_NAME_TABLE_SIZE];
//
// Local function prototypes
//
PACTRL_NAME_CACHE AccctrlpLookupNameInCache(PWSTR pwszName);
PACTRL_NAME_CACHE AccctrlpLookupSidInCache(PSID pSid);
DWORD AccctrlpNewNameSidNode(PWSTR pwszName, PSID pSid, SID_NAME_USE SidNameUse, PACTRL_NAME_CACHE *ppNewNode);
VOID AccctrlpInsertNameNode(PACTRL_NAME_CACHE *ppRootNode, PACTRL_NAME_CACHE pNewNode);
VOID AccctrlpInsertSidNode(PACTRL_NAME_CACHE *ppRootNode, PACTRL_NAME_CACHE pNewNode);
DWORD AccctrlpConvertUserToCacheName(PWSTR pwszServer, PWSTR pwszName, PWSTR *ppwszCacheName);
VOID AccctrlpFreeUserCacheName(PWSTR pwszName, PWSTR pwszCacheName);
static RTL_RESOURCE gSidCacheLock; BOOL bSidCacheLockInitialized = FALSE;
//+----------------------------------------------------------------------------
//
// Function: ActrlHashName
//
// Synopsis: Determines the hash index for the given name
//
// Arguments: pwszName -- Name to hash
//
// Returns: Hash index of the string
//
//-----------------------------------------------------------------------------
INT ActrlHashName(PWSTR pwszName) { //
// We'll hash off of just the user name, not the domain name or
// any other name format
//
PWSTR pwszUser = wcschr(pwszName, L'\\'); if(pwszUser == NULL) { pwszUser = pwszName; } else { pwszUser++; }
INT Hash = 0; if(pwszUser != NULL) { while(*pwszUser != L'\0') { Hash = (Hash * 16 + ( *pwszUser++)) % ACTRL_NAME_TABLE_SIZE; } }
acDebugOut((DEB_TRACE_LOOKUP,"Hashing %ws to %lu\n", pwszName, Hash));
return(Hash); }
//+----------------------------------------------------------------------------
//
// Function: ActrlHashSid
//
// Synopsis: Determines the hash index for the given sid
//
// Arguments: pSid -- Sid to hash
//
// Returns: Hash index of the Sid
//
//-----------------------------------------------------------------------------
INT ActrlHashSid(PSID pSid) { DWORD dwTotal = 0;
//
// Just deal with the sub authorities
//
for(INT i = 0; i < (INT)(((PISID)pSid)->SubAuthorityCount); i++) { dwTotal += ((PISID)pSid)->SubAuthority[i]; }
#if DBG
UNICODE_STRING SidString;
memset(&SidString, 0, sizeof(UNICODE_STRING));
if(pSid != NULL) { NTSTATUS Status = RtlConvertSidToUnicodeString(&SidString, pSid, TRUE); if(!NT_SUCCESS(Status)) { acDebugOut((DEB_ERROR, "Can't convert sid to string: 0x%lx\n", Status)); } else { acDebugOut((DEB_TRACE_LOOKUP,"Hashing %wZ (Total %lu) to %lu\n", &SidString, dwTotal, dwTotal % ACTRL_NAME_TABLE_SIZE)); } }
#endif
return(dwTotal % ACTRL_NAME_TABLE_SIZE); }
//+----------------------------------------------------------------------------
//
// Function: AccctrlInitializeSidNameCache
//
// Synopsis: Initialize the name/sid lookup cache
//
// Arguments: VOID
//
// Returns: ERROR_SUCCESS -- Success
//
//-----------------------------------------------------------------------------
DWORD AccctrlInitializeSidNameCache(VOID) { DWORD dwErr;
if (TRUE == bSidCacheLockInitialized) { //
// Just a precautionary measure to make sure that we do not initialize
// multiple times.
//
ASSERT(FALSE); return ERROR_SUCCESS; }
memset(grgNameCache, 0, sizeof(PACTRL_NAME_CACHE) * ACTRL_NAME_TABLE_SIZE); memset(grgSidCache, 0, sizeof(PACTRL_NAME_CACHE) * ACTRL_NAME_TABLE_SIZE);
__try { RtlInitializeResource(&gSidCacheLock); dwErr = ERROR_SUCCESS; bSidCacheLockInitialized = TRUE; } __except (EXCEPTION_EXECUTE_HANDLER) { dwErr = RtlNtStatusToDosError(GetExceptionCode()); }
return dwErr; }
//+----------------------------------------------------------------------------
//
// Function: AccctrlFreeSidNameCache
//
// Synopsis: Frees any memory allocated for the name/sid cache
//
// Arguments: VOID
//
// Returns: VOID
//
//-----------------------------------------------------------------------------
VOID AccctrlFreeSidNameCache(VOID) { INT i; PACTRL_NAME_CACHE pNode, pNext;
if (FALSE == bSidCacheLockInitialized) { return; }
for(i = 0; i < ACTRL_NAME_TABLE_SIZE; i++) { //
// Nodes are only inserted into the name cache, so that is the only
// place we delete them from
//
pNode = grgNameCache[i]; while(pNode != NULL) { pNext = pNode->pNextName; AccFree(pNode->pwszName); AccFree(pNode->pSid); AccFree(pNode); pNode = pNext; } }
RtlDeleteResource(&gSidCacheLock);
bSidCacheLockInitialized = FALSE;
}
//+----------------------------------------------------------------------------
//
// Function: AccctrlpLookupNameInCache
//
// Synopsis: Determines if the given name exists in the cache or not
//
// Arguments: [pwszName] -- Name to be looked up
//
// Returns: Matching node if found, NULL if not
//
//-----------------------------------------------------------------------------
PACTRL_NAME_CACHE AccctrlpLookupNameInCache(PWSTR pwszName) { PACTRL_NAME_CACHE pNode = NULL;
pNode = grgNameCache[ActrlHashName(pwszName)];
while(pNode != NULL) { if(_wcsicmp(pwszName, pNode->pwszName) == 0) { break; } pNode = pNode->pNextName; }
return(pNode); }
//+----------------------------------------------------------------------------
//
// Function: AccctrlpLookupSidInCache
//
// Synopsis: Determines if the given sid exists in the cache or not
//
// Arguments: [pSid] -- Sid to be looked up
//
// Returns: Matching node if found, NULL if not
//
//-----------------------------------------------------------------------------
PACTRL_NAME_CACHE AccctrlpLookupSidInCache(PSID pSid) { PACTRL_NAME_CACHE pNode = grgSidCache[ActrlHashSid(pSid)];
while(pNode != NULL) { if(RtlEqualSid(pSid, pNode->pSid) == TRUE) { break; } pNode = pNode->pNextSid; }
return(pNode); }
//+----------------------------------------------------------------------------
//
// Function: AccctrlpNewNameSidNode
//
// Synopsis: Allocates a new node and inserts them into the caches
//
// Arguments: [pwszName] -- Name to insert
// [pSid] -- Sid to insert
// [SidNameUse] -- Name use
// [pNewNode] -- Newly added node
//
// Returns: ERROR_SUCCESS -- Success
// ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
//
//-----------------------------------------------------------------------------
DWORD AccctrlpNewNameSidNode(PWSTR pwszName, PSID pSid, SID_NAME_USE SidNameUse, PACTRL_NAME_CACHE *ppNewNode) { DWORD dwErr = ERROR_SUCCESS;
PACTRL_NAME_CACHE pNewNode = (PACTRL_NAME_CACHE)AccAlloc( sizeof(ACTRL_NAME_CACHE)); if(pNewNode == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; } else { pNewNode->pwszName = pwszName; pNewNode->pSid = pSid; pNewNode->SidUse = SidNameUse; pNewNode->pNextName= NULL; pNewNode->pNextSid = NULL;
AccctrlpInsertNameNode(&(grgNameCache[ActrlHashName(pwszName)]), pNewNode);
AccctrlpInsertSidNode(&(grgSidCache[ActrlHashSid(pSid)]), pNewNode);
*ppNewNode = pNewNode;
} return(dwErr); }
//+----------------------------------------------------------------------------
//
// Function: AccctrlpInsertNameNode
//
// Synopsis: Inserts the specified new node into the caches
//
// Arguments: [ppRootNode] -- Root node in the name cache
// [pNewNode] -- Node to insert
//
// Returns: VOID
//
//-----------------------------------------------------------------------------
VOID AccctrlpInsertNameNode(PACTRL_NAME_CACHE *ppRootNode, PACTRL_NAME_CACHE pNewNode) { PACTRL_NAME_CACHE pNext = NULL;
if(*ppRootNode == NULL) { *ppRootNode = pNewNode; } else { acDebugOut((DEB_TRACE_LOOKUP, "Collision inserting %ws with:\n", pNewNode->pwszName));
pNext = *ppRootNode; acDebugOut((DEB_TRACE_LOOKUP, "\t%ws\n", pNext->pwszName)); while(pNext->pNextName != NULL) { #if DBG
if(_wcsicmp(pNewNode->pwszName, pNext->pwszName) == 0) { acDebugOut((DEB_ERROR, "Name %ws already in list: 0x%lx\n", pNewNode->pwszName, *ppRootNode)); // ASSERT(FALSE);
} #endif
pNext = pNext->pNextName; acDebugOut((DEB_TRACE_LOOKUP, "\t%ws\n", pNext->pwszName)); } pNext->pNextName = pNewNode; } }
//+----------------------------------------------------------------------------
//
// Function: AccctrlpInsertSidNode
//
// Synopsis: Inserts the specified new node into the caches
//
// Arguments: [ppRootNode] -- Root node in the name cache
// [pNewNode] -- Node to insert
//
// Returns: VOID
//
//-----------------------------------------------------------------------------
VOID AccctrlpInsertSidNode(PACTRL_NAME_CACHE *ppRootNode, PACTRL_NAME_CACHE pNewNode) { PACTRL_NAME_CACHE pNext = NULL;
if(*ppRootNode == NULL) { *ppRootNode = pNewNode; } else { acDebugOut((DEB_TRACE_LOOKUP, "Collision inserting %ws with:\n", pNewNode->pwszName));
pNext = *ppRootNode; acDebugOut((DEB_TRACE_LOOKUP, "\t%ws\n", pNext->pwszName)); while(pNext->pNextSid != NULL) { #if DBG
if(RtlEqualSid(pNewNode->pSid, pNext->pSid) == TRUE) { acDebugOut((DEB_ERROR, "Sid for %ws already in list: 0x%lx\n", pNewNode->pwszName, *ppRootNode)); // ASSERT(FALSE);
} #endif
pNext = pNext->pNextSid;
acDebugOut((DEB_TRACE_LOOKUP, "\t%ws\n", pNext->pwszName)); } pNext->pNextSid = pNewNode; } }
//+----------------------------------------------------------------------------
//
// Function: AccctrlLookupName
//
// Synopsis: Looks up the name for the specified SID
//
// Arguments: [pwszServer] -- Name of the server to remote the call to
// [pSid] -- Sid to lookup
// [fAllocateReturn]- If true, the name returned is allocated
// into a new buffer. Otherwise, a
// reference is returned.
// [ppwszName] -- Where the name is returned.
// [pSidNameUse] -- Type of the name that's returned.
//
// Returns: VOID
//
//-----------------------------------------------------------------------------
DWORD AccctrlLookupName(IN PWSTR pwszServer, IN PSID pSid, IN BOOL fAllocateReturn, OUT PWSTR *ppwszName, OUT PSID_NAME_USE pSidNameUse) { DWORD dwErr = ERROR_SUCCESS;
if(pSid == NULL) { return(ERROR_NONE_MAPPED); }
RtlAcquireResourceShared(&gSidCacheLock, TRUE);
#if DBG
UNICODE_STRING SidString;
memset(&SidString, 0, sizeof(UNICODE_STRING));
if(pSid != NULL) { NTSTATUS Status = RtlConvertSidToUnicodeString(&SidString, pSid, TRUE); if(!NT_SUCCESS(Status)) { acDebugOut((DEB_ERROR, "Can't convert sid to string: 0x%lx\n", Status)); } } #endif
//
// First, see if the sid alreadt exists in our cache
//
PACTRL_NAME_CACHE pNode = AccctrlpLookupSidInCache(pSid); if(pNode == NULL) { #if DBG
acDebugOut((DEB_TRACE_LOOKUP, "Sid %wZ not found in cache\n", &SidString)); #endif
//
// Grab a write lock
//
RtlConvertSharedToExclusive(&gSidCacheLock);
//
// We'll have to look it up...
//
PWSTR pwszName, pwszDomain; dwErr = AccLookupAccountName(pwszServer, pSid, &pwszName, &pwszDomain, pSidNameUse); if(dwErr == ERROR_SUCCESS) { PSID pNewSid = NULL; ACC_ALLOC_AND_COPY_SID(pSid, pNewSid, dwErr); if(dwErr == ERROR_SUCCESS) { dwErr = AccctrlpNewNameSidNode(pwszName, pNewSid, *pSidNameUse, &pNode); }
if(dwErr != ERROR_SUCCESS) { AccFree(pwszName); AccFree(pwszDomain); AccFree(pNewSid); } } } #if DBG
else { acDebugOut((DEB_TRACE_LOOKUP, "Sid %wZ found in cache\n", &SidString)); } #endif
//
// Finally, return the information
//
if(dwErr == ERROR_SUCCESS) { if(fAllocateReturn == TRUE) { ACC_ALLOC_AND_COPY_STRINGW(pNode->pwszName, *ppwszName, dwErr); } else { *ppwszName = pNode->pwszName; }
*pSidNameUse = pNode->SidUse; }
RtlReleaseResource(&gSidCacheLock);
return(dwErr); }
//+----------------------------------------------------------------------------
//
// Function: AccctrlLookupSid
//
// Synopsis: Looks up the SID for the specified name
//
// Arguments: [pwszServer] -- Name of the server to remote the call to
// [pwszName] -- Name to lookup
// [fAllocateReturn]- If true, the name returned is allocated
// into a new buffer. Otherwise, a
// reference is returned.
// [ppwszName] -- Where the name is returned.
// [pSidNameUse] -- Type of the sid that's returned.
//
// Returns: VOID
//
//-----------------------------------------------------------------------------
DWORD AccctrlLookupSid(IN PWSTR pwszServer, IN PWSTR pwszName, IN BOOL fAllocateReturn, OUT PSID *ppSid, OUT PSID_NAME_USE pSidNameUse) { DWORD dwErr = ERROR_SUCCESS; PWSTR pwszLookupName = pwszName;
RtlAcquireResourceShared(&gSidCacheLock, TRUE);
//
// If we get a local name, convert it into machine/domain relative, so we can
// look it up properly.
//
dwErr = AccctrlpConvertUserToCacheName(pwszServer, pwszName, &pwszLookupName);
//
// Just return if the conversion failed.
//
if (pwszLookupName == NULL) { if (dwErr == ERROR_SUCCESS) { dwErr = ERROR_ACCESS_DENIED; } }
if(dwErr == ERROR_SUCCESS) { //
// First, see if the sid already exists in our cache
//
PACTRL_NAME_CACHE pNode = AccctrlpLookupNameInCache(pwszLookupName); if(pNode == NULL) { //
// Grab a write lock
//
RtlConvertSharedToExclusive(&gSidCacheLock);
acDebugOut((DEB_TRACE_LOOKUP,"Name %ws not found in cache\n", pwszLookupName)); //
// We'll have to look it up...
//
TRUSTEE_W Trustee; memset(&Trustee, 0, sizeof(TRUSTEE_W)); Trustee.TrusteeForm = TRUSTEE_IS_NAME; Trustee.ptstrName = pwszLookupName;
dwErr = AccLookupAccountSid(pwszServer, &Trustee, ppSid, pSidNameUse); if(dwErr == ERROR_SUCCESS) { PWSTR pwszNewName = NULL; ACC_ALLOC_AND_COPY_STRINGW(pwszLookupName, pwszNewName, dwErr); if(dwErr == ERROR_SUCCESS) { dwErr = AccctrlpNewNameSidNode(pwszNewName, *ppSid, *pSidNameUse, &pNode); }
if(dwErr != ERROR_SUCCESS) { AccFree(pwszNewName); AccFree(*ppSid); } } } #if DBG
else { acDebugOut((DEB_TRACE_LOOKUP,"Name %ws found in cache\n", pwszLookupName)); } #endif
//
// Finally, return the information
//
if(dwErr == ERROR_SUCCESS) { if(fAllocateReturn == TRUE) { ACC_ALLOC_AND_COPY_SID(pNode->pSid, *ppSid, dwErr); } else { *ppSid = pNode->pSid; }
*pSidNameUse = pNode->SidUse; }
AccctrlpFreeUserCacheName(pwszName, pwszLookupName); }
RtlReleaseResource(&gSidCacheLock);
return(dwErr); }
//+----------------------------------------------------------------------------
//
// Function: AccctrlpConvertUserToCacheName
//
// Synopsis: Converts an input name that could be domain relative into a
// standard format for caching/returning
//
// Arguments: [pwszServer] -- Server to lookup the name on
// [pwszName] -- Original name format
// [ppwszCacheName]-- Name in the proper format
//
// Returns: ERROR_SUCCESS -- Success
// ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
//
//-----------------------------------------------------------------------------
DWORD AccctrlpConvertUserToCacheName(PWSTR pwszServer, PWSTR pwszName, PWSTR *ppwszCacheName) { DWORD dwErr = ERROR_SUCCESS;
//
// This is temporary until the name conversion APIs come into being
//
PSID pSid; SID_NAME_USE SNE; TRUSTEE_W Trustee; memset(&Trustee, 0, sizeof(TRUSTEE_W)); Trustee.TrusteeForm = TRUSTEE_IS_NAME; Trustee.ptstrName = pwszName;
dwErr = AccLookupAccountSid(pwszServer, &Trustee, &pSid, &SNE); if(dwErr == ERROR_SUCCESS) { PWSTR pwszDomain; dwErr = AccLookupAccountName(pwszServer, pSid, ppwszCacheName, &pwszDomain, &SNE); if(dwErr == ERROR_SUCCESS) { AccFree(pwszDomain); }
AccFree(pSid); }
return(dwErr); }
//+----------------------------------------------------------------------------
//
// Function: AccctrlpFreeUserCacheName
//
// Synopsis: Frees any memory potentially allocated by
// AccctrlpConvertUserToCacheName
//
// Arguments: [pwszName] -- Original name format
// [pwszCacheName] -- Name returned by
// AccctrlpConvertUserToCacheName
//
// Returns: VOID
//
//-----------------------------------------------------------------------------
VOID AccctrlpFreeUserCacheName(PWSTR pwszName, PWSTR pwszCacheName) { if(pwszName != pwszCacheName) { AccFree(pwszCacheName); } }
|