|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: schema.cpp
//
// This file contains the implementation of the Schema Cache
//
//--------------------------------------------------------------------------
#include "pch.h"
#include "sddl.h"
#include "sddlp.h"
//
// CSchemaCache object definition
//
#include "schemap.h"
PSCHEMACACHE g_pSchemaCache = NULL;
//
// Page size used for paging query result sets (better performance)
//
#define PAGE_SIZE 16
//
// The following array defines the permission names for DS objects.
//
SI_ACCESS g_siDSAccesses[] = { { &GUID_NULL, DS_GENERIC_ALL, MAKEINTRESOURCE(IDS_DS_GENERIC_ALL), SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC }, { &GUID_NULL, DS_GENERIC_READ, MAKEINTRESOURCE(IDS_DS_GENERIC_READ), SI_ACCESS_GENERAL }, { &GUID_NULL, DS_GENERIC_WRITE, MAKEINTRESOURCE(IDS_DS_GENERIC_WRITE), SI_ACCESS_GENERAL }, { &GUID_NULL, ACTRL_DS_LIST, MAKEINTRESOURCE(IDS_ACTRL_DS_LIST), SI_ACCESS_SPECIFIC }, { &GUID_NULL, ACTRL_DS_LIST_OBJECT, MAKEINTRESOURCE(IDS_ACTRL_DS_LIST_OBJECT), SI_ACCESS_SPECIFIC }, { &GUID_NULL, ACTRL_DS_READ_PROP, MAKEINTRESOURCE(IDS_ACTRL_DS_READ_PROP), SI_ACCESS_SPECIFIC | SI_ACCESS_PROPERTY }, { &GUID_NULL, ACTRL_DS_WRITE_PROP, MAKEINTRESOURCE(IDS_ACTRL_DS_WRITE_PROP), SI_ACCESS_SPECIFIC | SI_ACCESS_PROPERTY }, { &GUID_NULL, ACTRL_DS_WRITE_PROP|ACTRL_DS_READ_PROP, MAKEINTRESOURCE(IDS_ACTRL_DS_READ_WRITE_PROP), }, { &GUID_NULL, DELETE, MAKEINTRESOURCE(IDS_ACTRL_DELETE), SI_ACCESS_SPECIFIC }, { &GUID_NULL, ACTRL_DS_DELETE_TREE, MAKEINTRESOURCE(IDS_ACTRL_DS_DELETE_TREE), SI_ACCESS_SPECIFIC }, { &GUID_NULL, READ_CONTROL, MAKEINTRESOURCE(IDS_ACTRL_READ_CONTROL), SI_ACCESS_SPECIFIC }, { &GUID_NULL, WRITE_DAC, MAKEINTRESOURCE(IDS_ACTRL_CHANGE_ACCESS), SI_ACCESS_SPECIFIC }, { &GUID_NULL, WRITE_OWNER, MAKEINTRESOURCE(IDS_ACTRL_CHANGE_OWNER), SI_ACCESS_SPECIFIC }, { &GUID_NULL, 0, MAKEINTRESOURCE(IDS_NO_ACCESS), 0 }, { &GUID_NULL, ACTRL_DS_SELF, MAKEINTRESOURCE(IDS_ACTRL_DS_SELF), SI_ACCESS_SPECIFIC }, { &GUID_NULL, ACTRL_DS_CONTROL_ACCESS, MAKEINTRESOURCE(IDS_ACTRL_DS_CONTROL_ACCESS),SI_ACCESS_SPECIFIC }, { &GUID_NULL, ACTRL_DS_CREATE_CHILD, MAKEINTRESOURCE(IDS_ACTRL_DS_CREATE_CHILD), SI_ACCESS_CONTAINER | SI_ACCESS_SPECIFIC }, { &GUID_NULL, ACTRL_DS_DELETE_CHILD, MAKEINTRESOURCE(IDS_ACTRL_DS_DELETE_CHILD), SI_ACCESS_CONTAINER | SI_ACCESS_SPECIFIC }, { &GUID_NULL, ACTRL_DS_DELETE_CHILD|ACTRL_DS_CREATE_CHILD, MAKEINTRESOURCE(IDS_ACTRL_DS_CREATE_DELETE_CHILD), 0 }, //This won't show up as checkbox but used to display in advanced page.
}; #define g_iDSRead 1 // DS_GENERIC_READ
#define g_iDSListObject 4 // ACTRL_DS_LIST_OBJECT
#define g_iDSProperties 5 // Read/Write properties
#define g_iDSDefAccess g_iDSRead
#define g_iDSAllExtRights 15
#define g_iDSAllValRights 14
#define g_iDSDeleteTree 9
//
// The following array defines the inheritance types common to all DS containers.
//
SI_INHERIT_TYPE g_siDSInheritTypes[] = { { &GUID_NULL, 0, MAKEINTRESOURCE(IDS_DS_CONTAINER_ONLY) }, { &GUID_NULL, CONTAINER_INHERIT_ACE, MAKEINTRESOURCE(IDS_DS_CONTAINER_SUBITEMS) }, { &GUID_NULL, CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE, MAKEINTRESOURCE(IDS_DS_SUBITEMS_ONLY) }, };
//
//Used to store some temp info
//
typedef struct _temp_info { LPCGUID pguid; DWORD dwFilter; LPCWSTR pszLdapName; WCHAR szDisplayName[ANYSIZE_ARRAY]; } TEMP_INFO, *PTEMP_INFO;
//
// Helper functions for cleaning up DPA lists
//
int CALLBACK _LocalFreeCB(LPVOID pVoid, LPVOID /*pData*/) { LocalFree(pVoid); return 1; }
void DestroyDPA(HDPA hList) { if (hList != NULL) DPA_DestroyCallback(hList, _LocalFreeCB, 0); } //
// Callback function for merging. Passed to DPA_Merge
//
LPVOID CALLBACK _Merge(UINT , LPVOID pvDest, LPVOID , LPARAM ) { return pvDest; }
BSTR GetFilterFilePath(void) { WCHAR szFilterFile[MAX_PATH]; UINT cch = GetSystemDirectory(szFilterFile, ARRAYSIZE(szFilterFile)); if (0 == cch || cch >= ARRAYSIZE(szFilterFile)) return NULL; if (szFilterFile[cch-1] != L'\\') szFilterFile[cch++] = L'\\'; lstrcpynW(szFilterFile + cch, c_szFilterFile, ARRAYSIZE(szFilterFile) - cch); return SysAllocString(szFilterFile); }
//
// Local prototypes
//
HRESULT Schema_Search(LPWSTR pszSchemaSearchPath, LPCWSTR pszFilter, HDPA *phCache, BOOL bProperty);
//
// C wrappers for the schema cache object
//
HRESULT SchemaCache_Create(LPCWSTR pszServer) { HRESULT hr = S_OK;
if (g_pSchemaCache == NULL) { g_pSchemaCache = new CSchemaCache(pszServer);
if (g_pSchemaCache == NULL) hr = E_OUTOFMEMORY; }
return hr; }
void SchemaCache_Destroy(void) { delete g_pSchemaCache; g_pSchemaCache = NULL; }
HRESULT SchemaCache_GetInheritTypes(LPCGUID pguidObjectType, DWORD dwFlags, PSI_INHERIT_TYPE *ppInheritTypes, ULONG *pcInheritTypes) { HRESULT hr = E_UNEXPECTED;
if (g_pSchemaCache) hr = g_pSchemaCache->GetInheritTypes(pguidObjectType, dwFlags, ppInheritTypes, pcInheritTypes);
return hr; }
HRESULT SchemaCache_GetAccessRights(LPCGUID pguidObjectType, LPCWSTR pszClassName, HDPA hAuxList, LPCWSTR pszSchemaPath, DWORD dwFlags, PACCESS_INFO* ppAccesInfo) { HRESULT hr = E_UNEXPECTED;
if (g_pSchemaCache) hr = g_pSchemaCache->GetAccessRights(pguidObjectType, pszClassName, hAuxList, pszSchemaPath, dwFlags, ppAccesInfo); return hr; }
HRESULT Schema_GetDefaultSD( GUID *pSchemaIdGuid, PSID pDomainSid, PSID pRootDomainSid, PSECURITY_DESCRIPTOR *ppSD ) { HRESULT hr = E_UNEXPECTED; if( g_pSchemaCache ) hr = g_pSchemaCache->GetDefaultSD(pSchemaIdGuid, pDomainSid, pRootDomainSid, ppSD);
return hr;
}
HRESULT Schema_GetObjectTypeList(GUID *pSchamaGuid, HDPA hAuxList, LPCWSTR pszSchemaPath, DWORD dwFlags, POBJECT_TYPE_LIST *ppObjectTypeList, DWORD * pObjectTypeListCount) { HRESULT hr = E_UNEXPECTED; if( g_pSchemaCache ) hr = g_pSchemaCache->GetObjectTypeList( pSchamaGuid, hAuxList, pszSchemaPath, dwFlags, ppObjectTypeList, pObjectTypeListCount);
return hr;
}
HRESULT Schema_GetObjectTypeGuid(LPCWSTR pszClassName, LPGUID pGuid) { if( g_pSchemaCache ) return g_pSchemaCache->LookupClassID(pszClassName, pGuid); else return E_UNEXPECTED; }
AUTHZ_RESOURCE_MANAGER_HANDLE Schema_GetAUTHZ_RM() { if( g_pSchemaCache ) return g_pSchemaCache->GetAuthzRM();
return NULL; }
//
// DPA comparison functions used for sorting and searching the cache lists
//
int CALLBACK Schema_CompareLdapName(LPVOID p1, LPVOID p2, LPARAM lParam) { int nResult = 0; PID_CACHE_ENTRY pEntry1 = (PID_CACHE_ENTRY)p1; PID_CACHE_ENTRY pEntry2 = (PID_CACHE_ENTRY)p2; LPCWSTR pszFind = (LPCWSTR)lParam;
if (pEntry1) pszFind = pEntry1->szLdapName;
if (pszFind && pEntry2) { nResult = CompareStringW(LOCALE_USER_DEFAULT, 0, pszFind, -1, pEntry2->szLdapName, -1) - CSTR_EQUAL; }
return nResult; }
//
// Callback function used to sort based on display name
//
int CALLBACK Schema_CompareTempDisplayName(LPVOID p1, LPVOID p2, LPARAM ) { int nResult = 0; PTEMP_INFO pti1 = (PTEMP_INFO)p1; PTEMP_INFO pti2 = (PTEMP_INFO)p2;
if (pti1 && pti2) { LPCWSTR psz1 = pti1->szDisplayName; LPCWSTR psz2 = pti2->szDisplayName;
if (!*psz1) psz1 = pti1->pszLdapName; if (!*psz2) psz2 = pti2->pszLdapName;
// Note that we are sorting backwards
nResult = CompareStringW(LOCALE_USER_DEFAULT, 0, (LPCWSTR)psz2, -1, (LPCWSTR)psz1, -1) - CSTR_EQUAL; }
return nResult; }
//
// Callback function used to sort based on display name
//
int CALLBACK Schema_ComparePropDisplayName(LPVOID p1, LPVOID p2, LPARAM ) { int nResult = 0; PPROP_ENTRY pti1 = (PPROP_ENTRY)p1; PPROP_ENTRY pti2 = (PPROP_ENTRY)p2;
if (pti1 && pti2) { LPCWSTR psz1 = pti1->szName; LPCWSTR psz2 = pti2->szName;
nResult = CompareStringW(LOCALE_USER_DEFAULT, 0, (LPCWSTR)psz1, -1, (LPCWSTR)psz2, -1) - CSTR_EQUAL; }
return nResult; }
//
// DPA comparison function used for sorting the Extended Rights list
//
int CALLBACK Schema_CompareER(LPVOID p1, LPVOID p2, LPARAM /*lParam*/) { int nResult = 0; PER_ENTRY pEntry1 = (PER_ENTRY)p1; PER_ENTRY pEntry2 = (PER_ENTRY)p2;
if (pEntry1 && pEntry2) { nResult = CompareStringW(LOCALE_USER_DEFAULT, 0, pEntry1->szName, -1, pEntry2->szName, -1) - CSTR_EQUAL;
}
return nResult; }
//
// CSchemaCache object implementation
//
CSchemaCache::CSchemaCache(LPCWSTR pszServer) { HRESULT hr; IADsPathname *pPath = NULL; BSTR strRootDSEPath = NULL; IADs *pRootDSE = NULL; VARIANT var = {0}; DWORD dwThreadID; HANDLE ahWait[2]; TraceEnter(TRACE_SCHEMA, "CSchemaCache::CSchemaCache");
// Initialize everything
ZeroMemory(this, sizeof(CSchemaCache)); m_hrClassResult = E_UNEXPECTED; m_hrPropertyResult = E_UNEXPECTED; m_nDsListObjectEnforced = -1; m_hLoadLibPropWaitEvent = NULL; m_hLoadLibClassWaitEvent = NULL;
m_AICommon.pAccess = g_siDSAccesses; m_AICommon.cAccesses = ARRAYSIZE(g_siDSAccesses); m_AICommon.iDefaultAccess = g_iDSDefAccess; m_AICommon.bLocalFree = FALSE;
m_hClassCache = NULL; m_hPropertyCache = NULL; m_pInheritTypeArray = NULL; m_hObjectTypeCache = NULL; m_hAccessInfoCache = NULL;
ExceptionPropagatingInitializeCriticalSection(&m_ObjectTypeCacheCritSec);
if (pszServer && !*pszServer) pszServer = NULL;
// Create a path object for manipulating ADS paths
hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_IADsPathname, (LPVOID*)&pPath); FailGracefully(hr, "Unable to create ADsPathname object");
// Build RootDSE path with server
hr = pPath->Set((LPWSTR)c_szRootDsePath, ADS_SETTYPE_FULL); FailGracefully(hr, "Unable to initialize path object"); if (pszServer) { hr = pPath->Set((LPWSTR)pszServer, ADS_SETTYPE_SERVER); FailGracefully(hr, "Unable to initialize path object"); } hr = pPath->Retrieve(ADS_FORMAT_WINDOWS, &strRootDSEPath); FailGracefully(hr, "Unable to retrieve RootDSE path from path object");
// Bind to the RootDSE object
hr = OpenDSObject(strRootDSEPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IADs, (LPVOID*)&pRootDSE); if (FAILED(hr) && pszServer) { // Try again with no server
SysFreeString(strRootDSEPath);
hr = pPath->Retrieve(ADS_FORMAT_WINDOWS_NO_SERVER, &strRootDSEPath); FailGracefully(hr, "Unable to retrieve RootDSE path from path object");
hr = OpenDSObject(strRootDSEPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IADs, (LPVOID*)&pRootDSE); } FailGracefully(hr, "Failed to bind to root DSE");
// Build the schema root path
hr = pRootDSE->Get((LPWSTR)c_szSchemaContext, &var); FailGracefully(hr, "Unable to get schema naming context");
TraceAssert(V_VT(&var) == VT_BSTR); hr = pPath->Set(V_BSTR(&var), ADS_SETTYPE_DN); FailGracefully(hr, "Unable to initialize path object");
hr = pPath->Retrieve(ADS_FORMAT_WINDOWS, &m_strSchemaSearchPath); FailGracefully(hr, "Unable to retrieve schema search path from path object");
// Build the Extended Rights container path
VariantClear(&var); hr = pRootDSE->Get((LPWSTR)c_szConfigContext, &var); FailGracefully(hr, "Unable to get configuration naming context");
TraceAssert(V_VT(&var) == VT_BSTR); hr = pPath->Set(V_BSTR(&var), ADS_SETTYPE_DN); FailGracefully(hr, "Unable to initialize path object");
hr = pPath->AddLeafElement((LPWSTR)c_szERContainer); FailGracefully(hr, "Unable to build Extended Rights path");
hr = pPath->Retrieve(ADS_FORMAT_WINDOWS, &m_strERSearchPath); FailGracefully(hr, "Unable to retrieve Extended Rights search path from path object"); //Create the Events
m_hLoadLibPropWaitEvent = CreateEvent(NULL, TRUE, FALSE, NULL ); m_hLoadLibClassWaitEvent = CreateEvent(NULL, TRUE, FALSE, NULL );
if( m_hLoadLibPropWaitEvent && m_hLoadLibClassWaitEvent ) { // Start a thread to enumerate the schema classes
m_hClassThread = CreateThread(NULL, 0, SchemaClassThread, this, 0, &dwThreadID);
// Start a thread to enumerate the schema properties
m_hPropertyThread = CreateThread(NULL, 0, SchemaPropertyThread, this, 0, &dwThreadID);
ahWait[0] = m_hClassThread; ahWait[1] = m_hPropertyThread;
WaitForMultipleObjects(2, ahWait, TRUE, INFINITE); }
exit_gracefully:
VariantClear(&var); DoRelease(pRootDSE); DoRelease(pPath); SysFreeString(strRootDSEPath); if( m_hLoadLibPropWaitEvent ) CloseHandle( m_hLoadLibPropWaitEvent ); if( m_hLoadLibClassWaitEvent ) CloseHandle( m_hLoadLibClassWaitEvent );
TraceLeaveVoid(); }
CSchemaCache::~CSchemaCache() {
TraceEnter(TRACE_SCHEMA, "CSchemaCache::~CSchemaCache");
SysFreeString(m_strSchemaSearchPath); SysFreeString(m_strERSearchPath); SysFreeString(m_strFilterFile); DeleteCriticalSection(&m_ObjectTypeCacheCritSec);
DestroyDPA(m_hClassCache); DestroyDPA(m_hPropertyCache); if(m_hObjectTypeCache) { POBJECT_TYPE_CACHE pOTC = NULL; UINT cCount = DPA_GetPtrCount(m_hObjectTypeCache); for(UINT i = 0; i < cCount; ++i) { pOTC = (POBJECT_TYPE_CACHE)DPA_FastGetPtr(m_hObjectTypeCache, i); if(pOTC) { DestroyDPA(pOTC->hListChildObject); DestroyDPA(pOTC->hListExtRights); DestroyDPA(pOTC->hListProperty); DestroyDPA(pOTC->hListPropertySet); } } } DestroyDPA(m_hObjectTypeCache);
if (m_hAccessInfoCache != NULL) { UINT cItems = DPA_GetPtrCount(m_hAccessInfoCache); PACCESS_INFO pAI = NULL; while (cItems > 0) { pAI = (PACCESS_INFO)DPA_FastGetPtr(m_hAccessInfoCache, --cItems); if(pAI && pAI->pAccess) LocalFree(pAI->pAccess); } } DestroyDPA(m_hAccessInfoCache); if (m_pInheritTypeArray != NULL) LocalFree(m_pInheritTypeArray);
TraceMsg("CSchemaCache::~CSchemaCache exiting"); TraceLeaveVoid(); }
LPCWSTR CSchemaCache::GetClassName(LPCGUID pguidObjectType) { LPCWSTR pszLdapName = NULL; PID_CACHE_ENTRY pCacheEntry;
TraceEnter(TRACE_SCHEMACLASS, "CSchemaCache::GetClassName");
pCacheEntry = LookupClass(pguidObjectType);
if (pCacheEntry != NULL) pszLdapName = pCacheEntry->szLdapName;
TraceLeaveValue(pszLdapName); }
HRESULT CSchemaCache::GetInheritTypes(LPCGUID , DWORD dwFlags, PSI_INHERIT_TYPE *ppInheritTypes, ULONG *pcInheritTypes) { // We're going to find the inherit type array corresponding to the passed-in
// object type - pInheritTypeArray will point to it!
TraceEnter(TRACE_SCHEMACLASS, "CSchemaCache::GetInheritTypes"); TraceAssert(ppInheritTypes != NULL); TraceAssert(pcInheritTypes != NULL);
*pcInheritTypes = 0; *ppInheritTypes = NULL;
// If the filter state is changing, free everything
if (m_pInheritTypeArray && (m_pInheritTypeArray->dwFlags & SCHEMA_NO_FILTER) != (dwFlags & SCHEMA_NO_FILTER)) { LocalFree(m_pInheritTypeArray); m_pInheritTypeArray = NULL; }
// Build m_pInheritTypeArray if necessary
if (m_pInheritTypeArray == NULL) { BuildInheritTypeArray(dwFlags); }
// Return m_pInheritTypeArray if we have it, otherwise
// fall back on the static types
if (m_pInheritTypeArray) { *pcInheritTypes = m_pInheritTypeArray->cInheritTypes; *ppInheritTypes = m_pInheritTypeArray->aInheritType; } else { TraceMsg("Returning default inherit information"); *ppInheritTypes = g_siDSInheritTypes; *pcInheritTypes = ARRAYSIZE(g_siDSInheritTypes); }
TraceLeaveResult(S_OK); // always succeed
}
HRESULT CSchemaCache::GetAccessRights(LPCGUID pguidObjectType, LPCWSTR pszClassName, HDPA hAuxList, LPCWSTR pszSchemaPath, DWORD dwFlags, PACCESS_INFO *ppAccessInfo) { HRESULT hr = S_OK; HCURSOR hcur;
TraceEnter(TRACE_SCHEMA, "CSchemaCache::GetAccessRights"); TraceAssert(ppAccessInfo);
BOOL bAddToCache = FALSE; PACCESS_INFO pAI = NULL; //
// If the SCHEMA_COMMON_PERM flag is on, just return the permissions
// that are common to all DS objects (including containers).
//
if (dwFlags & SCHEMA_COMMON_PERM) { *ppAccessInfo = &m_AICommon; TraceLeaveResult(S_OK); }
TraceAssert(pguidObjectType); EnterCriticalSection(&m_ObjectTypeCacheCritSec);
//
//If AuxList is null, we can return the item from cache
//
if(hAuxList == NULL) { //There is no Aux Class. Check the m_hAccessInfoCache if we have access right
//for the pguidObjectType;
if (m_hAccessInfoCache != NULL) { UINT cItems = DPA_GetPtrCount(m_hAccessInfoCache);
while (cItems > 0) { pAI = (PACCESS_INFO)DPA_FastGetPtr(m_hAccessInfoCache, --cItems); //
//Found A match.
//
if(pAI && IsEqualGUID(pAI->ObjectTypeGuid, *pguidObjectType) && ((pAI->dwFlags & (SI_EDIT_PROPERTIES | SI_EDIT_EFFECTIVE)) == (dwFlags & (SI_EDIT_PROPERTIES | SI_EDIT_EFFECTIVE))))
break;
pAI = NULL; } if(pAI) { goto exit_gracefully; } } bAddToCache = TRUE; } pAI = (PACCESS_INFO)LocalAlloc(LPTR,sizeof(ACCESS_INFO)); if(!pAI) ExitGracefully(hr, E_OUTOFMEMORY, "LocalAlloc failed"); hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
hr = BuildAccessArray(pguidObjectType, pszClassName, pszSchemaPath, hAuxList, dwFlags, &pAI->pAccess, &pAI->cAccesses, &pAI->iDefaultAccess); FailGracefully(hr, "BuildAccessArray Failed");
if(bAddToCache) { if(!m_hAccessInfoCache) m_hAccessInfoCache = DPA_Create(4); if(!m_hAccessInfoCache) ExitGracefully(hr, E_OUTOFMEMORY, "DPA_Create Failed");
pAI->dwFlags = dwFlags; pAI->ObjectTypeGuid = *pguidObjectType; DPA_AppendPtr(m_hAccessInfoCache, pAI); } //
//If item is added to cache, don't localfree it. It will be free when
//DLL is unloaded
//
pAI->bLocalFree = !bAddToCache; SetCursor(hcur);
exit_gracefully:
if(FAILED(hr)) { if(pAI) { LocalFree(pAI); pAI = NULL; } }
*ppAccessInfo = pAI;
LeaveCriticalSection(&m_ObjectTypeCacheCritSec);
TraceLeaveResult(hr); }
HRESULT CSchemaCache::GetDefaultSD(GUID *pSchemaIDGuid, PSID pDomainSid, PSID pRootDomainSid, PSECURITY_DESCRIPTOR *ppSD) { TraceEnter(TRACE_SCHEMA, "CSchemaCache::GetDefaultSD"); TraceAssert( pSchemaIDGuid != NULL); TraceAssert( ppSD != NULL );
HRESULT hr = S_OK;
if( (pDomainSid && !IsValidSid(pDomainSid)) || (pRootDomainSid && !IsValidSid(pRootDomainSid)) ) return E_INVALIDARG;
LPWSTR pszDestData = NULL; IDirectorySearch * IDs = NULL; ADS_SEARCH_HANDLE hSearchHandle=NULL; LPWSTR lpszSchemaGuidFilter = L"(schemaIdGuid=%s)"; LPWSTR pszAttr[] = {L"defaultSecurityDescriptor"}; ADS_SEARCH_COLUMN col; WCHAR szSearchBuffer[MAX_PATH];
hr = ADsEncodeBinaryData( (PBYTE)pSchemaIDGuid, sizeof(GUID), &pszDestData ); FailGracefully(hr, "ADsEncodeBinaryData Failed"); wsprintf(szSearchBuffer, lpszSchemaGuidFilter,pszDestData); //We have Filter Now
//Search in Configuration Contianer
hr = OpenDSObject( m_strSchemaSearchPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectorySearch, (void **)&IDs ); FailGracefully(hr, "OpenDSObject Failed");
hr = IDs->ExecuteSearch(szSearchBuffer, pszAttr, 1, &hSearchHandle );
FailGracefully(hr, "Search in Schema Failed");
hr = IDs->GetFirstRow(hSearchHandle); if( hr == S_OK ) { //Get Guid
hr = IDs->GetColumn( hSearchHandle, pszAttr[0], &col ); FailGracefully(hr, "Failed to get column from search result");
if(pDomainSid && pRootDomainSid) { if(!ConvertStringSDToSDDomain(pDomainSid, pRootDomainSid, (LPCWSTR)(LPWSTR)col.pADsValues->CaseIgnoreString, SDDL_REVISION_1, ppSD, NULL )) { hr = GetLastError(); IDs->FreeColumn( &col ); ExitGracefully(hr, E_FAIL, "Unable to convert String SD to SD"); } } else { if ( !ConvertStringSecurityDescriptorToSecurityDescriptor( (LPCWSTR)(LPWSTR)col.pADsValues->CaseIgnoreString, SDDL_REVISION_1, ppSD, NULL ) ) { hr = GetLastError(); IDs->FreeColumn( &col ); ExitGracefully(hr, E_FAIL, "Unable to convert String SD to SD"); } } IDs->FreeColumn( &col ); } else ExitGracefully(hr, E_FAIL, "Schema search resulted in zero rows");
exit_gracefully:
if( IDs ) { if( hSearchHandle ) IDs->CloseSearchHandle( hSearchHandle ); IDs->Release(); } FreeADsMem(pszDestData); TraceLeaveResult(hr); }
VOID AddOTLToList( POBJECT_TYPE_LIST pOTL, WORD Level, LPGUID pGuidObject ) { (pOTL)->Level = Level; (pOTL)->ObjectType = pGuidObject; }
//Get the ObjectTypeList for pSchemaGuid class
OBJECT_TYPE_LIST g_DefaultOTL[] = { {0, 0, (LPGUID)&GUID_NULL}, }; HRESULT CSchemaCache::GetObjectTypeList( GUID *pguidObjectType, HDPA hAuxList, LPCWSTR pszSchemaPath, DWORD dwFlags, POBJECT_TYPE_LIST *ppObjectTypeList, DWORD * pObjectTypeListCount) { TraceEnter(TRACE_SCHEMA, "CSchemaCache::GetObjectTypeList"); TraceAssert( pguidObjectType != NULL); TraceAssert( ppObjectTypeList != NULL ); TraceAssert( pObjectTypeListCount != NULL ); TraceAssert(pszSchemaPath != NULL);
HRESULT hr = S_OK; //
//Lists
//
HDPA hExtRightList = NULL; HDPA hPropSetList = NULL; HDPA hPropertyList = NULL; HDPA hClassList = NULL; //
//List counts
//
ULONG cExtendedRights = 0; ULONG cPropertySets = 0; UINT cProperties = 0; UINT cChildClasses = 0;
POBJECT_TYPE_LIST pOTL = NULL; POBJECT_TYPE_LIST pTempOTL = NULL;
LPCWSTR pszClassName = NULL; UINT cGuidIndex = 0;
if( dwFlags & SCHEMA_COMMON_PERM ) { *ppObjectTypeList = (POBJECT_TYPE_LIST)LocalAlloc(LPTR,sizeof(OBJECT_TYPE_LIST)*ARRAYSIZE(g_DefaultOTL)); if(!*ppObjectTypeList) TraceLeaveResult(E_OUTOFMEMORY); //
//Note that default OTL is entry with all zero,thatz what LPTR does.
//so there is no need to copy
//
*pObjectTypeListCount = ARRAYSIZE(g_DefaultOTL); TraceLeaveResult(S_OK); }
EnterCriticalSection(&m_ObjectTypeCacheCritSec);
//
// Lookup the name of this class
//
if (pszClassName == NULL) pszClassName = GetClassName(pguidObjectType);
if(!pszClassName) ExitGracefully(hr, E_UNEXPECTED, "Unknown child object GUID"); //
// Get the list of Extended Rights for this page
//
if (pguidObjectType && SUCCEEDED(GetExtendedRightsForNClasses(m_strERSearchPath, pguidObjectType, hAuxList, &hExtRightList, &hPropSetList)))
{ if(hPropSetList) cPropertySets = DPA_GetPtrCount(hPropSetList); if(hExtRightList) cExtendedRights = DPA_GetPtrCount(hExtRightList); }
//
//Get the child classes
//
if( pguidObjectType && SUCCEEDED(GetChildClassesForNClasses(pguidObjectType, pszClassName, hAuxList, pszSchemaPath, &hClassList))) {
if(hClassList) cChildClasses = DPA_GetPtrCount(hClassList); } //
//Get the properties for the class
//
if (pguidObjectType && SUCCEEDED(GetPropertiesForNClasses(pguidObjectType, pszClassName, hAuxList, pszSchemaPath, &hPropertyList))) { if(hPropertyList) cProperties = DPA_GetPtrCount(hPropertyList); } pOTL = (POBJECT_TYPE_LIST)LocalAlloc(LPTR, (cPropertySets + cExtendedRights + cChildClasses + cProperties + 1)* sizeof(OBJECT_TYPE_LIST)); if(!pOTL) ExitGracefully(hr, E_OUTOFMEMORY, "Unable to create POBJECT_TYPE_LIST");
pTempOTL = pOTL;
//
//First Add the entry corresponding to Object
//
AddOTLToList(pTempOTL, ACCESS_OBJECT_GUID, pguidObjectType); pTempOTL++; cGuidIndex++; UINT i, j; for (i = 0; i < cExtendedRights; i++) { PER_ENTRY pER = (PER_ENTRY)DPA_FastGetPtr(hExtRightList, i); AddOTLToList(pTempOTL, ACCESS_PROPERTY_SET_GUID, &(pER->guid)); pTempOTL++; cGuidIndex++; } //
//Add Property Set
//
for(i = 0; i < cPropertySets; ++i) { PER_ENTRY pER = (PER_ENTRY)DPA_FastGetPtr(hPropSetList, i); AddOTLToList(pTempOTL, ACCESS_PROPERTY_SET_GUID, &pER->guid); cGuidIndex++; pTempOTL++; //
//Add all the properties which are member of this property set
//
for(j = 0; j < cProperties; ++j) { PPROP_ENTRY pProp = (PPROP_ENTRY)DPA_FastGetPtr(hPropertyList, j); if(IsEqualGUID(pER->guid, *pProp->pasguid)) { AddOTLToList(pTempOTL, ACCESS_PROPERTY_GUID, pProp->pguid); cGuidIndex++; pTempOTL++; pProp->dwFlags|= OTL_ADDED_TO_LIST; } } }
//Add all remaining properties
for( j =0; j < cProperties; ++j ) { PPROP_ENTRY pProp = (PPROP_ENTRY)DPA_FastGetPtr(hPropertyList, j); if( !(pProp->dwFlags & OTL_ADDED_TO_LIST) ) { AddOTLToList(pTempOTL, ACCESS_PROPERTY_SET_GUID, pProp->pguid); pTempOTL++; cGuidIndex++; } pProp->dwFlags &= ~OTL_ADDED_TO_LIST; } //All all child clasess
for( j = 0; j < cChildClasses; ++j ) { PPROP_ENTRY pClass= (PPROP_ENTRY)DPA_FastGetPtr(hClassList, j); AddOTLToList(pTempOTL, ACCESS_PROPERTY_SET_GUID, pClass->pguid); pTempOTL++; cGuidIndex++; }
exit_gracefully:
DPA_Destroy(hExtRightList); DPA_Destroy(hClassList); DPA_Destroy(hPropertyList); DPA_Destroy(hPropSetList);
LeaveCriticalSection(&m_ObjectTypeCacheCritSec);
if (FAILED(hr)) { *ppObjectTypeList = NULL; *pObjectTypeListCount = 0; } else { *ppObjectTypeList = pOTL; *pObjectTypeListCount = cGuidIndex; }
TraceLeaveResult(hr); }
PID_CACHE_ENTRY CSchemaCache::LookupID(HDPA hCache, LPCWSTR pszLdapName) { PID_CACHE_ENTRY pCacheEntry = NULL; int iEntry;
TraceEnter(TRACE_SCHEMA, "CSchemaCache::LookupID"); TraceAssert(hCache != NULL); TraceAssert(pszLdapName != NULL && *pszLdapName);
iEntry = DPA_Search(hCache, NULL, 0, Schema_CompareLdapName, (LPARAM)pszLdapName, DPAS_SORTED);
if (iEntry != -1) pCacheEntry = (PID_CACHE_ENTRY)DPA_FastGetPtr(hCache, iEntry);
TraceLeaveValue(pCacheEntry); }
BOOL CSchemaCache::IsAuxClass(LPCGUID pguidObjectType) { PID_CACHE_ENTRY pCacheEntry = NULL; HRESULT hr = S_OK; UINT cItems;
TraceEnter(TRACE_SCHEMACLASS, "CSchemaCache::LookupClass"); TraceAssert(pguidObjectType != NULL); if(IsEqualGUID(*pguidObjectType, GUID_NULL)) return FALSE;
hr = WaitOnClassThread(); FailGracefully(hr, "Class cache unavailable");
TraceAssert(m_hClassCache != NULL);
cItems = DPA_GetPtrCount(m_hClassCache);
while (cItems > 0) { PID_CACHE_ENTRY pTemp = (PID_CACHE_ENTRY)DPA_FastGetPtr(m_hClassCache, --cItems);
if (IsEqualGUID(*pguidObjectType, pTemp->guid)) { pCacheEntry = pTemp; break; } }
exit_gracefully:
if(pCacheEntry) return pCacheEntry->bAuxClass; else return FALSE; }
PID_CACHE_ENTRY CSchemaCache::LookupClass(LPCGUID pguidObjectType) { PID_CACHE_ENTRY pCacheEntry = NULL; HRESULT hr = S_OK; UINT cItems;
TraceEnter(TRACE_SCHEMACLASS, "CSchemaCache::LookupClass"); TraceAssert(pguidObjectType != NULL); TraceAssert(!IsEqualGUID(*pguidObjectType, GUID_NULL));
hr = WaitOnClassThread(); FailGracefully(hr, "Class cache unavailable");
TraceAssert(m_hClassCache != NULL);
cItems = DPA_GetPtrCount(m_hClassCache);
while (cItems > 0) { PID_CACHE_ENTRY pTemp = (PID_CACHE_ENTRY)DPA_FastGetPtr(m_hClassCache, --cItems);
if (IsEqualGUID(*pguidObjectType, pTemp->guid)) { pCacheEntry = pTemp; break; } }
exit_gracefully:
TraceLeaveValue(pCacheEntry); }
HRESULT CSchemaCache::LookupClassID(LPCWSTR pszClass, LPGUID pGuid) { TraceEnter(TRACE_SCHEMACLASS, "CSchemaCache::LookupClassID"); TraceAssert(pszClass != NULL && pGuid != NULL);
HRESULT hr = WaitOnClassThread(); if(SUCCEEDED(hr)) { TraceAssert(m_hClassCache != NULL); PID_CACHE_ENTRY pCacheEntry = LookupID(m_hClassCache, pszClass); if (pCacheEntry) *pGuid = pCacheEntry->guid; }
return hr; }
LPCGUID CSchemaCache::LookupPropertyID(LPCWSTR pszProperty) { LPCGUID pID = NULL;
TraceEnter(TRACE_SCHEMAPROP, "CSchemaCache::LookupPropertyID"); TraceAssert(pszProperty != NULL);
if (SUCCEEDED(WaitOnPropertyThread())) { TraceAssert(m_hPropertyCache != NULL); PID_CACHE_ENTRY pCacheEntry = LookupID(m_hPropertyCache, pszProperty); if (pCacheEntry) pID = &pCacheEntry->guid; }
TraceLeaveValue(pID); }
WCHAR const c_szDsHeuristics[] = L"dSHeuristics";
int CSchemaCache::GetListObjectEnforced(void) { int nListObjectEnforced = 0; // Assume "not enforced"
HRESULT hr; IADsPathname *pPath = NULL; const LPWSTR aszServicePath[] = { L"CN=Services", L"CN=Windows NT", L"CN=Directory Service", }; BSTR strServicePath = NULL; IDirectoryObject *pDirectoryService = NULL; LPWSTR pszDsHeuristics = (LPWSTR)c_szDsHeuristics; PADS_ATTR_INFO pAttributeInfo = NULL; DWORD dwAttributesReturned; LPWSTR pszHeuristicString; int i;
TraceEnter(TRACE_SCHEMA, "CSchemaCache::GetListObjectEnforced");
// Create a path object for manipulating ADS paths
hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_IADsPathname, (LPVOID*)&pPath); FailGracefully(hr, "Unable to create ADsPathname object");
hr = pPath->Set(m_strERSearchPath, ADS_SETTYPE_FULL); FailGracefully(hr, "Unable to initialize ADsPathname object");
hr = pPath->RemoveLeafElement(); for (i = 0; i < ARRAYSIZE(aszServicePath); i++) { hr = pPath->AddLeafElement(aszServicePath[i]); FailGracefully(hr, "Unable to build path to 'Directory Service' object"); }
hr = pPath->Retrieve(ADS_FORMAT_WINDOWS, &strServicePath); FailGracefully(hr, "Unable to build path to 'Directory Service' object");
hr = ADsGetObject(strServicePath, IID_IDirectoryObject, (LPVOID*)&pDirectoryService); FailGracefully(hr, "Unable to bind to 'Directory Service' object for heuristics");
hr = pDirectoryService->GetObjectAttributes(&pszDsHeuristics, 1, &pAttributeInfo, &dwAttributesReturned); if (!pAttributeInfo) ExitGracefully(hr, hr, "GetObjectAttributes failed to read dSHeuristics property");
TraceAssert(ADSTYPE_DN_STRING <= pAttributeInfo->dwADsType); TraceAssert(ADSTYPE_NUMERIC_STRING >= pAttributeInfo->dwADsType); TraceAssert(1 == pAttributeInfo->dwNumValues);
pszHeuristicString = pAttributeInfo->pADsValues->NumericString; if (pszHeuristicString && lstrlenW(pszHeuristicString) > 2 && L'0' != pszHeuristicString[2]) { nListObjectEnforced = 1; }
exit_gracefully:
if (pAttributeInfo) FreeADsMem(pAttributeInfo);
DoRelease(pDirectoryService); DoRelease(pPath);
SysFreeString(strServicePath);
TraceLeaveValue(nListObjectEnforced); }
BOOL CSchemaCache::HideListObjectAccess(void) { TraceEnter(TRACE_SCHEMA, "CSchemaCache::HideListObjectAccess");
if (-1 == m_nDsListObjectEnforced) { m_nDsListObjectEnforced = GetListObjectEnforced(); }
TraceLeaveValue(0 == m_nDsListObjectEnforced); }
#define ACCESS_LENGTH_0 (sizeof(SI_ACCESS) + MAX_TYPENAME_LENGTH * sizeof(WCHAR))
#define ACCESS_LENGTH_1 (sizeof(SI_ACCESS) + MAX_TYPENAME_LENGTH * sizeof(WCHAR))
#define ACCESS_LENGTH_2 (3 * sizeof(SI_ACCESS) + 3 * MAX_TYPENAME_LENGTH * sizeof(WCHAR))
HRESULT CSchemaCache::BuildAccessArray(LPCGUID pguidObjectType, LPCWSTR pszClassName, LPCWSTR pszSchemaPath, HDPA hAuxList, DWORD dwFlags, PSI_ACCESS *ppAccesses, ULONG *pcAccesses, ULONG *piDefaultAccess) { HRESULT hr = S_OK; DWORD dwBufferLength = 0; UINT cMaxAccesses; LPWSTR pszData = NULL; //
//Lists
//
HDPA hExtRightList = NULL; HDPA hPropSetList = NULL; HDPA hPropertyList = NULL; HDPA hClassList = NULL; //
//List counts
//
ULONG cExtendedRights = 0; ULONG cPropertySets = 0; UINT cProperties = 0; UINT cChildClasses = 0;
ULONG cBaseRights = 0; PSI_ACCESS pAccesses = NULL; PSI_ACCESS pTempAccesses = NULL; ULONG cAccesses = 0;
TraceEnter(TRACE_SCHEMA, "CSchemaCache::BuildAccessArray"); TraceAssert(pguidObjectType != NULL); TraceAssert(ppAccesses); TraceAssert(pcAccesses); TraceAssert(piDefaultAccess);
*ppAccesses = NULL; *pcAccesses = 0; *piDefaultAccess = 0; //
//Decide what all we need
//
BOOL bBasicRight = FALSE; BOOL bExtRight = FALSE; BOOL bChildClass = FALSE; BOOL bProp = FALSE;
//
// Lookup the name of this class
//
if (pszClassName == NULL) pszClassName = GetClassName(pguidObjectType); if(pszClassName == NULL) ExitGracefully(hr, E_UNEXPECTED, "Unknown child object GUID");
if(dwFlags & SI_EDIT_PROPERTIES) { bProp = TRUE; } else if(dwFlags & SI_EDIT_EFFECTIVE) { bExtRight = TRUE; bChildClass = TRUE; bProp = TRUE; } else { bExtRight = TRUE; bChildClass = TRUE; } //
//We don't show basicRights for Auxillary Classes.
//This happens when user selects Aux Class in Applyonto combo
//
bBasicRight = !IsAuxClass(pguidObjectType); //
// Get the list of Extended Rights for this page
//
if (pguidObjectType && SUCCEEDED(GetExtendedRightsForNClasses(m_strERSearchPath, pguidObjectType, hAuxList, bExtRight ? &hExtRightList : NULL, &hPropSetList)))
{ if(hPropSetList) cPropertySets = DPA_GetPtrCount(hPropSetList); if(hExtRightList) cExtendedRights = DPA_GetPtrCount(hExtRightList); }
if( bChildClass && pguidObjectType && SUCCEEDED(GetChildClassesForNClasses(pguidObjectType, pszClassName, hAuxList, pszSchemaPath, &hClassList))) {
if(hClassList) cChildClasses = DPA_GetPtrCount(hClassList); }
//
//Get the properties for the class
//
if (bProp && pguidObjectType && SUCCEEDED(GetPropertiesForNClasses(pguidObjectType, pszClassName, hAuxList, pszSchemaPath, &hPropertyList))) { if(hPropertyList) cProperties = DPA_GetPtrCount(hPropertyList); } if(bBasicRight) { //
//Only Read Property and write Property
//
if(dwFlags & SI_EDIT_PROPERTIES) { cBaseRights = 2; } else { cBaseRights = ARRAYSIZE(g_siDSAccesses); if (!cChildClasses) cBaseRights -= 3; // skip DS_CREATE_CHILD and DS_DELETE_CHILD and both
} }
//
//Three Entries per Child Class 1)Create 2)Delete 3) Create/Delete
//Three Entries per Prop Class 1) Read 2)Write 3)Read/Write
//
cMaxAccesses = cBaseRights + cExtendedRights + 3 * cChildClasses + 3 * cPropertySets + 3 * cProperties; //
//This can happen for Aux Class Object Right page
//As we don't show general rights for it.
//
if(cMaxAccesses == 0) goto exit_gracefully; //
// Allocate a buffer for the access array
//
dwBufferLength = cBaseRights * sizeof(SI_ACCESS) + cExtendedRights * ACCESS_LENGTH_1 + cChildClasses * ACCESS_LENGTH_2 + cPropertySets * ACCESS_LENGTH_2 + cProperties * ACCESS_LENGTH_2; pAccesses = (PSI_ACCESS)LocalAlloc(LPTR, dwBufferLength); if (pAccesses == NULL) ExitGracefully(hr, E_OUTOFMEMORY, "LocalAlloc failed");
pTempAccesses = pAccesses; pszData = (LPWSTR)(pTempAccesses + cMaxAccesses);
//
//Copy the basic right
//
if(bBasicRight) { if(dwFlags & SI_EDIT_PROPERTIES) { //
// Add "Read All Properties" and "Write All Properties"
//
CopyMemory(pTempAccesses, &g_siDSAccesses[g_iDSProperties], 2 * sizeof(SI_ACCESS)); pTempAccesses += 2; cAccesses += 2; } else { //
// Add normal entries
//
CopyMemory(pTempAccesses, g_siDSAccesses, cBaseRights * sizeof(SI_ACCESS)); pTempAccesses += cBaseRights; cAccesses += cBaseRights;
if (HideListObjectAccess()) { pAccesses[g_iDSRead].mask &= ~ACTRL_DS_LIST_OBJECT; pAccesses[g_iDSListObject].dwFlags = 0; } //
//If there are no child objects, don't show create/delete child objects
//
if(cChildClasses == 0) pAccesses[g_iDSDeleteTree].dwFlags = 0;
} }
//
// Add entries for creating & deleting child objects
//
if (bChildClass && cChildClasses) { TraceAssert(NULL != hClassList);
cAccesses += AddTempListToAccessList(hClassList, &pTempAccesses, &pszData, SI_ACCESS_SPECIFIC, SCHEMA_CLASS | (dwFlags & SCHEMA_NO_FILTER), FALSE); }
if(bExtRight) { //
//Decide if to show "All Extended Rights" entry
//and "All Validated Right Entry
//
BOOL bAllExtRights = FALSE; BOOL bAllValRights = FALSE; if(cExtendedRights) { //
// Add entries for Extended Rights
//
UINT i; for (i = 0; i < cExtendedRights; i++) { PER_ENTRY pER = (PER_ENTRY)DPA_FastGetPtr(hExtRightList, i);
//
//Show All Validated Right entry only if atleast one
//individual Validated Right is present
//
if(pER->mask & ACTRL_DS_SELF) bAllValRights = TRUE;
//
//Show All Validated Right entry only if atleast one
//individual Validated Right is present
//
if(pER->mask & ACTRL_DS_CONTROL_ACCESS) bAllExtRights = TRUE;
pTempAccesses->mask = pER->mask; //
//Extended Rights Are shown on both first page and advanced page
//
pTempAccesses->dwFlags = SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC; pTempAccesses->pguid = &pER->guid; pTempAccesses->pszName = pszData; lstrcpynW(pszData, pER->szName, MAX_TYPENAME_LENGTH); pszData += (lstrlen(pTempAccesses->pszName) + 1); pTempAccesses++; cAccesses++; } } if(!bAllExtRights && bBasicRight) pAccesses[g_iDSAllExtRights].dwFlags = 0;
if(!bAllValRights && bBasicRight) pAccesses[g_iDSAllValRights].dwFlags = 0;
}
//
//Add PropertySet Entries
//
if (cPropertySets > 0) { cAccesses += AddTempListToAccessList(hPropSetList, &pTempAccesses, &pszData, SI_ACCESS_GENERAL|SI_ACCESS_PROPERTY, (dwFlags & SCHEMA_NO_FILTER), TRUE); }
//
// Add property entries
//
if (bProp && cProperties > 0) { cAccesses += AddTempListToAccessList(hPropertyList, &pTempAccesses, &pszData, SI_ACCESS_PROPERTY, (dwFlags & SCHEMA_NO_FILTER), FALSE); }
*ppAccesses = pAccesses; *pcAccesses = cAccesses; *piDefaultAccess = bBasicRight ? g_iDSDefAccess : 0;
exit_gracefully:
if(hExtRightList) DPA_Destroy(hExtRightList); if(hClassList) DPA_Destroy(hClassList); if(hPropertyList) DPA_Destroy(hPropertyList); if(hPropSetList) DPA_Destroy(hPropSetList);
TraceLeaveResult(hr); }
HRESULT CSchemaCache::EnumVariantList(LPVARIANT pvarList, HDPA hTempList, DWORD dwFlags, IDsDisplaySpecifier *pDisplaySpec, LPCWSTR pszPropertyClass, BOOL ) { HRESULT hr = S_OK; LPVARIANT pvarItem = NULL; int cItems; BOOL bSafeArrayLocked = FALSE;
TraceEnter(TRACE_SCHEMA, "CSchemaCache::EnumVariantList"); TraceAssert(pvarList != NULL); TraceAssert(hTempList != NULL);
if (dwFlags & SCHEMA_CLASS) hr = WaitOnClassThread(); else hr = WaitOnPropertyThread();
FailGracefully(hr, "Required Cache Not Available");
if (V_VT(pvarList) == (VT_ARRAY | VT_VARIANT)) { hr = SafeArrayAccessData(V_ARRAY(pvarList), (LPVOID*)&pvarItem); FailGracefully(hr, "Unable to access SafeArray"); bSafeArrayLocked = TRUE; cItems = V_ARRAY(pvarList)->rgsabound[0].cElements; } else if (V_VT(pvarList) == VT_BSTR) // Single entry in list
{ pvarItem = pvarList; cItems = 1; } else { // Unknown format
ExitGracefully(hr, E_INVALIDARG, "Unexpected VARIANT type"); }
if (NULL == m_strFilterFile) m_strFilterFile = GetFilterFilePath();
//
// Enumerate the variant list and get information about each
// (filter, guid, display name)
//
for ( ; cItems > 0; pvarItem++, cItems--) { LPWSTR pszItem; DWORD dwFilter = 0; WCHAR wszDisplayName[MAX_PATH]; PPROP_ENTRY pti; PID_CACHE_ENTRY pid ;
//
//Get the ldapDisplayName
//
TraceAssert(V_VT(pvarItem) == VT_BSTR); pszItem = V_BSTR(pvarItem);
//
// Check for nonexistent or empty strings
//
if (!pszItem || !*pszItem) continue;
//
//Check if the string is filtered by dssec.dat file
//
if(m_strFilterFile) { if (dwFlags & SCHEMA_CLASS) { dwFilter = GetPrivateProfileIntW(pszItem, c_szClassKey, 0, m_strFilterFile); if(pszPropertyClass) dwFilter |= GetPrivateProfileIntW(pszPropertyClass, pszItem, 0, m_strFilterFile);
} else if (pszPropertyClass) { dwFilter = GetPrivateProfileIntW(pszPropertyClass, pszItem, 0, m_strFilterFile); } } //
// Note that IDC_CLASS_NO_CREATE == IDC_PROP_NO_READ
// and IDC_CLASS_NO_DELETE == IDC_PROP_NO_WRITE
//
dwFilter &= (IDC_CLASS_NO_CREATE | IDC_CLASS_NO_DELETE);
//
//Get the schema or property cache entry
//
if (dwFlags & SCHEMA_CLASS) pid = LookupID(m_hClassCache, pszItem); else pid = LookupID(m_hPropertyCache, pszItem); if(pid == NULL) continue;
//
//Get the Display Name
//
wszDisplayName[0] = L'\0';
if (pDisplaySpec) { if (dwFlags & SCHEMA_CLASS) { pDisplaySpec->GetFriendlyClassName(pszItem, wszDisplayName, ARRAYSIZE(wszDisplayName)); } else if (pszPropertyClass) { pDisplaySpec->GetFriendlyAttributeName(pszPropertyClass, pszItem, wszDisplayName, ARRAYSIZE(wszDisplayName)); } }
LPWSTR pszDisplay; pszDisplay = (wszDisplayName[0] != L'\0') ? wszDisplayName : pszItem; //
// Remember what we've got so far
//
pti = (PPROP_ENTRY)LocalAlloc(LPTR, sizeof(PROP_ENTRY) + StringByteSize(pszDisplay)); if (pti) { pti->pguid = &pid->guid; pti->pasguid = &pid->asGuid; pti->dwFlags |= dwFilter; lstrcpyW(pti->szName, pszDisplay); DPA_AppendPtr(hTempList, pti); } }
exit_gracefully:
if (bSafeArrayLocked) SafeArrayUnaccessData(V_ARRAY(pvarList));
TraceLeaveResult(hr); }
UINT CSchemaCache::AddTempListToAccessList(HDPA hTempList, PSI_ACCESS *ppAccess, LPWSTR *ppszData, DWORD dwAccessFlags, DWORD dwFlags, BOOL bPropSet) { UINT cTotalEntries = 0; int cItems; DWORD dwAccess1; DWORD dwAccess2; WCHAR szFmt1[MAX_TYPENAME_LENGTH]; WCHAR szFmt2[MAX_TYPENAME_LENGTH]; WCHAR szFmt3[MAX_TYPENAME_LENGTH];
TraceEnter(TRACE_SCHEMA, "CSchemaCache::AddTempListToAccessList"); TraceAssert(ppAccess != NULL); TraceAssert(ppszData != NULL);
cItems = DPA_GetPtrCount(hTempList); if (0 == cItems) ExitGracefully(cTotalEntries, 0, "empty list");
if (dwFlags & SCHEMA_CLASS) { dwAccess1 = ACTRL_DS_CREATE_CHILD; dwAccess2 = ACTRL_DS_DELETE_CHILD; LoadStringW(GLOBAL_HINSTANCE, IDS_DS_CREATE_CHILD_TYPE, szFmt1, ARRAYSIZE(szFmt1)); LoadStringW(GLOBAL_HINSTANCE, IDS_DS_DELETE_CHILD_TYPE, szFmt2, ARRAYSIZE(szFmt2)); LoadStringW(GLOBAL_HINSTANCE, IDS_DS_CREATEDELETE_TYPE, szFmt3, ARRAYSIZE(szFmt3)); } else { dwAccess1 = ACTRL_DS_READ_PROP; dwAccess2 = ACTRL_DS_WRITE_PROP; LoadStringW(GLOBAL_HINSTANCE, IDS_DS_READ_PROP_TYPE, szFmt1, ARRAYSIZE(szFmt1)); LoadStringW(GLOBAL_HINSTANCE, IDS_DS_WRITE_PROP_TYPE, szFmt2, ARRAYSIZE(szFmt2)); LoadStringW(GLOBAL_HINSTANCE, IDS_DS_READWRITE_TYPE, szFmt3, ARRAYSIZE(szFmt3)); }
// Enumerate the list and make up to 2 entries for each
for(int i = 0; i < cItems; ++i) { PER_ENTRY pER = NULL; PPROP_ENTRY pProp = NULL; LPWSTR pszData; LPGUID pGuid = NULL; PSI_ACCESS pNewAccess; LPCWSTR pszName; int cch; DWORD dwAccess3; DWORD dwFilter = 0; if(bPropSet) { pER = (PER_ENTRY)DPA_FastGetPtr(hTempList, i); if (!pER) continue; pGuid = &pER->guid; pszName = pER->szName; dwFilter = 0; } else { pProp = (PPROP_ENTRY)DPA_FastGetPtr(hTempList, i); if (!pProp) continue; pGuid = pProp->pguid; pszName = pProp->szName; dwFilter = pProp->dwFlags; } pszData = *ppszData; pNewAccess = *ppAccess;
dwAccess3 = 0; if ((dwFlags & SCHEMA_NO_FILTER) || !(dwFilter & IDC_CLASS_NO_CREATE)) { pNewAccess->mask = dwAccess1; pNewAccess->dwFlags = dwAccessFlags; pNewAccess->pguid = pGuid;
pNewAccess->pszName = (LPCWSTR)pszData; cch = wsprintfW((LPWSTR)pszData, szFmt1, pszName); pszData += (cch + 1);
cTotalEntries++; pNewAccess++;
dwAccess3 |= dwAccess1; }
if ((dwFlags & SCHEMA_NO_FILTER) || !(dwFilter & IDC_CLASS_NO_DELETE)) { pNewAccess->mask = dwAccess2; pNewAccess->dwFlags = dwAccessFlags; pNewAccess->pguid = pGuid;
pNewAccess->pszName = (LPCWSTR)pszData; cch = wsprintfW((LPWSTR)pszData, szFmt2, pszName); pszData += (cch + 1);
cTotalEntries++; pNewAccess++;
dwAccess3 |= dwAccess2; }
if (dwAccess3 == (dwAccess1 | dwAccess2)) { // Add a hidden entry for
// "Read/write <prop>"
// or
// "Create/delete <child>"
pNewAccess->mask = dwAccess3; // dwFlags = 0 means it will never show as a checkbox, but it
// may be used for the name displayed on the Advanced page.
pNewAccess->dwFlags = 0; pNewAccess->pguid = pGuid;
pNewAccess->pszName = (LPCWSTR)pszData; cch = wsprintfW((LPWSTR)pszData, szFmt3, pszName); pszData += (cch + 1);
cTotalEntries++; pNewAccess++; }
if (*ppAccess != pNewAccess) { *ppAccess = pNewAccess; // move past new entries
*ppszData = pszData; } }
exit_gracefully:
TraceLeaveValue(cTotalEntries); }
DWORD WINAPI CSchemaCache::SchemaClassThread(LPVOID pvThreadData) { PSCHEMACACHE pCache;
HINSTANCE hInstThisDll = LoadLibrary(c_szDllName); InterlockedIncrement(&GLOBAL_REFCOUNT);
pCache = (PSCHEMACACHE)pvThreadData; SetEvent(pCache->m_hLoadLibClassWaitEvent); TraceEnter(TRACE_SCHEMACLASS, "CSchemaCache::SchemaClassThread"); TraceAssert(pCache != NULL); TraceAssert(pCache->m_strSchemaSearchPath != NULL);
#if DBG
DWORD dwTime = GetTickCount(); #endif
ThreadCoInitialize();
pCache->m_hrClassResult = Schema_Search(pCache->m_strSchemaSearchPath, c_szClassFilter, &pCache->m_hClassCache, FALSE);
ThreadCoUninitialize();
#if DBG
Trace((TEXT("SchemaClassThread complete, elapsed time: %d ms"), GetTickCount() - dwTime)); #endif
TraceLeave();
InterlockedDecrement(&GLOBAL_REFCOUNT); FreeLibraryAndExitThread(hInstThisDll, 0); }
DWORD WINAPI CSchemaCache::SchemaPropertyThread(LPVOID pvThreadData) { PSCHEMACACHE pCache = NULL;
HINSTANCE hInstThisDll = LoadLibrary(c_szDllName); InterlockedIncrement(&GLOBAL_REFCOUNT);
pCache = (PSCHEMACACHE)pvThreadData; SetEvent(pCache->m_hLoadLibPropWaitEvent); TraceEnter(TRACE_SCHEMAPROP, "CSchemaCache::SchemaPropertyThread"); TraceAssert(pCache != NULL); TraceAssert(pCache->m_strSchemaSearchPath != NULL);
#if DBG
DWORD dwTime = GetTickCount(); #endif
ThreadCoInitialize();
pCache->m_hrPropertyResult = Schema_Search(pCache->m_strSchemaSearchPath, c_szPropertyFilter, &pCache->m_hPropertyCache, TRUE);
ThreadCoUninitialize();
#if DBG
Trace((TEXT("SchemaPropertyThread complete, elapsed time: %d ms"), GetTickCount() - dwTime)); #endif
TraceLeave();
InterlockedDecrement(&GLOBAL_REFCOUNT); FreeLibraryAndExitThread(hInstThisDll, 0);
}
HRESULT CSchemaCache::BuildInheritTypeArray(DWORD dwFlags) { HRESULT hr = S_OK; int cItems = 0; DWORD cbNames = 0; DWORD dwBufferLength; PINHERIT_TYPE_ARRAY pInheritTypeArray = NULL; PSI_INHERIT_TYPE pNewInheritType; LPGUID pGuidData = NULL; LPWSTR pszData = NULL; WCHAR szFormat[MAX_TYPENAME_LENGTH]; HDPA hTempList = NULL; PTEMP_INFO pti; IDsDisplaySpecifier *pDisplaySpec = NULL;
TraceEnter(TRACE_SCHEMACLASS, "CSchemaCache::BuildInheritTypeArray"); TraceAssert(m_pInheritTypeArray == NULL); // Don't want to build this twice
if (NULL == m_strFilterFile) m_strFilterFile = GetFilterFilePath();
hr = WaitOnClassThread(); FailGracefully(hr, "Class cache unavailable");
cItems = DPA_GetPtrCount(m_hClassCache); if (cItems == 0) ExitGracefully(hr, E_FAIL, "No schema classes available");
hTempList = DPA_Create(cItems); if (!hTempList) ExitGracefully(hr, E_OUTOFMEMORY, "Unable to create DPA");
// Get the display specifier object
CoCreateInstance(CLSID_DsDisplaySpecifier, NULL, CLSCTX_INPROC_SERVER, IID_IDsDisplaySpecifier, (void**)&pDisplaySpec);
// Enumerate child types, apply filtering, and get display names
while (cItems > 0) { PID_CACHE_ENTRY pCacheEntry; WCHAR wszDisplayName[MAX_PATH];
pCacheEntry = (PID_CACHE_ENTRY)DPA_FastGetPtr(m_hClassCache, --cItems);
if (!pCacheEntry) continue; if (m_strFilterFile && !(dwFlags & SCHEMA_NO_FILTER)) { DWORD dwFilter = GetPrivateProfileIntW(pCacheEntry->szLdapName, c_szClassKey, 0, m_strFilterFile); if (dwFilter & IDC_CLASS_NO_INHERIT) continue; }
wszDisplayName[0] = L'\0';
if (pDisplaySpec) { pDisplaySpec->GetFriendlyClassName(pCacheEntry->szLdapName, wszDisplayName, ARRAYSIZE(wszDisplayName)); }
if (L'\0' != wszDisplayName[0]) cbNames += StringByteSize(wszDisplayName); else cbNames += StringByteSize(pCacheEntry->szLdapName);
pti = (PTEMP_INFO)LocalAlloc(LPTR, sizeof(TEMP_INFO) + sizeof(WCHAR)*lstrlenW(wszDisplayName)); if (pti) { pti->pguid = &pCacheEntry->guid; pti->pszLdapName = pCacheEntry->szLdapName; lstrcpyW(pti->szDisplayName, wszDisplayName); DPA_AppendPtr(hTempList, pti); } }
// Sort by display name
DPA_Sort(hTempList, Schema_CompareTempDisplayName, 0);
// Get an accurate count
cItems = DPA_GetPtrCount(hTempList);
//
// Allocate a buffer for the inherit type array
//
dwBufferLength = sizeof(INHERIT_TYPE_ARRAY) - sizeof(SI_INHERIT_TYPE) + sizeof(g_siDSInheritTypes) + cItems * (sizeof(SI_INHERIT_TYPE) + sizeof(GUID) + MAX_TYPENAME_LENGTH*sizeof(WCHAR)) + cbNames;
pInheritTypeArray = (PINHERIT_TYPE_ARRAY)LocalAlloc(LPTR, dwBufferLength); if (pInheritTypeArray == NULL) ExitGracefully(hr, E_OUTOFMEMORY, "LocalAlloc failed");
pInheritTypeArray->cInheritTypes = ARRAYSIZE(g_siDSInheritTypes);
pNewInheritType = pInheritTypeArray->aInheritType; pGuidData = (LPGUID)(pNewInheritType + pInheritTypeArray->cInheritTypes + cItems); pszData = (LPWSTR)(pGuidData + cItems);
// Copy static entries
CopyMemory(pNewInheritType, g_siDSInheritTypes, sizeof(g_siDSInheritTypes)); pNewInheritType += ARRAYSIZE(g_siDSInheritTypes);
// Load format string
LoadString(GLOBAL_HINSTANCE, IDS_DS_INHERIT_TYPE, szFormat, ARRAYSIZE(szFormat));
// Enumerate child types and make an entry for each
while (cItems > 0) { int cch; LPCWSTR pszDisplayName;
pti = (PTEMP_INFO)DPA_FastGetPtr(hTempList, --cItems); if (!pti) continue;
if (pti->szDisplayName[0]) pszDisplayName = pti->szDisplayName; else pszDisplayName = pti->pszLdapName;
pNewInheritType->dwFlags = CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
// The class entry name is the child class name, e.g. "Domain" or "User"
pNewInheritType->pszName = pszData; cch = wsprintfW(pszData, szFormat, pszDisplayName); pszData += (cch + 1);
pNewInheritType->pguid = pGuidData; *pGuidData = *pti->pguid; pGuidData++;
pNewInheritType++; pInheritTypeArray->cInheritTypes++; }
exit_gracefully:
DoRelease(pDisplaySpec);
if (SUCCEEDED(hr)) { m_pInheritTypeArray = pInheritTypeArray; // Set this master inherit type array's GUID to null
m_pInheritTypeArray->guidObjectType = GUID_NULL; m_pInheritTypeArray->dwFlags = (dwFlags & SCHEMA_NO_FILTER); } else if (pInheritTypeArray != NULL) { LocalFree(pInheritTypeArray); }
DestroyDPA(hTempList);
TraceLeaveResult(hr); }
HRESULT Schema_BindToObject(LPCWSTR pszSchemaPath, LPCWSTR pszName, REFIID riid, LPVOID *ppv) { HRESULT hr; WCHAR szPath[MAX_PATH]; UINT nSchemaRootLen; WCHAR chTemp;
TraceEnter(TRACE_SCHEMA, "Schema_BindToObject"); TraceAssert(pszSchemaPath != NULL); TraceAssert(pszName == NULL || *pszName); TraceAssert(ppv != NULL);
if (pszSchemaPath == NULL) { ExitGracefully(hr, E_INVALIDARG, "No schema path provided"); }
nSchemaRootLen = lstrlenW(pszSchemaPath);
//
// Build the schema path to this object
//
lstrcpynW(szPath, pszSchemaPath, nSchemaRootLen + 1); chTemp = szPath[nSchemaRootLen-1]; if (pszName != NULL) { // If there is no trailing slash, add it
if (chTemp != TEXT('/')) { szPath[nSchemaRootLen] = TEXT('/'); nSchemaRootLen++; }
// Add the class or property name onto the end
lstrcpynW(szPath + nSchemaRootLen, pszName, ARRAYSIZE(szPath) - nSchemaRootLen); } else if (nSchemaRootLen > 0) { // If there is a trailing slash, remove it
if (chTemp == TEXT('/')) szPath[nSchemaRootLen-1] = TEXT('\0'); } else { ExitGracefully(hr, E_INVALIDARG, "Empty schema path"); }
//
// Instantiate the schema object
//
ThreadCoInitialize(); hr = OpenDSObject(szPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, riid, ppv);
exit_gracefully:
TraceLeaveResult(hr); }
HRESULT Schema_GetObjectID(IADs *pObj, LPGUID pGUID) { HRESULT hr; VARIANT varID = {0};
TraceEnter(TRACE_SCHEMA, "Schema_GetObjectID(IADs*)"); TraceAssert(pObj != NULL); TraceAssert(pGUID != NULL && !IsBadWritePtr(pGUID, sizeof(GUID)));
// Get the "schemaIDGUID" property
hr = pObj->Get((LPWSTR)c_szSchemaIDGUID, &varID);
if (SUCCEEDED(hr)) { LPGUID pID = NULL;
TraceAssert(V_VT(&varID) == (VT_ARRAY | VT_UI1)); TraceAssert(V_ARRAY(&varID) && varID.parray->cDims == 1); TraceAssert(V_ARRAY(&varID)->rgsabound[0].cElements >= sizeof(GUID));
hr = SafeArrayAccessData(V_ARRAY(&varID), (LPVOID*)&pID); if (SUCCEEDED(hr)) { *pGUID = *pID; SafeArrayUnaccessData(V_ARRAY(&varID)); } VariantClear(&varID); }
TraceLeaveResult(hr); }
HRESULT Schema_Search(LPWSTR pszSchemaSearchPath, LPCWSTR pszFilter, HDPA *phCache, BOOL bProperty) { HRESULT hr = S_OK; HDPA hCache = NULL; IDirectorySearch *pSchemaSearch = NULL; ADS_SEARCH_HANDLE hSearch = NULL; ADS_SEARCHPREF_INFO prefInfo[3]; const LPCWSTR pProperties1[] = { c_szLDAPDisplayName, // "lDAPDisplayName"
c_szSchemaIDGUID, // "schemaIDGUID"
c_szObjectClassCategory, }; const LPCWSTR pProperties2[] = { c_szLDAPDisplayName, c_szSchemaIDGUID, c_szAttributeSecurityGuid, };
TraceEnter(lstrcmp(pszFilter, c_szPropertyFilter) ? TRACE_SCHEMACLASS : TRACE_SCHEMAPROP, "Schema_Search"); TraceAssert(pszSchemaSearchPath != NULL); TraceAssert(phCache != NULL);
LPCWSTR * pProperties = (LPCWSTR *)( bProperty ? pProperties2 : pProperties1 ); DWORD dwSize = (DWORD)(bProperty ? ARRAYSIZE(pProperties2) : ARRAYSIZE(pProperties1)); //
// Create DPA if necessary
//
if (*phCache == NULL) *phCache = DPA_Create(100);
if (*phCache == NULL) ExitGracefully(hr, E_OUTOFMEMORY, "DPA_Create failed");
hCache = *phCache;
// Get the schema search object
hr = OpenDSObject(pszSchemaSearchPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectorySearch, (LPVOID*)&pSchemaSearch); FailGracefully(hr, "Failed to get schema search object");
// Set preferences to Asynchronous, Deep search, Paged results
prefInfo[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE; prefInfo[0].vValue.dwType = ADSTYPE_INTEGER; prefInfo[0].vValue.Integer = ADS_SCOPE_SUBTREE;
prefInfo[1].dwSearchPref = ADS_SEARCHPREF_ASYNCHRONOUS; prefInfo[1].vValue.dwType = ADSTYPE_BOOLEAN; prefInfo[1].vValue.Boolean = TRUE;
prefInfo[2].dwSearchPref = ADS_SEARCHPREF_PAGESIZE; prefInfo[2].vValue.dwType = ADSTYPE_INTEGER; prefInfo[2].vValue.Integer = PAGE_SIZE;
hr = pSchemaSearch->SetSearchPreference(prefInfo, ARRAYSIZE(prefInfo));
// Do the search
hr = pSchemaSearch->ExecuteSearch((LPWSTR)pszFilter, (LPWSTR*)pProperties, dwSize, &hSearch); FailGracefully(hr, "IDirectorySearch::ExecuteSearch failed");
// Loop through the rows, getting the name and ID of each property or class
for (;;) { ADS_SEARCH_COLUMN colLdapName; ADS_SEARCH_COLUMN colGuid; ADS_SEARCH_COLUMN colASGuid; LPWSTR pszLdapName; LPGUID pID; LPGUID pASID; INT iObjectClassCategory = 0; PID_CACHE_ENTRY pCacheEntry;
hr = pSchemaSearch->GetNextRow(hSearch);
if (FAILED(hr) || hr == S_ADS_NOMORE_ROWS) break;
// Get class/property internal name
hr = pSchemaSearch->GetColumn(hSearch, (LPWSTR)c_szLDAPDisplayName, &colLdapName); if (FAILED(hr)) { TraceMsg("lDAPDisplayName not found for class/property"); continue; }
TraceAssert(colLdapName.dwADsType >= ADSTYPE_DN_STRING && colLdapName.dwADsType <= ADSTYPE_NUMERIC_STRING); TraceAssert(colLdapName.dwNumValues == 1);
pszLdapName = colLdapName.pADsValues->CaseIgnoreString;
// Get the GUID column
hr = pSchemaSearch->GetColumn(hSearch, (LPWSTR)c_szSchemaIDGUID, &colGuid); if (FAILED(hr)) { Trace((TEXT("GUID not found for \"%s\""), pszLdapName)); pSchemaSearch->FreeColumn(&colLdapName); continue; }
// Get GUID from column
TraceAssert(colGuid.dwADsType == ADSTYPE_OCTET_STRING); TraceAssert(colGuid.dwNumValues == 1); TraceAssert(colGuid.pADsValues->OctetString.dwLength == sizeof(GUID));
pID = (LPGUID)(colGuid.pADsValues->OctetString.lpValue);
pASID = (LPGUID)&GUID_NULL; if( bProperty ) { // Get the AttrbiuteSecurityGUID column
hr = pSchemaSearch->GetColumn(hSearch, (LPWSTR)c_szAttributeSecurityGuid, &colASGuid); if (hr != E_ADS_COLUMN_NOT_SET && FAILED(hr)) { Trace((TEXT("AttributeSecurityGUID not found for \"%s\""), pszLdapName)); pSchemaSearch->FreeColumn(&colLdapName); pSchemaSearch->FreeColumn(&colGuid); continue; }
if( hr != E_ADS_COLUMN_NOT_SET ) { // Get GUID from column
TraceAssert(colASGuid.dwADsType == ADSTYPE_OCTET_STRING); TraceAssert(colASGuid.dwNumValues == 1); TraceAssert(colASGuid.pADsValues->OctetString.dwLength == sizeof(GUID));
pASID = (LPGUID)(colASGuid.pADsValues->OctetString.lpValue); } } else { // Get the c_szObjectClassCategory column
hr = pSchemaSearch->GetColumn(hSearch, (LPWSTR)c_szObjectClassCategory, &colASGuid); if (FAILED(hr)) { Trace((TEXT("ObjectClassCategory not found for \"%s\""), pszLdapName)); pSchemaSearch->FreeColumn(&colLdapName); pSchemaSearch->FreeColumn(&colGuid); continue; }
// Get GUID from column
TraceAssert(colASGuid.dwADsType == ADSTYPE_INTEGER); TraceAssert(colASGuid.dwNumValues == 1); iObjectClassCategory = colASGuid.pADsValues->Integer; }
pCacheEntry = (PID_CACHE_ENTRY)LocalAlloc(LPTR, sizeof(ID_CACHE_ENTRY) + sizeof(WCHAR)*lstrlenW(pszLdapName)); if (pCacheEntry != NULL) { // Copy the item name and ID
pCacheEntry->guid = *pID; pCacheEntry->asGuid = *pASID; pCacheEntry->bAuxClass = (iObjectClassCategory == 3); lstrcpyW(pCacheEntry->szLdapName, pszLdapName);
// Insert into cache
DPA_AppendPtr(hCache, pCacheEntry); } pSchemaSearch->FreeColumn(&colLdapName); pSchemaSearch->FreeColumn(&colGuid); if(!bProperty || hr != E_ADS_COLUMN_NOT_SET) pSchemaSearch->FreeColumn(&colASGuid); }
DPA_Sort(hCache, Schema_CompareLdapName, 0);
exit_gracefully:
if (hSearch != NULL) pSchemaSearch->CloseSearchHandle(hSearch);
DoRelease(pSchemaSearch);
if (FAILED(hr)) { DestroyDPA(hCache); *phCache = NULL; }
TraceLeaveResult(hr); }
//+--------------------------------------------------------------------------
//
// Function: Schema_GetExtendedRightsForOneClass
//
// Synopsis: This Function Gets the Extended Rights for One Class.
// It Adds all the control rights, validated rights to
// phERList. It Adds all the PropertySets to phPropSetList.
//
// Arguments: [pszSchemaSearchPath - IN] : Path to schema
// [pguidClass - In] : Guid Of the class
// [phERList - OUT] : Get the output Extended Right List
// [phPropSetList - OUT]: Gets the output PropertySet List
//
// Returns: HRESULT : S_OK if everything succeeded
// E_INVALIDARG if the object entry wasn't found
//
// History: 3-Nov 2000 hiteshr Created
//
//---------------------------------------------------------------------------
HRESULT CSchemaCache::GetExtendedRightsForOneClass(IN LPWSTR pszSchemaSearchPath, IN LPCGUID pguidClass, OUT HDPA *phERList, OUT HDPA *phPropSetList) { TraceEnter(TRACE_SCHEMA, "CSchemaCache::GetExtendedRightsForOneClass"); if(!pszSchemaSearchPath || !pguidClass || IsEqualGUID(*pguidClass, GUID_NULL) || !phERList || !phPropSetList) { Trace((L"Invalid Arguments Passed to Schema_GetExtendedRightsForOneClass")); return E_INVALIDARG; }
HRESULT hr = S_OK; IDirectorySearch *pSearch = NULL; ADS_SEARCH_HANDLE hSearch = NULL; ADS_SEARCHPREF_INFO prefInfo[3]; WCHAR szFilter[100]; HDPA hExtRightList = NULL; HDPA hPropSetList = NULL; POBJECT_TYPE_CACHE pOTC = NULL;
//
//Search in the cache
//
if (m_hObjectTypeCache != NULL) { UINT cItems = DPA_GetPtrCount(m_hObjectTypeCache);
while (cItems > 0) { pOTC = (POBJECT_TYPE_CACHE)DPA_FastGetPtr(m_hObjectTypeCache, --cItems); //
//Found A match.
//
if(IsEqualGUID(pOTC->guidObject, *pguidClass)) break; pOTC = NULL; } //
//Have we already got the properties
//
if(pOTC && pOTC->flags & OTC_EXTR) { *phERList = pOTC->hListExtRights; *phPropSetList = pOTC->hListPropertySet; return S_OK; } }
//
//Attributes to fetch
//
const LPCWSTR pProperties[] = { c_szDisplayName, // "displayName"
c_szDisplayID, // "localizationDisplayId"
c_szRightsGuid, // "rightsGuid"
c_szValidAccesses, // "validAccesses"
};
//
// Build the filter string
//
wsprintfW(szFilter, c_szERFilterFormat, pguidClass->Data1, pguidClass->Data2, pguidClass->Data3, pguidClass->Data4[0], pguidClass->Data4[1], pguidClass->Data4[2], pguidClass->Data4[3], pguidClass->Data4[4], pguidClass->Data4[5], pguidClass->Data4[6], pguidClass->Data4[7]); Trace((TEXT("Filter \"%s\""), szFilter));
//
// Create DPA to hold results
//
hExtRightList = DPA_Create(8);
if (hExtRightList == NULL) ExitGracefully(hr, E_OUTOFMEMORY, "DPA_Create failed");
hPropSetList = DPA_Create(8);
if( hPropSetList == NULL ) ExitGracefully(hr, E_OUTOFMEMORY, "DPA_Create failed");
//
// Get the schema search object
//
hr = OpenDSObject(pszSchemaSearchPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectorySearch, (LPVOID*)&pSearch); FailGracefully(hr, "Failed to get schema search object"); //
// Set preferences to Asynchronous, OneLevel search, Paged results
//
prefInfo[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE; prefInfo[0].vValue.dwType = ADSTYPE_INTEGER; prefInfo[0].vValue.Integer = ADS_SCOPE_ONELEVEL;
prefInfo[1].dwSearchPref = ADS_SEARCHPREF_ASYNCHRONOUS; prefInfo[1].vValue.dwType = ADSTYPE_BOOLEAN; prefInfo[1].vValue.Boolean = TRUE;
prefInfo[2].dwSearchPref = ADS_SEARCHPREF_PAGESIZE; prefInfo[2].vValue.dwType = ADSTYPE_INTEGER; prefInfo[2].vValue.Integer = PAGE_SIZE;
hr = pSearch->SetSearchPreference(prefInfo, ARRAYSIZE(prefInfo)); FailGracefully(hr, "IDirectorySearch::SetSearchPreference failed"); //
// Do the search
//
hr = pSearch->ExecuteSearch(szFilter, (LPWSTR*)pProperties, ARRAYSIZE(pProperties), &hSearch); FailGracefully(hr, "IDirectorySearch::ExecuteSearch failed"); //
// Loop through the rows, getting the name and ID of each property or class
//
for (;;) { ADS_SEARCH_COLUMN col; GUID guid; DWORD dwValidAccesses; LPWSTR pszName = NULL; WCHAR szDisplayName[MAX_PATH];
hr = pSearch->GetNextRow(hSearch);
if (FAILED(hr) || hr == S_ADS_NOMORE_ROWS) break; //
// Get the GUID
//
if (FAILED(pSearch->GetColumn(hSearch, (LPWSTR)c_szRightsGuid, &col))) { TraceMsg("GUID not found for extended right"); continue; } TraceAssert(col.dwADsType >= ADSTYPE_DN_STRING && col.dwADsType <= ADSTYPE_NUMERIC_STRING); wsprintfW(szFilter, c_szGUIDFormat, col.pADsValues->CaseIgnoreString); CLSIDFromString(szFilter, &guid); pSearch->FreeColumn(&col);
//
// Get the valid accesses mask
//
if (FAILED(pSearch->GetColumn(hSearch, (LPWSTR)c_szValidAccesses, &col))) { TraceMsg("validAccesses not found for Extended Right"); continue; } TraceAssert(col.dwADsType == ADSTYPE_INTEGER); TraceAssert(col.dwNumValues == 1); dwValidAccesses = (DWORD)(DS_GENERIC_ALL & col.pADsValues->Integer); pSearch->FreeColumn(&col); //
// Get the display name
//
szDisplayName[0] = L'\0'; if (SUCCEEDED(pSearch->GetColumn(hSearch, (LPWSTR)c_szDisplayID, &col))) { TraceAssert(col.dwADsType == ADSTYPE_INTEGER); TraceAssert(col.dwNumValues == 1); if (FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, g_hInstance, col.pADsValues->Integer, 0, szDisplayName, ARRAYSIZE(szDisplayName), NULL)) { pszName = szDisplayName; } pSearch->FreeColumn(&col); }
if (NULL == pszName && SUCCEEDED(pSearch->GetColumn(hSearch, (LPWSTR)c_szDisplayName, &col))) { TraceAssert(col.dwADsType >= ADSTYPE_DN_STRING && col.dwADsType <= ADSTYPE_NUMERIC_STRING); lstrcpynW(szDisplayName, col.pADsValues->CaseIgnoreString, ARRAYSIZE(szDisplayName)); pszName = szDisplayName; pSearch->FreeColumn(&col); }
if (NULL == pszName) { TraceMsg("displayName not found for Extended Right"); continue; }
//
//Create A new Cache Entry
//
PER_ENTRY pER = (PER_ENTRY)LocalAlloc(LPTR, sizeof(ER_ENTRY) + StringByteSize(pszName)); if( pER == NULL ) ExitGracefully(hr, E_OUTOFMEMORY, "LocalAlloc failed");
pER->guid = guid; pER->mask = dwValidAccesses; pER->dwFlags = 0; lstrcpyW(pER->szName, pszName); //
// Is it a Property Set?
//
if (dwValidAccesses & (ACTRL_DS_READ_PROP | ACTRL_DS_WRITE_PROP)) { //
// Insert into list
//
Trace((TEXT("Adding PropertySet\"%s\""), pszName)); DPA_AppendPtr(hPropSetList, pER); dwValidAccesses &= ~(ACTRL_DS_READ_PROP | ACTRL_DS_WRITE_PROP); } else if (dwValidAccesses) { //
// Must be a Control Right, Validated Write, etc.
//
Trace((TEXT("Adding Extended Right \"%s\""), pszName)); DPA_AppendPtr(hExtRightList, pER); } }
UINT cCount; //
//Get the count of Extended Rights
//
cCount = DPA_GetPtrCount(hExtRightList); if(!cCount) { DPA_Destroy(hExtRightList); hExtRightList = NULL; } else { DPA_Sort(hExtRightList, Schema_CompareER, 0); } //
//Get the Count of PropertySets
//
cCount = DPA_GetPtrCount(hPropSetList); if(!cCount) { DPA_Destroy(hPropSetList); hPropSetList = NULL; } else { DPA_Sort(hPropSetList,Schema_CompareER, 0 ); }
//
//Add entry to the cache
//
if(!m_hObjectTypeCache) m_hObjectTypeCache = DPA_Create(4); if(!m_hObjectTypeCache) ExitGracefully(hr, E_OUTOFMEMORY, "DPA_Create Failed");
if(!pOTC) { pOTC = (POBJECT_TYPE_CACHE)LocalAlloc(LPTR,sizeof(OBJECT_TYPE_CACHE)); if(!pOTC) ExitGracefully(hr, E_OUTOFMEMORY, "LocalAlloc Failed"); pOTC->guidObject = *pguidClass; DPA_AppendPtr(m_hObjectTypeCache, pOTC); }
pOTC->hListExtRights = hExtRightList; pOTC->hListPropertySet = hPropSetList; pOTC->flags |= OTC_EXTR;
exit_gracefully:
if (hSearch != NULL) pSearch->CloseSearchHandle(hSearch);
DoRelease(pSearch);
if (FAILED(hr)) { if(hExtRightList) { DestroyDPA(hExtRightList); hExtRightList = NULL; } if(hPropSetList) { DestroyDPA(hPropSetList); hPropSetList = NULL; } }
//
//Set The Output
//
*phERList = hExtRightList; *phPropSetList = hPropSetList;
TraceLeaveResult(hr); }
//+--------------------------------------------------------------------------
//
// Function: GetChildClassesForOneClass
//
// Synopsis: This Function Gets the List of child classes for a class.
//
// Arguments: [pguidObjectType - IN] : ObjectGuidType of the class
// [pszClassName - IN] : Class Name
// [pszSchemaPath - IN] : Schema Search Path
// [phChildList - OUT]: Output childclass List
//
// Returns: HRESULT : S_OK if everything succeeded
// E_INVALIDARG if the object entry wasn't found
//
// History: 3-Nov 2000 hiteshr Created
//
//---------------------------------------------------------------------------
HRESULT CSchemaCache::GetChildClassesForOneClass(IN LPCGUID pguidObjectType, IN LPCWSTR pszClassName, IN LPCWSTR pszSchemaPath, OUT HDPA *phChildList) { TraceEnter(TRACE_SCHEMA, "CSchemaCache::GetChildClassesForOneClass");
HRESULT hr = S_OK; BOOL bContainer = FALSE; VARIANT varContainment = {0}; HDPA hClassList = NULL; UINT cChildClass = 0; POBJECT_TYPE_CACHE pOTC = NULL;
if(!pguidObjectType || !pszSchemaPath || !phChildList) { Trace((L"Invalid Input Arguments Passed to Schema_GetExtendedRightsForOneClass")); return E_INVALIDARG; }
//
//Search in the cache
//
if (m_hObjectTypeCache != NULL) { UINT cItems = DPA_GetPtrCount(m_hObjectTypeCache);
while (cItems > 0) { pOTC = (POBJECT_TYPE_CACHE)DPA_FastGetPtr(m_hObjectTypeCache, --cItems); //
//Found A match.
//
if(IsEqualGUID(pOTC->guidObject, *pguidObjectType)) break;
pOTC = NULL; } //
//Have we already got the child classes
//
if(pOTC && pOTC->flags & OTC_COBJ) { *phChildList = pOTC->hListChildObject; return S_OK; } }
//
// Lookup the name of this class
//
if (pszClassName == NULL) pszClassName = GetClassName(pguidObjectType);
if (pszClassName == NULL) ExitGracefully(hr, E_UNEXPECTED, "Unknown child object GUID");
//
// Figure out if the object is a container by getting the list of child
// classes.
//
IADsClass *pDsClass;
//
// Get the schema object for this class
//
hr = Schema_BindToObject(pszSchemaPath, pszClassName, IID_IADsClass, (LPVOID*)&pDsClass); FailGracefully(hr, "Schema_BindToObjectFailed");
//
// Get the list of possible child classes
//
if (SUCCEEDED(pDsClass->get_Containment(&varContainment))) { if (V_VT(&varContainment) == (VT_ARRAY | VT_VARIANT)) { LPSAFEARRAY psa = V_ARRAY(&varContainment); TraceAssert(psa && psa->cDims == 1); if (psa->rgsabound[0].cElements > 0) bContainer = TRUE; } else if (V_VT(&varContainment) == VT_BSTR) // single entry
{ TraceAssert(V_BSTR(&varContainment)); bContainer = TRUE; } //
// (Requires the schema class enumeration thread to complete first,
// and it's usually not done yet the first time we get here.)
//
if(bContainer) { hClassList = DPA_Create(8); if (hClassList) { IDsDisplaySpecifier *pDisplaySpec = NULL; //
// Get the display specifier object
//
CoCreateInstance(CLSID_DsDisplaySpecifier, NULL, CLSCTX_INPROC_SERVER, IID_IDsDisplaySpecifier, (void**)&pDisplaySpec); //
// Filter the list & get display names
//
EnumVariantList(&varContainment, hClassList, SCHEMA_CLASS, pDisplaySpec, pszClassName, FALSE);
DoRelease(pDisplaySpec);
//
//Get the count of properties
//
cChildClass = DPA_GetPtrCount(hClassList); if(!cChildClass) { DPA_Destroy(hClassList); hClassList = NULL; } else { //
//Sort The list
//
DPA_Sort(hClassList,Schema_ComparePropDisplayName, 0 ); } } } } DoRelease(pDsClass);
//
//Add entry to the cache
//
if(!m_hObjectTypeCache) m_hObjectTypeCache = DPA_Create(4); if(!m_hObjectTypeCache) ExitGracefully(hr, E_OUTOFMEMORY, "DPA_Create Failed");
if(!pOTC) { pOTC = (POBJECT_TYPE_CACHE)LocalAlloc(LPTR,sizeof(OBJECT_TYPE_CACHE)); if(!pOTC) ExitGracefully(hr, E_OUTOFMEMORY, "LocalAlloc Failed"); pOTC->guidObject = *pguidObjectType; DPA_AppendPtr(m_hObjectTypeCache, pOTC); }
pOTC->hListChildObject = hClassList; pOTC->flags |= OTC_COBJ;
exit_gracefully:
VariantClear(&varContainment);
if(FAILED(hr)) { DestroyDPA(hClassList); hClassList = NULL; }
//
//Set the Output
//
*phChildList = hClassList;
TraceLeaveResult(hr); }
//+--------------------------------------------------------------------------
//
// Function: GetPropertiesForOneClass
//
// Synopsis: This Function Gets the List of properties for a class.
//
// Arguments: [pguidObjectType - IN] : ObjectGuidType of the class
// [pszClassName - IN] : Class Name
// [pszSchemaPath - IN] : Schema Search Path
// [phPropertyList - OUT]: Output Property List
//
// Returns: HRESULT : S_OK if everything succeeded
// E_INVALIDARG if the object entry wasn't found
//
// History: 3-Nov 2000 hiteshr Created
//
//---------------------------------------------------------------------------
HRESULT CSchemaCache::GetPropertiesForOneClass(IN LPCGUID pguidObjectType, IN LPCWSTR pszClassName, IN LPCWSTR pszSchemaPath, OUT HDPA *phPropertyList) { HRESULT hr; IADsClass *pDsClass = NULL; VARIANT varMandatoryProperties = {0}; VARIANT varOptionalProperties = {0}; UINT cProperties = 0; IDsDisplaySpecifier *pDisplaySpec = NULL; HDPA hPropertyList = NULL; POBJECT_TYPE_CACHE pOTC = NULL;
TraceEnter(TRACE_SCHEMA, "CSchemaCache::GetPropertiesForOneClass");
if(!pguidObjectType || !pszSchemaPath || !phPropertyList) { Trace((L"Invalid Input Arguments Passed to CSchemaCache::GetPropertiesForOneClass")); return E_INVALIDARG; }
//
//Search in the cache
//
if (m_hObjectTypeCache != NULL) { UINT cItems = DPA_GetPtrCount(m_hObjectTypeCache);
while (cItems > 0) { pOTC = (POBJECT_TYPE_CACHE)DPA_FastGetPtr(m_hObjectTypeCache, --cItems); //
//Found A match.
//
if(IsEqualGUID(pOTC->guidObject, *pguidObjectType)) break; pOTC = NULL; } //
//Have we already got the properties
//
if(pOTC && pOTC->flags & OTC_PROP) { *phPropertyList = pOTC->hListProperty; return S_OK; } }
//
// Get the schema object for this class
//
if (pszClassName == NULL) pszClassName = GetClassName(pguidObjectType);
if (pszClassName == NULL) ExitGracefully(hr, E_UNEXPECTED, "Unknown child object GUID");
hr = Schema_BindToObject(pszSchemaPath, pszClassName, IID_IADsClass, (LPVOID*)&pDsClass); FailGracefully(hr, "Unable to create schema object");
//
// Get the display specifier object
//
CoCreateInstance(CLSID_DsDisplaySpecifier, NULL, CLSCTX_INPROC_SERVER, IID_IDsDisplaySpecifier, (void**)&pDisplaySpec);
hPropertyList = DPA_Create(8); if (!hPropertyList) ExitGracefully(hr, E_OUTOFMEMORY, "Unable to create DPA");
//
// Get mandatory and optional property lists
//
if (SUCCEEDED(pDsClass->get_MandatoryProperties(&varMandatoryProperties))) { EnumVariantList(&varMandatoryProperties, hPropertyList, 0, pDisplaySpec, pszClassName, FALSE); } if (SUCCEEDED(pDsClass->get_OptionalProperties(&varOptionalProperties))) { EnumVariantList(&varOptionalProperties, hPropertyList, 0, pDisplaySpec, pszClassName, FALSE); }
//
//Get the Number of properties
//
cProperties = DPA_GetPtrCount(hPropertyList); if(!cProperties) { DPA_Destroy(hPropertyList); hPropertyList = NULL; } else { //
//Sort The list
//
DPA_Sort(hPropertyList,Schema_ComparePropDisplayName, 0 ); }
//
//Add entry to the cache
//
if(!m_hObjectTypeCache) m_hObjectTypeCache = DPA_Create(4); if(!m_hObjectTypeCache) ExitGracefully(hr, E_OUTOFMEMORY, "DPA_Create Failed");
if(!pOTC) { pOTC = (POBJECT_TYPE_CACHE)LocalAlloc(LPTR,sizeof(OBJECT_TYPE_CACHE)); if(!pOTC) ExitGracefully(hr, E_OUTOFMEMORY, "LocalAlloc Failed"); pOTC->guidObject = *pguidObjectType; DPA_AppendPtr(m_hObjectTypeCache, pOTC); }
pOTC->hListProperty = hPropertyList; pOTC->flags |= OTC_PROP;
exit_gracefully:
VariantClear(&varMandatoryProperties); VariantClear(&varOptionalProperties); DoRelease(pDsClass); DoRelease(pDisplaySpec);
if(FAILED(hr) && hPropertyList) { DestroyDPA(hPropertyList); hPropertyList = NULL; } //
//Set the Output
//
*phPropertyList = hPropertyList;
TraceLeaveResult(hr); } //+--------------------------------------------------------------------------
//
// Function: GetExtendedRightsForNClasses
//
// Synopsis:
// This function gets the ExtendedRigts(control rights,
// validated rights) and PropertySets for pszClassName and
// all the classes in AuxTypeList.
// Function Merges Extended Rights of all the classes in to a
// signle list form which duplicates are removed and list
// is sorted.
// Function Merges PropertySets of all the classes in to a
// signle list form which duplicates are removed and list
// is sorted.
//
// Arguments: [pguidClass - IN] : ObjectGuidType of the class
// [hAuxList - IN]:List of Auxillary Classes
// [pszSchemaSearchPath - IN] : Schema Search Path
// [phERList - OUT]: Output Extended Rights list
// [phPropSetList - OUT]: Output Propset List
//
// Returns: HRESULT : S_OK if everything succeeded
// E_INVALIDARG if the object entry wasn't found
// Note: Calling function must call DPA_Destroy on *phERList and *phPropSetList
// to Free the memory
//
// History: 3-Nov 2000 hiteshr Created
//
//---------------------------------------------------------------------------
HRESULT CSchemaCache::GetExtendedRightsForNClasses(IN LPWSTR pszSchemaSearchPath, IN LPCGUID pguidClass, IN HDPA hAuxList, OUT HDPA *phERList, OUT HDPA *phPropSetList) { TraceEnter(TRACE_SCHEMA, "CSchemaCache::GetExtendedRightsForNClasses");
if(!pguidClass || !pszSchemaSearchPath) { Trace((L"Invalid Input Arguments Passed to CSchemaCache::GetPropertiesForNClasses")); return E_INVALIDARG; }
HRESULT hr = S_OK; HDPA hERList = NULL; HDPA hPropSetList = NULL; HDPA hFinalErList = NULL; HDPA hFinalPropSetList = NULL;
//
//Get the extended rights for pguidClass
//
hr = GetExtendedRightsForOneClass(pszSchemaSearchPath, pguidClass, &hERList, &hPropSetList); FailGracefully(hr,"GetExtendedRightsForOneClasses failed");
if(hERList && phERList) { UINT cCount = DPA_GetPtrCount(hERList); hFinalErList = DPA_Create(cCount); if(!hFinalErList) ExitGracefully(hr, ERROR_NOT_ENOUGH_MEMORY,"DPA_Create Failed"); //
//Copy hERList to hFinalErList
//
DPA_Merge(hFinalErList, //Destination
hERList, //Source
DPAM_SORTED|DPAM_UNION, //Already Sorted And give me union
Schema_CompareER, _Merge, 0); }
if(hPropSetList && phPropSetList) { UINT cCount = DPA_GetPtrCount(hPropSetList); hFinalPropSetList = DPA_Create(cCount); if(!hFinalPropSetList) ExitGracefully(hr, ERROR_NOT_ENOUGH_MEMORY,"DPA_Create Failed");
//
//Copy hPropSetList to hFinalPropSetList
//
DPA_Merge(hFinalPropSetList, //Destination
hPropSetList, //Source
DPAM_SORTED|DPAM_UNION, //Already Sorted And give me union
Schema_CompareER, _Merge, 0); } //
//For each auxclass get the extended rights
//and property sets
//
if (hAuxList != NULL) {
UINT cItems = DPA_GetPtrCount(hAuxList);
while (cItems > 0) { PAUX_INFO pAI; pAI = (PAUX_INFO)DPA_FastGetPtr(hAuxList, --cItems); if(IsEqualGUID(pAI->guid, GUID_NULL)) { hr = LookupClassID(pAI->pszClassName, &pAI->guid); FailGracefully(hr,"Cache Not available"); } hERList = NULL; hPropSetList = NULL; //
//Get the ER and PropSet for AuxClass
//
hr = GetExtendedRightsForOneClass(pszSchemaSearchPath, &pAI->guid, &hERList, &hPropSetList); FailGracefully(hr,"GetExtendedRightsForOneClasses failed"); if(hERList && phERList) { if(!hFinalErList) { UINT cCount = DPA_GetPtrCount(hERList); hFinalErList = DPA_Create(cCount);
if(!hFinalErList) ExitGracefully(hr, ERROR_NOT_ENOUGH_MEMORY,"DPA_Create Failed"); } //
//Merge hERList into hFinalErList
//
DPA_Merge(hFinalErList, //Destination
hERList, //Source
DPAM_SORTED|DPAM_UNION, //Already Sorted And give me union
Schema_CompareER, _Merge, 0); } if(hPropSetList && phPropSetList) { if(!hFinalPropSetList) { UINT cCount = DPA_GetPtrCount(hPropSetList); hFinalPropSetList = DPA_Create(cCount);
if(!hFinalPropSetList) ExitGracefully(hr, ERROR_NOT_ENOUGH_MEMORY,"DPA_Create Failed"); }
//
//Merge hPropSetList into hFinalPropSetList
//
DPA_Merge(hFinalPropSetList, //Destination
hPropSetList, //Source
DPAM_SORTED|DPAM_UNION, //Already Sorted And give me union
Schema_CompareER, _Merge, 0); }
} }
exit_gracefully: if(FAILED(hr)) { if(hFinalPropSetList) DPA_Destroy(hFinalPropSetList);
if(hFinalErList) DPA_Destroy(hFinalErList);
hFinalErList = NULL; hFinalPropSetList = NULL; } if(phERList) *phERList = hFinalErList; if(phPropSetList) *phPropSetList = hFinalPropSetList; TraceLeaveResult(hr); }
//+--------------------------------------------------------------------------
//
// Function: GetChildClassesForNClasses
//
// Synopsis:
// This function gets the childclasses for pszClassName and
// all the classes in AuxTypeList. Function Merges child clasess
// of all the classes in to a signle list form which duplicates
// are removed and list is sorted
//
// Arguments: [pguidObjectType - IN] : ObjectGuidType of the class
// [pszClassName - IN] : Class Name
// [hAuxList - IN]:List of Auxillary Classes
// [pszSchemaPath - IN] : Schema Search Path
// [phChildList - OUT]: Output Child Classes List
//
// Returns: HRESULT : S_OK if everything succeeded
// E_INVALIDARG if the object entry wasn't found
// Note: Calling function must call DPA_Destroy on *phPropertyList to
// Free the memory
//
// History: 3-Nov 2000 hiteshr Created
//
//---------------------------------------------------------------------------
HRESULT CSchemaCache::GetChildClassesForNClasses(IN LPCGUID pguidObjectType, IN LPCWSTR pszClassName, IN HDPA hAuxList, IN LPCWSTR pszSchemaPath, OUT HDPA *phChildList) { TraceEnter(TRACE_SCHEMA, "CSchemaCache::GetChildClassesForNClasses");
if(!pguidObjectType || !pszSchemaPath || !phChildList) { Trace((L"Invalid Input Arguments Passed to CSchemaCache::GetPropertiesForNClasses")); return E_INVALIDARG; }
HRESULT hr = S_OK; HDPA hChildList = NULL; HDPA hFinalChildList = NULL;
//
//Get the Child Classes for pszClassName
//
hr = GetChildClassesForOneClass(pguidObjectType, pszClassName, pszSchemaPath, &hChildList); FailGracefully(hr,"GetExtendedRightsForOneClasses failed");
if(hChildList) { if(!hFinalChildList) { UINT cCount = DPA_GetPtrCount(hChildList); hFinalChildList = DPA_Create(cCount); if(!hFinalChildList) ExitGracefully(hr, ERROR_NOT_ENOUGH_MEMORY,"DPA_Create Failed"); } //
//Copy hChildList to hFinalChildList
//
DPA_Merge(hFinalChildList, //Destination
hChildList, //Source
DPAM_SORTED|DPAM_UNION, //Already Sorted And give me union
Schema_ComparePropDisplayName, _Merge, 0); }
//
//For each class in hAuxList get the child classes
//
if (hAuxList != NULL) {
UINT cItems = DPA_GetPtrCount(hAuxList);
while (cItems > 0) { PAUX_INFO pAI; pAI = (PAUX_INFO)DPA_FastGetPtr(hAuxList, --cItems); if(IsEqualGUID(pAI->guid, GUID_NULL)) { hr = LookupClassID(pAI->pszClassName, &pAI->guid); FailGracefully(hr,"Cache Not available"); } //
//GetPropertiesForOneClass returns the list of handles
//from cache so don't delete them. Simply set them to NULL
//
hChildList = NULL; hr = GetChildClassesForOneClass(&pAI->guid, pAI->pszClassName, pszSchemaPath, &hChildList); FailGracefully(hr,"GetExtendedRightsForOneClasses failed"); if(hChildList) { if(!hFinalChildList) { UINT cCount = DPA_GetPtrCount(hChildList); hFinalChildList = DPA_Create(cCount); if(!hFinalChildList) ExitGracefully(hr, ERROR_NOT_ENOUGH_MEMORY,"DPA_Create Failed"); } //
//Merge hChildList into hFinalChildList
//
DPA_Merge(hFinalChildList, //Destination
hChildList, //Source
DPAM_SORTED|DPAM_UNION, //Already Sorted And give me union
Schema_ComparePropDisplayName, _Merge, 0); }
} }
exit_gracefully: if(FAILED(hr)) { if(hFinalChildList) DPA_Destroy(hFinalChildList);
hFinalChildList = NULL; } //
//Set the output
//
*phChildList = hFinalChildList;
TraceLeaveResult(hr); }
//+--------------------------------------------------------------------------
//
// Function: GetPropertiesForNClasses
//
// Synopsis:
// This function gets the properties for pszClassName and
// all the classes in AuxTypeList. Function Merges properties
// of all the classes in to a signle list form which duplicates
//
// Arguments: [pguidObjectType - IN] : ObjectGuidType of the class
// [pszClassName - IN] : Class Name
// [hAuxList - IN]:List of Auxillary Classes
// [pszSchemaPath - IN] : Schema Search Path
// [phPropertyList - OUT]: Output Property List
//
// Returns: HRESULT : S_OK if everything succeeded
// E_INVALIDARG if the object entry wasn't found
// Note: Calling function must call DPA_Destroy on *phPropertyList to
// Free the memory
//
// History: 3-Nov 2000 hiteshr Created
//
//---------------------------------------------------------------------------
HRESULT CSchemaCache:: GetPropertiesForNClasses(IN LPCGUID pguidObjectType, IN LPCWSTR pszClassName, IN HDPA hAuxList, IN LPCWSTR pszSchemaPath, OUT HDPA *phPropertyList) { TraceEnter(TRACE_SCHEMA, "CSchemaCache::GetPropertiesForOneClass");
if(!pguidObjectType || !pszSchemaPath || !phPropertyList) { Trace((L"Invalid Input Arguments Passed to CSchemaCache::GetPropertiesForNClasses")); return E_INVALIDARG; }
HRESULT hr = S_OK; HDPA hPropertyList = NULL; HDPA hFinalPropertyList = NULL;
//
//Get The properties for pszClassName
//
hr = GetPropertiesForOneClass(pguidObjectType, pszClassName, pszSchemaPath, &hPropertyList); FailGracefully(hr,"GetPropertiesForOneClass failed");
if(hPropertyList) { UINT cCount = DPA_GetPtrCount(hPropertyList); hFinalPropertyList = DPA_Create(cCount); if(!hFinalPropertyList) ExitGracefully(hr, ERROR_NOT_ENOUGH_MEMORY,"DPA_Create Failed");
//
//Copy hPropertyList to hFinalPropertyList.
//
DPA_Merge(hFinalPropertyList, //Destination
hPropertyList, //Source
DPAM_SORTED|DPAM_UNION, //Already Sorted And give me union
Schema_ComparePropDisplayName, _Merge, 0); }
//
//Get the properties for each class in hAuxList
//and add them to hFinalPropertyList
//
if (hAuxList != NULL) {
UINT cItems = DPA_GetPtrCount(hAuxList);
while (cItems > 0) { PAUX_INFO pAI; pAI = (PAUX_INFO)DPA_FastGetPtr(hAuxList, --cItems); if(IsEqualGUID(pAI->guid, GUID_NULL)) { hr = LookupClassID(pAI->pszClassName, &pAI->guid); FailGracefully(hr,"Cache Not available"); } //
//GetPropertiesForOneClass returns the list of handles
//from cache so don't delete them. Simply set them to NULL
//
hPropertyList = NULL; //
//Get properties for Aux Class
//
hr = GetPropertiesForOneClass(&pAI->guid, pAI->pszClassName, pszSchemaPath, &hPropertyList); FailGracefully(hr,"GetExtendedRightsForOneClasses failed"); if(hPropertyList) { if(!hFinalPropertyList) { UINT cCount = DPA_GetPtrCount(hPropertyList); hFinalPropertyList = DPA_Create(cCount); if(!hFinalPropertyList) ExitGracefully(hr, ERROR_NOT_ENOUGH_MEMORY,"DPA_Create Failed"); } //
//Merge hPropertyList with hFinalPropertyList
//
DPA_Merge(hFinalPropertyList, //Destination
hPropertyList, //Source
DPAM_SORTED|DPAM_UNION, //Already Sorted And give me union
Schema_ComparePropDisplayName, _Merge, 0); }
} }
exit_gracefully: if(FAILED(hr)) { if(hFinalPropertyList) DPA_Destroy(hFinalPropertyList);
hFinalPropertyList = NULL; } //
//Set the Output
//
*phPropertyList = hFinalPropertyList;
TraceLeaveResult(hr); }
//+--------------------------------------------------------------------------
//
// Function: DoesPathContainServer
//
// Synopsis:
// Checks if the path contain server name in begining
// Arguments: [pszPath - IN] : Path to DS object
//
// Returns: BOOL: true if path contain server name
// false if not or error occurs
//
// History: 27 March 2000 hiteshr Created
//
//---------------------------------------------------------------------------
bool DoesPathContainServer(LPCWSTR pszPath) {
IADsPathname *pPath = NULL; BSTR strServerName = NULL; bool bReturn = false; BSTR strObjectPath = SysAllocString(pszPath); if(!strObjectPath) return false;
//
// Create an ADsPathname object to parse the path and get the
// server name
//
HRESULT hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_IADsPathname, (LPVOID*)&pPath); if (pPath) { //
//Set Full Path
//
if (SUCCEEDED(pPath->Set(strObjectPath, ADS_SETTYPE_FULL))) { //
//Retrieve servername
//
hr = pPath->Retrieve(ADS_FORMAT_SERVER, &strServerName); if(SUCCEEDED(hr) && strServerName) { bReturn = true; } } } DoRelease(pPath); if(strServerName) SysFreeString(strServerName); SysFreeString(strObjectPath);
return bReturn; }
//*************************************************************
//
// OpenDSObject()
//
// Purpose: Calls AdsOpenObject with ADS_SERVER_BIND
// Return: Same as AdsOpenObject
//
//*************************************************************
HRESULT OpenDSObject (LPTSTR lpPath, LPTSTR lpUserName, LPTSTR lpPassword, DWORD dwFlags, REFIID riid, void FAR * FAR * ppObject) { if (DoesPathContainServer(lpPath)) { dwFlags |= ADS_SERVER_BIND; }
return (ADsOpenObject(lpPath, lpUserName, lpPassword, dwFlags, riid, ppObject)); }
|