Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3286 lines
88 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999 - 1999
  6. //
  7. // File: _util.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. PWSTR g_wzRootDSE = L"RootDSE";
  11. PWSTR g_wzSchemaNamingContext = L"schemaNamingContext";
  12. PWSTR g_wzLDAPAbstractSchemaFormat = L"LDAP://%s/schema/%s";
  13. //
  14. // Attribute names:
  15. //
  16. PWSTR g_wzDescription = L"description"; // ADSTYPE_CASE_IGNORE_STRING
  17. PWSTR g_wzName = L"name"; // ADSTYPE_CASE_IGNORE_STRING
  18. PWSTR g_wzMemberAttr = L"member"; // ADSTYPE_DN_STRING
  19. #define _WIZ_FULL_CTRL _GRANT_ALL
  20. // turn off check for warning C4127: conditional expression is constant
  21. #pragma warning (disable : 4127)
  22. ///////////////////////////////////////////////////////////////////////
  23. // CWString
  24. BOOL CWString::LoadFromResource(UINT uID)
  25. {
  26. int nBufferSize = 128;
  27. static const int nCountMax = 4;
  28. int nCount = 1;
  29. do
  30. {
  31. LPWSTR lpszBuffer = (LPWSTR)alloca(nCount*nBufferSize*sizeof(WCHAR));
  32. int iRet = ::LoadString(_Module.GetResourceInstance(), uID,
  33. lpszBuffer, nBufferSize);
  34. if (iRet == 0)
  35. {
  36. (*this) = L"?";
  37. return FALSE; // not found
  38. }
  39. if (iRet == nBufferSize-1) // truncation
  40. {
  41. if (nCount > nCountMax)
  42. {
  43. // too many reallocations
  44. (*this) = lpszBuffer;
  45. return FALSE; // truncation
  46. }
  47. // try to expand buffer
  48. nBufferSize *=2;
  49. nCount++;
  50. }
  51. else
  52. {
  53. // got it
  54. (*this) = lpszBuffer;
  55. break;
  56. }
  57. }
  58. while (TRUE);
  59. return TRUE;
  60. }
  61. ///////////////////////////////////////////////////////////////////////////////////
  62. // catenate the server name and the 1779 name
  63. // to get an LDAP path like "LDAP://myserv.foo.com./cn=host,..."
  64. void BuildLdapPathHelper(LPCWSTR lpszServerName, LPCWSTR lpszNamingContext, CWString& szLdapPath)
  65. {
  66. static LPCWSTR lpszFmt = L"LDAP://%s/%s";
  67. int nServerNameLen = lstrlen(lpszServerName)+1;
  68. int nFormatStringLen = lstrlen(lpszFmt)+1;
  69. int nNamingContext = lstrlen(lpszNamingContext)+1;
  70. // build the LDAP path for the schema class
  71. WCHAR* pwszNewObjectPath =
  72. (WCHAR*)alloca(sizeof(WCHAR)*(nServerNameLen+nFormatStringLen+nNamingContext));
  73. wsprintf(pwszNewObjectPath, lpszFmt, lpszServerName, lpszNamingContext);
  74. szLdapPath = pwszNewObjectPath;
  75. }
  76. // catenate the server name and the 1779 name
  77. // to get something like "\\myserv.foo.com.\cn=host,..."
  78. void BuildWin32PathHelper(LPCWSTR lpszServerName, LPCWSTR lpszNamingContext, CWString& szWin32Path)
  79. {
  80. static LPCWSTR lpszFmt = L"\\\\%s\\%s";
  81. int nServerNameLen = lstrlen(lpszServerName)+1;
  82. int nFormatStringLen = lstrlen(lpszFmt)+1;
  83. int nNamingContext = lstrlen(lpszNamingContext)+1;
  84. // build the LDAP path for the schema class
  85. WCHAR* pwszNewObjectPath =
  86. (WCHAR*)alloca(sizeof(WCHAR)*(nServerNameLen+nFormatStringLen+nNamingContext));
  87. wsprintf(pwszNewObjectPath, lpszFmt, lpszServerName, lpszNamingContext);
  88. szWin32Path = pwszNewObjectPath;
  89. }
  90. HRESULT GetCanonicalNameFromNamingContext(LPCWSTR lpszNamingContext, CWString& szCanonicalName)
  91. {
  92. szCanonicalName = L"";
  93. // assume in the form "cn=xyz,..."
  94. LPWSTR lpszCanonicalName = NULL;
  95. HRESULT hr = CrackName((LPWSTR)lpszNamingContext, &lpszCanonicalName, GET_OBJ_CAN_NAME);
  96. if (SUCCEEDED(hr) && (lpszCanonicalName != NULL))
  97. {
  98. szCanonicalName = lpszCanonicalName;
  99. }
  100. if (lpszCanonicalName != NULL)
  101. ::LocalFree(lpszCanonicalName);
  102. return hr;
  103. }
  104. /////////////////////////////////////////////////////////////////////////
  105. class CContainerProxyBase
  106. {
  107. public:
  108. CContainerProxyBase() { }
  109. virtual ~CContainerProxyBase() {}
  110. virtual BOOL Add(LPCWSTR lpsz) = 0;
  111. };
  112. template <class TOBJ, class TARR, class TFILTR> class CContainerProxy
  113. : public CContainerProxyBase
  114. {
  115. public:
  116. CContainerProxy(TARR* pArr, TFILTR* pFilter)
  117. {
  118. m_pArr = pArr;
  119. m_pFilter = pFilter;
  120. }
  121. virtual BOOL Add(LPCWSTR lpsz)
  122. {
  123. ULONG filterFlags = 0x0;
  124. if ( (m_pFilter == NULL) ||
  125. (m_pFilter->CanAdd(lpsz, &filterFlags)) )
  126. {
  127. TOBJ* p = new TOBJ(filterFlags, lpsz);
  128. if (p == NULL)
  129. return FALSE;
  130. return m_pArr->Add(p);
  131. }
  132. return TRUE;
  133. }
  134. private:
  135. TARR* m_pArr;
  136. TFILTR* m_pFilter;
  137. };
  138. /////////////////////////////////////////////////////////////////////////
  139. BOOL LoadStringHelper(UINT uID, LPTSTR lpszBuffer, int nBufferMax)
  140. {
  141. int iRet = ::LoadString(_Module.GetResourceInstance(), uID,
  142. lpszBuffer, nBufferMax);
  143. if (iRet == 0)
  144. {
  145. lpszBuffer[0] = NULL;
  146. return FALSE; // not found
  147. }
  148. if (iRet == nBufferMax-1)
  149. return FALSE; // truncation
  150. return TRUE;
  151. }
  152. BOOL GetStringFromHRESULTError(HRESULT hr, CWString& szErrorString, BOOL bTryADsIErrors)
  153. {
  154. HRESULT hrGetLast = S_OK;
  155. DWORD status;
  156. PTSTR ptzSysMsg = NULL;
  157. // first check if we have extended ADs errors
  158. if ((hr != S_OK) && bTryADsIErrors)
  159. {
  160. WCHAR Buf1[256], Buf2[256];
  161. hrGetLast = ::ADsGetLastError(&status, Buf1, 256, Buf2, 256);
  162. TRACE(_T("ADsGetLastError returned status of %lx, error: %s, name %s\n"),
  163. status, Buf1, Buf2);
  164. if ((status != ERROR_INVALID_DATA) && (status != 0))
  165. {
  166. hr = status;
  167. }
  168. }
  169. // try the system first
  170. int nChars = ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
  171. | FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr,
  172. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  173. (PTSTR)&ptzSysMsg, 0, NULL);
  174. if (nChars == 0)
  175. {
  176. //try ads errors
  177. static HMODULE g_adsMod = 0;
  178. if (0 == g_adsMod)
  179. g_adsMod = GetModuleHandle (L"activeds.dll");
  180. nChars = ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
  181. | FORMAT_MESSAGE_FROM_HMODULE, g_adsMod, hr,
  182. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  183. (PTSTR)&ptzSysMsg, 0, NULL);
  184. }
  185. if (nChars > 0)
  186. {
  187. szErrorString = ptzSysMsg;
  188. ::LocalFree(ptzSysMsg);
  189. }
  190. return (nChars > 0);
  191. }
  192. BOOL GetStringFromWin32Error(DWORD dwErr, CWString& szErrorString)
  193. {
  194. return GetStringFromHRESULTError(HRESULT_FROM_WIN32(dwErr),szErrorString);
  195. }
  196. //
  197. // Given a GUID struct, it returns a GUID in string format, without {}
  198. //
  199. BOOL FormatStringGUID(LPWSTR lpszBuf, UINT nBufSize, const GUID* pGuid)
  200. {
  201. lpszBuf[0] = NULL;
  202. // if it is a NULL GUID*, just return an empty string
  203. if (pGuid == NULL)
  204. {
  205. return FALSE;
  206. }
  207. /*
  208. typedef struct _GUID {
  209. unsigned long Data1;
  210. unsigned short Data2;
  211. unsigned short Data3;
  212. unsigned char Data4[ 8 ];
  213. }
  214. int _snwprintf( wchar_t *buffer, size_t count, const wchar_t *format [, argument] ... );
  215. */
  216. return (_snwprintf(lpszBuf, nBufSize,
  217. L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
  218. pGuid->Data1, pGuid->Data2, pGuid->Data3,
  219. pGuid->Data4[0], pGuid->Data4[1],
  220. pGuid->Data4[2], pGuid->Data4[3], pGuid->Data4[4], pGuid->Data4[5], pGuid->Data4[6], pGuid->Data4[7]) > 0);
  221. }
  222. //
  223. // Given a GUID in string format (without {}) it returns a GUID struct
  224. //
  225. // e.g. "00299570-246d-11d0-a768-00aa006e0529" to a struct form
  226. //
  227. BOOL GuidFromString(GUID* pGuid, LPCWSTR lpszGuidString)
  228. {
  229. ZeroMemory(pGuid, sizeof(GUID));
  230. if (lpszGuidString == NULL)
  231. {
  232. return FALSE;
  233. }
  234. int nLen = lstrlen(lpszGuidString);
  235. // the string length should be 36
  236. if (nLen != 36)
  237. return FALSE;
  238. // add the braces to call the Win32 API
  239. LPWSTR lpszWithBraces = (LPWSTR)alloca((nLen+1+2)*sizeof(WCHAR)); // NULL plus {}
  240. wsprintf(lpszWithBraces, L"{%s}", lpszGuidString);
  241. return SUCCEEDED(::CLSIDFromString(lpszWithBraces, pGuid));
  242. }
  243. DWORD AddEntryInAcl(PEXPLICIT_ACCESS pAccessEntry, PACL* ppAcl)
  244. {
  245. // add an entry in the DACL
  246. PACL pOldAcl = *ppAcl;
  247. TRACE(L"Calling SetEntriesInAcl()\n");
  248. DWORD dwErr = ::SetEntriesInAcl(1, pAccessEntry, pOldAcl, ppAcl);
  249. TRACE(L"SetEntriesInAcl() returned dwErr = 0x%x\n", dwErr);
  250. if (dwErr == ERROR_SUCCESS && NULL != pOldAcl )
  251. {
  252. ::LocalFree(pOldAcl);
  253. }
  254. return dwErr;
  255. }
  256. #ifdef DBG
  257. void TraceGuid(LPCWSTR lpszMsg, const GUID* pGuid)
  258. {
  259. WCHAR szGuid[128];
  260. FormatStringGUID(szGuid, 128, pGuid);
  261. TRACE(L"%s %s\n", lpszMsg, szGuid);
  262. }
  263. #define TRACE_GUID(msg, pGuid)\
  264. TraceGuid(msg, pGuid);
  265. #else
  266. #define TRACE_GUID(msg, pGuid)
  267. #endif
  268. DWORD AddObjectRightInAcl(IN PSID pSid,
  269. IN ULONG uAccess,
  270. IN const GUID* pRightGUID,
  271. IN const GUID* pInheritGUID,
  272. IN OUT PACL* ppAcl)
  273. {
  274. // trace input parameters
  275. TRACE(L"AddObjectRightInAcl()\n");
  276. TRACE(L"ULONG uAccess = 0x%x\n", uAccess);
  277. TRACE_GUID(L"pRightGUID =", pRightGUID);
  278. TRACE_GUID(L"pInheritGUID =", pInheritGUID);
  279. EXPLICIT_ACCESS AccessEntry;
  280. ZeroMemory(&AccessEntry, sizeof(EXPLICIT_ACCESS));
  281. if( uAccess == 0 )
  282. return ERROR_SUCCESS;
  283. // initialize EXPLICIT_ACCESS
  284. AccessEntry.grfAccessPermissions = uAccess;
  285. AccessEntry.grfAccessMode = GRANT_ACCESS;
  286. AccessEntry.grfInheritance = SUB_CONTAINERS_ONLY_INHERIT;
  287. if (pInheritGUID != NULL)
  288. {
  289. AccessEntry.grfInheritance |= INHERIT_ONLY;
  290. }
  291. OBJECTS_AND_SID ObjectsAndSid;
  292. ZeroMemory(&ObjectsAndSid, sizeof(OBJECTS_AND_SID));
  293. TRACE(L"AccessEntry.grfAccessPermissions = 0x%x\n", AccessEntry.grfAccessPermissions);
  294. TRACE(L"AccessEntry.grfAccessMode = 0x%x\n", AccessEntry.grfAccessMode);
  295. TRACE(L"AccessEntry.grfInheritance = 0x%x\n", AccessEntry.grfInheritance);
  296. TRACE(L"BuildTrusteeWithObjectsAndSid()\n");
  297. BuildTrusteeWithObjectsAndSid(&(AccessEntry.Trustee),
  298. &ObjectsAndSid,
  299. const_cast<GUID*>(pRightGUID), // class, right or property
  300. const_cast<GUID*>(pInheritGUID), // inherit guid (class)
  301. pSid // SID for user or group
  302. );
  303. return ::AddEntryInAcl(&AccessEntry, ppAcl);
  304. }
  305. //////////////////////////////////////////////////////////////////////////////
  306. long SafeArrayGetCount(const VARIANT& refvar)
  307. {
  308. if (V_VT(&refvar) == VT_BSTR)
  309. {
  310. return (long)1;
  311. }
  312. if ( V_VT(&refvar) != ( VT_ARRAY | VT_VARIANT ) )
  313. {
  314. ASSERT(FALSE);
  315. return (long)0;
  316. }
  317. SAFEARRAY *saAttributes = V_ARRAY( &refvar );
  318. long start, end;
  319. HRESULT hr = SafeArrayGetLBound( saAttributes, 1, &start );
  320. if( FAILED(hr) )
  321. return (long)0;
  322. hr = SafeArrayGetUBound( saAttributes, 1, &end );
  323. if( FAILED(hr) )
  324. return (long)0;
  325. return (end - start + 1);
  326. }
  327. HRESULT VariantArrayToContainer(const VARIANT& refvar, CContainerProxyBase* pCont)
  328. {
  329. HRESULT hr = S_OK;
  330. long start, end, current;
  331. if (V_VT(&refvar) == VT_BSTR)
  332. {
  333. //TRACE(_T("VT_BSTR: %s\n"),V_BSTR(&refvar));
  334. pCont->Add(V_BSTR(&refvar));
  335. return S_OK;
  336. }
  337. //
  338. // Check the VARIANT to make sure we have
  339. // an array of variants.
  340. //
  341. if ( V_VT(&refvar) != ( VT_ARRAY | VT_VARIANT ) )
  342. {
  343. ASSERT(FALSE);
  344. return E_UNEXPECTED;
  345. }
  346. SAFEARRAY *saAttributes = V_ARRAY( &refvar );
  347. //
  348. // Figure out the dimensions of the array.
  349. //
  350. hr = SafeArrayGetLBound( saAttributes, 1, &start );
  351. if( FAILED(hr) )
  352. return hr;
  353. hr = SafeArrayGetUBound( saAttributes, 1, &end );
  354. if( FAILED(hr) )
  355. return hr;
  356. //
  357. // Process the array elements.
  358. //
  359. VARIANT SingleResult;
  360. for ( current = start ;
  361. current <= end ;
  362. current++ )
  363. {
  364. ::VariantInit( &SingleResult );
  365. hr = SafeArrayGetElement( saAttributes, &current, &SingleResult );
  366. if( FAILED(hr) )
  367. return hr;
  368. if ( V_VT(&SingleResult) != VT_BSTR )
  369. return E_UNEXPECTED;
  370. //TRACE(_T("VT_BSTR: %s\n"),V_BSTR(&SingleResult));
  371. pCont->Add(V_BSTR(&SingleResult));
  372. VariantClear( &SingleResult );
  373. }
  374. return S_OK;
  375. }
  376. HRESULT GetGlobalNamingContexts(LPCWSTR lpszServerName,
  377. CWString& szPhysicalSchemaNamingContext,
  378. CWString& szConfigurationNamingContext)
  379. {
  380. HRESULT hr = S_OK;
  381. CComPtr<IADs> spRootDSE;
  382. CWString szRootDSEPath;
  383. BuildLdapPathHelper(lpszServerName, g_wzRootDSE, szRootDSEPath);
  384. hr = ::ADsOpenObjectHelper(szRootDSEPath,
  385. IID_IADs,
  386. (void**)&spRootDSE
  387. );
  388. if (FAILED(hr))
  389. {
  390. TRACE(L"Error opening ADsOpenObjectHelper(%S), hr=%x\n", (LPCWSTR)szRootDSEPath,hr);
  391. return hr;
  392. }
  393. CComVariant varSchemaNamingContext;
  394. hr = spRootDSE->Get((PWSTR)g_wzSchemaNamingContext,
  395. &varSchemaNamingContext);
  396. if (FAILED(hr))
  397. {
  398. TRACE(_T("Error spRootDSE->Get((PWSTR)g_wzSchemaNamingContext), hr=%x\n"), hr);
  399. return hr;
  400. }
  401. // finally get value
  402. // (e.g. "cn=schema,cn=configuration,dc=marcocdev,dc=ntdev,dc=microsoft,dc=com")
  403. ASSERT(varSchemaNamingContext.vt == VT_BSTR);
  404. szPhysicalSchemaNamingContext = varSchemaNamingContext.bstrVal;
  405. // get the configuration container naming context
  406. CComVariant varConfigurationNamingContext;
  407. hr = spRootDSE->Get(L"configurationNamingContext",&varConfigurationNamingContext);
  408. if (FAILED(hr))
  409. {
  410. TRACE(L"Failed spRootDSE->Get(configurationNamingContext,&varConfigurationNamingContext), returned hr = 0x%x\n", hr);
  411. return hr;
  412. }
  413. ASSERT(varConfigurationNamingContext.vt == VT_BSTR);
  414. szConfigurationNamingContext = varConfigurationNamingContext.bstrVal;
  415. return hr;
  416. }
  417. HRESULT GetSchemaClassName(LPCWSTR lpszServerName, LPCWSTR lpszPhysicalSchemaNamingContext,
  418. LPCWSTR lpszClassLdapDisplayName, // e.g. "organizationalUnit"
  419. CWString& szClassName // e.g. "Organizational-Unit"
  420. )
  421. {
  422. szClassName = L"";
  423. // build the LDAP path for the schema class
  424. CWString szPhysicalSchemaPath;
  425. BuildLdapPathHelper(lpszServerName, lpszPhysicalSchemaNamingContext, szPhysicalSchemaPath);
  426. CAdsiSearch search;
  427. HRESULT hr = search.Init(szPhysicalSchemaPath);
  428. if (FAILED(hr))
  429. return hr;
  430. static LPCWSTR lpszFilterFormat = L"(&(objectCategory=CN=Class-Schema,%s)(lDAPDisplayName=%s))";
  431. int nFmtLen = lstrlen(lpszFilterFormat);
  432. int nSchemaContextLen = lstrlen(lpszPhysicalSchemaNamingContext);
  433. int nClassLen = lstrlen(lpszClassLdapDisplayName);
  434. WCHAR* lpszFilter = (WCHAR*)alloca(sizeof(WCHAR)*(nFmtLen+nSchemaContextLen+nClassLen+1));
  435. wsprintf(lpszFilter, lpszFilterFormat, lpszPhysicalSchemaNamingContext, lpszClassLdapDisplayName);
  436. static const int cAttrs = 1;
  437. static LPCWSTR pszAttribsArr[cAttrs] = {L"name"};
  438. hr = search.SetSearchScope(ADS_SCOPE_ONELEVEL);
  439. if (FAILED(hr))
  440. return hr;
  441. hr = search.DoQuery(lpszFilter, pszAttribsArr, cAttrs);
  442. if (FAILED(hr))
  443. return hr;
  444. // expact a single result
  445. hr = search.GetNextRow();
  446. if ( hr == S_ADS_NOMORE_ROWS)
  447. {
  448. hr = E_ADS_UNKNOWN_OBJECT;
  449. }
  450. if (FAILED(hr))
  451. return hr;
  452. hr = search.GetColumnString(pszAttribsArr[0], szClassName);
  453. return hr;
  454. }
  455. LPCWSTR g_lpszSummaryIdent = L" ";
  456. LPCWSTR g_lpszSummaryNewLine = L"\r\n";
  457. void WriteSummaryTitleLine(CWString& szSummary, UINT nTitleID, LPCWSTR lpszNewLine)
  458. {
  459. CWString szTemp;
  460. szTemp.LoadFromResource(nTitleID);
  461. WriteSummaryLine(szSummary, szTemp, NULL, lpszNewLine);
  462. szSummary += lpszNewLine;
  463. }
  464. void WriteSummaryLine(CWString& szSummary, LPCWSTR lpsz, LPCWSTR lpszIdent, LPCWSTR lpszNewLine)
  465. {
  466. if (lpszIdent != NULL)
  467. szSummary += lpszIdent;
  468. szSummary += lpsz;
  469. szSummary += lpszNewLine;
  470. }
  471. //////////////////////////////////////////////////////////////////////////////
  472. LPCWSTR _GetFilePath()
  473. {
  474. static LPCWSTR g_lpszFileName = L"\\system32\\dssec.dat";
  475. static WCHAR g_lpszFilePath[2*MAX_PATH] = L"";
  476. if (g_lpszFilePath[0] == NULL)
  477. {
  478. UINT nLen = ::GetSystemWindowsDirectory(g_lpszFilePath, MAX_PATH);
  479. if (nLen == 0)
  480. return NULL;
  481. wcscat(g_lpszFilePath, g_lpszFileName);
  482. }
  483. return g_lpszFilePath;
  484. }
  485. ULONG GetClassFlags(LPCWSTR lpszClassName)
  486. {
  487. LPCWSTR lpszAttr = L"@";
  488. INT nDefault = 0;
  489. return ::GetPrivateProfileInt(lpszClassName, lpszAttr, nDefault, _GetFilePath());
  490. //return nDefault;
  491. }
  492. /////////////////////////////////////////////////////////////////////////////
  493. // CFilterEntry
  494. class CFilterEntry
  495. {
  496. public:
  497. CFilterEntry(LPWSTR lpszEntry)
  498. {
  499. m_lpszName = lpszEntry;
  500. m_nFlags = 0;
  501. Parse();
  502. }
  503. LPCWSTR m_lpszName;
  504. ULONG m_nFlags;
  505. bool operator<(CFilterEntry& x)
  506. {
  507. UNREFERENCED_PARAMETER (x);
  508. return false;
  509. }
  510. private:
  511. void Parse()
  512. {
  513. WCHAR* p = (WCHAR*)m_lpszName;
  514. while (*p != NULL)
  515. {
  516. if (*p == TEXT('='))
  517. {
  518. *p = NULL;
  519. m_nFlags = _wtoi(p+1);
  520. break;
  521. }
  522. p++;
  523. }
  524. }
  525. };
  526. class CFilterEntryHolder
  527. {
  528. public:
  529. CFilterEntryHolder()
  530. {
  531. m_pCharBuf = NULL;
  532. m_dwCharBufSize = 0;
  533. }
  534. ~CFilterEntryHolder()
  535. {
  536. if (m_pCharBuf != NULL)
  537. free(m_pCharBuf);
  538. }
  539. ULONG GetAttributeFlags(LPCWSTR lpszClassName, LPCWSTR lpszAttr);
  540. private:
  541. CWString m_szClassName;
  542. CGrowableArr<CFilterEntry> m_entries;
  543. WCHAR* m_pCharBuf;
  544. DWORD m_dwCharBufSize;
  545. BOOL _ReadFile();
  546. void _LoadFromFile();
  547. ULONG _FindInCache(LPCWSTR lpszAttr);
  548. };
  549. BOOL CFilterEntryHolder::_ReadFile()
  550. {
  551. if (m_pCharBuf == NULL)
  552. {
  553. m_dwCharBufSize = 4096;
  554. m_pCharBuf = (WCHAR*)malloc(sizeof(WCHAR)*m_dwCharBufSize);
  555. }
  556. if (m_pCharBuf == NULL)
  557. return FALSE;
  558. BOOL bNeedRealloc = FALSE;
  559. int nReallocCount = 0;
  560. do
  561. {
  562. DWORD dwCharCount = ::GetPrivateProfileSection(m_szClassName,
  563. m_pCharBuf, m_dwCharBufSize, _GetFilePath());
  564. if (dwCharCount == 0)
  565. return FALSE;
  566. bNeedRealloc = dwCharCount == (m_dwCharBufSize - 2);
  567. if (bNeedRealloc)
  568. {
  569. if (nReallocCount > 4)
  570. return FALSE;
  571. m_dwCharBufSize = 2*m_dwCharBufSize;
  572. m_pCharBuf = (WCHAR*)realloc(m_pCharBuf, sizeof(WCHAR)*m_dwCharBufSize);
  573. nReallocCount++;
  574. }
  575. }
  576. while (bNeedRealloc);
  577. return TRUE;
  578. }
  579. void CFilterEntryHolder::_LoadFromFile()
  580. {
  581. m_entries.Clear();
  582. if (!_ReadFile())
  583. return;
  584. WCHAR* p = m_pCharBuf;
  585. WCHAR* pEntry = p;
  586. while ( ! (( *p == NULL ) && ( *(p+1) == NULL )) )
  587. {
  588. if (*p == NULL)
  589. {
  590. TRACE(_T("pEntry = <%s>\n"), pEntry);
  591. m_entries.Add(new CFilterEntry(pEntry));
  592. pEntry = p+1;
  593. }
  594. p++;
  595. }
  596. if ( pEntry < p)
  597. m_entries.Add(new CFilterEntry(pEntry)); // add the last one
  598. for (ULONG k=0; k<m_entries.GetCount(); k++)
  599. {
  600. TRACE(_T("k = %d, <%s> flags = %d\n"), k, m_entries[k]->m_lpszName, m_entries[k]->m_nFlags);
  601. }
  602. }
  603. ULONG CFilterEntryHolder::_FindInCache(LPCWSTR lpszAttr)
  604. {
  605. for (ULONG k=0; k<m_entries.GetCount(); k++)
  606. {
  607. if (_wcsicmp(m_entries[k]->m_lpszName, lpszAttr) == 0)
  608. return m_entries[k]->m_nFlags;
  609. }
  610. return 0; // default
  611. }
  612. ULONG CFilterEntryHolder::GetAttributeFlags(LPCWSTR lpszClassName, LPCWSTR lpszAttr)
  613. {
  614. if (_wcsicmp(lpszClassName, m_szClassName) != 0)
  615. {
  616. // class name changed
  617. m_szClassName = lpszClassName;
  618. _LoadFromFile();
  619. }
  620. return _FindInCache(lpszAttr);
  621. }
  622. ULONG GetAttributeFlags(LPCWSTR lpszClassName, LPCWSTR lpszAttr)
  623. {
  624. static CFilterEntryHolder g_holder;
  625. return g_holder.GetAttributeFlags(lpszClassName, lpszAttr);
  626. // INT nDefault = 0;
  627. // return ::GetPrivateProfileInt(lpszClassName, lpszAttr, nDefault, _GetFilePath());
  628. //return nDefault;
  629. }
  630. ///////////////////////////////////////////////////////////////////////
  631. // CPrincipal
  632. HRESULT CPrincipal::Initialize(PDS_SELECTION pDsSelection, HICON hClassIcon)
  633. {
  634. TRACE(_T("pwzName = %s\n"), pDsSelection->pwzName); // e.g. JoeB
  635. TRACE(_T("pwzADsPath = %s\n"), pDsSelection->pwzADsPath); // "LDAP:..." or "WINNT:..."
  636. TRACE(_T("pwzClass = %s\n"), pDsSelection->pwzClass); // e.g. "user"
  637. TRACE(_T("pwzUPN = %s\n"), pDsSelection->pwzUPN); // .e.g. "[email protected]."
  638. WCHAR const c_szClassComputer[] = L"computer";
  639. // get the SID
  640. ASSERT(pDsSelection->pvarFetchedAttributes);
  641. if (pDsSelection->pvarFetchedAttributes[0].vt == VT_EMPTY)
  642. {
  643. TRACE(L"CPrincipal::Initialize() failed on VT_EMPTY sid\n");
  644. // fatal error, we cannot proceed
  645. return E_INVALIDARG;
  646. }
  647. if (pDsSelection->pvarFetchedAttributes[0].vt != (VT_ARRAY | VT_UI1))
  648. {
  649. TRACE(L"CPrincipal::Initialize() failed on (VT_ARRAY | VT_UI1) sid\n");
  650. // fatal error, we cannot proceed
  651. return E_INVALIDARG;
  652. }
  653. // make sure we have a good SID
  654. PSID pSid = pDsSelection->pvarFetchedAttributes[0].parray->pvData;
  655. HRESULT hr = Initialize (pSid);
  656. if ( FAILED (hr) )
  657. return hr;
  658. // copy the icon
  659. m_hClassIcon = hClassIcon;
  660. // copy the strings
  661. m_szClass = pDsSelection->pwzClass;
  662. //Strip from Computer Name
  663. //16414 02/28/2000 *DS Admin snapin - DelWiz, need to strip the '$' from the end of computer names
  664. m_szName = pDsSelection->pwzName;
  665. if( m_szClass && m_szName && ( wcscmp( m_szClass, (LPWSTR)c_szClassComputer) == 0 ) )
  666. {
  667. // Strip the trailing '$'
  668. LPWSTR pszTemp;
  669. pszTemp= (LPWSTR)(LPCWSTR)m_szName;
  670. int nLen = lstrlen(pszTemp);
  671. if (nLen && pszTemp[nLen-1] == TEXT('$'))
  672. {
  673. pszTemp[nLen-1] = TEXT('\0');
  674. }
  675. }
  676. m_szADsPath = pDsSelection->pwzADsPath;
  677. if( m_szClass && m_szADsPath && ( wcscmp( m_szClass, (LPWSTR)c_szClassComputer) == 0 ) )
  678. {
  679. // Strip the trailing '$'
  680. LPWSTR pszTemp;
  681. pszTemp= (LPWSTR)(LPCWSTR)m_szADsPath;
  682. int nLen = lstrlen(pszTemp);
  683. if (nLen && pszTemp[nLen-1] == TEXT('$'))
  684. {
  685. pszTemp[nLen-1] = TEXT('\0');
  686. }
  687. }
  688. m_szUPN = pDsSelection->pwzUPN;
  689. // set the display name
  690. _ComposeDisplayName();
  691. return S_OK;
  692. }
  693. HRESULT CPrincipal::Initialize (PSID pSid)
  694. {
  695. if (!IsValidSid(pSid))
  696. {
  697. TRACE(L"CPrincipal::Initialize() failed on IsValidSid()\n");
  698. // fatal error, we cannot proceed
  699. return E_INVALIDARG;
  700. }
  701. // we have a good SID, copy it
  702. if (!m_sidHolder.Copy(pSid))
  703. {
  704. TRACE(L"CPrincipal::Initialize() failed on m_sidHolder.Copy(pSid)\n");
  705. // fatal error, we cannot proceed
  706. return E_OUTOFMEMORY;
  707. }
  708. return S_OK;
  709. }
  710. BOOL BuildSamName(LPCWSTR lpszPath, CWString& s)
  711. {
  712. // strip the WINNT provider and reverse slashes
  713. static LPCWSTR lpszPrefix = L"WinNT://";
  714. int nPrefixLen = lstrlen(lpszPrefix);
  715. if (_wcsnicmp(lpszPath, lpszPrefix, nPrefixLen ) != 0)
  716. {
  717. // not matching
  718. return FALSE;
  719. }
  720. // make a copy
  721. LPCWSTR lpzsTemp = lpszPath+nPrefixLen; // past the prefix
  722. s = L"";
  723. for (WCHAR* pChar = const_cast<LPWSTR>(lpzsTemp); (*pChar) != NULL; pChar++)
  724. {
  725. if (*pChar == L'/')
  726. s += L'\\';
  727. else
  728. s += *pChar;
  729. }
  730. return TRUE;
  731. }
  732. void CPrincipal::_ComposeDisplayName()
  733. {
  734. LPCWSTR lpszAddToName = NULL;
  735. // check if there is a UPN
  736. LPCWSTR lpszUPN = m_szUPN;
  737. if ( (lpszUPN != NULL) && (lstrlen(lpszUPN) > 0))
  738. {
  739. lpszAddToName = lpszUPN;
  740. }
  741. // as a second chance, add the domain\name
  742. LPCWSTR lpszPath = m_szADsPath;
  743. CWString sTemp;
  744. if ((lpszAddToName == NULL) && (lpszPath != NULL) && (lstrlen(lpszPath) > 0))
  745. {
  746. if (BuildSamName(lpszPath,sTemp))
  747. {
  748. lpszAddToName = sTemp;
  749. }
  750. }
  751. if (lpszAddToName != NULL)
  752. {
  753. static LPCWSTR lpszFormat = L"%s (%s)";
  754. size_t nLen = lstrlen(lpszAddToName) + lstrlen(lpszFormat) + m_szName.size() + 1;
  755. LPWSTR lpszTemp = (LPWSTR)alloca(nLen*sizeof(WCHAR));
  756. wsprintf(lpszTemp, lpszFormat, m_szName.c_str(), lpszAddToName);
  757. m_szDisplayName = lpszTemp;
  758. }
  759. else
  760. {
  761. // got nothing, just use the name
  762. m_szDisplayName = m_szName;
  763. }
  764. }
  765. BOOL CPrincipal::IsEqual(CPrincipal* p)
  766. {
  767. return (_wcsicmp(m_szADsPath, p->m_szADsPath) == 0);
  768. }
  769. BOOL CPrincipalList::AddIfNotPresent(CPrincipal* p)
  770. {
  771. CPrincipalList::iterator i;
  772. for (i = begin(); i != end(); ++i)
  773. {
  774. if ((*i)->IsEqual(p))
  775. {
  776. delete p; // duplicate
  777. return FALSE;
  778. }
  779. }
  780. push_back(p);
  781. return TRUE;
  782. }
  783. void CPrincipalList::WriteSummaryInfo(CWString& szSummary, LPCWSTR lpszIdent, LPCWSTR lpszNewLine)
  784. {
  785. WriteSummaryTitleLine(szSummary, IDS_DELEGWIZ_FINISH_PRINCIPALS, lpszNewLine);
  786. CPrincipalList::iterator i;
  787. for (i = begin(); i != end(); ++i)
  788. {
  789. WriteSummaryLine(szSummary, (*i)->GetDisplayName(), lpszIdent, lpszNewLine);
  790. }
  791. szSummary += lpszNewLine;
  792. }
  793. ///////////////////////////////////////////////////////////////////////
  794. // CControlRightInfo
  795. void CControlRightInfo::SetLocalizedName(UINT nLocalizationDisplayId, HMODULE hModule)
  796. {
  797. WCHAR szLocalizedDisplayName[256];
  798. DWORD dwChars = 0;
  799. if (hModule != NULL)
  800. {
  801. dwChars = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS,
  802. hModule,
  803. nLocalizationDisplayId,
  804. 0,
  805. szLocalizedDisplayName,
  806. 256,
  807. NULL);
  808. }
  809. if (dwChars > 0)
  810. {
  811. m_szLocalizedName = szLocalizedDisplayName;
  812. }
  813. else
  814. {
  815. // failed, just use the LDAP display name
  816. m_szLocalizedName = m_szLdapDisplayName;
  817. }
  818. // need to set the display name
  819. if (IsPropertySet())
  820. {
  821. CWString szPropertySetFormat;
  822. szPropertySetFormat.LoadFromResource(IDS_DELEGWIZ_RW_PROPERTYSET);
  823. WCHAR* lpszBuffer = (WCHAR*)alloca(sizeof(WCHAR)*(szPropertySetFormat.size()+m_szLocalizedName.size()+1));
  824. // we have a different display name
  825. wsprintf(lpszBuffer, szPropertySetFormat, (LPCWSTR)m_szLocalizedName);
  826. m_szDisplayName = lpszBuffer;
  827. }
  828. else
  829. {
  830. // same as raw
  831. m_szDisplayName = m_szLocalizedName;
  832. }
  833. }
  834. ///////////////////////////////////////////////////////////////////////
  835. // CControlRightInfoArray
  836. class CDsSecLib
  837. {
  838. public:
  839. CDsSecLib()
  840. {
  841. m_hInstance = ::LoadLibrary(L"dssec.dll");
  842. }
  843. ~CDsSecLib()
  844. {
  845. if (m_hInstance != NULL)
  846. ::FreeLibrary(m_hInstance);
  847. }
  848. HINSTANCE Get() { return m_hInstance; }
  849. private:
  850. HINSTANCE m_hInstance;
  851. };
  852. HRESULT CControlRightInfoArray::InitFromDS(CAdsiObject* pADSIObj,
  853. const GUID* pSchemaIDGUID)
  854. {
  855. TRACE(L"CControlRightInfoArray::InitFromDS()\n\n");
  856. ASSERT(pSchemaIDGUID != NULL);
  857. LPWSTR lpszSchemaIDGUID = (LPWSTR)alloca(128*sizeof(WCHAR));
  858. if(!lpszSchemaIDGUID)
  859. return E_OUTOFMEMORY;
  860. if (!FormatStringGUID(lpszSchemaIDGUID, 128, pSchemaIDGUID))
  861. {
  862. return E_INVALIDARG;
  863. }
  864. // build the LDAP path for the schema class
  865. CWString szPhysicalSchemaPath;
  866. LPCWSTR lpszPhysicalSchemaNamingContext = pADSIObj->GetPhysicalSchemaNamingContext();
  867. BuildLdapPathHelper(pADSIObj->GetServerName(), lpszPhysicalSchemaNamingContext, szPhysicalSchemaPath);
  868. // build the extended rights container naming context and LDAP path
  869. CWString szExtendedRightsNamingContext;
  870. szExtendedRightsNamingContext = L"CN=Extended-Rights,";
  871. szExtendedRightsNamingContext += pADSIObj->GetConfigurationNamingContext();
  872. CWString szExtendedRightsPath;
  873. BuildLdapPathHelper(pADSIObj->GetServerName(), szExtendedRightsNamingContext, szExtendedRightsPath);
  874. // bind a query to the extended rights container
  875. CAdsiSearch search;
  876. HRESULT hr = search.Init(szExtendedRightsPath);
  877. TRACE(L"search.Init(%s) returned hr = 0x%x\n", (LPCWSTR)szExtendedRightsPath, hr);
  878. if (FAILED(hr))
  879. {
  880. return hr;
  881. }
  882. // build an LDAP query string
  883. static LPCWSTR lpszFilterFormat = L"(&(objectCategory=CN=Control-Access-Right,%s)(AppliesTo=%s))";
  884. int nFmtLen = lstrlen(lpszFilterFormat);
  885. int nArgumentLen = lstrlen(lpszPhysicalSchemaNamingContext) + lstrlen(lpszSchemaIDGUID);
  886. WCHAR* lpszFilter = (WCHAR*)alloca(sizeof(WCHAR)*(nFmtLen+nArgumentLen+1));
  887. wsprintf(lpszFilter, lpszFilterFormat, lpszPhysicalSchemaNamingContext, lpszSchemaIDGUID);
  888. // build an array of wanted columns
  889. static const int cAttrs = 4;
  890. static LPCWSTR pszAttribsArr[cAttrs] =
  891. {
  892. L"displayName", // e.g. "Change Password"
  893. L"rightsGuid", // e.g. "ab721a53-1e2f-...." (i.e. GUID in string form w/o {})
  894. L"validAccesses", // bitmask of access righs
  895. L"localizationDisplayId" // bitmask of access righs
  896. };
  897. hr = search.SetSearchScope(ADS_SCOPE_ONELEVEL);
  898. TRACE(L"search.SetSearchScope(ADS_SCOPE_ONELEVEL) returned hr = 0x%x\n", hr);
  899. if (FAILED(hr))
  900. return hr;
  901. hr = search.DoQuery(lpszFilter, pszAttribsArr, cAttrs);
  902. TRACE(L"search.DoQuery(lpszFilter, pszAttribsArr, cAttrs) returned hr = 0x%x\n", hr);
  903. if (FAILED(hr))
  904. return hr;
  905. TRACE(L"\n");
  906. CWString szRightsGUID;
  907. ULONG nLocalizationDisplayId;
  908. // load DSSEC.DLL to provide localized
  909. CDsSecLib DsSecLib;
  910. while ((hr = search.GetNextRow()) != S_ADS_NOMORE_ROWS)
  911. {
  912. if (FAILED(hr))
  913. continue;
  914. CControlRightInfo* pInfo = new CControlRightInfo();
  915. HRESULT hr0 = search.GetColumnString(pszAttribsArr[0], pInfo->m_szLdapDisplayName);
  916. // the DS gives us the GUID in string form, but we need it in struct form
  917. HRESULT hr1 = search.GetColumnString(pszAttribsArr[1], szRightsGUID);
  918. if (SUCCEEDED(hr1))
  919. {
  920. if (!::GuidFromString(&(pInfo->m_rightsGUID), szRightsGUID.c_str()))
  921. {
  922. TRACE(L"GuidFromString(_, %s) failed!\n", szRightsGUID.c_str());
  923. hr1 = E_INVALIDARG;
  924. }
  925. }
  926. HRESULT hr2 = search.GetColumnInteger(pszAttribsArr[2], pInfo->m_fAccess);
  927. HRESULT hr3 = search.GetColumnInteger(pszAttribsArr[3], nLocalizationDisplayId);
  928. TRACE(L"Name = <%s>, \n Guid = <%s>, Access = 0x%x, nLocalizationDisplayId = %d\n",
  929. pInfo->m_szLdapDisplayName.c_str(), szRightsGUID.c_str(), pInfo->m_fAccess, nLocalizationDisplayId);
  930. if (FAILED(hr0) || FAILED(hr1) || FAILED(hr2) || FAILED(hr3))
  931. {
  932. TRACE(L"WARNING: discarding right, failed on columns: hr0 = 0x%x, hr1 = 0x%x, hr2 = 0x%x, hr3 = 0x%x\n",
  933. hr0, hr1, hr2, hr3);
  934. delete pInfo;
  935. }
  936. else
  937. {
  938. pInfo->SetLocalizedName(nLocalizationDisplayId, DsSecLib.Get());
  939. Add(pInfo);
  940. }
  941. } // while
  942. TRACE(L"\n\n");
  943. if (hr == S_ADS_NOMORE_ROWS)
  944. hr = S_OK;
  945. return hr;
  946. }
  947. //////////////////////////////////////////////////////////////////////
  948. // CPropertyRightInfo
  949. const ULONG CPropertyRightInfo::m_nRightCountMax = 2;
  950. const ULONG CPropertyRightInfo::m_nReadIndex = 0;
  951. const ULONG CPropertyRightInfo::m_nWriteIndex = 1;
  952. LPCWSTR CPropertyRightInfo::GetRightDisplayString(ULONG iRight)
  953. {
  954. static WCHAR szReadFmt[256] = L"";
  955. static WCHAR szWriteFmt[256] = L"";
  956. static WCHAR szReadAll[256] = L"";
  957. static WCHAR szWriteAll[256] = L"";
  958. static WCHAR szDisplay[512];
  959. ASSERT(GetName() != NULL); // must have a name!!!
  960. szDisplay[0] = NULL;
  961. WCHAR* pFmt = NULL;
  962. if (iRight == m_nReadIndex)
  963. {
  964. if (szReadFmt[0] == NULL)
  965. LoadStringHelper(IDS_DELEGWIZ_READ_PROPERTY, szReadFmt, ARRAYSIZE(szReadFmt));
  966. pFmt = szReadFmt;
  967. }
  968. else if (iRight == m_nWriteIndex)
  969. {
  970. if (szWriteFmt[0] == NULL)
  971. LoadStringHelper(IDS_DELEGWIZ_WRITE_PROPERTY, szWriteFmt, ARRAYSIZE(szWriteFmt));
  972. pFmt = szWriteFmt;
  973. }
  974. wsprintf(szDisplay, pFmt, GetDisplayName());
  975. return szDisplay;
  976. }
  977. void CPropertyRightInfo::SetRight(ULONG iRight, BOOL b)
  978. {
  979. switch (iRight)
  980. {
  981. case m_nReadIndex:
  982. if (b)
  983. m_Access |= ACTRL_DS_READ_PROP;
  984. else
  985. m_Access &= ~ACTRL_DS_READ_PROP;
  986. break;
  987. case m_nWriteIndex:
  988. if (b)
  989. m_Access |= ACTRL_DS_WRITE_PROP;
  990. else
  991. m_Access &= ~ACTRL_DS_WRITE_PROP;
  992. break;
  993. default:
  994. ASSERT(FALSE);
  995. };
  996. }
  997. ULONG CPropertyRightInfo::GetRight(ULONG iRight)
  998. {
  999. switch (iRight)
  1000. {
  1001. case m_nReadIndex:
  1002. return (ULONG)ACTRL_DS_READ_PROP;
  1003. break;
  1004. case m_nWriteIndex:
  1005. return (ULONG)ACTRL_DS_WRITE_PROP;
  1006. break;
  1007. default:
  1008. ASSERT(FALSE);
  1009. };
  1010. return 0;
  1011. }
  1012. BOOL CPropertyRightInfo::IsRightSelected(ULONG iRight)
  1013. {
  1014. BOOL bRes = FALSE;
  1015. switch (iRight)
  1016. {
  1017. case m_nReadIndex:
  1018. bRes = m_Access & ACTRL_DS_READ_PROP;
  1019. break;
  1020. case m_nWriteIndex:
  1021. bRes = m_Access & ACTRL_DS_WRITE_PROP;
  1022. break;
  1023. default:
  1024. ASSERT(FALSE);
  1025. };
  1026. return bRes;
  1027. }
  1028. //////////////////////////////////////////////////////////////////////
  1029. // CPropertyRightInfoArray
  1030. template <class T> class CClassPtr
  1031. {
  1032. public:
  1033. CClassPtr() { m_p = NULL;}
  1034. ~CClassPtr() { if (m_p) delete m_p;}
  1035. CClassPtr& operator=(T* p)
  1036. {
  1037. m_p = p;
  1038. return *this;
  1039. }
  1040. T* operator->()
  1041. {
  1042. return m_p;
  1043. }
  1044. T* operator&()
  1045. {
  1046. return m_p;
  1047. }
  1048. private:
  1049. T* m_p;
  1050. };
  1051. HRESULT CPropertyRightInfoArray::InitFromSchema(CAdsiObject* pADSIObj,
  1052. IADsClass * pDsSchemaClass,
  1053. LPCWSTR lpszClassName,
  1054. BOOL bUseFilter)
  1055. {
  1056. // setup
  1057. Clear();
  1058. CClassPtr<CPropertyRightInfoFilter> spFilter;
  1059. if (bUseFilter)
  1060. {
  1061. spFilter = new CPropertyRightInfoFilter();
  1062. spFilter->SetClassName(lpszClassName);
  1063. }
  1064. if (pDsSchemaClass == NULL)
  1065. {
  1066. ASSERT(lpszClassName == NULL);
  1067. return S_OK;
  1068. }
  1069. // get data from DS for specific properties
  1070. VARIANT MandatoryListVar, OptionalListVar;
  1071. ::VariantInit(&MandatoryListVar);
  1072. ::VariantInit(&OptionalListVar);
  1073. HRESULT hr = pDsSchemaClass->get_MandatoryProperties(&MandatoryListVar);
  1074. if (FAILED(hr))
  1075. {
  1076. ::VariantClear(&MandatoryListVar);
  1077. return hr;
  1078. }
  1079. hr = pDsSchemaClass->get_OptionalProperties(&OptionalListVar);
  1080. if (FAILED(hr))
  1081. {
  1082. ::VariantClear(&OptionalListVar);
  1083. return hr;
  1084. }
  1085. // add the results to the array
  1086. CContainerProxy<CPropertyRightInfo, CPropertyRightInfoArray, CPropertyRightInfoFilter>
  1087. cont(this, &spFilter);
  1088. VariantArrayToContainer(MandatoryListVar, &cont);
  1089. VariantArrayToContainer(OptionalListVar, &cont);
  1090. ::VariantClear(&MandatoryListVar);
  1091. ::VariantClear(&OptionalListVar);
  1092. // now need to set the friendly names
  1093. ULONG nCount = (ULONG) GetCount();
  1094. WCHAR szFrendlyName[1024];
  1095. HRESULT hrName;
  1096. for (ULONG i=0; i<nCount; i++)
  1097. {
  1098. LPCWSTR lpszName = (*this)[i]->GetName();
  1099. if (lpszName != NULL)
  1100. {
  1101. hrName = pADSIObj->GetFriendlyAttributeName(lpszClassName,
  1102. lpszName,
  1103. szFrendlyName, 1024);
  1104. ASSERT(SUCCEEDED(hrName));
  1105. (*this)[i]->SetDisplayName(SUCCEEDED(hrName) ? szFrendlyName : NULL);
  1106. }
  1107. }
  1108. // get guids
  1109. for (i=0; i<nCount; i++)
  1110. {
  1111. CPropertyRightInfo* pInfo = (*this)[i];
  1112. LPCWSTR lpszName = pInfo->GetName();
  1113. hr = pADSIObj->GetClassGuid(lpszName, TRUE, pInfo->m_schemaIDGUID);
  1114. if (SUCCEEDED(hr))
  1115. {
  1116. WCHAR szTest[128];
  1117. FormatStringGUID(szTest, 128, &(pInfo->m_schemaIDGUID));
  1118. TRACE(L"name = <%s>, guid = <%s>\n", lpszName, szTest);
  1119. }
  1120. else
  1121. {
  1122. TRACE(L"GetClassGuid(%s) failed hr = 0x%x\n", lpszName, hr);
  1123. return hr;
  1124. }
  1125. }
  1126. Sort();
  1127. return hr;
  1128. }
  1129. //////////////////////////////////////////////////////////////////////
  1130. // CClassRightInfo
  1131. const ULONG CClassRightInfo::m_nRightCountMax = 2;
  1132. const ULONG CClassRightInfo::m_nCreateIndex = 0;
  1133. const ULONG CClassRightInfo::m_nDeleteIndex = 1;
  1134. LPCWSTR CClassRightInfo::GetRightDisplayString(ULONG iRight)
  1135. {
  1136. static WCHAR szCreateFmt[256] = L"";
  1137. static WCHAR szDeleteFmt[256] = L"";
  1138. static WCHAR szCreateAll[256] = L"";
  1139. static WCHAR szDeleteAll[256] = L"";
  1140. static WCHAR szDisplay[512];
  1141. ASSERT(GetName() != NULL); // must have a name!!!
  1142. szDisplay[0] = NULL;
  1143. WCHAR* pFmt = NULL;
  1144. if (iRight == m_nCreateIndex)
  1145. {
  1146. if (szCreateFmt[0] == NULL)
  1147. LoadStringHelper(IDS_DELEGWIZ_CREATE_CLASS, szCreateFmt, ARRAYSIZE(szCreateFmt));
  1148. pFmt = szCreateFmt;
  1149. }
  1150. else if (iRight == m_nDeleteIndex)
  1151. {
  1152. if (szDeleteFmt[0] == NULL)
  1153. LoadStringHelper(IDS_DELEGWIZ_DELETE_CLASS, szDeleteFmt, ARRAYSIZE(szDeleteFmt));
  1154. pFmt = szDeleteFmt;
  1155. }
  1156. wsprintf(szDisplay, pFmt, GetDisplayName());
  1157. return szDisplay;
  1158. }
  1159. void CClassRightInfo::SetRight(ULONG iRight, BOOL b)
  1160. {
  1161. switch (iRight)
  1162. {
  1163. case m_nCreateIndex:
  1164. if (b)
  1165. m_Access |= ACTRL_DS_CREATE_CHILD;
  1166. else
  1167. m_Access &= ~ACTRL_DS_CREATE_CHILD;
  1168. break;
  1169. case m_nDeleteIndex:
  1170. if (b)
  1171. m_Access |= ACTRL_DS_DELETE_CHILD;
  1172. else
  1173. m_Access &= ~ACTRL_DS_DELETE_CHILD;
  1174. break;
  1175. default:
  1176. ASSERT(FALSE);
  1177. };
  1178. }
  1179. ULONG CClassRightInfo::GetRight(ULONG iRight)
  1180. {
  1181. switch (iRight)
  1182. {
  1183. case m_nCreateIndex:
  1184. return (ULONG)ACTRL_DS_CREATE_CHILD;
  1185. break;
  1186. case m_nDeleteIndex:
  1187. return (ULONG)ACTRL_DS_DELETE_CHILD;
  1188. break;
  1189. default:
  1190. ASSERT(FALSE);
  1191. };
  1192. return 0;
  1193. }
  1194. BOOL CClassRightInfo::IsRightSelected(ULONG iRight)
  1195. {
  1196. BOOL bRes = FALSE;
  1197. switch (iRight)
  1198. {
  1199. case m_nCreateIndex:
  1200. bRes = m_Access & ACTRL_DS_CREATE_CHILD;
  1201. break;
  1202. case m_nDeleteIndex:
  1203. bRes = m_Access & ACTRL_DS_DELETE_CHILD;
  1204. break;
  1205. default:
  1206. ASSERT(FALSE);
  1207. };
  1208. return bRes;
  1209. }
  1210. //////////////////////////////////////////////////////////////////////
  1211. // CClassRightInfoArray
  1212. HRESULT CClassRightInfoArray::InitFromSchema(CAdsiObject* pADSIObj,
  1213. IADsClass* pDsSchemaClass,
  1214. BOOL bUseFilter)
  1215. {
  1216. // setup
  1217. Clear();
  1218. if (pDsSchemaClass == NULL)
  1219. return S_OK;
  1220. // read from DS
  1221. VARIANT ContainmentListVar;
  1222. ::VariantInit(&ContainmentListVar);
  1223. HRESULT hr = pDsSchemaClass->get_Containment(&ContainmentListVar);
  1224. if (FAILED(hr))
  1225. {
  1226. ::VariantClear(&ContainmentListVar);
  1227. return hr;
  1228. }
  1229. CClassPtr<CClassRightInfoFilter> spFilter;
  1230. if (bUseFilter)
  1231. {
  1232. spFilter = new CClassRightInfoFilter();
  1233. }
  1234. // add to array and filter
  1235. CContainerProxy<CClassRightInfo, CClassRightInfoArray, CClassRightInfoFilter>
  1236. cont(this, &spFilter);
  1237. VariantArrayToContainer(ContainmentListVar, &cont);
  1238. ::VariantClear(&ContainmentListVar);
  1239. // now need to set the friendly names
  1240. ULONG nCount = (ULONG) GetCount();
  1241. WCHAR szFrendlyName[1024];
  1242. HRESULT hrName;
  1243. for (ULONG i=0; i<nCount; i++)
  1244. {
  1245. LPCWSTR lpszName = (*this)[i]->GetName();
  1246. if (lpszName != NULL)
  1247. {
  1248. hrName = pADSIObj->GetFriendlyClassName(lpszName, szFrendlyName, 1024);
  1249. ASSERT(SUCCEEDED(hrName));
  1250. (*this)[i]->SetDisplayName(SUCCEEDED(hrName) ? szFrendlyName : NULL);
  1251. }
  1252. }
  1253. // get guids
  1254. for (i=0; i<nCount; i++)
  1255. {
  1256. CClassRightInfo* pInfo = (*this)[i];
  1257. LPCWSTR lpszName = pInfo->GetName();
  1258. hr = pADSIObj->GetClassGuid(lpszName, FALSE, pInfo->m_schemaIDGUID);
  1259. if (SUCCEEDED(hr))
  1260. {
  1261. WCHAR szTest[128];
  1262. FormatStringGUID(szTest, 128, &(pInfo->m_schemaIDGUID));
  1263. TRACE(L"name = <%s>, guid = <%s>\n", lpszName, szTest);
  1264. }
  1265. else
  1266. {
  1267. TRACE(L"GetClassGuid(%s) failed hr = 0x%x\n", lpszName, hr);
  1268. return hr;
  1269. }
  1270. }
  1271. Sort();
  1272. return hr;
  1273. }
  1274. ///////////////////////////////////////////////////////////////////////
  1275. // CAccessPermissionsHolderBase
  1276. CAccessPermissionsHolderBase::CAccessPermissionsHolderBase(BOOL bUseFilter)
  1277. {
  1278. m_bUseFilter = bUseFilter;
  1279. }
  1280. CAccessPermissionsHolderBase::~CAccessPermissionsHolderBase()
  1281. {
  1282. Clear();
  1283. }
  1284. void CAccessPermissionsHolderBase::Clear()
  1285. {
  1286. m_accessRightInfoArr.Clear();
  1287. m_controlRightInfoArr.Clear();
  1288. m_propertyRightInfoArray.Clear();
  1289. m_classRightInfoArray.Clear();
  1290. }
  1291. BOOL CAccessPermissionsHolderBase::HasPermissionSelected()
  1292. {
  1293. ULONG i,j;
  1294. // check access rigths
  1295. for (i = 0; i < m_accessRightInfoArr.GetCount(); i++)
  1296. {
  1297. if (m_accessRightInfoArr[i]->IsSelected())
  1298. return TRUE;
  1299. }
  1300. // check control rigths
  1301. for (i = 0; i < m_controlRightInfoArr.GetCount(); i++)
  1302. {
  1303. if (m_controlRightInfoArr[i]->IsSelected())
  1304. return TRUE;
  1305. }
  1306. // subobjects rigths
  1307. for (i = 0; i < m_classRightInfoArray.GetCount(); i++)
  1308. {
  1309. for (j=0; j< m_classRightInfoArray[i]->GetRightCount(); j++)
  1310. {
  1311. if ( m_classRightInfoArray[i]->IsRightSelected(j) )
  1312. return TRUE;
  1313. }
  1314. }
  1315. // property rights
  1316. for (i = 0; i < m_propertyRightInfoArray.GetCount(); i++)
  1317. {
  1318. for (j=0; j< m_propertyRightInfoArray[i]->GetRightCount(); j++)
  1319. {
  1320. if ( m_propertyRightInfoArray[i]->IsRightSelected(j) )
  1321. return TRUE;
  1322. }
  1323. }
  1324. return FALSE;
  1325. }
  1326. /*
  1327. typedef struct _ACTRL_CONTROL_INFOW
  1328. {
  1329. LPWSTR lpControlId;
  1330. LPWSTR lpControlName;
  1331. } ACTRL_CONTROL_INFOW, *PACTRL_CONTROL_INFOW;
  1332. typedef struct _ACTRL_ACCESS_INFOW
  1333. {
  1334. ULONG fAccessPermission;
  1335. LPWSTR lpAccessPermissionName;
  1336. } ACTRL_ACCESS_INFOW, *PACTRL_ACCESS_INFOW;
  1337. */
  1338. HRESULT CAccessPermissionsHolderBase::ReadDataFromDS(CAdsiObject* pADSIObj,
  1339. LPCWSTR /*lpszObjectNamingContext*/,
  1340. LPCWSTR lpszClassName,
  1341. const GUID* pSchemaIDGUID,
  1342. BOOL bChildClass,
  1343. BOOL bHideListObject)
  1344. {
  1345. #if DBG
  1346. WCHAR szGUID[128];
  1347. FormatStringGUID(szGUID, 128, pSchemaIDGUID);
  1348. TRACE(L"CAccessPermissionsHolderBase::ReadDataFromDS(_, %s, %s)\n",
  1349. lpszClassName, szGUID);
  1350. #endif
  1351. Clear();
  1352. HRESULT hr = S_OK;
  1353. if (pSchemaIDGUID != NULL)
  1354. {
  1355. hr = m_controlRightInfoArr.InitFromDS(pADSIObj, pSchemaIDGUID);
  1356. TRACE(L"hr = m_controlRightInfoArr.InitFromDS(...) returned hr = 0x%x\n", hr);
  1357. if (FAILED(hr))
  1358. {
  1359. return hr;
  1360. }
  1361. }
  1362. hr = _ReadClassInfoFromDS(pADSIObj, lpszClassName);
  1363. if (FAILED(hr))
  1364. {
  1365. return hr;
  1366. }
  1367. hr = _LoadAccessRightInfoArrayFromTable(bChildClass,bHideListObject);
  1368. return hr;
  1369. }
  1370. HRESULT CAccessPermissionsHolderBase::_ReadClassInfoFromDS(CAdsiObject* pADSIObj,
  1371. LPCWSTR lpszClassName)
  1372. {
  1373. HRESULT hr = S_OK;
  1374. CComPtr<IADsClass> spSchemaObjectClass;
  1375. if (lpszClassName != NULL)
  1376. {
  1377. int nServerNameLen = lstrlen(pADSIObj->GetServerName());
  1378. int nClassNameLen = lstrlen(lpszClassName);
  1379. int nFormatStringLen = lstrlen(g_wzLDAPAbstractSchemaFormat);
  1380. // build the LDAP path for the schema class
  1381. WCHAR* pwszSchemaObjectPath =
  1382. (WCHAR*)alloca(sizeof(WCHAR)*(nServerNameLen+nClassNameLen+nFormatStringLen+1));
  1383. wsprintf(pwszSchemaObjectPath, g_wzLDAPAbstractSchemaFormat, pADSIObj->GetServerName(), lpszClassName);
  1384. // get the schema class ADSI object
  1385. hr = ::ADsOpenObjectHelper(pwszSchemaObjectPath,
  1386. IID_IADsClass, (void**)&spSchemaObjectClass);
  1387. if (FAILED(hr))
  1388. return hr;
  1389. }
  1390. //TRACE(_T("\nObject Properties\n\n"));
  1391. hr = m_propertyRightInfoArray.InitFromSchema(pADSIObj, spSchemaObjectClass,lpszClassName, m_bUseFilter);
  1392. if (FAILED(hr))
  1393. return hr;
  1394. //TRACE(_T("\nObject contained classes\n\n"));
  1395. return m_classRightInfoArray.InitFromSchema(pADSIObj, spSchemaObjectClass, m_bUseFilter);
  1396. }
  1397. DWORD CAccessPermissionsHolderBase::UpdateAccessList( CPrincipal* pPrincipal,
  1398. CSchemaClassInfo* pClassInfo,
  1399. LPCWSTR /*lpszServerName*/,
  1400. LPCWSTR /*lpszPhysicalSchemaNamingContext*/,
  1401. PACL *ppAcl)
  1402. {
  1403. TRACE(L"CAccessPermissionsHolderBase::UpdateAccessList()\n");
  1404. const GUID* pClassGUID = NULL;
  1405. TRACE(L"User or Group Name: %s\n", pPrincipal->GetDisplayName());
  1406. BOOL bChildClass = TRUE;
  1407. if (pClassInfo != NULL)
  1408. {
  1409. pClassGUID = pClassInfo->GetSchemaGUID();
  1410. bChildClass = (pClassInfo->m_dwChildClass != CHILD_CLASS_NOT_EXIST );
  1411. }
  1412. return _UpdateAccessListHelper(pPrincipal->GetSid(), pClassGUID, ppAcl,bChildClass);
  1413. }
  1414. DWORD CAccessPermissionsHolderBase::_UpdateAccessListHelper(PSID pSid,
  1415. const GUID* pClassGUID,
  1416. PACL *ppAcl,
  1417. BOOL bChildClass)
  1418. {
  1419. TRACE(L"CAccessPermissionsHolderBase::_UpdateAccessListHelper()\n");
  1420. ASSERT(pSid != NULL);
  1421. ULONG AccessAllClass = 0;
  1422. ULONG AccessAllProperty = 0;
  1423. DWORD dwErr = 0;
  1424. // set common variables
  1425. ULONG uAccess = 0; // to be set and reset as see fit
  1426. if (m_accessRightInfoArr[0]->IsSelected()) // full control
  1427. {
  1428. uAccess = _WIZ_FULL_CTRL;
  1429. dwErr = ::AddObjectRightInAcl(pSid, uAccess, NULL, pClassGUID, ppAcl);
  1430. if (dwErr != ERROR_SUCCESS)
  1431. goto exit;
  1432. }
  1433. else
  1434. {
  1435. // add an entry for all the standard access permissions:
  1436. // OR all the selected permissions together
  1437. uAccess = 0;
  1438. UINT nSel = 0;
  1439. for (UINT k=0; k < m_accessRightInfoArr.GetCount(); k++)
  1440. {
  1441. if (m_accessRightInfoArr[k]->IsSelected())
  1442. {
  1443. nSel++;
  1444. uAccess |= m_accessRightInfoArr[k]->GetAccess();
  1445. }
  1446. } // for
  1447. if( !bChildClass )
  1448. uAccess &= (~(ACTRL_DS_CREATE_CHILD|ACTRL_DS_DELETE_CHILD));
  1449. if (nSel > 0)
  1450. {
  1451. // keep track of "All" flags
  1452. if (uAccess & ACTRL_DS_READ_PROP)
  1453. AccessAllProperty |= ACTRL_DS_READ_PROP;
  1454. if (uAccess & ACTRL_DS_WRITE_PROP)
  1455. AccessAllProperty |= ACTRL_DS_WRITE_PROP;
  1456. if (uAccess & ACTRL_DS_CREATE_CHILD)
  1457. AccessAllClass |= ACTRL_DS_CREATE_CHILD;
  1458. if (uAccess & ACTRL_DS_DELETE_CHILD)
  1459. AccessAllClass |= ACTRL_DS_DELETE_CHILD;
  1460. dwErr = ::AddObjectRightInAcl(pSid, uAccess, NULL, pClassGUID, ppAcl);
  1461. if (dwErr != ERROR_SUCCESS)
  1462. goto exit;
  1463. }
  1464. // add an entry for each of the control rights
  1465. for (k=0; k < m_controlRightInfoArr.GetCount(); k++)
  1466. {
  1467. if (m_controlRightInfoArr[k]->IsSelected())
  1468. {
  1469. uAccess = m_controlRightInfoArr[k]->GetAccess();
  1470. dwErr = ::AddObjectRightInAcl(pSid, uAccess,
  1471. m_controlRightInfoArr[k]->GetRightsGUID(),
  1472. pClassGUID,
  1473. ppAcl);
  1474. if (dwErr != ERROR_SUCCESS)
  1475. goto exit;
  1476. }
  1477. } // for
  1478. // add an entry for each of the subobjects rigths
  1479. for (ULONG iClass = 0; iClass < m_classRightInfoArray.GetCount(); iClass++)
  1480. {
  1481. ULONG Access = m_classRightInfoArray[iClass]->GetAccess();
  1482. if (Access != 0)
  1483. {
  1484. if (iClass > 0)
  1485. {
  1486. ULONG nRightCount = m_classRightInfoArray[iClass]->GetRightCount();
  1487. for (ULONG iCurrRight=0; iCurrRight<nRightCount; iCurrRight++)
  1488. {
  1489. // the first entry is the Create/Delete All, no need for other permissions,
  1490. ULONG currAccess = m_classRightInfoArray[iClass]->GetRight(iCurrRight);
  1491. if (currAccess & AccessAllClass)
  1492. {
  1493. // right already present, strip out
  1494. Access &= ~currAccess;
  1495. }
  1496. } // for
  1497. }
  1498. if (Access != 0)
  1499. {
  1500. uAccess = Access;
  1501. dwErr = ::AddObjectRightInAcl(pSid, uAccess,
  1502. m_classRightInfoArray[iClass]->GetSchemaGUID(),
  1503. pClassGUID,
  1504. ppAcl);
  1505. if (dwErr != ERROR_SUCCESS)
  1506. goto exit;
  1507. }
  1508. }
  1509. } // for
  1510. // add an entry for each property right to set
  1511. for (ULONG iProperty=0; iProperty < m_propertyRightInfoArray.GetCount(); iProperty++)
  1512. {
  1513. ULONG Access = m_propertyRightInfoArray[iProperty]->GetAccess();
  1514. if (Access != 0)
  1515. {
  1516. if (iProperty > 0)
  1517. {
  1518. ULONG nRightCount = m_propertyRightInfoArray[iProperty]->GetRightCount();
  1519. for (ULONG iCurrRight=0; iCurrRight<nRightCount; iCurrRight++)
  1520. {
  1521. // the first entry is the Create/Delete All, no need for other permissions,
  1522. ULONG currAccess = m_propertyRightInfoArray[iProperty]->GetRight(iCurrRight);
  1523. if (currAccess & AccessAllProperty)
  1524. {
  1525. // right already present, strip out
  1526. Access &= ~currAccess;
  1527. }
  1528. } // for
  1529. }
  1530. if (Access != 0)
  1531. {
  1532. uAccess = Access;
  1533. dwErr = ::AddObjectRightInAcl(pSid, uAccess,
  1534. m_propertyRightInfoArray[iProperty]->GetSchemaGUID(),
  1535. pClassGUID,
  1536. ppAcl);
  1537. if (dwErr != ERROR_SUCCESS)
  1538. goto exit;
  1539. }
  1540. }
  1541. }
  1542. } // if
  1543. exit:
  1544. return dwErr;
  1545. }
  1546. ///////////////////////////////////////////////////////////////////////
  1547. // CCustomAccessPermissionsHolder
  1548. CCustomAccessPermissionsHolder::CCustomAccessPermissionsHolder()
  1549. : CAccessPermissionsHolderBase(TRUE)
  1550. {
  1551. }
  1552. CCustomAccessPermissionsHolder::~CCustomAccessPermissionsHolder()
  1553. {
  1554. Clear();
  1555. }
  1556. void CCustomAccessPermissionsHolder::Clear()
  1557. {
  1558. CAccessPermissionsHolderBase::Clear();
  1559. m_listViewItemArr.Clear();
  1560. }
  1561. struct CAccessRightTableEntry
  1562. {
  1563. UINT m_nStringID;
  1564. ULONG m_fAccess;
  1565. };
  1566. #define _WIZ_READ \
  1567. (READ_CONTROL | ACTRL_DS_LIST | ACTRL_DS_READ_PROP | ACTRL_DS_LIST_OBJECT)
  1568. #define _WIZ_WRITE \
  1569. (ACTRL_DS_SELF | ACTRL_DS_WRITE_PROP)
  1570. HRESULT CCustomAccessPermissionsHolder::_LoadAccessRightInfoArrayFromTable(BOOL bCreateDeleteChild,BOOL bHideListObject)
  1571. {
  1572. static CAccessRightTableEntry _pTable[] =
  1573. {
  1574. { IDS_DELEGWIZ_ACTRL_FULL, _WIZ_FULL_CTRL },
  1575. { IDS_DELEGWIZ_ACTRL_READ, _WIZ_READ },
  1576. { IDS_DELEGWIZ_ACTRL_WRITE, _WIZ_WRITE },
  1577. /*
  1578. { IDS_DELEGWIZ_ACTRL_SYSTEM_ACCESS, ACCESS_SYSTEM_SECURITY },
  1579. { IDS_DELEGWIZ_ACTRL_DELETE, DELETE },
  1580. { IDS_DELEGWIZ_ACTRL_READ_CONTROL, READ_CONTROL },
  1581. { IDS_DELEGWIZ_ACTRL_CHANGE_ACCESS, WRITE_DAC },
  1582. { IDS_DELEGWIZ_ACTRL_CHANGE_OWNER, WRITE_OWNER },
  1583. */
  1584. { IDS_DELEGWIZ_ACTRL_DS_CREATE_CHILD, ACTRL_DS_CREATE_CHILD },
  1585. { IDS_DELEGWIZ_ACTRL_DS_DELETE_CHILD, ACTRL_DS_DELETE_CHILD },
  1586. /*
  1587. { IDS_DELEGWIZ_ACTRL_DS_LIST, ACTRL_DS_LIST },
  1588. { IDS_DELEGWIZ_ACTRL_DS_SELF, ACTRL_DS_SELF },
  1589. */
  1590. { IDS_DELEGWIZ_ACTRL_DS_READ_PROP, ACTRL_DS_READ_PROP },
  1591. { IDS_DELEGWIZ_ACTRL_DS_WRITE_PROP, ACTRL_DS_WRITE_PROP },
  1592. /*
  1593. { IDS_DELEGWIZ_ACTRL_DS_DELETE_TREE, ACTRL_DS_DELETE_TREE },
  1594. { IDS_DELEGWIZ_ACTRL_DS_LIST_OBJECT, ACTRL_DS_LIST_OBJECT },
  1595. { IDS_DELEGWIZ_ACTRL_DS_CONTROL_ACCESS, ACTRL_DS_CONTROL_ACCESS },
  1596. */
  1597. {0, 0x0 } // end of table marker
  1598. };
  1599. if(bHideListObject)
  1600. {
  1601. _pTable[0].m_fAccess &= ~ACTRL_DS_LIST_OBJECT;
  1602. _pTable[1].m_fAccess &= ~ACTRL_DS_LIST_OBJECT;
  1603. }
  1604. TRACE(L"\nCCustomAccessPermissionsHolder::_LoadAccessRightInfoArrayFromTable()\n\n");
  1605. for(CAccessRightTableEntry* pCurrEntry = (CAccessRightTableEntry*)_pTable;
  1606. pCurrEntry->m_nStringID != NULL; pCurrEntry++)
  1607. {
  1608. if( !bCreateDeleteChild && (
  1609. (pCurrEntry->m_fAccess == ACTRL_DS_CREATE_CHILD) ||
  1610. (pCurrEntry->m_fAccess == ACTRL_DS_DELETE_CHILD ) ) )
  1611. continue;
  1612. CAccessRightInfo* pInfo = new CAccessRightInfo();
  1613. if( !pInfo )
  1614. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  1615. if (!pInfo->m_szDisplayName.LoadFromResource(pCurrEntry->m_nStringID))
  1616. {
  1617. delete pInfo;
  1618. continue;
  1619. }
  1620. pInfo->m_fAccess = pCurrEntry->m_fAccess;
  1621. TRACE(L"Display Name = <%s>, Access = 0x%x\n",
  1622. pInfo->m_szDisplayName.c_str(), pInfo->m_fAccess);
  1623. m_accessRightInfoArr.Add(pInfo);
  1624. }
  1625. TRACE(L"\nCCustomAccessPermissionsHolder::_LoadAccessRightInfoArrayFromTable() exiting\n\n");
  1626. return S_OK;
  1627. }
  1628. void CCustomAccessPermissionsHolder::_SelectAllRigths()
  1629. {
  1630. ULONG i,j;
  1631. // select all access rigths
  1632. for (i = 0; i < m_accessRightInfoArr.GetCount(); i++)
  1633. {
  1634. m_accessRightInfoArr[i]->Select(TRUE);
  1635. }
  1636. // select all control rights rigths
  1637. for (i = 0; i < m_controlRightInfoArr.GetCount(); i++)
  1638. {
  1639. m_controlRightInfoArr[i]->Select(TRUE);
  1640. }
  1641. // select all subobjects rigths
  1642. for (i = 0; i < m_classRightInfoArray.GetCount(); i++)
  1643. {
  1644. for (j=0; j< m_classRightInfoArray[i]->GetRightCount(); j++)
  1645. {
  1646. m_classRightInfoArray[i]->SetRight(j, TRUE);
  1647. }
  1648. }
  1649. // select all property rights
  1650. for (i = 0; i < m_propertyRightInfoArray.GetCount(); i++)
  1651. {
  1652. for (j=0; j< m_propertyRightInfoArray[i]->GetRightCount(); j++)
  1653. {
  1654. m_propertyRightInfoArray[i]->SetRight(j, TRUE);
  1655. }
  1656. }
  1657. }
  1658. void CCustomAccessPermissionsHolder::_SelectAllPropertyRigths(ULONG fAccessPermission)
  1659. {
  1660. for (UINT i=0; i<m_propertyRightInfoArray.GetCount(); i++)
  1661. {
  1662. m_propertyRightInfoArray[i]->AddAccessRight(fAccessPermission);
  1663. }
  1664. }
  1665. void CCustomAccessPermissionsHolder::_SelectAllSubObjectRigths(ULONG fAccessPermission)
  1666. {
  1667. for (UINT i=0; i<m_classRightInfoArray.GetCount(); i++)
  1668. {
  1669. m_classRightInfoArray[i]->AddAccessRight(fAccessPermission);
  1670. }
  1671. }
  1672. void CCustomAccessPermissionsHolder::_DeselectAssociatedRights(ULONG fAccessPermission)
  1673. {
  1674. // deselect full control first
  1675. m_accessRightInfoArr[0]->Select(FALSE);
  1676. if (fAccessPermission != 0)
  1677. {
  1678. // deselect any other basic right that contains the flag
  1679. UINT nCount = (ULONG) m_accessRightInfoArr.GetCount();
  1680. for (ULONG iAccess=0; iAccess<nCount; iAccess++)
  1681. {
  1682. if (m_accessRightInfoArr[iAccess]->GetAccess() & fAccessPermission)
  1683. m_accessRightInfoArr[iAccess]->Select(FALSE);
  1684. }
  1685. }
  1686. }
  1687. void CCustomAccessPermissionsHolder::Select(IN CRigthsListViewItem* pItem,
  1688. IN BOOL bSelect,
  1689. OUT ULONG* pnNewFilterState)
  1690. {
  1691. ASSERT(pItem != NULL);
  1692. *pnNewFilterState = 0;
  1693. switch (pItem->m_type)
  1694. {
  1695. case CRigthsListViewItem::access: // access rights
  1696. case CRigthsListViewItem::ctrl: // general rights
  1697. {
  1698. // make the change to the entry that was passed in as argument
  1699. if (pItem->m_type == CRigthsListViewItem::access)
  1700. {
  1701. m_accessRightInfoArr[pItem->m_iIndex]->Select(bSelect);
  1702. }
  1703. else
  1704. {
  1705. m_controlRightInfoArr[pItem->m_iIndex]->Select(bSelect);
  1706. }
  1707. // now see if this triggers changes to the other entries
  1708. if (bSelect)
  1709. {
  1710. if (pItem->m_type == CRigthsListViewItem::access)
  1711. {
  1712. if (pItem->m_iIndex == 0)
  1713. {
  1714. // the user checked full control, need to select all the rigths
  1715. _SelectAllRigths();
  1716. // set flags to mark which set of flags is affected
  1717. *pnNewFilterState |= FILTER_EXP_GEN;
  1718. if (m_propertyRightInfoArray.GetCount() > 0)
  1719. *pnNewFilterState |= FILTER_EXP_PROP;
  1720. if (m_classRightInfoArray.GetCount() > 0)
  1721. *pnNewFilterState |= FILTER_EXP_SUBOBJ;
  1722. }
  1723. else
  1724. {
  1725. // check if the user selected some read/write all or create/delete all right
  1726. UINT iAccess = pItem->m_iIndex;
  1727. ULONG fAccessPermission = m_accessRightInfoArr[iAccess]->GetAccess();
  1728. if ((fAccessPermission == _WIZ_READ) || (fAccessPermission == _WIZ_WRITE) )
  1729. {
  1730. // need to select all the Read or Write Properties entried
  1731. // and the ACTRL_DS_READ_PROP ACTRL_DS_WRITE_PROP (Read All/Write All)
  1732. // select all access rigths
  1733. UINT nAssociatedAccessRight =
  1734. (fAccessPermission == _WIZ_READ) ? ACTRL_DS_READ_PROP : ACTRL_DS_WRITE_PROP;
  1735. for (UINT i = 0; i < m_accessRightInfoArr.GetCount(); i++)
  1736. {
  1737. if (m_accessRightInfoArr[i]->GetAccess() == nAssociatedAccessRight)
  1738. {
  1739. m_accessRightInfoArr[i]->Select(TRUE);
  1740. _SelectAllPropertyRigths(nAssociatedAccessRight);
  1741. if (m_propertyRightInfoArray.GetCount() > 0)
  1742. *pnNewFilterState |= FILTER_EXP_PROP;
  1743. break;
  1744. }
  1745. }
  1746. }
  1747. if ( (fAccessPermission == ACTRL_DS_CREATE_CHILD) || (fAccessPermission == ACTRL_DS_DELETE_CHILD) )
  1748. {
  1749. // need to select all the Create or Delete Child entries, if present
  1750. _SelectAllSubObjectRigths(fAccessPermission);
  1751. // set the flags
  1752. if (m_classRightInfoArray.GetCount() > 0)
  1753. *pnNewFilterState |= FILTER_EXP_SUBOBJ;
  1754. }
  1755. else if ( (fAccessPermission == ACTRL_DS_READ_PROP) || (fAccessPermission == ACTRL_DS_WRITE_PROP) )
  1756. {
  1757. // need to select all the Read or Write Property entries, if present
  1758. _SelectAllPropertyRigths(fAccessPermission);
  1759. // set the flags
  1760. if (m_propertyRightInfoArray.GetCount() > 0)
  1761. *pnNewFilterState |= FILTER_EXP_PROP;
  1762. } // if
  1763. } // if index zero
  1764. } // if type is access
  1765. }
  1766. else // i.e. !bSelect
  1767. {
  1768. if (pItem->m_type == CRigthsListViewItem::access)
  1769. {
  1770. if (pItem->m_iIndex != 0)
  1771. {
  1772. // deselection on anything but full control
  1773. _DeselectAssociatedRights(m_accessRightInfoArr[pItem->m_iIndex]->GetAccess());
  1774. }
  1775. }
  1776. else if (pItem->m_type == CRigthsListViewItem::ctrl)
  1777. {
  1778. _DeselectAssociatedRights(m_controlRightInfoArr[pItem->m_iIndex]->GetAccess());
  1779. }
  1780. /*
  1781. // deselection on anything but full control
  1782. if ( !((pItem->m_iIndex == 0) && (pItem->m_type == CRigthsListViewItem::access)) )
  1783. {
  1784. _DeselectAssociatedRights(0);
  1785. }
  1786. */
  1787. }
  1788. }
  1789. break;
  1790. case CRigthsListViewItem::prop: // property rights
  1791. {
  1792. ASSERT(pItem->m_iIndex < m_propertyRightInfoArray.GetCount());
  1793. m_propertyRightInfoArray[pItem->m_iIndex]->SetRight(pItem->m_iRight, bSelect);
  1794. if (!bSelect)
  1795. {
  1796. // unchecking any Read/Write property, will unckeck the Read/Write All,
  1797. // Read and full control
  1798. _DeselectAssociatedRights(m_propertyRightInfoArray[pItem->m_iIndex]->GetRight(pItem->m_iRight));
  1799. }
  1800. }
  1801. break;
  1802. case CRigthsListViewItem::subobj: // subobject rigths
  1803. {
  1804. ASSERT(pItem->m_iIndex < m_classRightInfoArray.GetCount());
  1805. m_classRightInfoArray[pItem->m_iIndex]->SetRight(pItem->m_iRight, bSelect);
  1806. if (!bSelect)
  1807. {
  1808. // unchecking any Create/Delete property, will unckeck the Create/Delete All
  1809. // and full control
  1810. _DeselectAssociatedRights(m_classRightInfoArray[pItem->m_iIndex]->GetRight(pItem->m_iRight));
  1811. }
  1812. }
  1813. break;
  1814. default:
  1815. ASSERT(FALSE);
  1816. };
  1817. }
  1818. void CCustomAccessPermissionsHolder::FillAccessRightsListView(
  1819. CCheckListViewHelper* pListViewHelper,
  1820. ULONG nFilterState)
  1821. {
  1822. // clear the array of list view item proxies
  1823. m_listViewItemArr.Clear();
  1824. // enumerate the permissions and add to the checklist
  1825. ULONG i,j;
  1826. ULONG iListViewItem = 0;
  1827. // GENERAL RIGTHS
  1828. if (nFilterState & FILTER_EXP_GEN)
  1829. {
  1830. // add the list of access rights
  1831. UINT nAccessCount = (ULONG) m_accessRightInfoArr.GetCount();
  1832. for (i = 0; i < nAccessCount; i++)
  1833. {
  1834. // filter out entries with ACTRL_SYSTEM_ACCESS (auditing rigths)
  1835. if ( (m_accessRightInfoArr[i]->GetAccess() & ACTRL_SYSTEM_ACCESS) == 0)
  1836. {
  1837. CRigthsListViewItem* p = new CRigthsListViewItem(i, // index in m_accessRightInfoArr
  1838. 0, // iRight
  1839. CRigthsListViewItem::access);
  1840. m_listViewItemArr.Add(p);
  1841. pListViewHelper->InsertItem(iListViewItem,
  1842. m_accessRightInfoArr[i]->GetDisplayName(),
  1843. (LPARAM)p,
  1844. m_accessRightInfoArr[i]->IsSelected());
  1845. iListViewItem++;
  1846. }
  1847. }
  1848. // add the list of control rights
  1849. UINT nControlCount = (ULONG) m_controlRightInfoArr.GetCount();
  1850. for (i = 0; i < nControlCount; i++)
  1851. {
  1852. CRigthsListViewItem* p = new CRigthsListViewItem(i, // index in m_controlRightInfoArr
  1853. 0, // iRight
  1854. CRigthsListViewItem::ctrl);
  1855. m_listViewItemArr.Add(p);
  1856. pListViewHelper->InsertItem(iListViewItem,
  1857. m_controlRightInfoArr[i]->GetDisplayName(),
  1858. (LPARAM)p,
  1859. m_controlRightInfoArr[i]->IsSelected());
  1860. iListViewItem++;
  1861. }
  1862. }
  1863. // PROPERTY RIGTHS
  1864. if (nFilterState & FILTER_EXP_PROP)
  1865. {
  1866. // it expands (2x)
  1867. for (i = 0; i < (ULONG) m_propertyRightInfoArray.GetCount(); i++)
  1868. {
  1869. for (j=0; j< m_propertyRightInfoArray[i]->GetRightCount(); j++)
  1870. {
  1871. CRigthsListViewItem* p = new CRigthsListViewItem(i,j, CRigthsListViewItem::prop);
  1872. m_listViewItemArr.Add(p);
  1873. pListViewHelper->InsertItem(iListViewItem,
  1874. m_propertyRightInfoArray[i]->GetRightDisplayString(j),
  1875. (LPARAM)p,
  1876. m_propertyRightInfoArray[i]->IsRightSelected(j));
  1877. iListViewItem++;
  1878. }
  1879. }
  1880. }
  1881. // SUBOBJECT RIGTHS
  1882. if (nFilterState & FILTER_EXP_SUBOBJ)
  1883. {
  1884. // it expands (2x)
  1885. for (i = 0; i < m_classRightInfoArray.GetCount(); i++)
  1886. {
  1887. for (j=0; j< m_classRightInfoArray[i]->GetRightCount(); j++)
  1888. {
  1889. CRigthsListViewItem* p = new CRigthsListViewItem(i,j, CRigthsListViewItem::subobj);
  1890. m_listViewItemArr.Add(p);
  1891. pListViewHelper->InsertItem(iListViewItem,
  1892. m_classRightInfoArray[i]->GetRightDisplayString(j),
  1893. (LPARAM)p,
  1894. m_classRightInfoArray[i]->IsRightSelected(j));
  1895. iListViewItem++;
  1896. }
  1897. }
  1898. } // if
  1899. ASSERT(iListViewItem == m_listViewItemArr.GetCount());
  1900. }
  1901. void CCustomAccessPermissionsHolder::UpdateAccessRightsListViewSelection(
  1902. CCheckListViewHelper* pListViewHelper,
  1903. ULONG /*nFilterState*/)
  1904. {
  1905. // syncrhonize the UI with the data
  1906. int nListViewCount = pListViewHelper->GetItemCount();
  1907. for (int iListViewItem=0; iListViewItem < nListViewCount; iListViewItem++)
  1908. {
  1909. CRigthsListViewItem* pCurrItem =
  1910. (CRigthsListViewItem*)pListViewHelper->GetItemData(iListViewItem);
  1911. switch (pCurrItem->m_type)
  1912. {
  1913. case CRigthsListViewItem::access:
  1914. {
  1915. pListViewHelper->SetItemCheck(iListViewItem,
  1916. m_accessRightInfoArr[pCurrItem->m_iIndex]->IsSelected());
  1917. }
  1918. break;
  1919. case CRigthsListViewItem::ctrl:
  1920. {
  1921. pListViewHelper->SetItemCheck(iListViewItem,
  1922. m_controlRightInfoArr[pCurrItem->m_iIndex]->IsSelected());
  1923. }
  1924. break;
  1925. case CRigthsListViewItem::prop:
  1926. {
  1927. pListViewHelper->SetItemCheck(iListViewItem,
  1928. m_propertyRightInfoArray[pCurrItem->m_iIndex]->IsRightSelected(pCurrItem->m_iRight));
  1929. }
  1930. break;
  1931. case CRigthsListViewItem::subobj:
  1932. {
  1933. pListViewHelper->SetItemCheck(iListViewItem,
  1934. m_classRightInfoArray[pCurrItem->m_iIndex]->IsRightSelected(pCurrItem->m_iRight));
  1935. }
  1936. break;
  1937. } // switch
  1938. } // for
  1939. }
  1940. void CCustomAccessPermissionsHolder::WriteSummary(CWString& szSummary, LPCWSTR lpszIdent, LPCWSTR lpszNewLine)
  1941. {
  1942. WriteSummaryTitleLine(szSummary, IDS_DELEGWIZ_FINISH_PERMISSIONS, lpszNewLine);
  1943. if (m_accessRightInfoArr[0]->IsSelected()) // full control
  1944. {
  1945. WriteSummaryLine(szSummary, m_accessRightInfoArr[0]->GetDisplayName(), lpszIdent, lpszNewLine);
  1946. }
  1947. else
  1948. {
  1949. ULONG AccessAllClass = 0;
  1950. ULONG AccessAllProperty = 0;
  1951. UINT i,j,k;
  1952. // add an entry for all the standard access permissions:
  1953. for (k=0; k < m_accessRightInfoArr.GetCount(); k++)
  1954. {
  1955. if (m_accessRightInfoArr[k]->IsSelected())
  1956. {
  1957. // keep track of "All" flags
  1958. if (m_accessRightInfoArr[k]->GetAccess() & ACTRL_DS_READ_PROP)
  1959. AccessAllProperty |= ACTRL_DS_READ_PROP;
  1960. if (m_accessRightInfoArr[k]->GetAccess() & ACTRL_DS_WRITE_PROP)
  1961. AccessAllProperty |= ACTRL_DS_WRITE_PROP;
  1962. if (m_accessRightInfoArr[k]->GetAccess() & ACTRL_DS_CREATE_CHILD)
  1963. AccessAllClass |= ACTRL_DS_CREATE_CHILD;
  1964. if (m_accessRightInfoArr[k]->GetAccess() & ACTRL_DS_DELETE_CHILD)
  1965. AccessAllClass |= ACTRL_DS_DELETE_CHILD;
  1966. WriteSummaryLine(szSummary, m_accessRightInfoArr[k]->GetDisplayName(), lpszIdent, lpszNewLine);
  1967. }
  1968. } // for
  1969. // add an entry for each of the control rights
  1970. for (k=0; k < m_controlRightInfoArr.GetCount(); k++)
  1971. {
  1972. if (m_controlRightInfoArr[k]->IsSelected())
  1973. {
  1974. WriteSummaryLine(szSummary, m_controlRightInfoArr[k]->GetDisplayName(), lpszIdent, lpszNewLine);
  1975. }
  1976. } // for
  1977. // add an entry for each of the subobjects rigths
  1978. for (i = 0; i < m_classRightInfoArray.GetCount(); i++)
  1979. {
  1980. for (j=0; j< m_classRightInfoArray[i]->GetRightCount(); j++)
  1981. {
  1982. if ( m_classRightInfoArray[i]->IsRightSelected(j) &&
  1983. ((AccessAllClass & m_classRightInfoArray[i]->GetRight(j)) == 0) )
  1984. {
  1985. WriteSummaryLine(szSummary, m_classRightInfoArray[i]->GetRightDisplayString(j), lpszIdent, lpszNewLine);
  1986. }
  1987. }
  1988. }
  1989. // add an entry for each property right to set
  1990. for (i = 0; i < m_propertyRightInfoArray.GetCount(); i++)
  1991. {
  1992. for (j=0; j< m_propertyRightInfoArray[i]->GetRightCount(); j++)
  1993. {
  1994. if ( m_propertyRightInfoArray[i]->IsRightSelected(j) &&
  1995. ((AccessAllProperty & m_propertyRightInfoArray[0]->GetRight(j)) == 0) )
  1996. {
  1997. WriteSummaryLine(szSummary, m_propertyRightInfoArray[i]->GetRightDisplayString(j), lpszIdent, lpszNewLine);
  1998. }
  1999. }
  2000. }
  2001. } // if
  2002. szSummary += lpszNewLine;
  2003. }
  2004. ///////////////////////////////////////////////////////////////////////
  2005. // CCheckListViewHelper
  2006. #define CHECK_BIT(x) ((x >> 12) -1)
  2007. #define CHECK_CHANGED(pNMListView) \
  2008. (CHECK_BIT(pNMListView->uNewState) ^ CHECK_BIT(pNMListView->uOldState))
  2009. #define LVIS_STATEIMAGEMASK_CHECK (0x2000)
  2010. #define LVIS_STATEIMAGEMASK_UNCHECK (0x1000)
  2011. BOOL CCheckListViewHelper::IsChecked(NM_LISTVIEW* pNMListView)
  2012. {
  2013. return (CHECK_BIT(pNMListView->uNewState) != 0);
  2014. }
  2015. BOOL CCheckListViewHelper::CheckChanged(NM_LISTVIEW* pNMListView)
  2016. {
  2017. if (pNMListView->uOldState == 0)
  2018. return FALSE; // adding new items...
  2019. return CHECK_CHANGED(pNMListView) ? TRUE : FALSE;
  2020. }
  2021. BOOL CCheckListViewHelper::Initialize(UINT nID, HWND hParent)
  2022. {
  2023. m_hWnd = GetDlgItem(hParent, nID);
  2024. if (m_hWnd == NULL)
  2025. return FALSE;
  2026. ListView_SetExtendedListViewStyle(m_hWnd, LVS_EX_CHECKBOXES);
  2027. RECT r;
  2028. ::GetClientRect(m_hWnd, &r);
  2029. int scroll = ::GetSystemMetrics(SM_CXVSCROLL);
  2030. LV_COLUMN col;
  2031. ZeroMemory(&col, sizeof(LV_COLUMN));
  2032. col.mask = LVCF_WIDTH;
  2033. col.cx = (r.right - r.left) - scroll;
  2034. return (0 == ListView_InsertColumn(m_hWnd,0,&col));
  2035. }
  2036. int CCheckListViewHelper::InsertItem(int iItem, LPCTSTR lpszText, LPARAM lParam, BOOL bCheck)
  2037. {
  2038. TRACE(_T("CCheckListViewHelper::InsertItem(%d,%s,%x)\n"),iItem, lpszText, lParam);
  2039. LV_ITEM item;
  2040. ZeroMemory(&item, sizeof(LV_ITEM));
  2041. item.mask = LVIF_TEXT | LVIF_PARAM;
  2042. item.pszText = (LPTSTR)lpszText;
  2043. item.lParam = lParam;
  2044. item.iItem = iItem;
  2045. int iRes = ListView_InsertItem(m_hWnd, &item);
  2046. if ((iRes != -1) && bCheck)
  2047. SetItemCheck(iItem, TRUE);
  2048. return iRes;
  2049. }
  2050. BOOL CCheckListViewHelper::SetItemCheck(int iItem, BOOL bCheck)
  2051. {
  2052. LV_ITEM item;
  2053. ZeroMemory(&item, sizeof(LV_ITEM));
  2054. item.mask = LVIF_STATE;
  2055. item.state = bCheck ? LVIS_STATEIMAGEMASK_CHECK : LVIS_STATEIMAGEMASK_UNCHECK;
  2056. item.stateMask = LVIS_STATEIMAGEMASK;
  2057. item.iItem = iItem;
  2058. return ListView_SetItem(m_hWnd, &item);
  2059. }
  2060. void CCheckListViewHelper::SetCheckAll(BOOL bCheck)
  2061. {
  2062. LV_ITEM item;
  2063. ZeroMemory(&item, sizeof(LV_ITEM));
  2064. item.mask = LVIF_STATE;
  2065. item.state = bCheck ? LVIS_STATEIMAGEMASK_CHECK : LVIS_STATEIMAGEMASK_UNCHECK;
  2066. item.stateMask = LVIS_STATEIMAGEMASK;
  2067. int nCount = ListView_GetItemCount(m_hWnd);
  2068. for (int k = 0; k< nCount; k++)
  2069. {
  2070. item.iItem = k;
  2071. ListView_SetItem(m_hWnd, &item);
  2072. }
  2073. }
  2074. LPARAM CCheckListViewHelper::GetItemData(int iItem)
  2075. {
  2076. LV_ITEM item;
  2077. ZeroMemory(&item, sizeof(LV_ITEM));
  2078. item.mask = LVIF_PARAM;
  2079. item.iItem = iItem;
  2080. ListView_GetItem(m_hWnd, &item);
  2081. return item.lParam;
  2082. }
  2083. int CCheckListViewHelper::GetCheckCount()
  2084. {
  2085. int nCount = GetItemCount();
  2086. int nCheckCount = 0;
  2087. for (int k=0; k<nCount; k++)
  2088. {
  2089. if (ListView_GetCheckState(m_hWnd,k))
  2090. nCheckCount++;
  2091. }
  2092. return nCheckCount;
  2093. }
  2094. BOOL CCheckListViewHelper::IsItemChecked(int iItem)
  2095. {
  2096. return ListView_GetCheckState(m_hWnd, iItem);
  2097. }
  2098. void CCheckListViewHelper::GetCheckedItems(int nCheckCount, int* nCheckArray)
  2099. {
  2100. int nCount = GetItemCount();
  2101. int nCurrentCheck = 0;
  2102. for (int k=0; k<nCount; k++)
  2103. {
  2104. if (ListView_GetCheckState(m_hWnd,k) && nCurrentCheck < nCheckCount)
  2105. {
  2106. nCheckArray[nCurrentCheck++] = k;
  2107. }
  2108. }
  2109. }
  2110. ////////////////////////////////////////////////////////////////////////////
  2111. // CNamedSecurityInfo
  2112. /*
  2113. DWORD CNamedSecurityInfo::Get()
  2114. {
  2115. Reset(); // clear previous data
  2116. LPWSTR lpProvider = NULL; // not used
  2117. LPWSTR lpProperty = NULL; // want all
  2118. return ::GetNamedSecurityInfoEx(IN (LPWSTR) m_szObjectName.data(),
  2119. IN SE_DS_OBJECT_ALL,
  2120. IN DACL_SECURITY_INFORMATION,
  2121. IN lpProvider,
  2122. IN lpProperty,
  2123. OUT &m_pAccessList,
  2124. OUT &m_pAuditList,
  2125. OUT &m_pOwner,
  2126. OUT &m_pGroup);
  2127. }
  2128. DWORD CNamedSecurityInfo::Set()
  2129. {
  2130. LPWSTR lpProvider = NULL; // not used
  2131. dwErr = ::SetNamedSecurityInfoEx(IN (LPWSTR) m_szObjectName.data(),
  2132. IN SE_DS_OBJECT_ALL,
  2133. IN DACL_SECURITY_INFORMATION,
  2134. IN lpProvider,
  2135. IN m_pAccessList,
  2136. IN m_pAuditList,
  2137. IN m_pOwner,
  2138. IN m_pGroup,
  2139. IN NULL); // PACTRL_OVERLAPPED pOverlapped;
  2140. }
  2141. CNamedSecurityInfo::Reset()
  2142. {
  2143. if (m_pAuditList != NULL)
  2144. ::LocalFree(m_pAuditList);
  2145. if (m_pOwner != NULL)
  2146. ::LocalFree(m_pOwner);
  2147. if (m_pGroup != NULL)
  2148. ::LocalFree(m_pGroup);
  2149. if (m_pAccessList != NULL)
  2150. ::LocalFree(m_pAccessList);
  2151. }
  2152. */
  2153. ////////////////////////////////////////////////////////////////////////////
  2154. // CAdsiObject
  2155. HRESULT CAdsiObject::Bind(LPCWSTR lpszLdapPath)
  2156. {
  2157. _Clear();
  2158. CComBSTR bstrNamingContext;
  2159. CComBSTR bstrClass;
  2160. // try to bind to the given LDAP path
  2161. HRESULT hr = ::ADsOpenObjectHelper(lpszLdapPath,
  2162. IID_IADs,
  2163. (void **)&m_spIADs);
  2164. if (FAILED(hr))
  2165. {
  2166. TRACE(_T("Bind to DS object for IADs failed: %lx.\n"), hr);
  2167. goto error;
  2168. }
  2169. // get the DNS server name
  2170. hr = _QueryDNSServerName();
  2171. if (FAILED(hr))
  2172. {
  2173. TRACE(_T("Trying to get the DNS server name failed: %lx.\n"), hr);
  2174. goto error;
  2175. }
  2176. hr = _InitGlobalNamingContexts();
  2177. if (FAILED(hr))
  2178. {
  2179. TRACE(_T("Trying to get the physical schema naming context failed: %lx.\n"), hr);
  2180. goto error;
  2181. }
  2182. // need now to rebuild the LDAP path
  2183. // to make sure we talk always to the same server
  2184. hr = GetPathNameObject()->SkipPrefix(lpszLdapPath, &bstrNamingContext);
  2185. if (FAILED(hr))
  2186. {
  2187. TRACE(_T("Trying to get X500 name failed: %lx.\n"), hr);
  2188. goto error;
  2189. }
  2190. if ( (!bstrNamingContext ) || (!bstrNamingContext[0]))
  2191. {
  2192. goto error;
  2193. }
  2194. m_szNamingContext = bstrNamingContext;
  2195. BuildLdapPathHelper(GetServerName(), bstrNamingContext, m_szLdapPath);
  2196. // get the canonical name
  2197. hr = GetCanonicalNameFromNamingContext(bstrNamingContext, m_szCanonicalName);
  2198. if (FAILED(hr))
  2199. {
  2200. TRACE(_T("Trying to get canonical name failed, using naming context instead: %lx.\n"), hr);
  2201. m_szCanonicalName = bstrNamingContext;
  2202. }
  2203. // get the object class
  2204. hr = m_spIADs->get_Class(&bstrClass);
  2205. if (FAILED(hr))
  2206. {
  2207. TRACE(_T("Trying to get class name failed: %lx.\n"), hr);
  2208. goto error;
  2209. }
  2210. ASSERT(bstrClass != NULL);
  2211. m_szClass = bstrClass;
  2212. // load and set the display specifier cache
  2213. hr = ::CoCreateInstance(CLSID_DsDisplaySpecifier,
  2214. NULL,
  2215. CLSCTX_INPROC_SERVER,
  2216. IID_IDsDisplaySpecifier,
  2217. (void**)&m_spIDsDisplaySpecifier);
  2218. if (FAILED(hr))
  2219. {
  2220. TRACE(_T("Trying to get the display specifier cache failed: %lx.\n"), hr);
  2221. goto error;
  2222. }
  2223. hr = m_spIDsDisplaySpecifier->SetServer(GetServerName(), NULL, NULL, 0x0);
  2224. if (FAILED(hr))
  2225. {
  2226. TRACE(_T("m_spIDsDisplaySpecifier->SetServer(%s) failed\n"), GetServerName());
  2227. goto error;
  2228. }
  2229. ASSERT(SUCCEEDED(hr)); // all went fine
  2230. return hr;
  2231. error:
  2232. // on error condition, just reset the info, we do not
  2233. // want a partially constructed object
  2234. _Clear();
  2235. return hr;
  2236. }
  2237. #define DO_TIMING
  2238. HRESULT CAdsiObject::QuerySchemaClasses(CGrowableArr<CSchemaClassInfo>* pSchemaClassesInfoArray,
  2239. BOOL bGetAttributes)
  2240. {
  2241. TRACE(L"\n==================================================\n");
  2242. TRACE(L"CAdsiObject::QuerySchemaClasses\n\n");
  2243. #if defined (DO_TIMING)
  2244. DWORD dwTick1 = ::GetTickCount();
  2245. #endif
  2246. // make sure we are bound
  2247. if (m_spIADs == NULL)
  2248. {
  2249. return E_INVALIDARG;
  2250. }
  2251. // cleanup current entries in the list
  2252. pSchemaClassesInfoArray->Clear();
  2253. // build the LDAP path for the schema class
  2254. CWString szPhysicalSchemaPath;
  2255. LPCWSTR lpszPhysicalSchemaNamingContext = GetPhysicalSchemaNamingContext();
  2256. BuildLdapPathHelper(GetServerName(), lpszPhysicalSchemaNamingContext, szPhysicalSchemaPath);
  2257. CAdsiSearch search;
  2258. HRESULT hr = search.Init(szPhysicalSchemaPath);
  2259. if (FAILED(hr))
  2260. return hr;
  2261. static LPCWSTR lpszClassFilterFormat = L"(&(objectCategory=CN=Class-Schema,%s)(lDAPDisplayName=*))";
  2262. static LPCWSTR lpszAttributeFilterFormat = L"(&(objectCategory=CN=Attribute-Schema,%s)(lDAPDisplayName=*))";
  2263. LPCWSTR lpszFilterFormat = bGetAttributes ? lpszAttributeFilterFormat : lpszClassFilterFormat;
  2264. int nFmtLen = lstrlen(lpszFilterFormat);
  2265. int nSchemaContextLen = lstrlen(lpszPhysicalSchemaNamingContext);
  2266. WCHAR* lpszFilter = (WCHAR*)alloca(sizeof(WCHAR)*(nFmtLen+nSchemaContextLen+1));
  2267. wsprintf(lpszFilter, lpszFilterFormat, lpszPhysicalSchemaNamingContext);
  2268. static const int cAttrs = 4;
  2269. static LPCWSTR pszAttribsArr[cAttrs] =
  2270. {
  2271. L"lDAPDisplayName", // e.g. "organizationalUnit"
  2272. L"name", // e.g. "Organizational-Unit"
  2273. L"schemaIDGUID",
  2274. L"objectClassCategory",
  2275. };
  2276. hr = search.SetSearchScope(ADS_SCOPE_ONELEVEL);
  2277. if (FAILED(hr))
  2278. return hr;
  2279. hr = search.DoQuery(lpszFilter, pszAttribsArr, cAttrs);
  2280. if (FAILED(hr))
  2281. return hr;
  2282. CWString szLDAPName, szName;
  2283. szLDAPName = L"";
  2284. szName = L"";
  2285. GUID schemaIDGUID;
  2286. ULONG iObjectClassCategory=0;
  2287. while ((hr = search.GetNextRow()) != S_ADS_NOMORE_ROWS)
  2288. {
  2289. if (FAILED(hr))
  2290. continue;
  2291. HRESULT hr0 = search.GetColumnString(pszAttribsArr[0], szLDAPName);
  2292. HRESULT hr1 = search.GetColumnString(pszAttribsArr[1], szName);
  2293. HRESULT hr2 = search.GetColumnOctectStringGUID(pszAttribsArr[2], schemaIDGUID);
  2294. HRESULT hr3 = search.GetColumnInteger(pszAttribsArr[3], iObjectClassCategory);
  2295. if (FAILED(hr0) || FAILED(hr1) || FAILED(hr2) || FAILED(hr3))
  2296. continue;
  2297. ULONG fFilterFlags = ::GetClassFlags(szLDAPName);
  2298. CSchemaClassInfo* p = new CSchemaClassInfo(szLDAPName, szName, &schemaIDGUID);
  2299. if(!p)
  2300. return E_OUTOFMEMORY;
  2301. BOOL bFilter = (fFilterFlags & IDC_CLASS_NO);
  2302. if (bFilter)
  2303. p->SetFiltered();
  2304. //is class Auxiallary
  2305. if(iObjectClassCategory == 3)
  2306. p->SetAux();
  2307. pSchemaClassesInfoArray->Add(p);
  2308. //TRACE(L"Class %s inserted, IsFiltered() == %d\n", (LPCWSTR)szName, p->IsFiltered());
  2309. } // while
  2310. TRACE(L"\n================================================\n");
  2311. #if defined (DO_TIMING)
  2312. DWORD dwTick2 = ::GetTickCount();
  2313. TRACE(L"Time to do Schema Query loop (mSec) = %d\n", dwTick2-dwTick1);
  2314. #endif
  2315. _GetFriendlyClassNames(pSchemaClassesInfoArray);
  2316. #if defined (DO_TIMING)
  2317. dwTick2 = ::GetTickCount();
  2318. #endif
  2319. pSchemaClassesInfoArray->Sort(); // wrt friendly class name
  2320. #if defined (DO_TIMING)
  2321. DWORD dwTick3 = ::GetTickCount();
  2322. TRACE(L"Time to sort (mSec) = %d\n", dwTick3-dwTick2);
  2323. #endif
  2324. TRACE(L"exiting CAdsiObject::QuerySchemaClasses()\n\n");
  2325. return hr;
  2326. }
  2327. HRESULT CAdsiObject::GetClassGuid(LPCWSTR lpszClassLdapDisplayName, BOOL bGetAttribute, GUID& guid)
  2328. {
  2329. //TRACE(L"CAdsiObject::GetClassGuid(%s, _)\n\n", lpszClassLdapDisplayName);
  2330. ZeroMemory(&guid, sizeof(GUID));
  2331. // make sure we are bound
  2332. if (m_spIADs == NULL)
  2333. {
  2334. return E_INVALIDARG;
  2335. }
  2336. // build the LDAP path for the schema class
  2337. CWString szPhysicalSchemaPath;
  2338. LPCWSTR lpszPhysicalSchemaNamingContext = GetPhysicalSchemaNamingContext();
  2339. BuildLdapPathHelper(GetServerName(), lpszPhysicalSchemaNamingContext, szPhysicalSchemaPath);
  2340. CAdsiSearch search;
  2341. HRESULT hr = search.Init(szPhysicalSchemaPath);
  2342. if (FAILED(hr))
  2343. return hr;
  2344. static LPCWSTR lpszClassFilterFormat = L"(&(objectCategory=CN=Class-Schema,%s)(lDAPDisplayName=%s))";
  2345. static LPCWSTR lpszAttributeFilterFormat = L"(&(objectCategory=CN=Attribute-Schema,%s)(lDAPDisplayName=%s))";
  2346. LPCWSTR lpszFilterFormat = bGetAttribute ? lpszAttributeFilterFormat : lpszClassFilterFormat;
  2347. int nFmtLen = lstrlen(lpszFilterFormat);
  2348. int nSchemaContextLen = lstrlen(lpszPhysicalSchemaNamingContext);
  2349. int nlDAPDisplayNameLen = lstrlen(lpszClassLdapDisplayName);
  2350. WCHAR* lpszFilter = (WCHAR*)alloca(sizeof(WCHAR)*(nFmtLen+nSchemaContextLen+nlDAPDisplayNameLen+1));
  2351. wsprintf(lpszFilter, lpszFilterFormat, lpszPhysicalSchemaNamingContext, lpszClassLdapDisplayName);
  2352. //TRACE(L"lpszFilter = %s\n", lpszFilter);
  2353. static const int cAttrs = 1;
  2354. static LPCWSTR pszAttribsArr[cAttrs] =
  2355. {
  2356. L"schemaIDGUID",
  2357. };
  2358. hr = search.SetSearchScope(ADS_SCOPE_ONELEVEL);
  2359. if (FAILED(hr))
  2360. return hr;
  2361. hr = search.DoQuery(lpszFilter, pszAttribsArr, cAttrs);
  2362. if (FAILED(hr))
  2363. return hr;
  2364. // expect a single result
  2365. hr = search.GetNextRow();
  2366. if ( hr == S_ADS_NOMORE_ROWS)
  2367. {
  2368. hr = E_ADS_UNKNOWN_OBJECT;
  2369. }
  2370. if (FAILED(hr))
  2371. return hr;
  2372. hr = search.GetColumnOctectStringGUID(pszAttribsArr[0], guid);
  2373. //TRACE(L"exiting CAdsiObject::GetClassGuid()\n\n");
  2374. return hr;
  2375. }
  2376. HRESULT CAdsiObject::_QueryDNSServerName()
  2377. {
  2378. // make sure we are bound
  2379. if (m_spIADs == NULL)
  2380. {
  2381. return E_INVALIDARG;
  2382. }
  2383. m_szServerName = L"";
  2384. CComPtr<IADsObjectOptions> spIADsObjectOptions;
  2385. HRESULT hr = m_spIADs->QueryInterface(IID_IADsObjectOptions, (void**)&spIADsObjectOptions);
  2386. if (FAILED(hr))
  2387. return hr;
  2388. CComVariant var;
  2389. hr = spIADsObjectOptions->GetOption(ADS_OPTION_SERVERNAME, &var);
  2390. if (FAILED(hr))
  2391. return hr;
  2392. ASSERT(var.vt == VT_BSTR);
  2393. m_szServerName = V_BSTR(&var);
  2394. return hr;
  2395. }
  2396. HRESULT CAdsiObject::_InitGlobalNamingContexts()
  2397. {
  2398. return ::GetGlobalNamingContexts(GetServerName(),
  2399. m_szPhysicalSchemaNamingContext,
  2400. m_szConfigurationNamingContext);
  2401. }
  2402. HICON CAdsiObject::GetClassIcon(LPCWSTR lpszObjectClass)
  2403. {
  2404. ASSERT(m_spIDsDisplaySpecifier != NULL);
  2405. return m_spIDsDisplaySpecifier->GetIcon(lpszObjectClass,
  2406. DSGIF_ISNORMAL | DSGIF_GETDEFAULTICON,
  2407. 32, 32);
  2408. }
  2409. HRESULT CAdsiObject::GetFriendlyClassName(LPCWSTR lpszObjectClass,
  2410. LPWSTR lpszBuffer, int cchBuffer)
  2411. {
  2412. ASSERT(m_spIDsDisplaySpecifier != NULL);
  2413. return m_spIDsDisplaySpecifier->GetFriendlyClassName(lpszObjectClass,
  2414. lpszBuffer,
  2415. cchBuffer);
  2416. }
  2417. HRESULT CAdsiObject::GetFriendlyAttributeName(LPCWSTR lpszObjectClass,
  2418. LPCWSTR lpszAttributeName,
  2419. LPWSTR lpszBuffer, int cchBuffer)
  2420. {
  2421. ASSERT(m_spIDsDisplaySpecifier != NULL);
  2422. return m_spIDsDisplaySpecifier->GetFriendlyAttributeName(lpszObjectClass,
  2423. lpszAttributeName,
  2424. lpszBuffer, cchBuffer);
  2425. }
  2426. #if (FALSE)
  2427. HRESULT CAdsiObject::_GetFriendlyClassNames(CGrowableArr<CSchemaClassInfo>* pSchemaClassesInfoArray)
  2428. {
  2429. TRACE(L"begin _GetFriendlyClassNames() loop on all classes\n");
  2430. #if defined (DO_TIMING)
  2431. DWORD dwTick1 = ::GetTickCount();
  2432. #endif
  2433. // now get the friendly class name to display
  2434. ULONG nCount = pSchemaClassesInfoArray->GetCount();
  2435. WCHAR szFrendlyName[1024];
  2436. for (UINT k=0; k<nCount; k++)
  2437. {
  2438. CSchemaClassInfo* p = (*pSchemaClassesInfoArray)[k];
  2439. HRESULT hrFriendlyName = this->GetFriendlyClassName(p->GetName(), szFrendlyName, 1024);
  2440. ASSERT(SUCCEEDED(hrFriendlyName));
  2441. (*pSchemaClassesInfoArray)[k]->SetDisplayName(SUCCEEDED(hrFriendlyName) ? szFrendlyName : NULL);
  2442. }
  2443. #if defined (DO_TIMING)
  2444. DWORD dwTick2 = ::GetTickCount();
  2445. TRACE(L"Time to call _GetFriendlyClassNames() loop (mSec) = %d\n", dwTick2-dwTick1);
  2446. #endif
  2447. return S_OK;
  2448. }
  2449. #else
  2450. HRESULT CAdsiObject::_GetFriendlyClassNames(CGrowableArr<CSchemaClassInfo>* pSchemaClassesInfoArray)
  2451. {
  2452. TRACE(L"\nbegin _GetFriendlyClassNames() using ADSI query\n");
  2453. #if defined (DO_TIMING)
  2454. DWORD dwTick1 = ::GetTickCount();
  2455. #endif
  2456. ASSERT(m_spIDsDisplaySpecifier != NULL);
  2457. // get the display specifiers locale container (e.g. 409)
  2458. CComPtr<IADs> spLocaleContainer;
  2459. HRESULT hr = m_spIDsDisplaySpecifier->GetDisplaySpecifier(NULL, IID_IADs, (void**)&spLocaleContainer);
  2460. if (FAILED(hr))
  2461. return hr;
  2462. // get distinguished name of the container
  2463. CComVariant varLocaleContainerDN;
  2464. hr = spLocaleContainer->Get(L"distinguishedName", &varLocaleContainerDN);
  2465. if (FAILED(hr))
  2466. return hr;
  2467. // build the LDAP path for it
  2468. CWString szLocaleContainerPath;
  2469. BuildLdapPathHelper(GetServerName(), varLocaleContainerDN.bstrVal, szLocaleContainerPath);
  2470. // build the LDAP path for the schema class
  2471. CWString szPhysicalSchemaPath;
  2472. LPCWSTR lpszPhysicalSchemaNamingContext = GetPhysicalSchemaNamingContext();
  2473. BuildLdapPathHelper(GetServerName(), lpszPhysicalSchemaNamingContext, szPhysicalSchemaPath);
  2474. // build an LDAP query string
  2475. static LPCWSTR lpszFilterFormat = L"(objectCategory=CN=Display-Specifier,%s)";
  2476. int nFmtLen = lstrlen(lpszFilterFormat);
  2477. int nArgumentLen = lstrlen(lpszPhysicalSchemaNamingContext);
  2478. WCHAR* lpszFilter = (WCHAR*)alloca(sizeof(WCHAR)*(nFmtLen+nArgumentLen+1));
  2479. wsprintf(lpszFilter, lpszFilterFormat, lpszPhysicalSchemaNamingContext);
  2480. // execute a query to get the CN and the class display name
  2481. CAdsiSearch search;
  2482. hr = search.Init(szLocaleContainerPath);
  2483. if (FAILED(hr))
  2484. return hr;
  2485. // build an array of wanted columns
  2486. static const int cAttrs = 2;
  2487. static LPCWSTR pszAttribsArr[cAttrs] =
  2488. {
  2489. L"cn", // e.g. "organizationalUnit-Display"
  2490. L"classDisplayName", // e.g. "Organizational Unit" (i.e. the localizable one)
  2491. };
  2492. hr = search.SetSearchScope(ADS_SCOPE_ONELEVEL);
  2493. //TRACE(L"search.SetSearchScope(ADS_SCOPE_ONELEVEL) returned hr = 0x%x\n", hr);
  2494. if (FAILED(hr))
  2495. return hr;
  2496. hr = search.DoQuery(lpszFilter, pszAttribsArr, cAttrs);
  2497. //TRACE(L"search.DoQuery(lpszFilter, pszAttribsArr, cAttrs) returned hr = 0x%x\n", hr);
  2498. if (FAILED(hr))
  2499. return hr;
  2500. // need to keep track of matches
  2501. size_t nCount = pSchemaClassesInfoArray->GetCount();
  2502. BOOL* bFoundArray = (BOOL*)alloca(nCount*sizeof(BOOL));
  2503. ZeroMemory(bFoundArray, nCount*sizeof(BOOL));
  2504. WCHAR szBuffer[1024];
  2505. CWString szNamingAttribute, szClassDisplayName;
  2506. while ((hr = search.GetNextRow()) != S_ADS_NOMORE_ROWS)
  2507. {
  2508. if (FAILED(hr))
  2509. continue;
  2510. HRESULT hr0 = search.GetColumnString(pszAttribsArr[0], szNamingAttribute);
  2511. HRESULT hr1 = search.GetColumnString(pszAttribsArr[1], szClassDisplayName);
  2512. //TRACE(L"szNamingAttribute = <%s>, szClassDisplayName = <%s>\n",
  2513. // szNamingAttribute.c_str(), szClassDisplayName.c_str());
  2514. if (FAILED(hr0) || FAILED(hr1) )
  2515. {
  2516. TRACE(L"WARNING: discarding right, failed on columns: hr0 = 0x%x, hr1 = 0x%x\n",
  2517. hr0, hr1);
  2518. continue;
  2519. }
  2520. // got a good name, need to match with the entries in the array
  2521. for (UINT k=0; k<nCount; k++)
  2522. {
  2523. if (!bFoundArray[k])
  2524. {
  2525. CSchemaClassInfo* p = (*pSchemaClassesInfoArray)[k];
  2526. wsprintf(szBuffer, L"%s-Display",p->GetName());
  2527. if (_wcsicmp(szBuffer, szNamingAttribute) == 0)
  2528. {
  2529. //TRACE(L" matching for %s\n",p->GetName());
  2530. p->SetDisplayName(szClassDisplayName);
  2531. bFoundArray[k] = TRUE;
  2532. }
  2533. }
  2534. } // for
  2535. } // while
  2536. // take care of the ones that did not have any display specifier
  2537. for (UINT k=0; k<nCount; k++)
  2538. {
  2539. if (!bFoundArray[k])
  2540. {
  2541. (*pSchemaClassesInfoArray)[k]->SetDisplayName(NULL);
  2542. }
  2543. } // for
  2544. TRACE(L"\n\n");
  2545. if (hr == S_ADS_NOMORE_ROWS)
  2546. hr = S_OK;
  2547. #if defined (DO_TIMING)
  2548. DWORD dwTick2 = ::GetTickCount();
  2549. TRACE(L"Time to call _GetFriendlyClassNames() on ADSI query (mSec) = %d\n", dwTick2-dwTick1);
  2550. #endif
  2551. return hr;
  2552. }
  2553. #endif
  2554. bool
  2555. CAdsiObject::GetListObjectEnforced()
  2556. {
  2557. if(m_iListObjectEnforced != -1)
  2558. return (m_iListObjectEnforced==1);
  2559. PADS_ATTR_INFO pAttributeInfo = NULL;
  2560. IDirectoryObject *pDirectoryService = NULL;
  2561. IADsPathname *pPath = NULL;
  2562. BSTR strServicePath = NULL;
  2563. do
  2564. {
  2565. m_iListObjectEnforced = 0; // Assume "not enforced"
  2566. HRESULT hr = S_OK;
  2567. int i;
  2568. // Create a path object for manipulating ADS paths
  2569. hr = CoCreateInstance(CLSID_Pathname,
  2570. NULL,
  2571. CLSCTX_INPROC_SERVER,
  2572. IID_IADsPathname,
  2573. (LPVOID*)&pPath);
  2574. if(FAILED(hr))
  2575. break;
  2576. CComBSTR bstrConfigPath = L"LDAP://";
  2577. if(GetServerName())
  2578. {
  2579. bstrConfigPath += GetServerName();
  2580. bstrConfigPath += L"/";
  2581. }
  2582. if(!GetConfigurationNamingContext())
  2583. break;
  2584. bstrConfigPath += GetConfigurationNamingContext();
  2585. if(!bstrConfigPath.Length())
  2586. break;
  2587. hr = pPath->Set(bstrConfigPath, ADS_SETTYPE_FULL);
  2588. if(FAILED(hr))
  2589. break;
  2590. const LPWSTR aszServicePath[] =
  2591. {
  2592. L"CN=Services",
  2593. L"CN=Windows NT",
  2594. L"CN=Directory Service",
  2595. };
  2596. for (i = 0; i < ARRAYSIZE(aszServicePath); i++)
  2597. {
  2598. hr = pPath->AddLeafElement(aszServicePath[i]);
  2599. if(FAILED(hr))
  2600. break;
  2601. }
  2602. hr = pPath->Retrieve(ADS_FORMAT_WINDOWS, &strServicePath);
  2603. if(FAILED(hr))
  2604. break;
  2605. hr = ADsGetObject(strServicePath,
  2606. IID_IDirectoryObject,
  2607. (LPVOID*)&pDirectoryService);
  2608. if(FAILED(hr))
  2609. break;
  2610. WCHAR const c_szDsHeuristics[] = L"dSHeuristics";
  2611. LPWSTR pszDsHeuristics = (LPWSTR)c_szDsHeuristics;
  2612. DWORD dwAttributesReturned = 0;
  2613. hr = pDirectoryService->GetObjectAttributes(&pszDsHeuristics,
  2614. 1,
  2615. &pAttributeInfo,
  2616. &dwAttributesReturned);
  2617. if (FAILED(hr)|| !pAttributeInfo)
  2618. break;
  2619. ASSERT(ADSTYPE_DN_STRING <= pAttributeInfo->dwADsType);
  2620. ASSERT(ADSTYPE_NUMERIC_STRING >= pAttributeInfo->dwADsType);
  2621. ASSERT(1 == pAttributeInfo->dwNumValues);
  2622. LPWSTR pszHeuristicString = pAttributeInfo->pADsValues->NumericString;
  2623. if (pszHeuristicString &&
  2624. lstrlenW(pszHeuristicString) > 2 &&
  2625. L'0' != pszHeuristicString[2])
  2626. {
  2627. m_iListObjectEnforced = 1;
  2628. }
  2629. }while(0);
  2630. if (pAttributeInfo)
  2631. FreeADsMem(pAttributeInfo);
  2632. if(pDirectoryService)
  2633. pDirectoryService->Release();
  2634. if(pPath)
  2635. pPath->Release();
  2636. if(strServicePath)
  2637. SysFreeString(strServicePath);
  2638. return (m_iListObjectEnforced==1);
  2639. }
  2640. ////////////////////////////////////////////////////////////////////////////////////////
  2641. // CAdsiSearch
  2642. HRESULT CAdsiSearch::DoQuery(LPCWSTR lpszFilter, LPCWSTR* pszAttribsArr, int cAttrs)
  2643. {
  2644. if (m_spSearchObj == NULL)
  2645. return E_ADS_BAD_PATHNAME;
  2646. static const int NUM_PREFS=3;
  2647. static const int QUERY_PAGESIZE = 256;
  2648. ADS_SEARCHPREF_INFO aSearchPref[NUM_PREFS];
  2649. aSearchPref[0].dwSearchPref = ADS_SEARCHPREF_CHASE_REFERRALS;
  2650. aSearchPref[0].vValue.dwType = ADSTYPE_INTEGER;
  2651. aSearchPref[0].vValue.Integer = ADS_CHASE_REFERRALS_EXTERNAL;
  2652. aSearchPref[1].dwSearchPref = ADS_SEARCHPREF_PAGESIZE;
  2653. aSearchPref[1].vValue.dwType = ADSTYPE_INTEGER;
  2654. aSearchPref[1].vValue.Integer = QUERY_PAGESIZE;
  2655. aSearchPref[2].dwSearchPref = ADS_SEARCHPREF_CACHE_RESULTS;
  2656. aSearchPref[2].vValue.dwType = ADSTYPE_BOOLEAN;
  2657. aSearchPref[2].vValue.Integer = FALSE;
  2658. HRESULT hr = m_spSearchObj->SetSearchPreference (aSearchPref, NUM_PREFS);
  2659. if (FAILED(hr))
  2660. return hr;
  2661. return m_spSearchObj->ExecuteSearch((LPWSTR)lpszFilter,
  2662. (LPWSTR*)pszAttribsArr,
  2663. cAttrs,
  2664. &m_SearchHandle);
  2665. }