Source code of Windows XP (NT5)
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

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: schema.cpp
  8. //
  9. // This file contains the implementation of the Schema Cache
  10. //
  11. //--------------------------------------------------------------------------
  12. #include "pch.h"
  13. #include "sddl.h"
  14. #include "sddlp.h"
  15. //
  16. // CSchemaCache object definition
  17. //
  18. #include "schemap.h"
  19. PSCHEMACACHE g_pSchemaCache = NULL;
  20. //
  21. // Page size used for paging query result sets (better performance)
  22. //
  23. #define PAGE_SIZE 16
  24. //
  25. // The following array defines the permission names for DS objects.
  26. //
  27. SI_ACCESS g_siDSAccesses[] =
  28. {
  29. { &GUID_NULL, DS_GENERIC_ALL, MAKEINTRESOURCE(IDS_DS_GENERIC_ALL), SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC },
  30. { &GUID_NULL, DS_GENERIC_READ, MAKEINTRESOURCE(IDS_DS_GENERIC_READ), SI_ACCESS_GENERAL },
  31. { &GUID_NULL, DS_GENERIC_WRITE, MAKEINTRESOURCE(IDS_DS_GENERIC_WRITE), SI_ACCESS_GENERAL },
  32. { &GUID_NULL, ACTRL_DS_LIST, MAKEINTRESOURCE(IDS_ACTRL_DS_LIST), SI_ACCESS_SPECIFIC },
  33. { &GUID_NULL, ACTRL_DS_LIST_OBJECT, MAKEINTRESOURCE(IDS_ACTRL_DS_LIST_OBJECT), SI_ACCESS_SPECIFIC },
  34. { &GUID_NULL, ACTRL_DS_READ_PROP, MAKEINTRESOURCE(IDS_ACTRL_DS_READ_PROP), SI_ACCESS_SPECIFIC | SI_ACCESS_PROPERTY },
  35. { &GUID_NULL, ACTRL_DS_WRITE_PROP, MAKEINTRESOURCE(IDS_ACTRL_DS_WRITE_PROP), SI_ACCESS_SPECIFIC | SI_ACCESS_PROPERTY },
  36. { &GUID_NULL, ACTRL_DS_WRITE_PROP|ACTRL_DS_READ_PROP, MAKEINTRESOURCE(IDS_ACTRL_DS_READ_WRITE_PROP), },
  37. { &GUID_NULL, DELETE, MAKEINTRESOURCE(IDS_ACTRL_DELETE), SI_ACCESS_SPECIFIC },
  38. { &GUID_NULL, ACTRL_DS_DELETE_TREE, MAKEINTRESOURCE(IDS_ACTRL_DS_DELETE_TREE), SI_ACCESS_SPECIFIC },
  39. { &GUID_NULL, READ_CONTROL, MAKEINTRESOURCE(IDS_ACTRL_READ_CONTROL), SI_ACCESS_SPECIFIC },
  40. { &GUID_NULL, WRITE_DAC, MAKEINTRESOURCE(IDS_ACTRL_CHANGE_ACCESS), SI_ACCESS_SPECIFIC },
  41. { &GUID_NULL, WRITE_OWNER, MAKEINTRESOURCE(IDS_ACTRL_CHANGE_OWNER), SI_ACCESS_SPECIFIC },
  42. { &GUID_NULL, 0, MAKEINTRESOURCE(IDS_NO_ACCESS), 0 },
  43. { &GUID_NULL, ACTRL_DS_SELF, MAKEINTRESOURCE(IDS_ACTRL_DS_SELF), SI_ACCESS_SPECIFIC },
  44. { &GUID_NULL, ACTRL_DS_CONTROL_ACCESS, MAKEINTRESOURCE(IDS_ACTRL_DS_CONTROL_ACCESS),SI_ACCESS_SPECIFIC },
  45. { &GUID_NULL, ACTRL_DS_CREATE_CHILD, MAKEINTRESOURCE(IDS_ACTRL_DS_CREATE_CHILD), SI_ACCESS_CONTAINER | SI_ACCESS_SPECIFIC },
  46. { &GUID_NULL, ACTRL_DS_DELETE_CHILD, MAKEINTRESOURCE(IDS_ACTRL_DS_DELETE_CHILD), SI_ACCESS_CONTAINER | SI_ACCESS_SPECIFIC },
  47. { &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.
  48. };
  49. #define g_iDSRead 1 // DS_GENERIC_READ
  50. #define g_iDSListObject 4 // ACTRL_DS_LIST_OBJECT
  51. #define g_iDSProperties 5 // Read/Write properties
  52. #define g_iDSDefAccess g_iDSRead
  53. #define g_iDSAllExtRights 15
  54. #define g_iDSAllValRights 14
  55. #define g_iDSDeleteTree 9
  56. //
  57. // The following array defines the inheritance types common to all DS containers.
  58. //
  59. SI_INHERIT_TYPE g_siDSInheritTypes[] =
  60. {
  61. { &GUID_NULL, 0, MAKEINTRESOURCE(IDS_DS_CONTAINER_ONLY) },
  62. { &GUID_NULL, CONTAINER_INHERIT_ACE, MAKEINTRESOURCE(IDS_DS_CONTAINER_SUBITEMS) },
  63. { &GUID_NULL, CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE, MAKEINTRESOURCE(IDS_DS_SUBITEMS_ONLY) },
  64. };
  65. //
  66. //Used to store some temp info
  67. //
  68. typedef struct _temp_info
  69. {
  70. LPCGUID pguid;
  71. DWORD dwFilter;
  72. LPCWSTR pszLdapName;
  73. WCHAR szDisplayName[ANYSIZE_ARRAY];
  74. } TEMP_INFO, *PTEMP_INFO;
  75. //
  76. // Helper functions for cleaning up DPA lists
  77. //
  78. int CALLBACK
  79. _LocalFreeCB(LPVOID pVoid, LPVOID /*pData*/)
  80. {
  81. LocalFree(pVoid);
  82. return 1;
  83. }
  84. void
  85. DestroyDPA(HDPA hList)
  86. {
  87. if (hList != NULL)
  88. DPA_DestroyCallback(hList, _LocalFreeCB, 0);
  89. }
  90. //
  91. // Callback function for merging. Passed to DPA_Merge
  92. //
  93. LPVOID CALLBACK _Merge(UINT , LPVOID pvDest, LPVOID , LPARAM )
  94. {
  95. return pvDest;
  96. }
  97. BSTR
  98. GetFilterFilePath(void)
  99. {
  100. WCHAR szFilterFile[MAX_PATH];
  101. UINT cch = GetSystemDirectory(szFilterFile, ARRAYSIZE(szFilterFile));
  102. if (0 == cch || cch >= ARRAYSIZE(szFilterFile))
  103. return NULL;
  104. if (szFilterFile[cch-1] != L'\\')
  105. szFilterFile[cch++] = L'\\';
  106. lstrcpynW(szFilterFile + cch, c_szFilterFile, ARRAYSIZE(szFilterFile) - cch);
  107. return SysAllocString(szFilterFile);
  108. }
  109. //
  110. // Local prototypes
  111. //
  112. HRESULT
  113. Schema_Search(LPWSTR pszSchemaSearchPath,
  114. LPCWSTR pszFilter,
  115. HDPA *phCache,
  116. BOOL bProperty);
  117. //
  118. // C wrappers for the schema cache object
  119. //
  120. HRESULT
  121. SchemaCache_Create(LPCWSTR pszServer)
  122. {
  123. HRESULT hr = S_OK;
  124. if (g_pSchemaCache == NULL)
  125. {
  126. g_pSchemaCache = new CSchemaCache(pszServer);
  127. if (g_pSchemaCache == NULL)
  128. hr = E_OUTOFMEMORY;
  129. }
  130. return hr;
  131. }
  132. void
  133. SchemaCache_Destroy(void)
  134. {
  135. delete g_pSchemaCache;
  136. g_pSchemaCache = NULL;
  137. }
  138. HRESULT
  139. SchemaCache_GetInheritTypes(LPCGUID pguidObjectType,
  140. DWORD dwFlags,
  141. PSI_INHERIT_TYPE *ppInheritTypes,
  142. ULONG *pcInheritTypes)
  143. {
  144. HRESULT hr = E_UNEXPECTED;
  145. if (g_pSchemaCache)
  146. hr = g_pSchemaCache->GetInheritTypes(pguidObjectType, dwFlags, ppInheritTypes, pcInheritTypes);
  147. return hr;
  148. }
  149. HRESULT
  150. SchemaCache_GetAccessRights(LPCGUID pguidObjectType,
  151. LPCWSTR pszClassName,
  152. HDPA hAuxList,
  153. LPCWSTR pszSchemaPath,
  154. DWORD dwFlags,
  155. PACCESS_INFO* ppAccesInfo)
  156. {
  157. HRESULT hr = E_UNEXPECTED;
  158. if (g_pSchemaCache)
  159. hr = g_pSchemaCache->GetAccessRights(pguidObjectType,
  160. pszClassName,
  161. hAuxList,
  162. pszSchemaPath,
  163. dwFlags,
  164. ppAccesInfo);
  165. return hr;
  166. }
  167. HRESULT
  168. Schema_GetDefaultSD( GUID *pSchemaIdGuid,
  169. PSID pDomainSid,
  170. PSID pRootDomainSid,
  171. PSECURITY_DESCRIPTOR *ppSD )
  172. {
  173. HRESULT hr = E_UNEXPECTED;
  174. if( g_pSchemaCache )
  175. hr = g_pSchemaCache->GetDefaultSD(pSchemaIdGuid,
  176. pDomainSid,
  177. pRootDomainSid,
  178. ppSD);
  179. return hr;
  180. }
  181. HRESULT Schema_GetObjectTypeList(GUID *pSchamaGuid,
  182. HDPA hAuxList,
  183. LPCWSTR pszSchemaPath,
  184. DWORD dwFlags,
  185. POBJECT_TYPE_LIST *ppObjectTypeList,
  186. DWORD * pObjectTypeListCount)
  187. {
  188. HRESULT hr = E_UNEXPECTED;
  189. if( g_pSchemaCache )
  190. hr = g_pSchemaCache->GetObjectTypeList( pSchamaGuid,
  191. hAuxList,
  192. pszSchemaPath,
  193. dwFlags,
  194. ppObjectTypeList,
  195. pObjectTypeListCount);
  196. return hr;
  197. }
  198. HRESULT Schema_GetObjectTypeGuid(LPCWSTR pszClassName, LPGUID pGuid)
  199. {
  200. if( g_pSchemaCache )
  201. return g_pSchemaCache->LookupClassID(pszClassName, pGuid);
  202. else
  203. return E_UNEXPECTED;
  204. }
  205. AUTHZ_RESOURCE_MANAGER_HANDLE Schema_GetAUTHZ_RM()
  206. {
  207. if( g_pSchemaCache )
  208. return g_pSchemaCache->GetAuthzRM();
  209. return NULL;
  210. }
  211. //
  212. // DPA comparison functions used for sorting and searching the cache lists
  213. //
  214. int CALLBACK
  215. Schema_CompareLdapName(LPVOID p1, LPVOID p2, LPARAM lParam)
  216. {
  217. int nResult = 0;
  218. PID_CACHE_ENTRY pEntry1 = (PID_CACHE_ENTRY)p1;
  219. PID_CACHE_ENTRY pEntry2 = (PID_CACHE_ENTRY)p2;
  220. LPCWSTR pszFind = (LPCWSTR)lParam;
  221. if (pEntry1)
  222. pszFind = pEntry1->szLdapName;
  223. if (pszFind && pEntry2)
  224. {
  225. nResult = CompareStringW(LOCALE_USER_DEFAULT,
  226. 0,
  227. pszFind,
  228. -1,
  229. pEntry2->szLdapName,
  230. -1) - CSTR_EQUAL;
  231. }
  232. return nResult;
  233. }
  234. //
  235. // Callback function used to sort based on display name
  236. //
  237. int CALLBACK
  238. Schema_CompareTempDisplayName(LPVOID p1, LPVOID p2, LPARAM )
  239. {
  240. int nResult = 0;
  241. PTEMP_INFO pti1 = (PTEMP_INFO)p1;
  242. PTEMP_INFO pti2 = (PTEMP_INFO)p2;
  243. if (pti1 && pti2)
  244. {
  245. LPCWSTR psz1 = pti1->szDisplayName;
  246. LPCWSTR psz2 = pti2->szDisplayName;
  247. if (!*psz1)
  248. psz1 = pti1->pszLdapName;
  249. if (!*psz2)
  250. psz2 = pti2->pszLdapName;
  251. // Note that we are sorting backwards
  252. nResult = CompareStringW(LOCALE_USER_DEFAULT,
  253. 0,
  254. (LPCWSTR)psz2,
  255. -1,
  256. (LPCWSTR)psz1,
  257. -1) - CSTR_EQUAL;
  258. }
  259. return nResult;
  260. }
  261. //
  262. // Callback function used to sort based on display name
  263. //
  264. int CALLBACK
  265. Schema_ComparePropDisplayName(LPVOID p1, LPVOID p2, LPARAM )
  266. {
  267. int nResult = 0;
  268. PPROP_ENTRY pti1 = (PPROP_ENTRY)p1;
  269. PPROP_ENTRY pti2 = (PPROP_ENTRY)p2;
  270. if (pti1 && pti2)
  271. {
  272. LPCWSTR psz1 = pti1->szName;
  273. LPCWSTR psz2 = pti2->szName;
  274. nResult = CompareStringW(LOCALE_USER_DEFAULT,
  275. 0,
  276. (LPCWSTR)psz1,
  277. -1,
  278. (LPCWSTR)psz2,
  279. -1) - CSTR_EQUAL;
  280. }
  281. return nResult;
  282. }
  283. //
  284. // DPA comparison function used for sorting the Extended Rights list
  285. //
  286. int CALLBACK
  287. Schema_CompareER(LPVOID p1, LPVOID p2, LPARAM /*lParam*/)
  288. {
  289. int nResult = 0;
  290. PER_ENTRY pEntry1 = (PER_ENTRY)p1;
  291. PER_ENTRY pEntry2 = (PER_ENTRY)p2;
  292. if (pEntry1 && pEntry2)
  293. {
  294. nResult = CompareStringW(LOCALE_USER_DEFAULT,
  295. 0,
  296. pEntry1->szName,
  297. -1,
  298. pEntry2->szName,
  299. -1) - CSTR_EQUAL;
  300. }
  301. return nResult;
  302. }
  303. //
  304. // CSchemaCache object implementation
  305. //
  306. CSchemaCache::CSchemaCache(LPCWSTR pszServer)
  307. {
  308. HRESULT hr;
  309. IADsPathname *pPath = NULL;
  310. BSTR strRootDSEPath = NULL;
  311. IADs *pRootDSE = NULL;
  312. VARIANT var = {0};
  313. DWORD dwThreadID;
  314. HANDLE ahWait[2];
  315. TraceEnter(TRACE_SCHEMA, "CSchemaCache::CSchemaCache");
  316. // Initialize everything
  317. ZeroMemory(this, sizeof(CSchemaCache));
  318. m_hrClassResult = E_UNEXPECTED;
  319. m_hrPropertyResult = E_UNEXPECTED;
  320. m_nDsListObjectEnforced = -1;
  321. m_hLoadLibPropWaitEvent = NULL;
  322. m_hLoadLibClassWaitEvent = NULL;
  323. m_AICommon.pAccess = g_siDSAccesses;
  324. m_AICommon.cAccesses = ARRAYSIZE(g_siDSAccesses);
  325. m_AICommon.iDefaultAccess = g_iDSDefAccess;
  326. m_AICommon.bLocalFree = FALSE;
  327. m_hClassCache = NULL;
  328. m_hPropertyCache = NULL;
  329. m_pInheritTypeArray = NULL;
  330. m_hObjectTypeCache = NULL;
  331. m_hAccessInfoCache = NULL;
  332. ExceptionPropagatingInitializeCriticalSection(&m_ObjectTypeCacheCritSec);
  333. if (pszServer && !*pszServer)
  334. pszServer = NULL;
  335. // Create a path object for manipulating ADS paths
  336. hr = CoCreateInstance(CLSID_Pathname,
  337. NULL,
  338. CLSCTX_INPROC_SERVER,
  339. IID_IADsPathname,
  340. (LPVOID*)&pPath);
  341. FailGracefully(hr, "Unable to create ADsPathname object");
  342. // Build RootDSE path with server
  343. hr = pPath->Set((LPWSTR)c_szRootDsePath, ADS_SETTYPE_FULL);
  344. FailGracefully(hr, "Unable to initialize path object");
  345. if (pszServer)
  346. {
  347. hr = pPath->Set((LPWSTR)pszServer, ADS_SETTYPE_SERVER);
  348. FailGracefully(hr, "Unable to initialize path object");
  349. }
  350. hr = pPath->Retrieve(ADS_FORMAT_WINDOWS, &strRootDSEPath);
  351. FailGracefully(hr, "Unable to retrieve RootDSE path from path object");
  352. // Bind to the RootDSE object
  353. hr = OpenDSObject(strRootDSEPath,
  354. NULL,
  355. NULL,
  356. ADS_SECURE_AUTHENTICATION,
  357. IID_IADs,
  358. (LPVOID*)&pRootDSE);
  359. if (FAILED(hr) && pszServer)
  360. {
  361. // Try again with no server
  362. SysFreeString(strRootDSEPath);
  363. hr = pPath->Retrieve(ADS_FORMAT_WINDOWS_NO_SERVER, &strRootDSEPath);
  364. FailGracefully(hr, "Unable to retrieve RootDSE path from path object");
  365. hr = OpenDSObject(strRootDSEPath,
  366. NULL,
  367. NULL,
  368. ADS_SECURE_AUTHENTICATION,
  369. IID_IADs,
  370. (LPVOID*)&pRootDSE);
  371. }
  372. FailGracefully(hr, "Failed to bind to root DSE");
  373. // Build the schema root path
  374. hr = pRootDSE->Get((LPWSTR)c_szSchemaContext, &var);
  375. FailGracefully(hr, "Unable to get schema naming context");
  376. TraceAssert(V_VT(&var) == VT_BSTR);
  377. hr = pPath->Set(V_BSTR(&var), ADS_SETTYPE_DN);
  378. FailGracefully(hr, "Unable to initialize path object");
  379. hr = pPath->Retrieve(ADS_FORMAT_WINDOWS, &m_strSchemaSearchPath);
  380. FailGracefully(hr, "Unable to retrieve schema search path from path object");
  381. // Build the Extended Rights container path
  382. VariantClear(&var);
  383. hr = pRootDSE->Get((LPWSTR)c_szConfigContext, &var);
  384. FailGracefully(hr, "Unable to get configuration naming context");
  385. TraceAssert(V_VT(&var) == VT_BSTR);
  386. hr = pPath->Set(V_BSTR(&var), ADS_SETTYPE_DN);
  387. FailGracefully(hr, "Unable to initialize path object");
  388. hr = pPath->AddLeafElement((LPWSTR)c_szERContainer);
  389. FailGracefully(hr, "Unable to build Extended Rights path");
  390. hr = pPath->Retrieve(ADS_FORMAT_WINDOWS, &m_strERSearchPath);
  391. FailGracefully(hr, "Unable to retrieve Extended Rights search path from path object");
  392. //Create the Events
  393. m_hLoadLibPropWaitEvent = CreateEvent(NULL,
  394. TRUE,
  395. FALSE,
  396. NULL );
  397. m_hLoadLibClassWaitEvent = CreateEvent(NULL,
  398. TRUE,
  399. FALSE,
  400. NULL );
  401. if( m_hLoadLibPropWaitEvent && m_hLoadLibClassWaitEvent )
  402. {
  403. // Start a thread to enumerate the schema classes
  404. m_hClassThread = CreateThread(NULL,
  405. 0,
  406. SchemaClassThread,
  407. this,
  408. 0,
  409. &dwThreadID);
  410. // Start a thread to enumerate the schema properties
  411. m_hPropertyThread = CreateThread(NULL,
  412. 0,
  413. SchemaPropertyThread,
  414. this,
  415. 0,
  416. &dwThreadID);
  417. ahWait[0] = m_hClassThread;
  418. ahWait[1] = m_hPropertyThread;
  419. WaitForMultipleObjects(2,
  420. ahWait,
  421. TRUE,
  422. INFINITE);
  423. }
  424. exit_gracefully:
  425. VariantClear(&var);
  426. DoRelease(pRootDSE);
  427. DoRelease(pPath);
  428. SysFreeString(strRootDSEPath);
  429. if( m_hLoadLibPropWaitEvent )
  430. CloseHandle( m_hLoadLibPropWaitEvent );
  431. if( m_hLoadLibClassWaitEvent )
  432. CloseHandle( m_hLoadLibClassWaitEvent );
  433. TraceLeaveVoid();
  434. }
  435. CSchemaCache::~CSchemaCache()
  436. {
  437. TraceEnter(TRACE_SCHEMA, "CSchemaCache::~CSchemaCache");
  438. SysFreeString(m_strSchemaSearchPath);
  439. SysFreeString(m_strERSearchPath);
  440. SysFreeString(m_strFilterFile);
  441. DeleteCriticalSection(&m_ObjectTypeCacheCritSec);
  442. DestroyDPA(m_hClassCache);
  443. DestroyDPA(m_hPropertyCache);
  444. if(m_hObjectTypeCache)
  445. {
  446. POBJECT_TYPE_CACHE pOTC = NULL;
  447. UINT cCount = DPA_GetPtrCount(m_hObjectTypeCache);
  448. for(UINT i = 0; i < cCount; ++i)
  449. {
  450. pOTC = (POBJECT_TYPE_CACHE)DPA_FastGetPtr(m_hObjectTypeCache, i);
  451. if(pOTC)
  452. {
  453. DestroyDPA(pOTC->hListChildObject);
  454. DestroyDPA(pOTC->hListExtRights);
  455. DestroyDPA(pOTC->hListProperty);
  456. DestroyDPA(pOTC->hListPropertySet);
  457. }
  458. }
  459. }
  460. DestroyDPA(m_hObjectTypeCache);
  461. if (m_hAccessInfoCache != NULL)
  462. {
  463. UINT cItems = DPA_GetPtrCount(m_hAccessInfoCache);
  464. PACCESS_INFO pAI = NULL;
  465. while (cItems > 0)
  466. {
  467. pAI = (PACCESS_INFO)DPA_FastGetPtr(m_hAccessInfoCache, --cItems);
  468. if(pAI && pAI->pAccess)
  469. LocalFree(pAI->pAccess);
  470. }
  471. }
  472. DestroyDPA(m_hAccessInfoCache);
  473. if (m_pInheritTypeArray != NULL)
  474. LocalFree(m_pInheritTypeArray);
  475. TraceMsg("CSchemaCache::~CSchemaCache exiting");
  476. TraceLeaveVoid();
  477. }
  478. LPCWSTR
  479. CSchemaCache::GetClassName(LPCGUID pguidObjectType)
  480. {
  481. LPCWSTR pszLdapName = NULL;
  482. PID_CACHE_ENTRY pCacheEntry;
  483. TraceEnter(TRACE_SCHEMACLASS, "CSchemaCache::GetClassName");
  484. pCacheEntry = LookupClass(pguidObjectType);
  485. if (pCacheEntry != NULL)
  486. pszLdapName = pCacheEntry->szLdapName;
  487. TraceLeaveValue(pszLdapName);
  488. }
  489. HRESULT
  490. CSchemaCache::GetInheritTypes(LPCGUID ,
  491. DWORD dwFlags,
  492. PSI_INHERIT_TYPE *ppInheritTypes,
  493. ULONG *pcInheritTypes)
  494. {
  495. // We're going to find the inherit type array corresponding to the passed-in
  496. // object type - pInheritTypeArray will point to it!
  497. TraceEnter(TRACE_SCHEMACLASS, "CSchemaCache::GetInheritTypes");
  498. TraceAssert(ppInheritTypes != NULL);
  499. TraceAssert(pcInheritTypes != NULL);
  500. *pcInheritTypes = 0;
  501. *ppInheritTypes = NULL;
  502. // If the filter state is changing, free everything
  503. if (m_pInheritTypeArray &&
  504. (m_pInheritTypeArray->dwFlags & SCHEMA_NO_FILTER) != (dwFlags & SCHEMA_NO_FILTER))
  505. {
  506. LocalFree(m_pInheritTypeArray);
  507. m_pInheritTypeArray = NULL;
  508. }
  509. // Build m_pInheritTypeArray if necessary
  510. if (m_pInheritTypeArray == NULL)
  511. {
  512. BuildInheritTypeArray(dwFlags);
  513. }
  514. // Return m_pInheritTypeArray if we have it, otherwise
  515. // fall back on the static types
  516. if (m_pInheritTypeArray)
  517. {
  518. *pcInheritTypes = m_pInheritTypeArray->cInheritTypes;
  519. *ppInheritTypes = m_pInheritTypeArray->aInheritType;
  520. }
  521. else
  522. {
  523. TraceMsg("Returning default inherit information");
  524. *ppInheritTypes = g_siDSInheritTypes;
  525. *pcInheritTypes = ARRAYSIZE(g_siDSInheritTypes);
  526. }
  527. TraceLeaveResult(S_OK); // always succeed
  528. }
  529. HRESULT
  530. CSchemaCache::GetAccessRights(LPCGUID pguidObjectType,
  531. LPCWSTR pszClassName,
  532. HDPA hAuxList,
  533. LPCWSTR pszSchemaPath,
  534. DWORD dwFlags,
  535. PACCESS_INFO *ppAccessInfo)
  536. {
  537. HRESULT hr = S_OK;
  538. HCURSOR hcur;
  539. TraceEnter(TRACE_SCHEMA, "CSchemaCache::GetAccessRights");
  540. TraceAssert(ppAccessInfo);
  541. BOOL bAddToCache = FALSE;
  542. PACCESS_INFO pAI = NULL;
  543. //
  544. // If the SCHEMA_COMMON_PERM flag is on, just return the permissions
  545. // that are common to all DS objects (including containers).
  546. //
  547. if (dwFlags & SCHEMA_COMMON_PERM)
  548. {
  549. *ppAccessInfo = &m_AICommon;
  550. TraceLeaveResult(S_OK);
  551. }
  552. TraceAssert(pguidObjectType);
  553. EnterCriticalSection(&m_ObjectTypeCacheCritSec);
  554. //
  555. //If AuxList is null, we can return the item from cache
  556. //
  557. if(hAuxList == NULL)
  558. {
  559. //There is no Aux Class. Check the m_hAccessInfoCache if we have access right
  560. //for the pguidObjectType;
  561. if (m_hAccessInfoCache != NULL)
  562. {
  563. UINT cItems = DPA_GetPtrCount(m_hAccessInfoCache);
  564. while (cItems > 0)
  565. {
  566. pAI = (PACCESS_INFO)DPA_FastGetPtr(m_hAccessInfoCache, --cItems);
  567. //
  568. //Found A match.
  569. //
  570. if(pAI &&
  571. IsEqualGUID(pAI->ObjectTypeGuid, *pguidObjectType) &&
  572. ((pAI->dwFlags & (SI_EDIT_PROPERTIES | SI_EDIT_EFFECTIVE)) ==
  573. (dwFlags & (SI_EDIT_PROPERTIES | SI_EDIT_EFFECTIVE))))
  574. break;
  575. pAI = NULL;
  576. }
  577. if(pAI)
  578. {
  579. goto exit_gracefully;
  580. }
  581. }
  582. bAddToCache = TRUE;
  583. }
  584. pAI = (PACCESS_INFO)LocalAlloc(LPTR,sizeof(ACCESS_INFO));
  585. if(!pAI)
  586. ExitGracefully(hr, E_OUTOFMEMORY, "LocalAlloc failed");
  587. hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  588. hr = BuildAccessArray(pguidObjectType,
  589. pszClassName,
  590. pszSchemaPath,
  591. hAuxList,
  592. dwFlags,
  593. &pAI->pAccess,
  594. &pAI->cAccesses,
  595. &pAI->iDefaultAccess);
  596. FailGracefully(hr, "BuildAccessArray Failed");
  597. if(bAddToCache)
  598. {
  599. if(!m_hAccessInfoCache)
  600. m_hAccessInfoCache = DPA_Create(4);
  601. if(!m_hAccessInfoCache)
  602. ExitGracefully(hr, E_OUTOFMEMORY, "DPA_Create Failed");
  603. pAI->dwFlags = dwFlags;
  604. pAI->ObjectTypeGuid = *pguidObjectType;
  605. DPA_AppendPtr(m_hAccessInfoCache, pAI);
  606. }
  607. //
  608. //If item is added to cache, don't localfree it. It will be free when
  609. //DLL is unloaded
  610. //
  611. pAI->bLocalFree = !bAddToCache;
  612. SetCursor(hcur);
  613. exit_gracefully:
  614. if(FAILED(hr))
  615. {
  616. if(pAI)
  617. {
  618. LocalFree(pAI);
  619. pAI = NULL;
  620. }
  621. }
  622. *ppAccessInfo = pAI;
  623. LeaveCriticalSection(&m_ObjectTypeCacheCritSec);
  624. TraceLeaveResult(hr);
  625. }
  626. HRESULT
  627. CSchemaCache::GetDefaultSD(GUID *pSchemaIDGuid,
  628. PSID pDomainSid,
  629. PSID pRootDomainSid,
  630. PSECURITY_DESCRIPTOR *ppSD)
  631. {
  632. TraceEnter(TRACE_SCHEMA, "CSchemaCache::GetDefaultSD");
  633. TraceAssert( pSchemaIDGuid != NULL);
  634. TraceAssert( ppSD != NULL );
  635. HRESULT hr = S_OK;
  636. if( (pDomainSid && !IsValidSid(pDomainSid)) ||
  637. (pRootDomainSid && !IsValidSid(pRootDomainSid)) )
  638. return E_INVALIDARG;
  639. LPWSTR pszDestData = NULL;
  640. IDirectorySearch * IDs = NULL;
  641. ADS_SEARCH_HANDLE hSearchHandle=NULL;
  642. LPWSTR lpszSchemaGuidFilter = L"(schemaIdGuid=%s)";
  643. LPWSTR pszAttr[] = {L"defaultSecurityDescriptor"};
  644. ADS_SEARCH_COLUMN col;
  645. WCHAR szSearchBuffer[MAX_PATH];
  646. hr = ADsEncodeBinaryData( (PBYTE)pSchemaIDGuid,
  647. sizeof(GUID),
  648. &pszDestData );
  649. FailGracefully(hr, "ADsEncodeBinaryData Failed");
  650. wsprintf(szSearchBuffer, lpszSchemaGuidFilter,pszDestData);
  651. //We have Filter Now
  652. //Search in Configuration Contianer
  653. hr = OpenDSObject( m_strSchemaSearchPath,
  654. NULL,
  655. NULL,
  656. ADS_SECURE_AUTHENTICATION,
  657. IID_IDirectorySearch,
  658. (void **)&IDs );
  659. FailGracefully(hr, "OpenDSObject Failed");
  660. hr = IDs->ExecuteSearch(szSearchBuffer,
  661. pszAttr,
  662. 1,
  663. &hSearchHandle );
  664. FailGracefully(hr, "Search in Schema Failed");
  665. hr = IDs->GetFirstRow(hSearchHandle);
  666. if( hr == S_OK )
  667. {
  668. //Get Guid
  669. hr = IDs->GetColumn( hSearchHandle, pszAttr[0], &col );
  670. FailGracefully(hr, "Failed to get column from search result");
  671. if(pDomainSid && pRootDomainSid)
  672. {
  673. if(!ConvertStringSDToSDDomain(pDomainSid,
  674. pRootDomainSid,
  675. (LPCWSTR)(LPWSTR)col.pADsValues->CaseIgnoreString,
  676. SDDL_REVISION_1,
  677. ppSD,
  678. NULL ))
  679. {
  680. hr = GetLastError();
  681. IDs->FreeColumn( &col );
  682. ExitGracefully(hr, E_FAIL, "Unable to convert String SD to SD");
  683. }
  684. }
  685. else
  686. {
  687. if ( !ConvertStringSecurityDescriptorToSecurityDescriptor( (LPCWSTR)(LPWSTR)col.pADsValues->CaseIgnoreString,
  688. SDDL_REVISION_1,
  689. ppSD,
  690. NULL ) )
  691. {
  692. hr = GetLastError();
  693. IDs->FreeColumn( &col );
  694. ExitGracefully(hr, E_FAIL, "Unable to convert String SD to SD");
  695. }
  696. }
  697. IDs->FreeColumn( &col );
  698. }
  699. else
  700. ExitGracefully(hr, E_FAIL, "Schema search resulted in zero rows");
  701. exit_gracefully:
  702. if( IDs )
  703. {
  704. if( hSearchHandle )
  705. IDs->CloseSearchHandle( hSearchHandle );
  706. IDs->Release();
  707. }
  708. FreeADsMem(pszDestData);
  709. TraceLeaveResult(hr);
  710. }
  711. VOID AddOTLToList( POBJECT_TYPE_LIST pOTL, WORD Level, LPGUID pGuidObject )
  712. {
  713. (pOTL)->Level = Level;
  714. (pOTL)->ObjectType = pGuidObject;
  715. }
  716. //Get the ObjectTypeList for pSchemaGuid class
  717. OBJECT_TYPE_LIST g_DefaultOTL[] = {
  718. {0, 0, (LPGUID)&GUID_NULL},
  719. };
  720. HRESULT
  721. CSchemaCache::GetObjectTypeList( GUID *pguidObjectType,
  722. HDPA hAuxList,
  723. LPCWSTR pszSchemaPath,
  724. DWORD dwFlags,
  725. POBJECT_TYPE_LIST *ppObjectTypeList,
  726. DWORD * pObjectTypeListCount)
  727. {
  728. TraceEnter(TRACE_SCHEMA, "CSchemaCache::GetObjectTypeList");
  729. TraceAssert( pguidObjectType != NULL);
  730. TraceAssert( ppObjectTypeList != NULL );
  731. TraceAssert( pObjectTypeListCount != NULL );
  732. TraceAssert(pszSchemaPath != NULL);
  733. HRESULT hr = S_OK;
  734. //
  735. //Lists
  736. //
  737. HDPA hExtRightList = NULL;
  738. HDPA hPropSetList = NULL;
  739. HDPA hPropertyList = NULL;
  740. HDPA hClassList = NULL;
  741. //
  742. //List counts
  743. //
  744. ULONG cExtendedRights = 0;
  745. ULONG cPropertySets = 0;
  746. UINT cProperties = 0;
  747. UINT cChildClasses = 0;
  748. POBJECT_TYPE_LIST pOTL = NULL;
  749. POBJECT_TYPE_LIST pTempOTL = NULL;
  750. LPCWSTR pszClassName = NULL;
  751. UINT cGuidIndex = 0;
  752. if( dwFlags & SCHEMA_COMMON_PERM )
  753. {
  754. *ppObjectTypeList =
  755. (POBJECT_TYPE_LIST)LocalAlloc(LPTR,sizeof(OBJECT_TYPE_LIST)*ARRAYSIZE(g_DefaultOTL));
  756. if(!*ppObjectTypeList)
  757. TraceLeaveResult(E_OUTOFMEMORY);
  758. //
  759. //Note that default OTL is entry with all zero,thatz what LPTR does.
  760. //so there is no need to copy
  761. //
  762. *pObjectTypeListCount = ARRAYSIZE(g_DefaultOTL);
  763. TraceLeaveResult(S_OK);
  764. }
  765. EnterCriticalSection(&m_ObjectTypeCacheCritSec);
  766. //
  767. // Lookup the name of this class
  768. //
  769. if (pszClassName == NULL)
  770. pszClassName = GetClassName(pguidObjectType);
  771. if(!pszClassName)
  772. ExitGracefully(hr, E_UNEXPECTED, "Unknown child object GUID");
  773. //
  774. // Get the list of Extended Rights for this page
  775. //
  776. if (pguidObjectType &&
  777. SUCCEEDED(GetExtendedRightsForNClasses(m_strERSearchPath,
  778. pguidObjectType,
  779. hAuxList,
  780. &hExtRightList,
  781. &hPropSetList)))
  782. {
  783. if(hPropSetList)
  784. cPropertySets = DPA_GetPtrCount(hPropSetList);
  785. if(hExtRightList)
  786. cExtendedRights = DPA_GetPtrCount(hExtRightList);
  787. }
  788. //
  789. //Get the child classes
  790. //
  791. if( pguidObjectType &&
  792. SUCCEEDED(GetChildClassesForNClasses(pguidObjectType,
  793. pszClassName,
  794. hAuxList,
  795. pszSchemaPath,
  796. &hClassList)))
  797. {
  798. if(hClassList)
  799. cChildClasses = DPA_GetPtrCount(hClassList);
  800. }
  801. //
  802. //Get the properties for the class
  803. //
  804. if (pguidObjectType &&
  805. SUCCEEDED(GetPropertiesForNClasses(pguidObjectType,
  806. pszClassName,
  807. hAuxList,
  808. pszSchemaPath,
  809. &hPropertyList)))
  810. {
  811. if(hPropertyList)
  812. cProperties = DPA_GetPtrCount(hPropertyList);
  813. }
  814. pOTL = (POBJECT_TYPE_LIST)LocalAlloc(LPTR,
  815. (cPropertySets +
  816. cExtendedRights +
  817. cChildClasses +
  818. cProperties +
  819. 1)* sizeof(OBJECT_TYPE_LIST));
  820. if(!pOTL)
  821. ExitGracefully(hr, E_OUTOFMEMORY, "Unable to create POBJECT_TYPE_LIST");
  822. pTempOTL = pOTL;
  823. //
  824. //First Add the entry corresponding to Object
  825. //
  826. AddOTLToList(pTempOTL,
  827. ACCESS_OBJECT_GUID,
  828. pguidObjectType);
  829. pTempOTL++;
  830. cGuidIndex++;
  831. UINT i, j;
  832. for (i = 0; i < cExtendedRights; i++)
  833. {
  834. PER_ENTRY pER = (PER_ENTRY)DPA_FastGetPtr(hExtRightList, i);
  835. AddOTLToList(pTempOTL,
  836. ACCESS_PROPERTY_SET_GUID,
  837. &(pER->guid));
  838. pTempOTL++;
  839. cGuidIndex++;
  840. }
  841. //
  842. //Add Property Set
  843. //
  844. for(i = 0; i < cPropertySets; ++i)
  845. {
  846. PER_ENTRY pER = (PER_ENTRY)DPA_FastGetPtr(hPropSetList, i);
  847. AddOTLToList(pTempOTL,
  848. ACCESS_PROPERTY_SET_GUID,
  849. &pER->guid);
  850. cGuidIndex++;
  851. pTempOTL++;
  852. //
  853. //Add all the properties which are member of this property set
  854. //
  855. for(j = 0; j < cProperties; ++j)
  856. {
  857. PPROP_ENTRY pProp = (PPROP_ENTRY)DPA_FastGetPtr(hPropertyList, j);
  858. if(IsEqualGUID(pER->guid, *pProp->pasguid))
  859. {
  860. AddOTLToList(pTempOTL,
  861. ACCESS_PROPERTY_GUID,
  862. pProp->pguid);
  863. cGuidIndex++;
  864. pTempOTL++;
  865. pProp->dwFlags|= OTL_ADDED_TO_LIST;
  866. }
  867. }
  868. }
  869. //Add all remaining properties
  870. for( j =0; j < cProperties; ++j )
  871. {
  872. PPROP_ENTRY pProp = (PPROP_ENTRY)DPA_FastGetPtr(hPropertyList, j);
  873. if( !(pProp->dwFlags & OTL_ADDED_TO_LIST) )
  874. {
  875. AddOTLToList(pTempOTL,
  876. ACCESS_PROPERTY_SET_GUID,
  877. pProp->pguid);
  878. pTempOTL++;
  879. cGuidIndex++;
  880. }
  881. pProp->dwFlags &= ~OTL_ADDED_TO_LIST;
  882. }
  883. //All all child clasess
  884. for( j = 0; j < cChildClasses; ++j )
  885. {
  886. PPROP_ENTRY pClass= (PPROP_ENTRY)DPA_FastGetPtr(hClassList, j);
  887. AddOTLToList(pTempOTL,
  888. ACCESS_PROPERTY_SET_GUID,
  889. pClass->pguid);
  890. pTempOTL++;
  891. cGuidIndex++;
  892. }
  893. exit_gracefully:
  894. DPA_Destroy(hExtRightList);
  895. DPA_Destroy(hClassList);
  896. DPA_Destroy(hPropertyList);
  897. DPA_Destroy(hPropSetList);
  898. LeaveCriticalSection(&m_ObjectTypeCacheCritSec);
  899. if (FAILED(hr))
  900. {
  901. *ppObjectTypeList = NULL;
  902. *pObjectTypeListCount = 0;
  903. }
  904. else
  905. {
  906. *ppObjectTypeList = pOTL;
  907. *pObjectTypeListCount = cGuidIndex;
  908. }
  909. TraceLeaveResult(hr);
  910. }
  911. PID_CACHE_ENTRY
  912. CSchemaCache::LookupID(HDPA hCache, LPCWSTR pszLdapName)
  913. {
  914. PID_CACHE_ENTRY pCacheEntry = NULL;
  915. int iEntry;
  916. TraceEnter(TRACE_SCHEMA, "CSchemaCache::LookupID");
  917. TraceAssert(hCache != NULL);
  918. TraceAssert(pszLdapName != NULL && *pszLdapName);
  919. iEntry = DPA_Search(hCache,
  920. NULL,
  921. 0,
  922. Schema_CompareLdapName,
  923. (LPARAM)pszLdapName,
  924. DPAS_SORTED);
  925. if (iEntry != -1)
  926. pCacheEntry = (PID_CACHE_ENTRY)DPA_FastGetPtr(hCache, iEntry);
  927. TraceLeaveValue(pCacheEntry);
  928. }
  929. BOOL
  930. CSchemaCache::IsAuxClass(LPCGUID pguidObjectType)
  931. {
  932. PID_CACHE_ENTRY pCacheEntry = NULL;
  933. HRESULT hr = S_OK;
  934. UINT cItems;
  935. TraceEnter(TRACE_SCHEMACLASS, "CSchemaCache::LookupClass");
  936. TraceAssert(pguidObjectType != NULL);
  937. if(IsEqualGUID(*pguidObjectType, GUID_NULL))
  938. return FALSE;
  939. hr = WaitOnClassThread();
  940. FailGracefully(hr, "Class cache unavailable");
  941. TraceAssert(m_hClassCache != NULL);
  942. cItems = DPA_GetPtrCount(m_hClassCache);
  943. while (cItems > 0)
  944. {
  945. PID_CACHE_ENTRY pTemp = (PID_CACHE_ENTRY)DPA_FastGetPtr(m_hClassCache, --cItems);
  946. if (IsEqualGUID(*pguidObjectType, pTemp->guid))
  947. {
  948. pCacheEntry = pTemp;
  949. break;
  950. }
  951. }
  952. exit_gracefully:
  953. if(pCacheEntry)
  954. return pCacheEntry->bAuxClass;
  955. else
  956. return FALSE;
  957. }
  958. PID_CACHE_ENTRY
  959. CSchemaCache::LookupClass(LPCGUID pguidObjectType)
  960. {
  961. PID_CACHE_ENTRY pCacheEntry = NULL;
  962. HRESULT hr = S_OK;
  963. UINT cItems;
  964. TraceEnter(TRACE_SCHEMACLASS, "CSchemaCache::LookupClass");
  965. TraceAssert(pguidObjectType != NULL);
  966. TraceAssert(!IsEqualGUID(*pguidObjectType, GUID_NULL));
  967. hr = WaitOnClassThread();
  968. FailGracefully(hr, "Class cache unavailable");
  969. TraceAssert(m_hClassCache != NULL);
  970. cItems = DPA_GetPtrCount(m_hClassCache);
  971. while (cItems > 0)
  972. {
  973. PID_CACHE_ENTRY pTemp = (PID_CACHE_ENTRY)DPA_FastGetPtr(m_hClassCache, --cItems);
  974. if (IsEqualGUID(*pguidObjectType, pTemp->guid))
  975. {
  976. pCacheEntry = pTemp;
  977. break;
  978. }
  979. }
  980. exit_gracefully:
  981. TraceLeaveValue(pCacheEntry);
  982. }
  983. HRESULT
  984. CSchemaCache::LookupClassID(LPCWSTR pszClass, LPGUID pGuid)
  985. {
  986. TraceEnter(TRACE_SCHEMACLASS, "CSchemaCache::LookupClassID");
  987. TraceAssert(pszClass != NULL && pGuid != NULL);
  988. HRESULT hr = WaitOnClassThread();
  989. if(SUCCEEDED(hr))
  990. {
  991. TraceAssert(m_hClassCache != NULL);
  992. PID_CACHE_ENTRY pCacheEntry = LookupID(m_hClassCache, pszClass);
  993. if (pCacheEntry)
  994. *pGuid = pCacheEntry->guid;
  995. }
  996. return hr;
  997. }
  998. LPCGUID
  999. CSchemaCache::LookupPropertyID(LPCWSTR pszProperty)
  1000. {
  1001. LPCGUID pID = NULL;
  1002. TraceEnter(TRACE_SCHEMAPROP, "CSchemaCache::LookupPropertyID");
  1003. TraceAssert(pszProperty != NULL);
  1004. if (SUCCEEDED(WaitOnPropertyThread()))
  1005. {
  1006. TraceAssert(m_hPropertyCache != NULL);
  1007. PID_CACHE_ENTRY pCacheEntry = LookupID(m_hPropertyCache, pszProperty);
  1008. if (pCacheEntry)
  1009. pID = &pCacheEntry->guid;
  1010. }
  1011. TraceLeaveValue(pID);
  1012. }
  1013. WCHAR const c_szDsHeuristics[] = L"dSHeuristics";
  1014. int
  1015. CSchemaCache::GetListObjectEnforced(void)
  1016. {
  1017. int nListObjectEnforced = 0; // Assume "not enforced"
  1018. HRESULT hr;
  1019. IADsPathname *pPath = NULL;
  1020. const LPWSTR aszServicePath[] =
  1021. {
  1022. L"CN=Services",
  1023. L"CN=Windows NT",
  1024. L"CN=Directory Service",
  1025. };
  1026. BSTR strServicePath = NULL;
  1027. IDirectoryObject *pDirectoryService = NULL;
  1028. LPWSTR pszDsHeuristics = (LPWSTR)c_szDsHeuristics;
  1029. PADS_ATTR_INFO pAttributeInfo = NULL;
  1030. DWORD dwAttributesReturned;
  1031. LPWSTR pszHeuristicString;
  1032. int i;
  1033. TraceEnter(TRACE_SCHEMA, "CSchemaCache::GetListObjectEnforced");
  1034. // Create a path object for manipulating ADS paths
  1035. hr = CoCreateInstance(CLSID_Pathname,
  1036. NULL,
  1037. CLSCTX_INPROC_SERVER,
  1038. IID_IADsPathname,
  1039. (LPVOID*)&pPath);
  1040. FailGracefully(hr, "Unable to create ADsPathname object");
  1041. hr = pPath->Set(m_strERSearchPath, ADS_SETTYPE_FULL);
  1042. FailGracefully(hr, "Unable to initialize ADsPathname object");
  1043. hr = pPath->RemoveLeafElement();
  1044. for (i = 0; i < ARRAYSIZE(aszServicePath); i++)
  1045. {
  1046. hr = pPath->AddLeafElement(aszServicePath[i]);
  1047. FailGracefully(hr, "Unable to build path to 'Directory Service' object");
  1048. }
  1049. hr = pPath->Retrieve(ADS_FORMAT_WINDOWS, &strServicePath);
  1050. FailGracefully(hr, "Unable to build path to 'Directory Service' object");
  1051. hr = ADsGetObject(strServicePath,
  1052. IID_IDirectoryObject,
  1053. (LPVOID*)&pDirectoryService);
  1054. FailGracefully(hr, "Unable to bind to 'Directory Service' object for heuristics");
  1055. hr = pDirectoryService->GetObjectAttributes(&pszDsHeuristics,
  1056. 1,
  1057. &pAttributeInfo,
  1058. &dwAttributesReturned);
  1059. if (!pAttributeInfo)
  1060. ExitGracefully(hr, hr, "GetObjectAttributes failed to read dSHeuristics property");
  1061. TraceAssert(ADSTYPE_DN_STRING <= pAttributeInfo->dwADsType);
  1062. TraceAssert(ADSTYPE_NUMERIC_STRING >= pAttributeInfo->dwADsType);
  1063. TraceAssert(1 == pAttributeInfo->dwNumValues);
  1064. pszHeuristicString = pAttributeInfo->pADsValues->NumericString;
  1065. if (pszHeuristicString &&
  1066. lstrlenW(pszHeuristicString) > 2 &&
  1067. L'0' != pszHeuristicString[2])
  1068. {
  1069. nListObjectEnforced = 1;
  1070. }
  1071. exit_gracefully:
  1072. if (pAttributeInfo)
  1073. FreeADsMem(pAttributeInfo);
  1074. DoRelease(pDirectoryService);
  1075. DoRelease(pPath);
  1076. SysFreeString(strServicePath);
  1077. TraceLeaveValue(nListObjectEnforced);
  1078. }
  1079. BOOL
  1080. CSchemaCache::HideListObjectAccess(void)
  1081. {
  1082. TraceEnter(TRACE_SCHEMA, "CSchemaCache::HideListObjectAccess");
  1083. if (-1 == m_nDsListObjectEnforced)
  1084. {
  1085. m_nDsListObjectEnforced = GetListObjectEnforced();
  1086. }
  1087. TraceLeaveValue(0 == m_nDsListObjectEnforced);
  1088. }
  1089. #define ACCESS_LENGTH_0 (sizeof(SI_ACCESS) + MAX_TYPENAME_LENGTH * sizeof(WCHAR))
  1090. #define ACCESS_LENGTH_1 (sizeof(SI_ACCESS) + MAX_TYPENAME_LENGTH * sizeof(WCHAR))
  1091. #define ACCESS_LENGTH_2 (3 * sizeof(SI_ACCESS) + 3 * MAX_TYPENAME_LENGTH * sizeof(WCHAR))
  1092. HRESULT
  1093. CSchemaCache::BuildAccessArray(LPCGUID pguidObjectType,
  1094. LPCWSTR pszClassName,
  1095. LPCWSTR pszSchemaPath,
  1096. HDPA hAuxList,
  1097. DWORD dwFlags,
  1098. PSI_ACCESS *ppAccesses,
  1099. ULONG *pcAccesses,
  1100. ULONG *piDefaultAccess)
  1101. {
  1102. HRESULT hr = S_OK;
  1103. DWORD dwBufferLength = 0;
  1104. UINT cMaxAccesses;
  1105. LPWSTR pszData = NULL;
  1106. //
  1107. //Lists
  1108. //
  1109. HDPA hExtRightList = NULL;
  1110. HDPA hPropSetList = NULL;
  1111. HDPA hPropertyList = NULL;
  1112. HDPA hClassList = NULL;
  1113. //
  1114. //List counts
  1115. //
  1116. ULONG cExtendedRights = 0;
  1117. ULONG cPropertySets = 0;
  1118. UINT cProperties = 0;
  1119. UINT cChildClasses = 0;
  1120. ULONG cBaseRights = 0;
  1121. PSI_ACCESS pAccesses = NULL;
  1122. PSI_ACCESS pTempAccesses = NULL;
  1123. ULONG cAccesses = 0;
  1124. TraceEnter(TRACE_SCHEMA, "CSchemaCache::BuildAccessArray");
  1125. TraceAssert(pguidObjectType != NULL);
  1126. TraceAssert(ppAccesses);
  1127. TraceAssert(pcAccesses);
  1128. TraceAssert(piDefaultAccess);
  1129. *ppAccesses = NULL;
  1130. *pcAccesses = 0;
  1131. *piDefaultAccess = 0;
  1132. //
  1133. //Decide what all we need
  1134. //
  1135. BOOL bBasicRight = FALSE;
  1136. BOOL bExtRight = FALSE;
  1137. BOOL bChildClass = FALSE;
  1138. BOOL bProp = FALSE;
  1139. //
  1140. // Lookup the name of this class
  1141. //
  1142. if (pszClassName == NULL)
  1143. pszClassName = GetClassName(pguidObjectType);
  1144. if(pszClassName == NULL)
  1145. ExitGracefully(hr, E_UNEXPECTED, "Unknown child object GUID");
  1146. if(dwFlags & SI_EDIT_PROPERTIES)
  1147. {
  1148. bProp = TRUE;
  1149. }
  1150. else if(dwFlags & SI_EDIT_EFFECTIVE)
  1151. {
  1152. bExtRight = TRUE;
  1153. bChildClass = TRUE;
  1154. bProp = TRUE;
  1155. }
  1156. else
  1157. {
  1158. bExtRight = TRUE;
  1159. bChildClass = TRUE;
  1160. }
  1161. //
  1162. //We don't show basicRights for Auxillary Classes.
  1163. //This happens when user selects Aux Class in Applyonto combo
  1164. //
  1165. bBasicRight = !IsAuxClass(pguidObjectType);
  1166. //
  1167. // Get the list of Extended Rights for this page
  1168. //
  1169. if (pguidObjectType &&
  1170. SUCCEEDED(GetExtendedRightsForNClasses(m_strERSearchPath,
  1171. pguidObjectType,
  1172. hAuxList,
  1173. bExtRight ? &hExtRightList : NULL,
  1174. &hPropSetList)))
  1175. {
  1176. if(hPropSetList)
  1177. cPropertySets = DPA_GetPtrCount(hPropSetList);
  1178. if(hExtRightList)
  1179. cExtendedRights = DPA_GetPtrCount(hExtRightList);
  1180. }
  1181. if( bChildClass &&
  1182. pguidObjectType &&
  1183. SUCCEEDED(GetChildClassesForNClasses(pguidObjectType,
  1184. pszClassName,
  1185. hAuxList,
  1186. pszSchemaPath,
  1187. &hClassList)))
  1188. {
  1189. if(hClassList)
  1190. cChildClasses = DPA_GetPtrCount(hClassList);
  1191. }
  1192. //
  1193. //Get the properties for the class
  1194. //
  1195. if (bProp &&
  1196. pguidObjectType &&
  1197. SUCCEEDED(GetPropertiesForNClasses(pguidObjectType,
  1198. pszClassName,
  1199. hAuxList,
  1200. pszSchemaPath,
  1201. &hPropertyList)))
  1202. {
  1203. if(hPropertyList)
  1204. cProperties = DPA_GetPtrCount(hPropertyList);
  1205. }
  1206. if(bBasicRight)
  1207. {
  1208. //
  1209. //Only Read Property and write Property
  1210. //
  1211. if(dwFlags & SI_EDIT_PROPERTIES)
  1212. {
  1213. cBaseRights = 2;
  1214. }
  1215. else
  1216. {
  1217. cBaseRights = ARRAYSIZE(g_siDSAccesses);
  1218. if (!cChildClasses)
  1219. cBaseRights -= 3; // skip DS_CREATE_CHILD and DS_DELETE_CHILD and both
  1220. }
  1221. }
  1222. //
  1223. //Three Entries per Child Class 1)Create 2)Delete 3) Create/Delete
  1224. //Three Entries per Prop Class 1) Read 2)Write 3)Read/Write
  1225. //
  1226. cMaxAccesses = cBaseRights +
  1227. cExtendedRights +
  1228. 3 * cChildClasses +
  1229. 3 * cPropertySets +
  1230. 3 * cProperties;
  1231. //
  1232. //This can happen for Aux Class Object Right page
  1233. //As we don't show general rights for it.
  1234. //
  1235. if(cMaxAccesses == 0)
  1236. goto exit_gracefully;
  1237. //
  1238. // Allocate a buffer for the access array
  1239. //
  1240. dwBufferLength = cBaseRights * sizeof(SI_ACCESS)
  1241. + cExtendedRights * ACCESS_LENGTH_1
  1242. + cChildClasses * ACCESS_LENGTH_2
  1243. + cPropertySets * ACCESS_LENGTH_2
  1244. + cProperties * ACCESS_LENGTH_2;
  1245. pAccesses = (PSI_ACCESS)LocalAlloc(LPTR, dwBufferLength);
  1246. if (pAccesses == NULL)
  1247. ExitGracefully(hr, E_OUTOFMEMORY, "LocalAlloc failed");
  1248. pTempAccesses = pAccesses;
  1249. pszData = (LPWSTR)(pTempAccesses + cMaxAccesses);
  1250. //
  1251. //Copy the basic right
  1252. //
  1253. if(bBasicRight)
  1254. {
  1255. if(dwFlags & SI_EDIT_PROPERTIES)
  1256. {
  1257. //
  1258. // Add "Read All Properties" and "Write All Properties"
  1259. //
  1260. CopyMemory(pTempAccesses, &g_siDSAccesses[g_iDSProperties], 2 * sizeof(SI_ACCESS));
  1261. pTempAccesses += 2;
  1262. cAccesses += 2;
  1263. }
  1264. else
  1265. {
  1266. //
  1267. // Add normal entries
  1268. //
  1269. CopyMemory(pTempAccesses, g_siDSAccesses, cBaseRights * sizeof(SI_ACCESS));
  1270. pTempAccesses += cBaseRights;
  1271. cAccesses += cBaseRights;
  1272. if (HideListObjectAccess())
  1273. {
  1274. pAccesses[g_iDSRead].mask &= ~ACTRL_DS_LIST_OBJECT;
  1275. pAccesses[g_iDSListObject].dwFlags = 0;
  1276. }
  1277. //
  1278. //If there are no child objects, don't show create/delete child objects
  1279. //
  1280. if(cChildClasses == 0)
  1281. pAccesses[g_iDSDeleteTree].dwFlags = 0;
  1282. }
  1283. }
  1284. //
  1285. // Add entries for creating & deleting child objects
  1286. //
  1287. if (bChildClass && cChildClasses)
  1288. {
  1289. TraceAssert(NULL != hClassList);
  1290. cAccesses += AddTempListToAccessList(hClassList,
  1291. &pTempAccesses,
  1292. &pszData,
  1293. SI_ACCESS_SPECIFIC,
  1294. SCHEMA_CLASS | (dwFlags & SCHEMA_NO_FILTER),
  1295. FALSE);
  1296. }
  1297. if(bExtRight)
  1298. {
  1299. //
  1300. //Decide if to show "All Extended Rights" entry
  1301. //and "All Validated Right Entry
  1302. //
  1303. BOOL bAllExtRights = FALSE;
  1304. BOOL bAllValRights = FALSE;
  1305. if(cExtendedRights)
  1306. {
  1307. //
  1308. // Add entries for Extended Rights
  1309. //
  1310. UINT i;
  1311. for (i = 0; i < cExtendedRights; i++)
  1312. {
  1313. PER_ENTRY pER = (PER_ENTRY)DPA_FastGetPtr(hExtRightList, i);
  1314. //
  1315. //Show All Validated Right entry only if atleast one
  1316. //individual Validated Right is present
  1317. //
  1318. if(pER->mask & ACTRL_DS_SELF)
  1319. bAllValRights = TRUE;
  1320. //
  1321. //Show All Validated Right entry only if atleast one
  1322. //individual Validated Right is present
  1323. //
  1324. if(pER->mask & ACTRL_DS_CONTROL_ACCESS)
  1325. bAllExtRights = TRUE;
  1326. pTempAccesses->mask = pER->mask;
  1327. //
  1328. //Extended Rights Are shown on both first page and advanced page
  1329. //
  1330. pTempAccesses->dwFlags = SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC;
  1331. pTempAccesses->pguid = &pER->guid;
  1332. pTempAccesses->pszName = pszData;
  1333. lstrcpynW(pszData, pER->szName, MAX_TYPENAME_LENGTH);
  1334. pszData += (lstrlen(pTempAccesses->pszName) + 1);
  1335. pTempAccesses++;
  1336. cAccesses++;
  1337. }
  1338. }
  1339. if(!bAllExtRights && bBasicRight)
  1340. pAccesses[g_iDSAllExtRights].dwFlags = 0;
  1341. if(!bAllValRights && bBasicRight)
  1342. pAccesses[g_iDSAllValRights].dwFlags = 0;
  1343. }
  1344. //
  1345. //Add PropertySet Entries
  1346. //
  1347. if (cPropertySets > 0)
  1348. {
  1349. cAccesses += AddTempListToAccessList(hPropSetList,
  1350. &pTempAccesses,
  1351. &pszData,
  1352. SI_ACCESS_GENERAL|SI_ACCESS_PROPERTY,
  1353. (dwFlags & SCHEMA_NO_FILTER),
  1354. TRUE);
  1355. }
  1356. //
  1357. // Add property entries
  1358. //
  1359. if (bProp && cProperties > 0)
  1360. {
  1361. cAccesses += AddTempListToAccessList(hPropertyList,
  1362. &pTempAccesses,
  1363. &pszData,
  1364. SI_ACCESS_PROPERTY,
  1365. (dwFlags & SCHEMA_NO_FILTER),
  1366. FALSE);
  1367. }
  1368. *ppAccesses = pAccesses;
  1369. *pcAccesses = cAccesses;
  1370. *piDefaultAccess = bBasicRight ? g_iDSDefAccess : 0;
  1371. exit_gracefully:
  1372. if(hExtRightList)
  1373. DPA_Destroy(hExtRightList);
  1374. if(hClassList)
  1375. DPA_Destroy(hClassList);
  1376. if(hPropertyList)
  1377. DPA_Destroy(hPropertyList);
  1378. if(hPropSetList)
  1379. DPA_Destroy(hPropSetList);
  1380. TraceLeaveResult(hr);
  1381. }
  1382. HRESULT
  1383. CSchemaCache::EnumVariantList(LPVARIANT pvarList,
  1384. HDPA hTempList,
  1385. DWORD dwFlags,
  1386. IDsDisplaySpecifier *pDisplaySpec,
  1387. LPCWSTR pszPropertyClass,
  1388. BOOL )
  1389. {
  1390. HRESULT hr = S_OK;
  1391. LPVARIANT pvarItem = NULL;
  1392. int cItems;
  1393. BOOL bSafeArrayLocked = FALSE;
  1394. TraceEnter(TRACE_SCHEMA, "CSchemaCache::EnumVariantList");
  1395. TraceAssert(pvarList != NULL);
  1396. TraceAssert(hTempList != NULL);
  1397. if (dwFlags & SCHEMA_CLASS)
  1398. hr = WaitOnClassThread();
  1399. else
  1400. hr = WaitOnPropertyThread();
  1401. FailGracefully(hr, "Required Cache Not Available");
  1402. if (V_VT(pvarList) == (VT_ARRAY | VT_VARIANT))
  1403. {
  1404. hr = SafeArrayAccessData(V_ARRAY(pvarList), (LPVOID*)&pvarItem);
  1405. FailGracefully(hr, "Unable to access SafeArray");
  1406. bSafeArrayLocked = TRUE;
  1407. cItems = V_ARRAY(pvarList)->rgsabound[0].cElements;
  1408. }
  1409. else if (V_VT(pvarList) == VT_BSTR) // Single entry in list
  1410. {
  1411. pvarItem = pvarList;
  1412. cItems = 1;
  1413. }
  1414. else
  1415. {
  1416. // Unknown format
  1417. ExitGracefully(hr, E_INVALIDARG, "Unexpected VARIANT type");
  1418. }
  1419. if (NULL == m_strFilterFile)
  1420. m_strFilterFile = GetFilterFilePath();
  1421. //
  1422. // Enumerate the variant list and get information about each
  1423. // (filter, guid, display name)
  1424. //
  1425. for ( ; cItems > 0; pvarItem++, cItems--)
  1426. {
  1427. LPWSTR pszItem;
  1428. DWORD dwFilter = 0;
  1429. WCHAR wszDisplayName[MAX_PATH];
  1430. PPROP_ENTRY pti;
  1431. PID_CACHE_ENTRY pid ;
  1432. //
  1433. //Get the ldapDisplayName
  1434. //
  1435. TraceAssert(V_VT(pvarItem) == VT_BSTR);
  1436. pszItem = V_BSTR(pvarItem);
  1437. //
  1438. // Check for nonexistent or empty strings
  1439. //
  1440. if (!pszItem || !*pszItem)
  1441. continue;
  1442. //
  1443. //Check if the string is filtered by dssec.dat file
  1444. //
  1445. if(m_strFilterFile)
  1446. {
  1447. if (dwFlags & SCHEMA_CLASS)
  1448. {
  1449. dwFilter = GetPrivateProfileIntW(pszItem,
  1450. c_szClassKey,
  1451. 0,
  1452. m_strFilterFile);
  1453. if(pszPropertyClass)
  1454. dwFilter |= GetPrivateProfileIntW(pszPropertyClass,
  1455. pszItem,
  1456. 0,
  1457. m_strFilterFile);
  1458. }
  1459. else if (pszPropertyClass)
  1460. {
  1461. dwFilter = GetPrivateProfileIntW(pszPropertyClass,
  1462. pszItem,
  1463. 0,
  1464. m_strFilterFile);
  1465. }
  1466. }
  1467. //
  1468. // Note that IDC_CLASS_NO_CREATE == IDC_PROP_NO_READ
  1469. // and IDC_CLASS_NO_DELETE == IDC_PROP_NO_WRITE
  1470. //
  1471. dwFilter &= (IDC_CLASS_NO_CREATE | IDC_CLASS_NO_DELETE);
  1472. //
  1473. //Get the schema or property cache entry
  1474. //
  1475. if (dwFlags & SCHEMA_CLASS)
  1476. pid = LookupID(m_hClassCache, pszItem);
  1477. else
  1478. pid = LookupID(m_hPropertyCache, pszItem);
  1479. if(pid == NULL)
  1480. continue;
  1481. //
  1482. //Get the Display Name
  1483. //
  1484. wszDisplayName[0] = L'\0';
  1485. if (pDisplaySpec)
  1486. {
  1487. if (dwFlags & SCHEMA_CLASS)
  1488. {
  1489. pDisplaySpec->GetFriendlyClassName(pszItem,
  1490. wszDisplayName,
  1491. ARRAYSIZE(wszDisplayName));
  1492. }
  1493. else if (pszPropertyClass)
  1494. {
  1495. pDisplaySpec->GetFriendlyAttributeName(pszPropertyClass,
  1496. pszItem,
  1497. wszDisplayName,
  1498. ARRAYSIZE(wszDisplayName));
  1499. }
  1500. }
  1501. LPWSTR pszDisplay;
  1502. pszDisplay = (wszDisplayName[0] != L'\0') ? wszDisplayName : pszItem;
  1503. //
  1504. // Remember what we've got so far
  1505. //
  1506. pti = (PPROP_ENTRY)LocalAlloc(LPTR, sizeof(PROP_ENTRY) + StringByteSize(pszDisplay));
  1507. if (pti)
  1508. {
  1509. pti->pguid = &pid->guid;
  1510. pti->pasguid = &pid->asGuid;
  1511. pti->dwFlags |= dwFilter;
  1512. lstrcpyW(pti->szName, pszDisplay);
  1513. DPA_AppendPtr(hTempList, pti);
  1514. }
  1515. }
  1516. exit_gracefully:
  1517. if (bSafeArrayLocked)
  1518. SafeArrayUnaccessData(V_ARRAY(pvarList));
  1519. TraceLeaveResult(hr);
  1520. }
  1521. UINT
  1522. CSchemaCache::AddTempListToAccessList(HDPA hTempList,
  1523. PSI_ACCESS *ppAccess,
  1524. LPWSTR *ppszData,
  1525. DWORD dwAccessFlags,
  1526. DWORD dwFlags,
  1527. BOOL bPropSet)
  1528. {
  1529. UINT cTotalEntries = 0;
  1530. int cItems;
  1531. DWORD dwAccess1;
  1532. DWORD dwAccess2;
  1533. WCHAR szFmt1[MAX_TYPENAME_LENGTH];
  1534. WCHAR szFmt2[MAX_TYPENAME_LENGTH];
  1535. WCHAR szFmt3[MAX_TYPENAME_LENGTH];
  1536. TraceEnter(TRACE_SCHEMA, "CSchemaCache::AddTempListToAccessList");
  1537. TraceAssert(ppAccess != NULL);
  1538. TraceAssert(ppszData != NULL);
  1539. cItems = DPA_GetPtrCount(hTempList);
  1540. if (0 == cItems)
  1541. ExitGracefully(cTotalEntries, 0, "empty list");
  1542. if (dwFlags & SCHEMA_CLASS)
  1543. {
  1544. dwAccess1 = ACTRL_DS_CREATE_CHILD;
  1545. dwAccess2 = ACTRL_DS_DELETE_CHILD;
  1546. LoadStringW(GLOBAL_HINSTANCE, IDS_DS_CREATE_CHILD_TYPE, szFmt1, ARRAYSIZE(szFmt1));
  1547. LoadStringW(GLOBAL_HINSTANCE, IDS_DS_DELETE_CHILD_TYPE, szFmt2, ARRAYSIZE(szFmt2));
  1548. LoadStringW(GLOBAL_HINSTANCE, IDS_DS_CREATEDELETE_TYPE, szFmt3, ARRAYSIZE(szFmt3));
  1549. }
  1550. else
  1551. {
  1552. dwAccess1 = ACTRL_DS_READ_PROP;
  1553. dwAccess2 = ACTRL_DS_WRITE_PROP;
  1554. LoadStringW(GLOBAL_HINSTANCE, IDS_DS_READ_PROP_TYPE, szFmt1, ARRAYSIZE(szFmt1));
  1555. LoadStringW(GLOBAL_HINSTANCE, IDS_DS_WRITE_PROP_TYPE, szFmt2, ARRAYSIZE(szFmt2));
  1556. LoadStringW(GLOBAL_HINSTANCE, IDS_DS_READWRITE_TYPE, szFmt3, ARRAYSIZE(szFmt3));
  1557. }
  1558. // Enumerate the list and make up to 2 entries for each
  1559. for(int i = 0; i < cItems; ++i)
  1560. {
  1561. PER_ENTRY pER = NULL;
  1562. PPROP_ENTRY pProp = NULL;
  1563. LPWSTR pszData;
  1564. LPGUID pGuid = NULL;
  1565. PSI_ACCESS pNewAccess;
  1566. LPCWSTR pszName;
  1567. int cch;
  1568. DWORD dwAccess3;
  1569. DWORD dwFilter = 0;
  1570. if(bPropSet)
  1571. {
  1572. pER = (PER_ENTRY)DPA_FastGetPtr(hTempList, i);
  1573. if (!pER)
  1574. continue;
  1575. pGuid = &pER->guid;
  1576. pszName = pER->szName;
  1577. dwFilter = 0;
  1578. }
  1579. else
  1580. {
  1581. pProp = (PPROP_ENTRY)DPA_FastGetPtr(hTempList, i);
  1582. if (!pProp)
  1583. continue;
  1584. pGuid = pProp->pguid;
  1585. pszName = pProp->szName;
  1586. dwFilter = pProp->dwFlags;
  1587. }
  1588. pszData = *ppszData;
  1589. pNewAccess = *ppAccess;
  1590. dwAccess3 = 0;
  1591. if ((dwFlags & SCHEMA_NO_FILTER) ||
  1592. !(dwFilter & IDC_CLASS_NO_CREATE))
  1593. {
  1594. pNewAccess->mask = dwAccess1;
  1595. pNewAccess->dwFlags = dwAccessFlags;
  1596. pNewAccess->pguid = pGuid;
  1597. pNewAccess->pszName = (LPCWSTR)pszData;
  1598. cch = wsprintfW((LPWSTR)pszData, szFmt1, pszName);
  1599. pszData += (cch + 1);
  1600. cTotalEntries++;
  1601. pNewAccess++;
  1602. dwAccess3 |= dwAccess1;
  1603. }
  1604. if ((dwFlags & SCHEMA_NO_FILTER) ||
  1605. !(dwFilter & IDC_CLASS_NO_DELETE))
  1606. {
  1607. pNewAccess->mask = dwAccess2;
  1608. pNewAccess->dwFlags = dwAccessFlags;
  1609. pNewAccess->pguid = pGuid;
  1610. pNewAccess->pszName = (LPCWSTR)pszData;
  1611. cch = wsprintfW((LPWSTR)pszData, szFmt2, pszName);
  1612. pszData += (cch + 1);
  1613. cTotalEntries++;
  1614. pNewAccess++;
  1615. dwAccess3 |= dwAccess2;
  1616. }
  1617. if (dwAccess3 == (dwAccess1 | dwAccess2))
  1618. {
  1619. // Add a hidden entry for
  1620. // "Read/write <prop>"
  1621. // or
  1622. // "Create/delete <child>"
  1623. pNewAccess->mask = dwAccess3;
  1624. // dwFlags = 0 means it will never show as a checkbox, but it
  1625. // may be used for the name displayed on the Advanced page.
  1626. pNewAccess->dwFlags = 0;
  1627. pNewAccess->pguid = pGuid;
  1628. pNewAccess->pszName = (LPCWSTR)pszData;
  1629. cch = wsprintfW((LPWSTR)pszData, szFmt3, pszName);
  1630. pszData += (cch + 1);
  1631. cTotalEntries++;
  1632. pNewAccess++;
  1633. }
  1634. if (*ppAccess != pNewAccess)
  1635. {
  1636. *ppAccess = pNewAccess; // move past new entries
  1637. *ppszData = pszData;
  1638. }
  1639. }
  1640. exit_gracefully:
  1641. TraceLeaveValue(cTotalEntries);
  1642. }
  1643. DWORD WINAPI
  1644. CSchemaCache::SchemaClassThread(LPVOID pvThreadData)
  1645. {
  1646. PSCHEMACACHE pCache;
  1647. HINSTANCE hInstThisDll = LoadLibrary(c_szDllName);
  1648. InterlockedIncrement(&GLOBAL_REFCOUNT);
  1649. pCache = (PSCHEMACACHE)pvThreadData;
  1650. SetEvent(pCache->m_hLoadLibClassWaitEvent);
  1651. TraceEnter(TRACE_SCHEMACLASS, "CSchemaCache::SchemaClassThread");
  1652. TraceAssert(pCache != NULL);
  1653. TraceAssert(pCache->m_strSchemaSearchPath != NULL);
  1654. #if DBG
  1655. DWORD dwTime = GetTickCount();
  1656. #endif
  1657. ThreadCoInitialize();
  1658. pCache->m_hrClassResult = Schema_Search(pCache->m_strSchemaSearchPath,
  1659. c_szClassFilter,
  1660. &pCache->m_hClassCache,
  1661. FALSE);
  1662. ThreadCoUninitialize();
  1663. #if DBG
  1664. Trace((TEXT("SchemaClassThread complete, elapsed time: %d ms"), GetTickCount() - dwTime));
  1665. #endif
  1666. TraceLeave();
  1667. InterlockedDecrement(&GLOBAL_REFCOUNT);
  1668. FreeLibraryAndExitThread(hInstThisDll, 0);
  1669. }
  1670. DWORD WINAPI
  1671. CSchemaCache::SchemaPropertyThread(LPVOID pvThreadData)
  1672. {
  1673. PSCHEMACACHE pCache = NULL;
  1674. HINSTANCE hInstThisDll = LoadLibrary(c_szDllName);
  1675. InterlockedIncrement(&GLOBAL_REFCOUNT);
  1676. pCache = (PSCHEMACACHE)pvThreadData;
  1677. SetEvent(pCache->m_hLoadLibPropWaitEvent);
  1678. TraceEnter(TRACE_SCHEMAPROP, "CSchemaCache::SchemaPropertyThread");
  1679. TraceAssert(pCache != NULL);
  1680. TraceAssert(pCache->m_strSchemaSearchPath != NULL);
  1681. #if DBG
  1682. DWORD dwTime = GetTickCount();
  1683. #endif
  1684. ThreadCoInitialize();
  1685. pCache->m_hrPropertyResult = Schema_Search(pCache->m_strSchemaSearchPath,
  1686. c_szPropertyFilter,
  1687. &pCache->m_hPropertyCache,
  1688. TRUE);
  1689. ThreadCoUninitialize();
  1690. #if DBG
  1691. Trace((TEXT("SchemaPropertyThread complete, elapsed time: %d ms"), GetTickCount() - dwTime));
  1692. #endif
  1693. TraceLeave();
  1694. InterlockedDecrement(&GLOBAL_REFCOUNT);
  1695. FreeLibraryAndExitThread(hInstThisDll, 0);
  1696. }
  1697. HRESULT
  1698. CSchemaCache::BuildInheritTypeArray(DWORD dwFlags)
  1699. {
  1700. HRESULT hr = S_OK;
  1701. int cItems = 0;
  1702. DWORD cbNames = 0;
  1703. DWORD dwBufferLength;
  1704. PINHERIT_TYPE_ARRAY pInheritTypeArray = NULL;
  1705. PSI_INHERIT_TYPE pNewInheritType;
  1706. LPGUID pGuidData = NULL;
  1707. LPWSTR pszData = NULL;
  1708. WCHAR szFormat[MAX_TYPENAME_LENGTH];
  1709. HDPA hTempList = NULL;
  1710. PTEMP_INFO pti;
  1711. IDsDisplaySpecifier *pDisplaySpec = NULL;
  1712. TraceEnter(TRACE_SCHEMACLASS, "CSchemaCache::BuildInheritTypeArray");
  1713. TraceAssert(m_pInheritTypeArray == NULL); // Don't want to build this twice
  1714. if (NULL == m_strFilterFile)
  1715. m_strFilterFile = GetFilterFilePath();
  1716. hr = WaitOnClassThread();
  1717. FailGracefully(hr, "Class cache unavailable");
  1718. cItems = DPA_GetPtrCount(m_hClassCache);
  1719. if (cItems == 0)
  1720. ExitGracefully(hr, E_FAIL, "No schema classes available");
  1721. hTempList = DPA_Create(cItems);
  1722. if (!hTempList)
  1723. ExitGracefully(hr, E_OUTOFMEMORY, "Unable to create DPA");
  1724. // Get the display specifier object
  1725. CoCreateInstance(CLSID_DsDisplaySpecifier,
  1726. NULL,
  1727. CLSCTX_INPROC_SERVER,
  1728. IID_IDsDisplaySpecifier,
  1729. (void**)&pDisplaySpec);
  1730. // Enumerate child types, apply filtering, and get display names
  1731. while (cItems > 0)
  1732. {
  1733. PID_CACHE_ENTRY pCacheEntry;
  1734. WCHAR wszDisplayName[MAX_PATH];
  1735. pCacheEntry = (PID_CACHE_ENTRY)DPA_FastGetPtr(m_hClassCache, --cItems);
  1736. if (!pCacheEntry)
  1737. continue;
  1738. if (m_strFilterFile && !(dwFlags & SCHEMA_NO_FILTER))
  1739. {
  1740. DWORD dwFilter = GetPrivateProfileIntW(pCacheEntry->szLdapName,
  1741. c_szClassKey,
  1742. 0,
  1743. m_strFilterFile);
  1744. if (dwFilter & IDC_CLASS_NO_INHERIT)
  1745. continue;
  1746. }
  1747. wszDisplayName[0] = L'\0';
  1748. if (pDisplaySpec)
  1749. {
  1750. pDisplaySpec->GetFriendlyClassName(pCacheEntry->szLdapName,
  1751. wszDisplayName,
  1752. ARRAYSIZE(wszDisplayName));
  1753. }
  1754. if (L'\0' != wszDisplayName[0])
  1755. cbNames += StringByteSize(wszDisplayName);
  1756. else
  1757. cbNames += StringByteSize(pCacheEntry->szLdapName);
  1758. pti = (PTEMP_INFO)LocalAlloc(LPTR, sizeof(TEMP_INFO) + sizeof(WCHAR)*lstrlenW(wszDisplayName));
  1759. if (pti)
  1760. {
  1761. pti->pguid = &pCacheEntry->guid;
  1762. pti->pszLdapName = pCacheEntry->szLdapName;
  1763. lstrcpyW(pti->szDisplayName, wszDisplayName);
  1764. DPA_AppendPtr(hTempList, pti);
  1765. }
  1766. }
  1767. // Sort by display name
  1768. DPA_Sort(hTempList, Schema_CompareTempDisplayName, 0);
  1769. // Get an accurate count
  1770. cItems = DPA_GetPtrCount(hTempList);
  1771. //
  1772. // Allocate a buffer for the inherit type array
  1773. //
  1774. dwBufferLength = sizeof(INHERIT_TYPE_ARRAY) - sizeof(SI_INHERIT_TYPE)
  1775. + sizeof(g_siDSInheritTypes)
  1776. + cItems * (sizeof(SI_INHERIT_TYPE) + sizeof(GUID) + MAX_TYPENAME_LENGTH*sizeof(WCHAR))
  1777. + cbNames;
  1778. pInheritTypeArray = (PINHERIT_TYPE_ARRAY)LocalAlloc(LPTR, dwBufferLength);
  1779. if (pInheritTypeArray == NULL)
  1780. ExitGracefully(hr, E_OUTOFMEMORY, "LocalAlloc failed");
  1781. pInheritTypeArray->cInheritTypes = ARRAYSIZE(g_siDSInheritTypes);
  1782. pNewInheritType = pInheritTypeArray->aInheritType;
  1783. pGuidData = (LPGUID)(pNewInheritType + pInheritTypeArray->cInheritTypes + cItems);
  1784. pszData = (LPWSTR)(pGuidData + cItems);
  1785. // Copy static entries
  1786. CopyMemory(pNewInheritType, g_siDSInheritTypes, sizeof(g_siDSInheritTypes));
  1787. pNewInheritType += ARRAYSIZE(g_siDSInheritTypes);
  1788. // Load format string
  1789. LoadString(GLOBAL_HINSTANCE,
  1790. IDS_DS_INHERIT_TYPE,
  1791. szFormat,
  1792. ARRAYSIZE(szFormat));
  1793. // Enumerate child types and make an entry for each
  1794. while (cItems > 0)
  1795. {
  1796. int cch;
  1797. LPCWSTR pszDisplayName;
  1798. pti = (PTEMP_INFO)DPA_FastGetPtr(hTempList, --cItems);
  1799. if (!pti)
  1800. continue;
  1801. if (pti->szDisplayName[0])
  1802. pszDisplayName = pti->szDisplayName;
  1803. else
  1804. pszDisplayName = pti->pszLdapName;
  1805. pNewInheritType->dwFlags = CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
  1806. // The class entry name is the child class name, e.g. "Domain" or "User"
  1807. pNewInheritType->pszName = pszData;
  1808. cch = wsprintfW(pszData, szFormat, pszDisplayName);
  1809. pszData += (cch + 1);
  1810. pNewInheritType->pguid = pGuidData;
  1811. *pGuidData = *pti->pguid;
  1812. pGuidData++;
  1813. pNewInheritType++;
  1814. pInheritTypeArray->cInheritTypes++;
  1815. }
  1816. exit_gracefully:
  1817. DoRelease(pDisplaySpec);
  1818. if (SUCCEEDED(hr))
  1819. {
  1820. m_pInheritTypeArray = pInheritTypeArray;
  1821. // Set this master inherit type array's GUID to null
  1822. m_pInheritTypeArray->guidObjectType = GUID_NULL;
  1823. m_pInheritTypeArray->dwFlags = (dwFlags & SCHEMA_NO_FILTER);
  1824. }
  1825. else if (pInheritTypeArray != NULL)
  1826. {
  1827. LocalFree(pInheritTypeArray);
  1828. }
  1829. DestroyDPA(hTempList);
  1830. TraceLeaveResult(hr);
  1831. }
  1832. HRESULT
  1833. Schema_BindToObject(LPCWSTR pszSchemaPath,
  1834. LPCWSTR pszName,
  1835. REFIID riid,
  1836. LPVOID *ppv)
  1837. {
  1838. HRESULT hr;
  1839. WCHAR szPath[MAX_PATH];
  1840. UINT nSchemaRootLen;
  1841. WCHAR chTemp;
  1842. TraceEnter(TRACE_SCHEMA, "Schema_BindToObject");
  1843. TraceAssert(pszSchemaPath != NULL);
  1844. TraceAssert(pszName == NULL || *pszName);
  1845. TraceAssert(ppv != NULL);
  1846. if (pszSchemaPath == NULL)
  1847. {
  1848. ExitGracefully(hr, E_INVALIDARG, "No schema path provided");
  1849. }
  1850. nSchemaRootLen = lstrlenW(pszSchemaPath);
  1851. //
  1852. // Build the schema path to this object
  1853. //
  1854. lstrcpynW(szPath, pszSchemaPath, nSchemaRootLen + 1);
  1855. chTemp = szPath[nSchemaRootLen-1];
  1856. if (pszName != NULL)
  1857. {
  1858. // If there is no trailing slash, add it
  1859. if (chTemp != TEXT('/'))
  1860. {
  1861. szPath[nSchemaRootLen] = TEXT('/');
  1862. nSchemaRootLen++;
  1863. }
  1864. // Add the class or property name onto the end
  1865. lstrcpynW(szPath + nSchemaRootLen,
  1866. pszName,
  1867. ARRAYSIZE(szPath) - nSchemaRootLen);
  1868. }
  1869. else if (nSchemaRootLen > 0)
  1870. {
  1871. // If there is a trailing slash, remove it
  1872. if (chTemp == TEXT('/'))
  1873. szPath[nSchemaRootLen-1] = TEXT('\0');
  1874. }
  1875. else
  1876. {
  1877. ExitGracefully(hr, E_INVALIDARG, "Empty schema path");
  1878. }
  1879. //
  1880. // Instantiate the schema object
  1881. //
  1882. ThreadCoInitialize();
  1883. hr = OpenDSObject(szPath,
  1884. NULL,
  1885. NULL,
  1886. ADS_SECURE_AUTHENTICATION,
  1887. riid,
  1888. ppv);
  1889. exit_gracefully:
  1890. TraceLeaveResult(hr);
  1891. }
  1892. HRESULT
  1893. Schema_GetObjectID(IADs *pObj, LPGUID pGUID)
  1894. {
  1895. HRESULT hr;
  1896. VARIANT varID = {0};
  1897. TraceEnter(TRACE_SCHEMA, "Schema_GetObjectID(IADs*)");
  1898. TraceAssert(pObj != NULL);
  1899. TraceAssert(pGUID != NULL && !IsBadWritePtr(pGUID, sizeof(GUID)));
  1900. // Get the "schemaIDGUID" property
  1901. hr = pObj->Get((LPWSTR)c_szSchemaIDGUID, &varID);
  1902. if (SUCCEEDED(hr))
  1903. {
  1904. LPGUID pID = NULL;
  1905. TraceAssert(V_VT(&varID) == (VT_ARRAY | VT_UI1));
  1906. TraceAssert(V_ARRAY(&varID) && varID.parray->cDims == 1);
  1907. TraceAssert(V_ARRAY(&varID)->rgsabound[0].cElements >= sizeof(GUID));
  1908. hr = SafeArrayAccessData(V_ARRAY(&varID), (LPVOID*)&pID);
  1909. if (SUCCEEDED(hr))
  1910. {
  1911. *pGUID = *pID;
  1912. SafeArrayUnaccessData(V_ARRAY(&varID));
  1913. }
  1914. VariantClear(&varID);
  1915. }
  1916. TraceLeaveResult(hr);
  1917. }
  1918. HRESULT
  1919. Schema_Search(LPWSTR pszSchemaSearchPath,
  1920. LPCWSTR pszFilter,
  1921. HDPA *phCache,
  1922. BOOL bProperty)
  1923. {
  1924. HRESULT hr = S_OK;
  1925. HDPA hCache = NULL;
  1926. IDirectorySearch *pSchemaSearch = NULL;
  1927. ADS_SEARCH_HANDLE hSearch = NULL;
  1928. ADS_SEARCHPREF_INFO prefInfo[3];
  1929. const LPCWSTR pProperties1[] =
  1930. {
  1931. c_szLDAPDisplayName, // "lDAPDisplayName"
  1932. c_szSchemaIDGUID, // "schemaIDGUID"
  1933. c_szObjectClassCategory,
  1934. };
  1935. const LPCWSTR pProperties2[] =
  1936. {
  1937. c_szLDAPDisplayName,
  1938. c_szSchemaIDGUID,
  1939. c_szAttributeSecurityGuid,
  1940. };
  1941. TraceEnter(lstrcmp(pszFilter, c_szPropertyFilter) ? TRACE_SCHEMACLASS : TRACE_SCHEMAPROP, "Schema_Search");
  1942. TraceAssert(pszSchemaSearchPath != NULL);
  1943. TraceAssert(phCache != NULL);
  1944. LPCWSTR * pProperties = (LPCWSTR *)( bProperty ? pProperties2 : pProperties1 );
  1945. DWORD dwSize = (DWORD)(bProperty ? ARRAYSIZE(pProperties2) : ARRAYSIZE(pProperties1));
  1946. //
  1947. // Create DPA if necessary
  1948. //
  1949. if (*phCache == NULL)
  1950. *phCache = DPA_Create(100);
  1951. if (*phCache == NULL)
  1952. ExitGracefully(hr, E_OUTOFMEMORY, "DPA_Create failed");
  1953. hCache = *phCache;
  1954. // Get the schema search object
  1955. hr = OpenDSObject(pszSchemaSearchPath,
  1956. NULL,
  1957. NULL,
  1958. ADS_SECURE_AUTHENTICATION,
  1959. IID_IDirectorySearch,
  1960. (LPVOID*)&pSchemaSearch);
  1961. FailGracefully(hr, "Failed to get schema search object");
  1962. // Set preferences to Asynchronous, Deep search, Paged results
  1963. prefInfo[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
  1964. prefInfo[0].vValue.dwType = ADSTYPE_INTEGER;
  1965. prefInfo[0].vValue.Integer = ADS_SCOPE_SUBTREE;
  1966. prefInfo[1].dwSearchPref = ADS_SEARCHPREF_ASYNCHRONOUS;
  1967. prefInfo[1].vValue.dwType = ADSTYPE_BOOLEAN;
  1968. prefInfo[1].vValue.Boolean = TRUE;
  1969. prefInfo[2].dwSearchPref = ADS_SEARCHPREF_PAGESIZE;
  1970. prefInfo[2].vValue.dwType = ADSTYPE_INTEGER;
  1971. prefInfo[2].vValue.Integer = PAGE_SIZE;
  1972. hr = pSchemaSearch->SetSearchPreference(prefInfo, ARRAYSIZE(prefInfo));
  1973. // Do the search
  1974. hr = pSchemaSearch->ExecuteSearch((LPWSTR)pszFilter,
  1975. (LPWSTR*)pProperties,
  1976. dwSize,
  1977. &hSearch);
  1978. FailGracefully(hr, "IDirectorySearch::ExecuteSearch failed");
  1979. // Loop through the rows, getting the name and ID of each property or class
  1980. for (;;)
  1981. {
  1982. ADS_SEARCH_COLUMN colLdapName;
  1983. ADS_SEARCH_COLUMN colGuid;
  1984. ADS_SEARCH_COLUMN colASGuid;
  1985. LPWSTR pszLdapName;
  1986. LPGUID pID;
  1987. LPGUID pASID;
  1988. INT iObjectClassCategory = 0;
  1989. PID_CACHE_ENTRY pCacheEntry;
  1990. hr = pSchemaSearch->GetNextRow(hSearch);
  1991. if (FAILED(hr) || hr == S_ADS_NOMORE_ROWS)
  1992. break;
  1993. // Get class/property internal name
  1994. hr = pSchemaSearch->GetColumn(hSearch, (LPWSTR)c_szLDAPDisplayName, &colLdapName);
  1995. if (FAILED(hr))
  1996. {
  1997. TraceMsg("lDAPDisplayName not found for class/property");
  1998. continue;
  1999. }
  2000. TraceAssert(colLdapName.dwADsType >= ADSTYPE_DN_STRING
  2001. && colLdapName.dwADsType <= ADSTYPE_NUMERIC_STRING);
  2002. TraceAssert(colLdapName.dwNumValues == 1);
  2003. pszLdapName = colLdapName.pADsValues->CaseIgnoreString;
  2004. // Get the GUID column
  2005. hr = pSchemaSearch->GetColumn(hSearch, (LPWSTR)c_szSchemaIDGUID, &colGuid);
  2006. if (FAILED(hr))
  2007. {
  2008. Trace((TEXT("GUID not found for \"%s\""), pszLdapName));
  2009. pSchemaSearch->FreeColumn(&colLdapName);
  2010. continue;
  2011. }
  2012. // Get GUID from column
  2013. TraceAssert(colGuid.dwADsType == ADSTYPE_OCTET_STRING);
  2014. TraceAssert(colGuid.dwNumValues == 1);
  2015. TraceAssert(colGuid.pADsValues->OctetString.dwLength == sizeof(GUID));
  2016. pID = (LPGUID)(colGuid.pADsValues->OctetString.lpValue);
  2017. pASID = (LPGUID)&GUID_NULL;
  2018. if( bProperty )
  2019. {
  2020. // Get the AttrbiuteSecurityGUID column
  2021. hr = pSchemaSearch->GetColumn(hSearch, (LPWSTR)c_szAttributeSecurityGuid, &colASGuid);
  2022. if (hr != E_ADS_COLUMN_NOT_SET && FAILED(hr))
  2023. {
  2024. Trace((TEXT("AttributeSecurityGUID not found for \"%s\""), pszLdapName));
  2025. pSchemaSearch->FreeColumn(&colLdapName);
  2026. pSchemaSearch->FreeColumn(&colGuid);
  2027. continue;
  2028. }
  2029. if( hr != E_ADS_COLUMN_NOT_SET )
  2030. {
  2031. // Get GUID from column
  2032. TraceAssert(colASGuid.dwADsType == ADSTYPE_OCTET_STRING);
  2033. TraceAssert(colASGuid.dwNumValues == 1);
  2034. TraceAssert(colASGuid.pADsValues->OctetString.dwLength == sizeof(GUID));
  2035. pASID = (LPGUID)(colASGuid.pADsValues->OctetString.lpValue);
  2036. }
  2037. }
  2038. else
  2039. {
  2040. // Get the c_szObjectClassCategory column
  2041. hr = pSchemaSearch->GetColumn(hSearch, (LPWSTR)c_szObjectClassCategory, &colASGuid);
  2042. if (FAILED(hr))
  2043. {
  2044. Trace((TEXT("ObjectClassCategory not found for \"%s\""), pszLdapName));
  2045. pSchemaSearch->FreeColumn(&colLdapName);
  2046. pSchemaSearch->FreeColumn(&colGuid);
  2047. continue;
  2048. }
  2049. // Get GUID from column
  2050. TraceAssert(colASGuid.dwADsType == ADSTYPE_INTEGER);
  2051. TraceAssert(colASGuid.dwNumValues == 1);
  2052. iObjectClassCategory = colASGuid.pADsValues->Integer;
  2053. }
  2054. pCacheEntry = (PID_CACHE_ENTRY)LocalAlloc(LPTR,
  2055. sizeof(ID_CACHE_ENTRY)
  2056. + sizeof(WCHAR)*lstrlenW(pszLdapName));
  2057. if (pCacheEntry != NULL)
  2058. {
  2059. // Copy the item name and ID
  2060. pCacheEntry->guid = *pID;
  2061. pCacheEntry->asGuid = *pASID;
  2062. pCacheEntry->bAuxClass = (iObjectClassCategory == 3);
  2063. lstrcpyW(pCacheEntry->szLdapName, pszLdapName);
  2064. // Insert into cache
  2065. DPA_AppendPtr(hCache, pCacheEntry);
  2066. }
  2067. pSchemaSearch->FreeColumn(&colLdapName);
  2068. pSchemaSearch->FreeColumn(&colGuid);
  2069. if(!bProperty || hr != E_ADS_COLUMN_NOT_SET)
  2070. pSchemaSearch->FreeColumn(&colASGuid);
  2071. }
  2072. DPA_Sort(hCache, Schema_CompareLdapName, 0);
  2073. exit_gracefully:
  2074. if (hSearch != NULL)
  2075. pSchemaSearch->CloseSearchHandle(hSearch);
  2076. DoRelease(pSchemaSearch);
  2077. if (FAILED(hr))
  2078. {
  2079. DestroyDPA(hCache);
  2080. *phCache = NULL;
  2081. }
  2082. TraceLeaveResult(hr);
  2083. }
  2084. //+--------------------------------------------------------------------------
  2085. //
  2086. // Function: Schema_GetExtendedRightsForOneClass
  2087. //
  2088. // Synopsis: This Function Gets the Extended Rights for One Class.
  2089. // It Adds all the control rights, validated rights to
  2090. // phERList. It Adds all the PropertySets to phPropSetList.
  2091. //
  2092. // Arguments: [pszSchemaSearchPath - IN] : Path to schema
  2093. // [pguidClass - In] : Guid Of the class
  2094. // [phERList - OUT] : Get the output Extended Right List
  2095. // [phPropSetList - OUT]: Gets the output PropertySet List
  2096. //
  2097. // Returns: HRESULT : S_OK if everything succeeded
  2098. // E_INVALIDARG if the object entry wasn't found
  2099. //
  2100. // History: 3-Nov 2000 hiteshr Created
  2101. //
  2102. //---------------------------------------------------------------------------
  2103. HRESULT
  2104. CSchemaCache::GetExtendedRightsForOneClass(IN LPWSTR pszSchemaSearchPath,
  2105. IN LPCGUID pguidClass,
  2106. OUT HDPA *phERList,
  2107. OUT HDPA *phPropSetList)
  2108. {
  2109. TraceEnter(TRACE_SCHEMA, "CSchemaCache::GetExtendedRightsForOneClass");
  2110. if(!pszSchemaSearchPath
  2111. || !pguidClass
  2112. || IsEqualGUID(*pguidClass, GUID_NULL)
  2113. || !phERList
  2114. || !phPropSetList)
  2115. {
  2116. Trace((L"Invalid Arguments Passed to Schema_GetExtendedRightsForOneClass"));
  2117. return E_INVALIDARG;
  2118. }
  2119. HRESULT hr = S_OK;
  2120. IDirectorySearch *pSearch = NULL;
  2121. ADS_SEARCH_HANDLE hSearch = NULL;
  2122. ADS_SEARCHPREF_INFO prefInfo[3];
  2123. WCHAR szFilter[100];
  2124. HDPA hExtRightList = NULL;
  2125. HDPA hPropSetList = NULL;
  2126. POBJECT_TYPE_CACHE pOTC = NULL;
  2127. //
  2128. //Search in the cache
  2129. //
  2130. if (m_hObjectTypeCache != NULL)
  2131. {
  2132. UINT cItems = DPA_GetPtrCount(m_hObjectTypeCache);
  2133. while (cItems > 0)
  2134. {
  2135. pOTC = (POBJECT_TYPE_CACHE)DPA_FastGetPtr(m_hObjectTypeCache, --cItems);
  2136. //
  2137. //Found A match.
  2138. //
  2139. if(IsEqualGUID(pOTC->guidObject, *pguidClass))
  2140. break;
  2141. pOTC = NULL;
  2142. }
  2143. //
  2144. //Have we already got the properties
  2145. //
  2146. if(pOTC && pOTC->flags & OTC_EXTR)
  2147. {
  2148. *phERList = pOTC->hListExtRights;
  2149. *phPropSetList = pOTC->hListPropertySet;
  2150. return S_OK;
  2151. }
  2152. }
  2153. //
  2154. //Attributes to fetch
  2155. //
  2156. const LPCWSTR pProperties[] =
  2157. {
  2158. c_szDisplayName, // "displayName"
  2159. c_szDisplayID, // "localizationDisplayId"
  2160. c_szRightsGuid, // "rightsGuid"
  2161. c_szValidAccesses, // "validAccesses"
  2162. };
  2163. //
  2164. // Build the filter string
  2165. //
  2166. wsprintfW(szFilter, c_szERFilterFormat,
  2167. pguidClass->Data1, pguidClass->Data2, pguidClass->Data3,
  2168. pguidClass->Data4[0], pguidClass->Data4[1],
  2169. pguidClass->Data4[2], pguidClass->Data4[3],
  2170. pguidClass->Data4[4], pguidClass->Data4[5],
  2171. pguidClass->Data4[6], pguidClass->Data4[7]);
  2172. Trace((TEXT("Filter \"%s\""), szFilter));
  2173. //
  2174. // Create DPA to hold results
  2175. //
  2176. hExtRightList = DPA_Create(8);
  2177. if (hExtRightList == NULL)
  2178. ExitGracefully(hr, E_OUTOFMEMORY, "DPA_Create failed");
  2179. hPropSetList = DPA_Create(8);
  2180. if( hPropSetList == NULL )
  2181. ExitGracefully(hr, E_OUTOFMEMORY, "DPA_Create failed");
  2182. //
  2183. // Get the schema search object
  2184. //
  2185. hr = OpenDSObject(pszSchemaSearchPath,
  2186. NULL,
  2187. NULL,
  2188. ADS_SECURE_AUTHENTICATION,
  2189. IID_IDirectorySearch,
  2190. (LPVOID*)&pSearch);
  2191. FailGracefully(hr, "Failed to get schema search object");
  2192. //
  2193. // Set preferences to Asynchronous, OneLevel search, Paged results
  2194. //
  2195. prefInfo[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
  2196. prefInfo[0].vValue.dwType = ADSTYPE_INTEGER;
  2197. prefInfo[0].vValue.Integer = ADS_SCOPE_ONELEVEL;
  2198. prefInfo[1].dwSearchPref = ADS_SEARCHPREF_ASYNCHRONOUS;
  2199. prefInfo[1].vValue.dwType = ADSTYPE_BOOLEAN;
  2200. prefInfo[1].vValue.Boolean = TRUE;
  2201. prefInfo[2].dwSearchPref = ADS_SEARCHPREF_PAGESIZE;
  2202. prefInfo[2].vValue.dwType = ADSTYPE_INTEGER;
  2203. prefInfo[2].vValue.Integer = PAGE_SIZE;
  2204. hr = pSearch->SetSearchPreference(prefInfo, ARRAYSIZE(prefInfo));
  2205. FailGracefully(hr, "IDirectorySearch::SetSearchPreference failed");
  2206. //
  2207. // Do the search
  2208. //
  2209. hr = pSearch->ExecuteSearch(szFilter,
  2210. (LPWSTR*)pProperties,
  2211. ARRAYSIZE(pProperties),
  2212. &hSearch);
  2213. FailGracefully(hr, "IDirectorySearch::ExecuteSearch failed");
  2214. //
  2215. // Loop through the rows, getting the name and ID of each property or class
  2216. //
  2217. for (;;)
  2218. {
  2219. ADS_SEARCH_COLUMN col;
  2220. GUID guid;
  2221. DWORD dwValidAccesses;
  2222. LPWSTR pszName = NULL;
  2223. WCHAR szDisplayName[MAX_PATH];
  2224. hr = pSearch->GetNextRow(hSearch);
  2225. if (FAILED(hr) || hr == S_ADS_NOMORE_ROWS)
  2226. break;
  2227. //
  2228. // Get the GUID
  2229. //
  2230. if (FAILED(pSearch->GetColumn(hSearch, (LPWSTR)c_szRightsGuid, &col)))
  2231. {
  2232. TraceMsg("GUID not found for extended right");
  2233. continue;
  2234. }
  2235. TraceAssert(col.dwADsType >= ADSTYPE_DN_STRING
  2236. && col.dwADsType <= ADSTYPE_NUMERIC_STRING);
  2237. wsprintfW(szFilter, c_szGUIDFormat, col.pADsValues->CaseIgnoreString);
  2238. CLSIDFromString(szFilter, &guid);
  2239. pSearch->FreeColumn(&col);
  2240. //
  2241. // Get the valid accesses mask
  2242. //
  2243. if (FAILED(pSearch->GetColumn(hSearch, (LPWSTR)c_szValidAccesses, &col)))
  2244. {
  2245. TraceMsg("validAccesses not found for Extended Right");
  2246. continue;
  2247. }
  2248. TraceAssert(col.dwADsType == ADSTYPE_INTEGER);
  2249. TraceAssert(col.dwNumValues == 1);
  2250. dwValidAccesses = (DWORD)(DS_GENERIC_ALL & col.pADsValues->Integer);
  2251. pSearch->FreeColumn(&col);
  2252. //
  2253. // Get the display name
  2254. //
  2255. szDisplayName[0] = L'\0';
  2256. if (SUCCEEDED(pSearch->GetColumn(hSearch, (LPWSTR)c_szDisplayID, &col)))
  2257. {
  2258. TraceAssert(col.dwADsType == ADSTYPE_INTEGER);
  2259. TraceAssert(col.dwNumValues == 1);
  2260. if (FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS,
  2261. g_hInstance,
  2262. col.pADsValues->Integer,
  2263. 0,
  2264. szDisplayName,
  2265. ARRAYSIZE(szDisplayName),
  2266. NULL))
  2267. {
  2268. pszName = szDisplayName;
  2269. }
  2270. pSearch->FreeColumn(&col);
  2271. }
  2272. if (NULL == pszName &&
  2273. SUCCEEDED(pSearch->GetColumn(hSearch, (LPWSTR)c_szDisplayName, &col)))
  2274. {
  2275. TraceAssert(col.dwADsType >= ADSTYPE_DN_STRING
  2276. && col.dwADsType <= ADSTYPE_NUMERIC_STRING);
  2277. lstrcpynW(szDisplayName, col.pADsValues->CaseIgnoreString, ARRAYSIZE(szDisplayName));
  2278. pszName = szDisplayName;
  2279. pSearch->FreeColumn(&col);
  2280. }
  2281. if (NULL == pszName)
  2282. {
  2283. TraceMsg("displayName not found for Extended Right");
  2284. continue;
  2285. }
  2286. //
  2287. //Create A new Cache Entry
  2288. //
  2289. PER_ENTRY pER = (PER_ENTRY)LocalAlloc(LPTR, sizeof(ER_ENTRY) + StringByteSize(pszName));
  2290. if( pER == NULL )
  2291. ExitGracefully(hr, E_OUTOFMEMORY, "LocalAlloc failed");
  2292. pER->guid = guid;
  2293. pER->mask = dwValidAccesses;
  2294. pER->dwFlags = 0;
  2295. lstrcpyW(pER->szName, pszName);
  2296. //
  2297. // Is it a Property Set?
  2298. //
  2299. if (dwValidAccesses & (ACTRL_DS_READ_PROP | ACTRL_DS_WRITE_PROP))
  2300. {
  2301. //
  2302. // Insert into list
  2303. //
  2304. Trace((TEXT("Adding PropertySet\"%s\""), pszName));
  2305. DPA_AppendPtr(hPropSetList, pER);
  2306. dwValidAccesses &= ~(ACTRL_DS_READ_PROP | ACTRL_DS_WRITE_PROP);
  2307. }
  2308. else if (dwValidAccesses)
  2309. {
  2310. //
  2311. // Must be a Control Right, Validated Write, etc.
  2312. //
  2313. Trace((TEXT("Adding Extended Right \"%s\""), pszName));
  2314. DPA_AppendPtr(hExtRightList, pER);
  2315. }
  2316. }
  2317. UINT cCount;
  2318. //
  2319. //Get the count of Extended Rights
  2320. //
  2321. cCount = DPA_GetPtrCount(hExtRightList);
  2322. if(!cCount)
  2323. {
  2324. DPA_Destroy(hExtRightList);
  2325. hExtRightList = NULL;
  2326. }
  2327. else
  2328. {
  2329. DPA_Sort(hExtRightList, Schema_CompareER, 0);
  2330. }
  2331. //
  2332. //Get the Count of PropertySets
  2333. //
  2334. cCount = DPA_GetPtrCount(hPropSetList);
  2335. if(!cCount)
  2336. {
  2337. DPA_Destroy(hPropSetList);
  2338. hPropSetList = NULL;
  2339. }
  2340. else
  2341. {
  2342. DPA_Sort(hPropSetList,Schema_CompareER, 0 );
  2343. }
  2344. //
  2345. //Add entry to the cache
  2346. //
  2347. if(!m_hObjectTypeCache)
  2348. m_hObjectTypeCache = DPA_Create(4);
  2349. if(!m_hObjectTypeCache)
  2350. ExitGracefully(hr, E_OUTOFMEMORY, "DPA_Create Failed");
  2351. if(!pOTC)
  2352. {
  2353. pOTC = (POBJECT_TYPE_CACHE)LocalAlloc(LPTR,sizeof(OBJECT_TYPE_CACHE));
  2354. if(!pOTC)
  2355. ExitGracefully(hr, E_OUTOFMEMORY, "LocalAlloc Failed");
  2356. pOTC->guidObject = *pguidClass;
  2357. DPA_AppendPtr(m_hObjectTypeCache, pOTC);
  2358. }
  2359. pOTC->hListExtRights = hExtRightList;
  2360. pOTC->hListPropertySet = hPropSetList;
  2361. pOTC->flags |= OTC_EXTR;
  2362. exit_gracefully:
  2363. if (hSearch != NULL)
  2364. pSearch->CloseSearchHandle(hSearch);
  2365. DoRelease(pSearch);
  2366. if (FAILED(hr))
  2367. {
  2368. if(hExtRightList)
  2369. {
  2370. DestroyDPA(hExtRightList);
  2371. hExtRightList = NULL;
  2372. }
  2373. if(hPropSetList)
  2374. {
  2375. DestroyDPA(hPropSetList);
  2376. hPropSetList = NULL;
  2377. }
  2378. }
  2379. //
  2380. //Set The Output
  2381. //
  2382. *phERList = hExtRightList;
  2383. *phPropSetList = hPropSetList;
  2384. TraceLeaveResult(hr);
  2385. }
  2386. //+--------------------------------------------------------------------------
  2387. //
  2388. // Function: GetChildClassesForOneClass
  2389. //
  2390. // Synopsis: This Function Gets the List of child classes for a class.
  2391. //
  2392. // Arguments: [pguidObjectType - IN] : ObjectGuidType of the class
  2393. // [pszClassName - IN] : Class Name
  2394. // [pszSchemaPath - IN] : Schema Search Path
  2395. // [phChildList - OUT]: Output childclass List
  2396. //
  2397. // Returns: HRESULT : S_OK if everything succeeded
  2398. // E_INVALIDARG if the object entry wasn't found
  2399. //
  2400. // History: 3-Nov 2000 hiteshr Created
  2401. //
  2402. //---------------------------------------------------------------------------
  2403. HRESULT
  2404. CSchemaCache::GetChildClassesForOneClass(IN LPCGUID pguidObjectType,
  2405. IN LPCWSTR pszClassName,
  2406. IN LPCWSTR pszSchemaPath,
  2407. OUT HDPA *phChildList)
  2408. {
  2409. TraceEnter(TRACE_SCHEMA, "CSchemaCache::GetChildClassesForOneClass");
  2410. HRESULT hr = S_OK;
  2411. BOOL bContainer = FALSE;
  2412. VARIANT varContainment = {0};
  2413. HDPA hClassList = NULL;
  2414. UINT cChildClass = 0;
  2415. POBJECT_TYPE_CACHE pOTC = NULL;
  2416. if(!pguidObjectType ||
  2417. !pszSchemaPath ||
  2418. !phChildList)
  2419. {
  2420. Trace((L"Invalid Input Arguments Passed to Schema_GetExtendedRightsForOneClass"));
  2421. return E_INVALIDARG;
  2422. }
  2423. //
  2424. //Search in the cache
  2425. //
  2426. if (m_hObjectTypeCache != NULL)
  2427. {
  2428. UINT cItems = DPA_GetPtrCount(m_hObjectTypeCache);
  2429. while (cItems > 0)
  2430. {
  2431. pOTC = (POBJECT_TYPE_CACHE)DPA_FastGetPtr(m_hObjectTypeCache, --cItems);
  2432. //
  2433. //Found A match.
  2434. //
  2435. if(IsEqualGUID(pOTC->guidObject, *pguidObjectType))
  2436. break;
  2437. pOTC = NULL;
  2438. }
  2439. //
  2440. //Have we already got the child classes
  2441. //
  2442. if(pOTC && pOTC->flags & OTC_COBJ)
  2443. {
  2444. *phChildList = pOTC->hListChildObject;
  2445. return S_OK;
  2446. }
  2447. }
  2448. //
  2449. // Lookup the name of this class
  2450. //
  2451. if (pszClassName == NULL)
  2452. pszClassName = GetClassName(pguidObjectType);
  2453. if (pszClassName == NULL)
  2454. ExitGracefully(hr, E_UNEXPECTED, "Unknown child object GUID");
  2455. //
  2456. // Figure out if the object is a container by getting the list of child
  2457. // classes.
  2458. //
  2459. IADsClass *pDsClass;
  2460. //
  2461. // Get the schema object for this class
  2462. //
  2463. hr = Schema_BindToObject(pszSchemaPath,
  2464. pszClassName,
  2465. IID_IADsClass,
  2466. (LPVOID*)&pDsClass);
  2467. FailGracefully(hr, "Schema_BindToObjectFailed");
  2468. //
  2469. // Get the list of possible child classes
  2470. //
  2471. if (SUCCEEDED(pDsClass->get_Containment(&varContainment)))
  2472. {
  2473. if (V_VT(&varContainment) == (VT_ARRAY | VT_VARIANT))
  2474. {
  2475. LPSAFEARRAY psa = V_ARRAY(&varContainment);
  2476. TraceAssert(psa && psa->cDims == 1);
  2477. if (psa->rgsabound[0].cElements > 0)
  2478. bContainer = TRUE;
  2479. }
  2480. else if (V_VT(&varContainment) == VT_BSTR) // single entry
  2481. {
  2482. TraceAssert(V_BSTR(&varContainment));
  2483. bContainer = TRUE;
  2484. }
  2485. //
  2486. // (Requires the schema class enumeration thread to complete first,
  2487. // and it's usually not done yet the first time we get here.)
  2488. //
  2489. if(bContainer)
  2490. {
  2491. hClassList = DPA_Create(8);
  2492. if (hClassList)
  2493. {
  2494. IDsDisplaySpecifier *pDisplaySpec = NULL;
  2495. //
  2496. // Get the display specifier object
  2497. //
  2498. CoCreateInstance(CLSID_DsDisplaySpecifier,
  2499. NULL,
  2500. CLSCTX_INPROC_SERVER,
  2501. IID_IDsDisplaySpecifier,
  2502. (void**)&pDisplaySpec);
  2503. //
  2504. // Filter the list & get display names
  2505. //
  2506. EnumVariantList(&varContainment,
  2507. hClassList,
  2508. SCHEMA_CLASS,
  2509. pDisplaySpec,
  2510. pszClassName,
  2511. FALSE);
  2512. DoRelease(pDisplaySpec);
  2513. //
  2514. //Get the count of properties
  2515. //
  2516. cChildClass = DPA_GetPtrCount(hClassList);
  2517. if(!cChildClass)
  2518. {
  2519. DPA_Destroy(hClassList);
  2520. hClassList = NULL;
  2521. }
  2522. else
  2523. {
  2524. //
  2525. //Sort The list
  2526. //
  2527. DPA_Sort(hClassList,Schema_ComparePropDisplayName, 0 );
  2528. }
  2529. }
  2530. }
  2531. }
  2532. DoRelease(pDsClass);
  2533. //
  2534. //Add entry to the cache
  2535. //
  2536. if(!m_hObjectTypeCache)
  2537. m_hObjectTypeCache = DPA_Create(4);
  2538. if(!m_hObjectTypeCache)
  2539. ExitGracefully(hr, E_OUTOFMEMORY, "DPA_Create Failed");
  2540. if(!pOTC)
  2541. {
  2542. pOTC = (POBJECT_TYPE_CACHE)LocalAlloc(LPTR,sizeof(OBJECT_TYPE_CACHE));
  2543. if(!pOTC)
  2544. ExitGracefully(hr, E_OUTOFMEMORY, "LocalAlloc Failed");
  2545. pOTC->guidObject = *pguidObjectType;
  2546. DPA_AppendPtr(m_hObjectTypeCache, pOTC);
  2547. }
  2548. pOTC->hListChildObject = hClassList;
  2549. pOTC->flags |= OTC_COBJ;
  2550. exit_gracefully:
  2551. VariantClear(&varContainment);
  2552. if(FAILED(hr))
  2553. {
  2554. DestroyDPA(hClassList);
  2555. hClassList = NULL;
  2556. }
  2557. //
  2558. //Set the Output
  2559. //
  2560. *phChildList = hClassList;
  2561. TraceLeaveResult(hr);
  2562. }
  2563. //+--------------------------------------------------------------------------
  2564. //
  2565. // Function: GetPropertiesForOneClass
  2566. //
  2567. // Synopsis: This Function Gets the List of properties for a class.
  2568. //
  2569. // Arguments: [pguidObjectType - IN] : ObjectGuidType of the class
  2570. // [pszClassName - IN] : Class Name
  2571. // [pszSchemaPath - IN] : Schema Search Path
  2572. // [phPropertyList - OUT]: Output Property List
  2573. //
  2574. // Returns: HRESULT : S_OK if everything succeeded
  2575. // E_INVALIDARG if the object entry wasn't found
  2576. //
  2577. // History: 3-Nov 2000 hiteshr Created
  2578. //
  2579. //---------------------------------------------------------------------------
  2580. HRESULT
  2581. CSchemaCache::GetPropertiesForOneClass(IN LPCGUID pguidObjectType,
  2582. IN LPCWSTR pszClassName,
  2583. IN LPCWSTR pszSchemaPath,
  2584. OUT HDPA *phPropertyList)
  2585. {
  2586. HRESULT hr;
  2587. IADsClass *pDsClass = NULL;
  2588. VARIANT varMandatoryProperties = {0};
  2589. VARIANT varOptionalProperties = {0};
  2590. UINT cProperties = 0;
  2591. IDsDisplaySpecifier *pDisplaySpec = NULL;
  2592. HDPA hPropertyList = NULL;
  2593. POBJECT_TYPE_CACHE pOTC = NULL;
  2594. TraceEnter(TRACE_SCHEMA, "CSchemaCache::GetPropertiesForOneClass");
  2595. if(!pguidObjectType ||
  2596. !pszSchemaPath ||
  2597. !phPropertyList)
  2598. {
  2599. Trace((L"Invalid Input Arguments Passed to CSchemaCache::GetPropertiesForOneClass"));
  2600. return E_INVALIDARG;
  2601. }
  2602. //
  2603. //Search in the cache
  2604. //
  2605. if (m_hObjectTypeCache != NULL)
  2606. {
  2607. UINT cItems = DPA_GetPtrCount(m_hObjectTypeCache);
  2608. while (cItems > 0)
  2609. {
  2610. pOTC = (POBJECT_TYPE_CACHE)DPA_FastGetPtr(m_hObjectTypeCache, --cItems);
  2611. //
  2612. //Found A match.
  2613. //
  2614. if(IsEqualGUID(pOTC->guidObject, *pguidObjectType))
  2615. break;
  2616. pOTC = NULL;
  2617. }
  2618. //
  2619. //Have we already got the properties
  2620. //
  2621. if(pOTC && pOTC->flags & OTC_PROP)
  2622. {
  2623. *phPropertyList = pOTC->hListProperty;
  2624. return S_OK;
  2625. }
  2626. }
  2627. //
  2628. // Get the schema object for this class
  2629. //
  2630. if (pszClassName == NULL)
  2631. pszClassName = GetClassName(pguidObjectType);
  2632. if (pszClassName == NULL)
  2633. ExitGracefully(hr, E_UNEXPECTED, "Unknown child object GUID");
  2634. hr = Schema_BindToObject(pszSchemaPath,
  2635. pszClassName,
  2636. IID_IADsClass,
  2637. (LPVOID*)&pDsClass);
  2638. FailGracefully(hr, "Unable to create schema object");
  2639. //
  2640. // Get the display specifier object
  2641. //
  2642. CoCreateInstance(CLSID_DsDisplaySpecifier,
  2643. NULL,
  2644. CLSCTX_INPROC_SERVER,
  2645. IID_IDsDisplaySpecifier,
  2646. (void**)&pDisplaySpec);
  2647. hPropertyList = DPA_Create(8);
  2648. if (!hPropertyList)
  2649. ExitGracefully(hr, E_OUTOFMEMORY, "Unable to create DPA");
  2650. //
  2651. // Get mandatory and optional property lists
  2652. //
  2653. if (SUCCEEDED(pDsClass->get_MandatoryProperties(&varMandatoryProperties)))
  2654. {
  2655. EnumVariantList(&varMandatoryProperties,
  2656. hPropertyList,
  2657. 0,
  2658. pDisplaySpec,
  2659. pszClassName,
  2660. FALSE);
  2661. }
  2662. if (SUCCEEDED(pDsClass->get_OptionalProperties(&varOptionalProperties)))
  2663. {
  2664. EnumVariantList(&varOptionalProperties,
  2665. hPropertyList,
  2666. 0,
  2667. pDisplaySpec,
  2668. pszClassName,
  2669. FALSE);
  2670. }
  2671. //
  2672. //Get the Number of properties
  2673. //
  2674. cProperties = DPA_GetPtrCount(hPropertyList);
  2675. if(!cProperties)
  2676. {
  2677. DPA_Destroy(hPropertyList);
  2678. hPropertyList = NULL;
  2679. }
  2680. else
  2681. {
  2682. //
  2683. //Sort The list
  2684. //
  2685. DPA_Sort(hPropertyList,Schema_ComparePropDisplayName, 0 );
  2686. }
  2687. //
  2688. //Add entry to the cache
  2689. //
  2690. if(!m_hObjectTypeCache)
  2691. m_hObjectTypeCache = DPA_Create(4);
  2692. if(!m_hObjectTypeCache)
  2693. ExitGracefully(hr, E_OUTOFMEMORY, "DPA_Create Failed");
  2694. if(!pOTC)
  2695. {
  2696. pOTC = (POBJECT_TYPE_CACHE)LocalAlloc(LPTR,sizeof(OBJECT_TYPE_CACHE));
  2697. if(!pOTC)
  2698. ExitGracefully(hr, E_OUTOFMEMORY, "LocalAlloc Failed");
  2699. pOTC->guidObject = *pguidObjectType;
  2700. DPA_AppendPtr(m_hObjectTypeCache, pOTC);
  2701. }
  2702. pOTC->hListProperty = hPropertyList;
  2703. pOTC->flags |= OTC_PROP;
  2704. exit_gracefully:
  2705. VariantClear(&varMandatoryProperties);
  2706. VariantClear(&varOptionalProperties);
  2707. DoRelease(pDsClass);
  2708. DoRelease(pDisplaySpec);
  2709. if(FAILED(hr) && hPropertyList)
  2710. {
  2711. DestroyDPA(hPropertyList);
  2712. hPropertyList = NULL;
  2713. }
  2714. //
  2715. //Set the Output
  2716. //
  2717. *phPropertyList = hPropertyList;
  2718. TraceLeaveResult(hr);
  2719. }
  2720. //+--------------------------------------------------------------------------
  2721. //
  2722. // Function: GetExtendedRightsForNClasses
  2723. //
  2724. // Synopsis:
  2725. // This function gets the ExtendedRigts(control rights,
  2726. // validated rights) and PropertySets for pszClassName and
  2727. // all the classes in AuxTypeList.
  2728. // Function Merges Extended Rights of all the classes in to a
  2729. // signle list form which duplicates are removed and list
  2730. // is sorted.
  2731. // Function Merges PropertySets of all the classes in to a
  2732. // signle list form which duplicates are removed and list
  2733. // is sorted.
  2734. //
  2735. // Arguments: [pguidClass - IN] : ObjectGuidType of the class
  2736. // [hAuxList - IN]:List of Auxillary Classes
  2737. // [pszSchemaSearchPath - IN] : Schema Search Path
  2738. // [phERList - OUT]: Output Extended Rights list
  2739. // [phPropSetList - OUT]: Output Propset List
  2740. //
  2741. // Returns: HRESULT : S_OK if everything succeeded
  2742. // E_INVALIDARG if the object entry wasn't found
  2743. // Note: Calling function must call DPA_Destroy on *phERList and *phPropSetList
  2744. // to Free the memory
  2745. //
  2746. // History: 3-Nov 2000 hiteshr Created
  2747. //
  2748. //---------------------------------------------------------------------------
  2749. HRESULT
  2750. CSchemaCache::GetExtendedRightsForNClasses(IN LPWSTR pszSchemaSearchPath,
  2751. IN LPCGUID pguidClass,
  2752. IN HDPA hAuxList,
  2753. OUT HDPA *phERList,
  2754. OUT HDPA *phPropSetList)
  2755. {
  2756. TraceEnter(TRACE_SCHEMA, "CSchemaCache::GetExtendedRightsForNClasses");
  2757. if(!pguidClass ||
  2758. !pszSchemaSearchPath)
  2759. {
  2760. Trace((L"Invalid Input Arguments Passed to CSchemaCache::GetPropertiesForNClasses"));
  2761. return E_INVALIDARG;
  2762. }
  2763. HRESULT hr = S_OK;
  2764. HDPA hERList = NULL;
  2765. HDPA hPropSetList = NULL;
  2766. HDPA hFinalErList = NULL;
  2767. HDPA hFinalPropSetList = NULL;
  2768. //
  2769. //Get the extended rights for pguidClass
  2770. //
  2771. hr = GetExtendedRightsForOneClass(pszSchemaSearchPath,
  2772. pguidClass,
  2773. &hERList,
  2774. &hPropSetList);
  2775. FailGracefully(hr,"GetExtendedRightsForOneClasses failed");
  2776. if(hERList && phERList)
  2777. {
  2778. UINT cCount = DPA_GetPtrCount(hERList);
  2779. hFinalErList = DPA_Create(cCount);
  2780. if(!hFinalErList)
  2781. ExitGracefully(hr, ERROR_NOT_ENOUGH_MEMORY,"DPA_Create Failed");
  2782. //
  2783. //Copy hERList to hFinalErList
  2784. //
  2785. DPA_Merge(hFinalErList, //Destination
  2786. hERList, //Source
  2787. DPAM_SORTED|DPAM_UNION, //Already Sorted And give me union
  2788. Schema_CompareER,
  2789. _Merge,
  2790. 0);
  2791. }
  2792. if(hPropSetList && phPropSetList)
  2793. {
  2794. UINT cCount = DPA_GetPtrCount(hPropSetList);
  2795. hFinalPropSetList = DPA_Create(cCount);
  2796. if(!hFinalPropSetList)
  2797. ExitGracefully(hr, ERROR_NOT_ENOUGH_MEMORY,"DPA_Create Failed");
  2798. //
  2799. //Copy hPropSetList to hFinalPropSetList
  2800. //
  2801. DPA_Merge(hFinalPropSetList, //Destination
  2802. hPropSetList, //Source
  2803. DPAM_SORTED|DPAM_UNION, //Already Sorted And give me union
  2804. Schema_CompareER,
  2805. _Merge,
  2806. 0);
  2807. }
  2808. //
  2809. //For each auxclass get the extended rights
  2810. //and property sets
  2811. //
  2812. if (hAuxList != NULL)
  2813. {
  2814. UINT cItems = DPA_GetPtrCount(hAuxList);
  2815. while (cItems > 0)
  2816. {
  2817. PAUX_INFO pAI;
  2818. pAI = (PAUX_INFO)DPA_FastGetPtr(hAuxList, --cItems);
  2819. if(IsEqualGUID(pAI->guid, GUID_NULL))
  2820. {
  2821. hr = LookupClassID(pAI->pszClassName, &pAI->guid);
  2822. FailGracefully(hr,"Cache Not available");
  2823. }
  2824. hERList = NULL;
  2825. hPropSetList = NULL;
  2826. //
  2827. //Get the ER and PropSet for AuxClass
  2828. //
  2829. hr = GetExtendedRightsForOneClass(pszSchemaSearchPath,
  2830. &pAI->guid,
  2831. &hERList,
  2832. &hPropSetList);
  2833. FailGracefully(hr,"GetExtendedRightsForOneClasses failed");
  2834. if(hERList && phERList)
  2835. {
  2836. if(!hFinalErList)
  2837. {
  2838. UINT cCount = DPA_GetPtrCount(hERList);
  2839. hFinalErList = DPA_Create(cCount);
  2840. if(!hFinalErList)
  2841. ExitGracefully(hr, ERROR_NOT_ENOUGH_MEMORY,"DPA_Create Failed");
  2842. }
  2843. //
  2844. //Merge hERList into hFinalErList
  2845. //
  2846. DPA_Merge(hFinalErList, //Destination
  2847. hERList, //Source
  2848. DPAM_SORTED|DPAM_UNION, //Already Sorted And give me union
  2849. Schema_CompareER,
  2850. _Merge,
  2851. 0);
  2852. }
  2853. if(hPropSetList && phPropSetList)
  2854. {
  2855. if(!hFinalPropSetList)
  2856. {
  2857. UINT cCount = DPA_GetPtrCount(hPropSetList);
  2858. hFinalPropSetList = DPA_Create(cCount);
  2859. if(!hFinalPropSetList)
  2860. ExitGracefully(hr, ERROR_NOT_ENOUGH_MEMORY,"DPA_Create Failed");
  2861. }
  2862. //
  2863. //Merge hPropSetList into hFinalPropSetList
  2864. //
  2865. DPA_Merge(hFinalPropSetList, //Destination
  2866. hPropSetList, //Source
  2867. DPAM_SORTED|DPAM_UNION, //Already Sorted And give me union
  2868. Schema_CompareER,
  2869. _Merge,
  2870. 0);
  2871. }
  2872. }
  2873. }
  2874. exit_gracefully:
  2875. if(FAILED(hr))
  2876. {
  2877. if(hFinalPropSetList)
  2878. DPA_Destroy(hFinalPropSetList);
  2879. if(hFinalErList)
  2880. DPA_Destroy(hFinalErList);
  2881. hFinalErList = NULL;
  2882. hFinalPropSetList = NULL;
  2883. }
  2884. if(phERList)
  2885. *phERList = hFinalErList;
  2886. if(phPropSetList)
  2887. *phPropSetList = hFinalPropSetList;
  2888. TraceLeaveResult(hr);
  2889. }
  2890. //+--------------------------------------------------------------------------
  2891. //
  2892. // Function: GetChildClassesForNClasses
  2893. //
  2894. // Synopsis:
  2895. // This function gets the childclasses for pszClassName and
  2896. // all the classes in AuxTypeList. Function Merges child clasess
  2897. // of all the classes in to a signle list form which duplicates
  2898. // are removed and list is sorted
  2899. //
  2900. // Arguments: [pguidObjectType - IN] : ObjectGuidType of the class
  2901. // [pszClassName - IN] : Class Name
  2902. // [hAuxList - IN]:List of Auxillary Classes
  2903. // [pszSchemaPath - IN] : Schema Search Path
  2904. // [phChildList - OUT]: Output Child Classes List
  2905. //
  2906. // Returns: HRESULT : S_OK if everything succeeded
  2907. // E_INVALIDARG if the object entry wasn't found
  2908. // Note: Calling function must call DPA_Destroy on *phPropertyList to
  2909. // Free the memory
  2910. //
  2911. // History: 3-Nov 2000 hiteshr Created
  2912. //
  2913. //---------------------------------------------------------------------------
  2914. HRESULT
  2915. CSchemaCache::GetChildClassesForNClasses(IN LPCGUID pguidObjectType,
  2916. IN LPCWSTR pszClassName,
  2917. IN HDPA hAuxList,
  2918. IN LPCWSTR pszSchemaPath,
  2919. OUT HDPA *phChildList)
  2920. {
  2921. TraceEnter(TRACE_SCHEMA, "CSchemaCache::GetChildClassesForNClasses");
  2922. if(!pguidObjectType ||
  2923. !pszSchemaPath ||
  2924. !phChildList)
  2925. {
  2926. Trace((L"Invalid Input Arguments Passed to CSchemaCache::GetPropertiesForNClasses"));
  2927. return E_INVALIDARG;
  2928. }
  2929. HRESULT hr = S_OK;
  2930. HDPA hChildList = NULL;
  2931. HDPA hFinalChildList = NULL;
  2932. //
  2933. //Get the Child Classes for pszClassName
  2934. //
  2935. hr = GetChildClassesForOneClass(pguidObjectType,
  2936. pszClassName,
  2937. pszSchemaPath,
  2938. &hChildList);
  2939. FailGracefully(hr,"GetExtendedRightsForOneClasses failed");
  2940. if(hChildList)
  2941. {
  2942. if(!hFinalChildList)
  2943. {
  2944. UINT cCount = DPA_GetPtrCount(hChildList);
  2945. hFinalChildList = DPA_Create(cCount);
  2946. if(!hFinalChildList)
  2947. ExitGracefully(hr, ERROR_NOT_ENOUGH_MEMORY,"DPA_Create Failed");
  2948. }
  2949. //
  2950. //Copy hChildList to hFinalChildList
  2951. //
  2952. DPA_Merge(hFinalChildList, //Destination
  2953. hChildList, //Source
  2954. DPAM_SORTED|DPAM_UNION, //Already Sorted And give me union
  2955. Schema_ComparePropDisplayName,
  2956. _Merge,
  2957. 0);
  2958. }
  2959. //
  2960. //For each class in hAuxList get the child classes
  2961. //
  2962. if (hAuxList != NULL)
  2963. {
  2964. UINT cItems = DPA_GetPtrCount(hAuxList);
  2965. while (cItems > 0)
  2966. {
  2967. PAUX_INFO pAI;
  2968. pAI = (PAUX_INFO)DPA_FastGetPtr(hAuxList, --cItems);
  2969. if(IsEqualGUID(pAI->guid, GUID_NULL))
  2970. {
  2971. hr = LookupClassID(pAI->pszClassName, &pAI->guid);
  2972. FailGracefully(hr,"Cache Not available");
  2973. }
  2974. //
  2975. //GetPropertiesForOneClass returns the list of handles
  2976. //from cache so don't delete them. Simply set them to NULL
  2977. //
  2978. hChildList = NULL;
  2979. hr = GetChildClassesForOneClass(&pAI->guid,
  2980. pAI->pszClassName,
  2981. pszSchemaPath,
  2982. &hChildList);
  2983. FailGracefully(hr,"GetExtendedRightsForOneClasses failed");
  2984. if(hChildList)
  2985. {
  2986. if(!hFinalChildList)
  2987. {
  2988. UINT cCount = DPA_GetPtrCount(hChildList);
  2989. hFinalChildList = DPA_Create(cCount);
  2990. if(!hFinalChildList)
  2991. ExitGracefully(hr, ERROR_NOT_ENOUGH_MEMORY,"DPA_Create Failed");
  2992. }
  2993. //
  2994. //Merge hChildList into hFinalChildList
  2995. //
  2996. DPA_Merge(hFinalChildList, //Destination
  2997. hChildList, //Source
  2998. DPAM_SORTED|DPAM_UNION, //Already Sorted And give me union
  2999. Schema_ComparePropDisplayName,
  3000. _Merge,
  3001. 0);
  3002. }
  3003. }
  3004. }
  3005. exit_gracefully:
  3006. if(FAILED(hr))
  3007. {
  3008. if(hFinalChildList)
  3009. DPA_Destroy(hFinalChildList);
  3010. hFinalChildList = NULL;
  3011. }
  3012. //
  3013. //Set the output
  3014. //
  3015. *phChildList = hFinalChildList;
  3016. TraceLeaveResult(hr);
  3017. }
  3018. //+--------------------------------------------------------------------------
  3019. //
  3020. // Function: GetPropertiesForNClasses
  3021. //
  3022. // Synopsis:
  3023. // This function gets the properties for pszClassName and
  3024. // all the classes in AuxTypeList. Function Merges properties
  3025. // of all the classes in to a signle list form which duplicates
  3026. //
  3027. // Arguments: [pguidObjectType - IN] : ObjectGuidType of the class
  3028. // [pszClassName - IN] : Class Name
  3029. // [hAuxList - IN]:List of Auxillary Classes
  3030. // [pszSchemaPath - IN] : Schema Search Path
  3031. // [phPropertyList - OUT]: Output Property List
  3032. //
  3033. // Returns: HRESULT : S_OK if everything succeeded
  3034. // E_INVALIDARG if the object entry wasn't found
  3035. // Note: Calling function must call DPA_Destroy on *phPropertyList to
  3036. // Free the memory
  3037. //
  3038. // History: 3-Nov 2000 hiteshr Created
  3039. //
  3040. //---------------------------------------------------------------------------
  3041. HRESULT
  3042. CSchemaCache::
  3043. GetPropertiesForNClasses(IN LPCGUID pguidObjectType,
  3044. IN LPCWSTR pszClassName,
  3045. IN HDPA hAuxList,
  3046. IN LPCWSTR pszSchemaPath,
  3047. OUT HDPA *phPropertyList)
  3048. {
  3049. TraceEnter(TRACE_SCHEMA, "CSchemaCache::GetPropertiesForOneClass");
  3050. if(!pguidObjectType ||
  3051. !pszSchemaPath ||
  3052. !phPropertyList)
  3053. {
  3054. Trace((L"Invalid Input Arguments Passed to CSchemaCache::GetPropertiesForNClasses"));
  3055. return E_INVALIDARG;
  3056. }
  3057. HRESULT hr = S_OK;
  3058. HDPA hPropertyList = NULL;
  3059. HDPA hFinalPropertyList = NULL;
  3060. //
  3061. //Get The properties for pszClassName
  3062. //
  3063. hr = GetPropertiesForOneClass(pguidObjectType,
  3064. pszClassName,
  3065. pszSchemaPath,
  3066. &hPropertyList);
  3067. FailGracefully(hr,"GetPropertiesForOneClass failed");
  3068. if(hPropertyList)
  3069. {
  3070. UINT cCount = DPA_GetPtrCount(hPropertyList);
  3071. hFinalPropertyList = DPA_Create(cCount);
  3072. if(!hFinalPropertyList)
  3073. ExitGracefully(hr, ERROR_NOT_ENOUGH_MEMORY,"DPA_Create Failed");
  3074. //
  3075. //Copy hPropertyList to hFinalPropertyList.
  3076. //
  3077. DPA_Merge(hFinalPropertyList, //Destination
  3078. hPropertyList, //Source
  3079. DPAM_SORTED|DPAM_UNION, //Already Sorted And give me union
  3080. Schema_ComparePropDisplayName,
  3081. _Merge,
  3082. 0);
  3083. }
  3084. //
  3085. //Get the properties for each class in hAuxList
  3086. //and add them to hFinalPropertyList
  3087. //
  3088. if (hAuxList != NULL)
  3089. {
  3090. UINT cItems = DPA_GetPtrCount(hAuxList);
  3091. while (cItems > 0)
  3092. {
  3093. PAUX_INFO pAI;
  3094. pAI = (PAUX_INFO)DPA_FastGetPtr(hAuxList, --cItems);
  3095. if(IsEqualGUID(pAI->guid, GUID_NULL))
  3096. {
  3097. hr = LookupClassID(pAI->pszClassName, &pAI->guid);
  3098. FailGracefully(hr,"Cache Not available");
  3099. }
  3100. //
  3101. //GetPropertiesForOneClass returns the list of handles
  3102. //from cache so don't delete them. Simply set them to NULL
  3103. //
  3104. hPropertyList = NULL;
  3105. //
  3106. //Get properties for Aux Class
  3107. //
  3108. hr = GetPropertiesForOneClass(&pAI->guid,
  3109. pAI->pszClassName,
  3110. pszSchemaPath,
  3111. &hPropertyList);
  3112. FailGracefully(hr,"GetExtendedRightsForOneClasses failed");
  3113. if(hPropertyList)
  3114. {
  3115. if(!hFinalPropertyList)
  3116. {
  3117. UINT cCount = DPA_GetPtrCount(hPropertyList);
  3118. hFinalPropertyList = DPA_Create(cCount);
  3119. if(!hFinalPropertyList)
  3120. ExitGracefully(hr, ERROR_NOT_ENOUGH_MEMORY,"DPA_Create Failed");
  3121. }
  3122. //
  3123. //Merge hPropertyList with hFinalPropertyList
  3124. //
  3125. DPA_Merge(hFinalPropertyList, //Destination
  3126. hPropertyList, //Source
  3127. DPAM_SORTED|DPAM_UNION, //Already Sorted And give me union
  3128. Schema_ComparePropDisplayName,
  3129. _Merge,
  3130. 0);
  3131. }
  3132. }
  3133. }
  3134. exit_gracefully:
  3135. if(FAILED(hr))
  3136. {
  3137. if(hFinalPropertyList)
  3138. DPA_Destroy(hFinalPropertyList);
  3139. hFinalPropertyList = NULL;
  3140. }
  3141. //
  3142. //Set the Output
  3143. //
  3144. *phPropertyList = hFinalPropertyList;
  3145. TraceLeaveResult(hr);
  3146. }
  3147. //+--------------------------------------------------------------------------
  3148. //
  3149. // Function: DoesPathContainServer
  3150. //
  3151. // Synopsis:
  3152. // Checks if the path contain server name in begining
  3153. // Arguments: [pszPath - IN] : Path to DS object
  3154. //
  3155. // Returns: BOOL: true if path contain server name
  3156. // false if not or error occurs
  3157. //
  3158. // History: 27 March 2000 hiteshr Created
  3159. //
  3160. //---------------------------------------------------------------------------
  3161. bool DoesPathContainServer(LPCWSTR pszPath)
  3162. {
  3163. IADsPathname *pPath = NULL;
  3164. BSTR strServerName = NULL;
  3165. bool bReturn = false;
  3166. BSTR strObjectPath = SysAllocString(pszPath);
  3167. if(!strObjectPath)
  3168. return false;
  3169. //
  3170. // Create an ADsPathname object to parse the path and get the
  3171. // server name
  3172. //
  3173. HRESULT hr = CoCreateInstance(CLSID_Pathname,
  3174. NULL,
  3175. CLSCTX_INPROC_SERVER,
  3176. IID_IADsPathname,
  3177. (LPVOID*)&pPath);
  3178. if (pPath)
  3179. {
  3180. //
  3181. //Set Full Path
  3182. //
  3183. if (SUCCEEDED(pPath->Set(strObjectPath, ADS_SETTYPE_FULL)))
  3184. {
  3185. //
  3186. //Retrieve servername
  3187. //
  3188. hr = pPath->Retrieve(ADS_FORMAT_SERVER, &strServerName);
  3189. if(SUCCEEDED(hr) && strServerName)
  3190. {
  3191. bReturn = true;
  3192. }
  3193. }
  3194. }
  3195. DoRelease(pPath);
  3196. if(strServerName)
  3197. SysFreeString(strServerName);
  3198. SysFreeString(strObjectPath);
  3199. return bReturn;
  3200. }
  3201. //*************************************************************
  3202. //
  3203. // OpenDSObject()
  3204. //
  3205. // Purpose: Calls AdsOpenObject with ADS_SERVER_BIND
  3206. // Return: Same as AdsOpenObject
  3207. //
  3208. //*************************************************************
  3209. HRESULT OpenDSObject (LPTSTR lpPath, LPTSTR lpUserName, LPTSTR lpPassword, DWORD dwFlags, REFIID riid, void FAR * FAR * ppObject)
  3210. {
  3211. if (DoesPathContainServer(lpPath))
  3212. {
  3213. dwFlags |= ADS_SERVER_BIND;
  3214. }
  3215. return (ADsOpenObject(lpPath, lpUserName, lpPassword, dwFlags,
  3216. riid, ppObject));
  3217. }