mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3846 lines
113 KiB
3846 lines
113 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// 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));
|
|
}
|