Leaked source code of windows server 2003
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.

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