//+------------------------------------------------------------------------- // // 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" #include "AdsOpenFlags.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) { //NTRAID#NTBUG9-577753-2002/04/01-hiteshr WCHAR szFilterFile[MAX_PATH+1]; UINT cch = GetSystemDirectory(szFilterFile, ARRAYSIZE(szFilterFile)); if (0 == cch || cch >= ARRAYSIZE(szFilterFile)) return NULL; if (szFilterFile[cch-1] != L'\\') { if(FAILED(StringCchCat(szFilterFile,ARRAYSIZE(szFilterFile),L"\\"))) return NULL; } if(SUCCEEDED(StringCchCat(szFilterFile,ARRAYSIZE(szFilterFile), c_szFilterFile))) return SysAllocString(szFilterFile); else return NULL; } // // 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(AutoBstr(c_szRootDsePath), ADS_SETTYPE_FULL); FailGracefully(hr, "Unable to initialize path object"); if (pszServer) { hr = pPath->Set(AutoBstr(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(AutoBstr(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(AutoBstr(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(AutoBstr(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"); hr = StringCchPrintf(szSearchBuffer, ARRAYSIZE(szSearchBuffer), lpszSchemaGuidFilter, pszDestData); FailGracefully(hr, "StringCchPrintf Failed"); //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::IsAuxClass"); 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(AutoBstr(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; 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; //New Comments: Always show Validated Rights since they //Form Write permission on first page and hiding them //on advanced page cause confusion(lots of). See //bug 495391 // //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; } // //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 " // or // "Create/delete " 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(); ASSERT( 0 != GLOBAL_REFCOUNT ); 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(); ASSERT( 0 != GLOBAL_REFCOUNT ); 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) { TraceEnter(TRACE_SCHEMA, "Schema_BindToObject"); TraceAssert(pszSchemaPath != NULL); TraceAssert(pszName == NULL || *pszName); TraceAssert(ppv != NULL); HRESULT hr = S_OK; if (pszSchemaPath == NULL) { ExitGracefully(hr, E_INVALIDARG, "No schema path provided"); } WCHAR szPath[MAX_PATH]; // // Build the schema path to this object // hr = StringCchCopy(szPath, ARRAYSIZE(szPath),pszSchemaPath); FailGracefully(hr, "StringCchCopy Failed"); //Get the last character UINT nSchemaRootLen = lstrlenW(pszSchemaPath); WCHAR chTemp = szPath[nSchemaRootLen-1]; if (pszName != NULL) { // If there is no trailing slash, add it if (chTemp != TEXT('/')) { hr = StringCchCat(szPath,ARRAYSIZE(szPath),L"/"); FailGracefully(hr, "StringCchCat Failed to add /"); } // Add the class or property name onto the end hr = StringCchCat(szPath,ARRAYSIZE(szPath),pszName); FailGracefully(hr, "StringCchCat Failed to pszName"); } 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(AutoBstr(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 // hr = StringCchPrintf(szFilter, ARRAYSIZE(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]); FailGracefully(hr, "StringCchPrintf Failed"); 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); hr = StringCchPrintf(szFilter, ARRAYSIZE(szFilter), c_szGUIDFormat, col.pADsValues->CaseIgnoreString); pSearch->FreeColumn(&col); if(FAILED(hr)) { continue; } CLSIDFromString(szFilter, &guid); // // 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::GetPropertiesForNClasses"); 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) { static DWORD additionalFlags = GetADsOpenObjectFlags(); dwFlags |= additionalFlags; if (DoesPathContainServer(lpPath)) { dwFlags |= ADS_SERVER_BIND; } return (ADsOpenObject(lpPath, lpUserName, lpPassword, dwFlags, riid, ppObject)); }