windows-nt/Source/XPSP1/NT/ds/security/ntmarta/newsrc/idcache.cxx

1261 lines
35 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+-------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997 - 1997.
//
// File: idcache.cxx
//
// Contents: Implementation of the DS guid/name lookup cache
//
// History: 20-Feb-97 MacM Created
//
//--------------------------------------------------------------------
#include <aclpch.hxx>
#pragma hdrstop
#include <stdio.h>
#include <alsup.hxx>
//
// This list contains pointers to memory allocated when a node is converted
// to/from a guid via Rpc apis. It gets freed during cleanup.
//
typedef struct _ACTRL_ID_MEM
{
PVOID pv;
BOOL fRpc;
struct _ACTRL_ID_MEM *pNext;
} ACTRL_ID_MEM, *PACTRL_ID_MEM;
//
// Global name/id cache
//
PACTRL_OBJ_ID_CACHE grgIdNameCache[ACTRL_OBJ_ID_TABLE_SIZE];
PACTRL_OBJ_ID_CACHE grgIdGuidCache[ACTRL_OBJ_ID_TABLE_SIZE];
//
// Mem list head pointer
//
PACTRL_ID_MEM gpMemCleanupList;
//
// Last connection info/time we read from the schema
//
static ACTRL_ID_SCHEMA_INFO LastSchemaRead;
//
// Defines for attribute strings
//
#define ACTRL_OBJ_NAME L"NAME '"
#define ACTRL_OBJ_GUID L"PROPERTY-GUID '"
#define ACTRL_OBJ_CLASS L"CLASS-GUID '"
#define ACTRL_OBJ_NAME_LEN sizeof(ACTRL_OBJ_NAME) / sizeof(WCHAR) - 1
#define ACTRL_OBJ_GUID_LEN sizeof(ACTRL_OBJ_GUID) / sizeof(WCHAR) - 1
#define ACTRL_OBJ_CLASS_LEN sizeof(ACTRL_OBJ_CLASS) / sizeof(WCHAR) - 1
//
// Local function prototypes
//
PACTRL_NAME_CACHE AccctrlpLookupIdNameInCache(PWSTR pwszName);
PACTRL_NAME_CACHE AccctrlpLookupGuidInCache(PSID pSid);
DWORD AccctrlpNewNameGuidNode(PWSTR pwszName,
PGUID pGuid,
PACTRL_OBJ_ID_CACHE *ppNewNode);
BOOL AccctrlpInsertIdNameNode(PACTRL_OBJ_ID_CACHE *ppRootNode,
PACTRL_OBJ_ID_CACHE pNewNode);
BOOL AccctrlpInsertGuidNode(PACTRL_OBJ_ID_CACHE *ppRootNode,
PACTRL_OBJ_ID_CACHE pNewNode);
VOID AccctrlpRemoveIdNameNode(PACTRL_OBJ_ID_CACHE *ppRootNode,
PACTRL_OBJ_ID_CACHE pNewNode);
VOID AccctrlpFreeUserCacheName(PWSTR pwszName,
PWSTR pwszCacheName);
DWORD AccctrlpLoadCacheFromSchema(PLDAP pLDAP,
PWSTR pwszDsPath);
static RTL_RESOURCE gIdCacheLock;
BOOL bIdCacheLockInitialized = FALSE;
//+----------------------------------------------------------------------------
//
// Function: ActrlHashIdName
//
// Synopsis: Determines the hash index for the given ldap display name
//
// Arguments: pwszName -- Name to hash
//
// Returns: Hash index of the string
//
//-----------------------------------------------------------------------------
INT
ActrlHashIdName(PWSTR pwszName)
{
INT Hash = 0;
#if DBG
PWSTR pwsz = pwszName;
#endif
if(pwszName != NULL)
{
while(*pwszName != L'\0')
{
Hash = (Hash * 16 + ( tolower(*pwszName++))) % ACTRL_OBJ_ID_TABLE_SIZE;
}
}
#if DBG
acDebugOut((DEB_TRACE_LOOKUP,"Hashing id name %ws to %lu\n",
pwsz, Hash));
#endif
return(Hash);
}
//+----------------------------------------------------------------------------
//
// Function: ActrlHashGuid
//
// Synopsis: Determines the hash index for the given guid
//
// Arguments: pGuid -- Guid to hash
//
// Returns: Hash index of the Guid
//
//-----------------------------------------------------------------------------
INT
ActrlHashGuid(PGUID pGuid)
{
DWORD dwTotal = 0;
//
// Just deal with the sub authorities
//
for(INT i = 0; i < sizeof(GUID) / sizeof(DWORD); i++)
{
dwTotal += ((PULONG)pGuid)[i];
}
#if DBG
CHAR szGuid[38];
memset( szGuid,
0,
sizeof(szGuid));
sprintf(szGuid, "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x",
pGuid->Data1,pGuid->Data2,pGuid->Data3,pGuid->Data4[0],
pGuid->Data4[1],pGuid->Data4[2],pGuid->Data4[3],
pGuid->Data4[4],pGuid->Data4[5],pGuid->Data4[6],
pGuid->Data4[7]);
acDebugOut((DEB_TRACE_LOOKUP,
"Hashing id %s (Total %lu) to %lu\n",
szGuid, dwTotal, dwTotal % ACTRL_OBJ_ID_TABLE_SIZE));
#endif
return(dwTotal % ACTRL_OBJ_ID_TABLE_SIZE);
}
//+----------------------------------------------------------------------------
//
// Function: AccctrlInitializeIdNameCache
//
// Synopsis: Initialize the ID name/Guid lookup cache
//
// Arguments: VOID
//
// Returns: ERROR_SUCCESS -- Success
//
//-----------------------------------------------------------------------------
DWORD AccctrlInitializeIdNameCache(VOID)
{
DWORD dwErr;
if (TRUE == bIdCacheLockInitialized)
{
// Just a precautionary measure to make sure that we do not initialize
// multiple times.
//
ASSERT(FALSE);
return ERROR_SUCCESS;
}
memset(grgIdNameCache, 0,
sizeof(PACTRL_OBJ_ID_CACHE) * ACTRL_OBJ_ID_TABLE_SIZE);
memset(grgIdGuidCache, 0,
sizeof(PACTRL_OBJ_ID_CACHE) * ACTRL_OBJ_ID_TABLE_SIZE);
gpMemCleanupList = NULL;
memset(&LastSchemaRead, 0, sizeof(ACTRL_ID_SCHEMA_INFO));
__try
{
RtlInitializeResource(&gIdCacheLock);
dwErr = ERROR_SUCCESS;
bIdCacheLockInitialized = TRUE;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwErr = RtlNtStatusToDosError(GetExceptionCode());
}
return dwErr;
}
//+----------------------------------------------------------------------------
//
// Function: AccctrlFreeIdNameCache
//
// Synopsis: Frees any memory allocated for the id name/guid cache
//
// Arguments: VOID
//
// Returns: VOID
//
//-----------------------------------------------------------------------------
VOID AccctrlFreeIdNameCache(VOID)
{
INT i;
PACTRL_OBJ_ID_CACHE pNode, pNext;
if (FALSE == bIdCacheLockInitialized)
{
return;
}
for(i = 0; i < ACTRL_OBJ_ID_TABLE_SIZE; i++)
{
//
// Nodes are only inserted into the name cache, so that is the only
// place we delete them from
//
pNode = grgIdNameCache[i];
while(pNode != NULL)
{
pNext = pNode->pNextName;
AccFree(pNode->pwszName);
AccFree(pNode);
pNode = pNext;
}
}
PACTRL_ID_MEM pMem = gpMemCleanupList;
while(pMem != NULL)
{
if(pMem->fRpc == TRUE)
{
PWSTR pwsz = (PWSTR)pMem->pv;
RpcStringFree(&pwsz);
}
else
{
AccFree(pMem->pv);
}
pMem = pMem->pNext;
}
AccFree(LastSchemaRead.pwszPath);
RtlDeleteResource(&gIdCacheLock);
bIdCacheLockInitialized = FALSE;
}
//+----------------------------------------------------------------------------
//
// Function: AccctrlpLookupIdNameInCache
//
// 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_OBJ_ID_CACHE AccctrlpLookupNameInCache(PWSTR pwszName)
{
PACTRL_OBJ_ID_CACHE pNode = NULL;
pNode = grgIdNameCache[ActrlHashIdName(pwszName)];
while(pNode != NULL)
{
if(_wcsicmp(pwszName, pNode->pwszName) == 0)
{
break;
}
pNode = pNode->pNextName;
}
#if DBG
if(pNode != NULL )
{
CHAR szGuid[38];
PGUID pGuid = &pNode->Guid;
sprintf(szGuid, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
pGuid->Data1,pGuid->Data2,pGuid->Data3,pGuid->Data4[0],
pGuid->Data4[1],pGuid->Data4[2],pGuid->Data4[3],
pGuid->Data4[4],pGuid->Data4[5],pGuid->Data4[6],
pGuid->Data4[7]);
acDebugOut((DEB_TRACE_LOOKUP,
"LookupName on %ws found %s\n",
pwszName, szGuid));
}
#endif
return(pNode);
}
//+----------------------------------------------------------------------------
//
// Function: AccctrlpLookupGuidInCache
//
// Synopsis: Determines if the given guid exists in the cache or not
//
// Arguments: [pGuid] -- Guid to be looked up
//
// Returns: Matching node if found, NULL if not
//
//-----------------------------------------------------------------------------
PACTRL_OBJ_ID_CACHE AccctrlpLookupGuidInCache(PGUID pGuid)
{
PACTRL_OBJ_ID_CACHE pNode = grgIdGuidCache[ActrlHashGuid(pGuid)];
while(pNode != NULL)
{
if(memcmp(pGuid, &(pNode->Guid), sizeof(GUID)) == 0)
{
break;
}
pNode = pNode->pNextGuid;
}
#if DBG
if(pNode != NULL )
{
CHAR szGuid[37];
sprintf(szGuid, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
pGuid->Data1,pGuid->Data2,pGuid->Data3,pGuid->Data4[0],
pGuid->Data4[1],pGuid->Data4[2],pGuid->Data4[3],
pGuid->Data4[4],pGuid->Data4[5],pGuid->Data4[6],
pGuid->Data4[7]);
acDebugOut((DEB_TRACE_LOOKUP,
"LookupGuid on %s found %ws\n",
szGuid, pNode->pwszName));
}
#endif
return(pNode);
}
//+----------------------------------------------------------------------------
//
// Function: AccctrlpNewNameGuidNode
//
// Synopsis: Allocates a new node and inserts them into the caches
//
// Arguments: [pwszName] -- Name to insert
// [pGuid] -- Guid to insert
// [pNewNode] -- Newly added node
//
// Returns: ERROR_SUCCESS -- Success
// ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
// ERROR_INVALID_DATA A node was only inserted in one list
//
//-----------------------------------------------------------------------------
DWORD AccctrlpNewNameGuidNode(PWSTR pwszName,
PGUID pGuid,
PACTRL_OBJ_ID_CACHE *ppNewNode)
{
DWORD dwErr = ERROR_SUCCESS;
BOOL fNameRet = FALSE, fGuidRet = FALSE;
PACTRL_OBJ_ID_CACHE pNewNode = (PACTRL_OBJ_ID_CACHE)AccAlloc(
sizeof(ACTRL_OBJ_ID_CACHE));
if(pNewNode == NULL)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
pNewNode->pwszName = pwszName;
memcpy(&pNewNode->Guid, pGuid, sizeof(GUID));
pNewNode->pNextName= NULL;
pNewNode->pNextGuid= NULL;
fNameRet = AccctrlpInsertIdNameNode(
&(grgIdNameCache[ActrlHashIdName(pwszName)]),
pNewNode);
if ( fNameRet == TRUE ) {
fGuidRet = AccctrlpInsertGuidNode(
&(grgIdGuidCache[ActrlHashGuid(pGuid)]),
pNewNode);
}
if(fNameRet == TRUE && fGuidRet == TRUE)
{
*ppNewNode = pNewNode;
}
else
{
dwErr = ERROR_INVALID_DATA;
if( fNameRet == TRUE )
{
AccctrlpRemoveIdNameNode( &(grgIdNameCache[ActrlHashIdName(pwszName)]),
pNewNode);
}
AccFree(pNewNode);
*ppNewNode = NULL;
}
}
return(dwErr);
}
//+----------------------------------------------------------------------------
//
// Function: AccctrlpInsertIdNameNode
//
// Synopsis: Inserts the specified new node into the caches
//
// Arguments: [ppRootNode] -- Root node in the name cache
// [pNewNode] -- Node to insert
//
// Returns: VOID
//
//-----------------------------------------------------------------------------
BOOL AccctrlpInsertIdNameNode(PACTRL_OBJ_ID_CACHE *ppRootNode,
PACTRL_OBJ_ID_CACHE pNewNode)
{
PACTRL_OBJ_ID_CACHE pNext = NULL, pTrail = NULL;
BOOL fReturn = TRUE;
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 != NULL)
{
if(_wcsicmp(pNewNode->pwszName, pNext->pwszName) == 0)
{
//
// If a node is already found, exit
//
fReturn = FALSE;
acDebugOut((DEB_TRACE_LOOKUP, "Name %ws already exists. Bailing\n",
pNewNode->pwszName));
break;
}
pTrail = pNext;
pNext = pNext->pNextName;
// acDebugOut((DEB_TRACE_LOOKUP, "\t%ws\n", pNext->pwszName));
}
if(fReturn == TRUE)
{
if ( pTrail == NULL ) {
(*ppRootNode)->pNextName = pNewNode;
} else {
pTrail->pNextName = pNewNode;
}
}
}
return(fReturn);
}
//+----------------------------------------------------------------------------
//
// Function: AccctrlpInsertGuidNode
//
// Synopsis: Inserts the specified new node into the caches
//
// Arguments: [ppRootNode] -- Root node in the name cache
// [pNewNode] -- Node to insert
//
// Returns: VOID
//
//-----------------------------------------------------------------------------
BOOL AccctrlpInsertGuidNode(PACTRL_OBJ_ID_CACHE *ppRootNode,
PACTRL_OBJ_ID_CACHE pNewNode)
{
PACTRL_OBJ_ID_CACHE pNext = NULL, pTrail = NULL;
BOOL fReturn = TRUE;
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 != NULL)
{
if(memcmp(&(pNewNode->Guid), &(pNext->Guid), sizeof(GUID)) == 0)
{
fReturn = FALSE;
acDebugOut((DEB_TRACE_LOOKUP, "Guid for %ws already exists. Bailing\n",
pNewNode->pwszName));
break;
}
pTrail = pNext;
pNext = pNext->pNextGuid;
// acDebugOut((DEB_TRACE_LOOKUP, "\t%ws\n", pNext->pwszName));
}
if(fReturn == TRUE)
{
if ( pTrail == NULL ) {
(*ppRootNode)->pNextGuid = pNewNode;
} else {
pTrail->pNextGuid = pNewNode;
}
}
}
return(fReturn);
}
//+----------------------------------------------------------------------------
//
// Function: AccctrlLookupIdName
//
// Synopsis: Looks up the name for the specified GUID.
// Algorithm:
// Search cache for ID
// If not found, reload table from schema on DS referenced
// by the DS path
// Search the cache for the ID
// If not found, return the string version of the ID
//
// Arguments: [pGuid] -- Guid 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.
//
// Returns: VOID
//
//-----------------------------------------------------------------------------
DWORD
AccctrlLookupIdName(IN PLDAP pLDAP,
IN PWSTR pwszDsPath,
IN PGUID pGuid,
IN BOOL fAllocateReturn,
IN BOOL fHandleObjectGuids,
OUT PWSTR *ppwszName)
{
DWORD dwErr = ERROR_SUCCESS;
PWSTR pwszStringId = NULL;
RtlAcquireResourceShared(&gIdCacheLock, TRUE);
#if DBG
CHAR szGuid[38];
sprintf(szGuid,
"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
pGuid->Data1,pGuid->Data2,pGuid->Data3,
pGuid->Data4[0],
pGuid->Data4[1],pGuid->Data4[2],pGuid->Data4[3],
pGuid->Data4[4],pGuid->Data4[5],pGuid->Data4[6],
pGuid->Data4[7]);
#endif
//
// First, see if the sid alreadt exists in our cache
//
PACTRL_OBJ_ID_CACHE pNode = AccctrlpLookupGuidInCache(pGuid);
if(pNode == NULL)
{
acDebugOut((DEB_TRACE_LOOKUP, "Guid %s not found in cache\n", szGuid));
//
// Grab a write lock
//
RtlConvertSharedToExclusive(&gIdCacheLock);
//
// We'll have to look it up...
//
dwErr = AccctrlpLoadCacheFromSchema(pLDAP, pwszDsPath);
if(dwErr == ERROR_SUCCESS)
{
pNode = AccctrlpLookupGuidInCache(pGuid);
//
// If we've been asked to handle individual object guids,
// see if this GUID is one.
//
if ( fHandleObjectGuids ) {
PWSTR pwszUuid;
DWORD dwUuidLen;
PWSTR pwszDSObj;
PDS_NAME_RESULTW pNameRes;
//
// Convert the GUID to a string.
//
dwErr = UuidToString(pGuid, &pwszUuid);
if ( dwErr == ERROR_SUCCESS ) {
//
// Convert the string-ized GUID to an object name.
//
dwUuidLen = wcslen( pwszUuid );
pwszDSObj = (PWSTR) AccAlloc( (dwUuidLen+3)*sizeof(WCHAR) );
if ( pwszDSObj == NULL) {
dwErr = ERROR_NOT_ENOUGH_MEMORY;
} else {
PWSTR pwszServer = NULL, pwszObject = NULL;
pwszDSObj[0] = L'{';
memcpy( &pwszDSObj[1], pwszUuid, dwUuidLen*sizeof(WCHAR) );
pwszDSObj[dwUuidLen+1] = L'}';
pwszDSObj[dwUuidLen+2] = L'\0';
//
// Crack the name into canonical form
//
dwErr = DspSplitPath( pwszDSObj, &pwszServer, &pwszObject );
if(dwErr == ERROR_SUCCESS)
{
dwErr = DspBindAndCrackEx(
pwszServer,
pwszObject,
0,
DS_CANONICAL_NAME,
&pNameRes );
if ( dwErr == ERROR_SUCCESS ) {
if(pNameRes->cItems == 0 || pNameRes->rItems[0].status != 0) {
dwErr = ERROR_SUCCESS;
} else {
//
// Cache our newly found name.
//
dwErr = AccctrlpNewNameGuidNode( pNameRes->rItems[0].pName,
pGuid,
&pNode);
}
// Clean up
DsFreeNameResultW(pNameRes);
} else {
// Failure to find name isn't fatal
dwErr = ERROR_SUCCESS;
}
AccFree(pwszServer);
}
// Clean up
AccFree( pwszDSObj );
}
// Clean up
RpcStringFree(&pwszUuid);
}
}
//
// If it wasn't found, return the string version of the ID
//
if( dwErr == ERROR_SUCCESS && pNode == NULL)
{
dwErr = UuidToString(pGuid, &pwszStringId);
}
}
}
else
{
acDebugOut((DEB_TRACE_LOOKUP, "Guid %s found in cache\n", szGuid));
}
//
// Finally, return the information
//
if(dwErr == ERROR_SUCCESS)
{
PWSTR pwszName;
if(pNode != NULL)
{
pwszName = pNode->pwszName;
}
else
{
pwszName = pwszStringId;
}
if(fAllocateReturn == TRUE)
{
ACC_ALLOC_AND_COPY_STRINGW(pwszName, *ppwszName, dwErr);
}
else
{
*ppwszName = pwszName;
if(pwszStringId != NULL)
{
PACTRL_ID_MEM pMem = (PACTRL_ID_MEM)AccAlloc(sizeof(ACTRL_ID_MEM));
if(pMem == NULL)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
RpcStringFree(&pwszStringId);
}
else
{
pMem->pv = pwszStringId;
pMem->fRpc = TRUE;
pMem->pNext = gpMemCleanupList;
gpMemCleanupList = pMem;
}
}
}
}
RtlReleaseResource(&gIdCacheLock);
return(dwErr);
}
//+----------------------------------------------------------------------------
//
// Function: AccctrlLookupGuid
//
// Synopsis: Looks up the GUID for the specified name
//
// Arguments: [pwszName] -- Name to lookup
// [fAllocateReturn]- If true, the name returned is allocated
// into a new buffer. Otherwise, a
// reference is returned.
// [ppGuid] -- Where the guid is returned.
//
// Returns: VOID
//
//-----------------------------------------------------------------------------
DWORD
AccctrlLookupGuid(IN PLDAP pLDAP,
IN PWSTR pwszDsPath,
IN PWSTR pwszName,
IN BOOL fAllocateReturn,
OUT PGUID *ppGuid)
{
DWORD dwErr = ERROR_SUCCESS;
GUID guid, *pguid = NULL;
BOOL fConverted = FALSE;
RtlAcquireResourceShared(&gIdCacheLock, TRUE);
//
// First, see if the sid already exists in our cache
//
PACTRL_OBJ_ID_CACHE pNode = AccctrlpLookupNameInCache(pwszName);
if(pNode == NULL)
{
//
// Grab a write lock
//
RtlConvertSharedToExclusive(&gIdCacheLock);
acDebugOut((DEB_TRACE_LOOKUP,"Name %ws not found in cache\n",
pwszName));
//
// We'll have to look it up...
//
dwErr = AccctrlpLoadCacheFromSchema(pLDAP, pwszDsPath);
if(dwErr == ERROR_SUCCESS)
{
pNode = AccctrlpLookupNameInCache(pwszName);
//
// If it wasn't found, return the ID from the string
//
if(pNode == NULL)
{
dwErr = UuidFromString(pwszName, &guid);
fConverted = TRUE;
pguid = &guid;
}
else
{
pguid = &pNode->Guid;
}
}
}
else
{
acDebugOut((DEB_TRACE_LOOKUP,"Name %ws found in cache\n", pwszName));
pguid = &pNode->Guid;
}
//
// Finally, return the information
//
if(dwErr == ERROR_SUCCESS)
{
if(fAllocateReturn == TRUE)
{
ACC_ALLOC_AND_COPY_GUID(pguid, *ppGuid, dwErr);
}
else
{
if(fConverted == TRUE)
{
ACC_ALLOC_AND_COPY_GUID(pguid, *ppGuid, dwErr);
if(dwErr == ERROR_SUCCESS)
{
PACTRL_ID_MEM pMem = (PACTRL_ID_MEM)AccAlloc(
sizeof(ACTRL_ID_MEM));
if(pMem == NULL)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
AccFree(*ppGuid);
}
else
{
pMem->pv = *ppGuid;
pMem->pNext = gpMemCleanupList;
gpMemCleanupList = pMem;
}
}
}
else
{
*ppGuid = pguid;
}
}
}
RtlReleaseResource(&gIdCacheLock);
return(dwErr);
}
#define WCHAR_TO_HEX_BYTE(wc) \
(BYTE)((wc) >= L'0' && (wc) <= L'9' ? (wc) - L'0' : towlower( (wc) ) - L'a' + 10)
#define WCHAR_TO_HI_HEX_BYTE(wc) (WCHAR_TO_HEX_BYTE(wc) << 4 )
//+----------------------------------------------------------------------------
//
// Function: AccctrlpDsStrGuidToGuid
//
// Synopsis: Converts a read string guid into an actual guid
//
// Arguments: [pwszStrGuid] -- String version of the id
// [pGuid] -- Where the build ID is returned
//
// Returns: ERROR_SUCCESS -- Success
//
//-----------------------------------------------------------------------------
DWORD AccctrlpDsStrGuidToGuid(IN PWSTR pwszStrGuid,
OUT PGUID pGuid)
{
DWORD dwErr = ERROR_SUCCESS;
if(pwszStrGuid == NULL || wcsstr(pwszStrGuid, L"'") - pwszStrGuid != sizeof(GUID) * sizeof(WCHAR))
{
dwErr = ERROR_INVALID_PARAMETER;
}
else
{
#if 1
//
// The string guid we're given is not in a standard UuidToString form,
// so we'll have to convert it
//
PBYTE pCurr = (PBYTE)pGuid;
for(ULONG i = 0; i < sizeof(GUID); i++)
{
*pCurr = WCHAR_TO_HI_HEX_BYTE(*pwszStrGuid) | WCHAR_TO_HEX_BYTE(*(pwszStrGuid + 1));
pCurr++;
pwszStrGuid += 2;
}
#else
//
// Whack it into the right form...
//
WCHAR wszStrFormat[sizeof(GUID) * sizeof(WCHAR) + 7];
ULONG Blocks[] = {8, 4, 4, 4, 12};
PWSTR pwszStrFor = wszStrFormat;
for(ULONG i = 0 ; i < sizeof(Blocks) / sizeof(ULONG) ; i++ )
{
for(ULONG j = 0; j < Blocks[i]; j++)
{
*pwszStrFor++ = *pwszStrGuid++;
}
*pwszStrFor++ = L'-';
}
pwszStrFor--;
*pwszStrFor = UNICODE_NULL;
dwErr = UuidFromString(wszStrFormat, pGuid);
#endif
}
return(dwErr);
}
//+----------------------------------------------------------------------------
//
// Function: AccctrlpLoadCacheFromSchema
//
// Synopsis: Reads the schema cache and adds the entries into the
// cache
//
// Arguments: [pLDAP] -- LDAP connection to the server
// [pwszPath] -- DS path to the object
//
// Returns: ERROR_SUCCESS -- Success
//
//-----------------------------------------------------------------------------
DWORD AccctrlpLoadCacheFromSchema(PLDAP pLDAP,
PWSTR pwszDsPath)
{
DWORD dwErr = ERROR_SUCCESS;
PLDAP pLocalLDAP = pLDAP;
ULONG cValues[2];
PWSTR *ppwszValues[2];
PWSTR rgwszGuidStrs[] = {ACTRL_OBJ_CLASS, ACTRL_OBJ_GUID};
ULONG rgGuidStrLen[] = {ACTRL_OBJ_CLASS_LEN, ACTRL_OBJ_GUID_LEN};
acDebugOut((DEB_TRACE_LOOKUP, "Reloading cache from schema\n"));
//
// If we have no parameters, just return...
//
if(pLDAP == NULL && pwszDsPath == NULL)
{
return(ERROR_SUCCESS);
}
//
// See if we need to read... If our data is over 5 minutes old or if our path referenced is
// not the same as the last one...
//
#define FIVE_MINUTES 300000
if((LastSchemaRead.LastReadTime != 0 &&
(GetTickCount() - LastSchemaRead.LastReadTime < FIVE_MINUTES)) &&
DoPropertiesMatch(pwszDsPath, LastSchemaRead.pwszPath) &&
((pLDAP == NULL && LastSchemaRead.fLDAP == FALSE) ||
(pLDAP != NULL && memcmp(pLDAP, &(LastSchemaRead.LDAP), sizeof(LDAP)))))
{
acDebugOut((DEB_TRACE_LOOKUP,"Cache up to date...\n"));
return(ERROR_SUCCESS);
}
else
{
//
// Need to reinitialize it...
//
if(pLDAP == NULL)
{
LastSchemaRead.fLDAP = FALSE;
}
else
{
LastSchemaRead.fLDAP = TRUE;
memcpy(&(LastSchemaRead.LDAP), pLDAP, sizeof(LDAP));
}
AccFree(LastSchemaRead.pwszPath);
if(pwszDsPath != NULL)
{
ACC_ALLOC_AND_COPY_STRINGW(pwszDsPath, LastSchemaRead.pwszPath, dwErr);
}
LastSchemaRead.LastReadTime = GetTickCount();
}
if(dwErr == ERROR_SUCCESS && pLocalLDAP == NULL)
{
PWSTR pwszServer = NULL, pwszObject = NULL;
dwErr = DspSplitPath( pwszDsPath, &pwszServer, &pwszObject );
if(dwErr == ERROR_SUCCESS)
{
dwErr = BindToDSObject(pwszServer, pwszObject, &pLocalLDAP);
LocalFree(pwszServer);
}
}
//
// Now, get the info. First, extended rights, then the schema info
//
if(dwErr == ERROR_SUCCESS)
{
dwErr = AccDsReadExtendedRights(pLocalLDAP,
&(cValues[0]),
&(ppwszValues[0]),
&(ppwszValues[1]));
if(dwErr == ERROR_SUCCESS )
{
for(ULONG j = 0; j < cValues[0] && dwErr == ERROR_SUCCESS; j++)
{
GUID guid;
dwErr = UuidFromString(ppwszValues[1][j], &guid);
if(dwErr == ERROR_SUCCESS)
{
PACTRL_OBJ_ID_CACHE pNewNode;
PWSTR pwsz;
ACC_ALLOC_AND_COPY_STRINGW(ppwszValues[0][j], pwsz, dwErr);
if(dwErr == ERROR_SUCCESS )
{
dwErr = AccctrlpNewNameGuidNode(pwsz,
&guid,
&pNewNode);
if(dwErr != ERROR_SUCCESS)
{
AccFree(pwsz);
if ( dwErr == ERROR_INVALID_DATA ) {
dwErr = ERROR_SUCCESS;
}
}
}
}
}
AccDsFreeExtendedRights(cValues[0],
ppwszValues[0],
ppwszValues[1]);
}
if(dwErr == ERROR_SUCCESS)
{
dwErr = AccDsReadSchemaInfo(pLocalLDAP,
&(cValues[0]),
&(ppwszValues[0]),
&(cValues[1]),
&(ppwszValues[1]));
if(dwErr == ERROR_SUCCESS )
{
for(ULONG i = 0; i < 2 && dwErr == ERROR_SUCCESS; i++)
{
for(ULONG j = 0;
j < cValues[i] && dwErr == ERROR_SUCCESS; j++)
{
PWSTR pwszVal = ppwszValues[i][j];
GUID guid;
PWSTR pwszName, pwszGuid, pwszTick;
pwszName = wcswcs(pwszVal, ACTRL_OBJ_NAME) + ACTRL_OBJ_NAME_LEN;
pwszGuid = wcswcs(pwszName, rgwszGuidStrs[i]) + rgGuidStrLen[i];
pwszTick = wcswcs(pwszName, L"'");
if(pwszTick != NULL)
{
*pwszTick = UNICODE_NULL;
}
dwErr = AccctrlpDsStrGuidToGuid(pwszGuid, &guid);
if(dwErr == ERROR_SUCCESS)
{
PACTRL_OBJ_ID_CACHE pNewNode;
PWSTR pwsz;
ACC_ALLOC_AND_COPY_STRINGW(pwszName, pwsz, dwErr);
if(dwErr == ERROR_SUCCESS )
{
dwErr = AccctrlpNewNameGuidNode(pwsz,
&guid,
&pNewNode);
if(dwErr != ERROR_SUCCESS)
{
AccFree(pwsz);
if ( dwErr == ERROR_INVALID_DATA ) {
dwErr = ERROR_SUCCESS;
}
}
}
}
pwszVal = pwszGuid;
}
}
ldap_value_free(ppwszValues[0]);
ldap_value_free(ppwszValues[1]);
}
}
}
//
// See if we need to release our ldap connection
//
if(pLocalLDAP != pLDAP && pLocalLDAP != NULL)
{
UnBindFromDSObject(&pLocalLDAP);
}
return(dwErr);
}
//+----------------------------------------------------------------------------
//
// Function: AccctrlpRemoveIdNameNode
//
// Synopsis: Removes the specified new node into the caches
//
// Arguments: [ppRootNode] -- Root node in the name cache
// [pNewNode] -- Node to remove
//
// Returns: VOID
//
//-----------------------------------------------------------------------------
VOID AccctrlpRemoveIdNameNode(PACTRL_OBJ_ID_CACHE *ppRootNode,
PACTRL_OBJ_ID_CACHE pNewNode)
{
PACTRL_OBJ_ID_CACHE pNext = NULL, pPrev;
ASSERT( *ppRootNode != NULL );
if(_wcsicmp((*ppRootNode)->pwszName, pNewNode->pwszName) == 0)
{
*ppRootNode = NULL;
}
else
{
pNext = (*ppRootNode)->pNextName;
pPrev = *ppRootNode;
while(pNext != NULL)
{
if(_wcsicmp(pNewNode->pwszName, pNext->pwszName) == 0)
{
//
// Remove the node
//
pPrev->pNextName = pNext->pNextName;
acDebugOut((DEB_TRACE_LOOKUP, "Removed node for %ws\n",
pNext->pwszName));
break;
}
pPrev = pNext;
pNext = pNext->pNextName;
}
}
return;
}