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.

1977 lines
59 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000
  5. //
  6. // File: display.cpp
  7. //
  8. // Contents: Defines the functions used to convert values to strings
  9. // for display purposes
  10. //
  11. // History: 17-Oct-2000 JeffJon Created
  12. //
  13. //
  14. //--------------------------------------------------------------------------
  15. #include <pch.h>
  16. #include "cstrings.h"
  17. #include "gettable.h"
  18. #include "display.h"
  19. #include "output.h"
  20. #include "query.h"
  21. #include <lmaccess.h> // UF_* for userAccountControl flags
  22. #include <ntsam.h> // GROUP_TYPE_*
  23. #include <ntdsapi.h> // NTDSSETTINGS_OPT_*
  24. //
  25. // All these functions are of type PGETDISPLAYSTRINGFUNC as defined in
  26. // gettable.h
  27. //
  28. HRESULT CommonDisplayStringFunc(PCWSTR /*pszDN*/,
  29. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  30. const CDSCmdCredentialObject& /*refCredentialObject*/,
  31. _DSGetObjectTableEntry* pEntry,
  32. ARG_RECORD* pRecord,
  33. PADS_ATTR_INFO pAttrInfo,
  34. CComPtr<IDirectoryObject>& /*spDirObject*/,
  35. PDSGET_DISPLAY_INFO pDisplayInfo)
  36. {
  37. ENTER_FUNCTION_HR(LEVEL5_LOGGING, CommonDisplayStringFunc, hr);
  38. do // false loop
  39. {
  40. //
  41. // Verify parameters
  42. //
  43. if (!pEntry ||
  44. !pRecord ||
  45. !pDisplayInfo)
  46. {
  47. ASSERT(pEntry);
  48. ASSERT(pRecord);
  49. ASSERT(pDisplayInfo);
  50. hr = E_INVALIDARG;
  51. break;
  52. }
  53. if (pAttrInfo && pAttrInfo->pADsValues)
  54. {
  55. DEBUG_OUTPUT(FULL_LOGGING,
  56. L"Adding %d values:",
  57. pAttrInfo->dwNumValues);
  58. DWORD dwValuesAdded = 0;
  59. for (DWORD dwIdx = 0; dwIdx < pAttrInfo->dwNumValues; dwIdx++)
  60. {
  61. WCHAR* pBuffer = new WCHAR[MAXSTR];
  62. if (!pBuffer)
  63. {
  64. hr = E_OUTOFMEMORY;
  65. break;
  66. }
  67. hr = GetStringFromADs(&(pAttrInfo->pADsValues[dwIdx]),
  68. pAttrInfo->dwADsType,
  69. pBuffer,
  70. MAXSTR);
  71. if (SUCCEEDED(hr))
  72. {
  73. hr = pDisplayInfo->AddValue(pBuffer);
  74. if (FAILED(hr))
  75. {
  76. delete[] pBuffer;
  77. pBuffer = NULL;
  78. break;
  79. }
  80. delete[] pBuffer;
  81. pBuffer = NULL;
  82. dwValuesAdded++;
  83. }
  84. }
  85. }
  86. } while (false);
  87. return hr;
  88. }
  89. HRESULT DisplayCanChangePassword(PCWSTR pszDN,
  90. CDSCmdBasePathsInfo& refBasePathsInfo,
  91. const CDSCmdCredentialObject& refCredentialObject,
  92. _DSGetObjectTableEntry* pEntry,
  93. ARG_RECORD* pRecord,
  94. PADS_ATTR_INFO /*pAttrInfo*/,
  95. CComPtr<IDirectoryObject>& /*spDirObject*/,
  96. PDSGET_DISPLAY_INFO pDisplayInfo)
  97. {
  98. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayCanChangePassword, hr);
  99. do // false loop
  100. {
  101. //
  102. // Verify parameters
  103. //
  104. if (!pszDN ||
  105. !pEntry ||
  106. !pRecord ||
  107. !pDisplayInfo)
  108. {
  109. ASSERT(pszDN);
  110. ASSERT(pEntry);
  111. ASSERT(pRecord);
  112. ASSERT(pDisplayInfo);
  113. hr = E_INVALIDARG;
  114. break;
  115. }
  116. bool bCanChangePassword = false;
  117. hr = EvaluateCanChangePasswordAces(pszDN,
  118. refBasePathsInfo,
  119. refCredentialObject,
  120. bCanChangePassword);
  121. if (FAILED(hr))
  122. {
  123. break;
  124. }
  125. DEBUG_OUTPUT(LEVEL8_LOGGING,
  126. L"Can change password: %s",
  127. bCanChangePassword ? g_pszYes : g_pszNo);
  128. hr = pDisplayInfo->AddValue(bCanChangePassword ? g_pszYes : g_pszNo);
  129. } while (false);
  130. return hr;
  131. }
  132. HRESULT DisplayMustChangePassword(PCWSTR /*pszDN*/,
  133. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  134. const CDSCmdCredentialObject& /*refCredentialObject*/,
  135. _DSGetObjectTableEntry* pEntry,
  136. ARG_RECORD* pRecord,
  137. PADS_ATTR_INFO pAttrInfo,
  138. CComPtr<IDirectoryObject>& /*spDirObject*/,
  139. PDSGET_DISPLAY_INFO pDisplayInfo)
  140. {
  141. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayMustChangePassword, hr);
  142. do // false loop
  143. {
  144. //
  145. // Verify parameters
  146. //
  147. if (!pEntry ||
  148. !pRecord ||
  149. !pDisplayInfo)
  150. {
  151. ASSERT(pEntry);
  152. ASSERT(pRecord);
  153. ASSERT(pDisplayInfo);
  154. hr = E_INVALIDARG;
  155. break;
  156. }
  157. if (pAttrInfo->pADsValues && pAttrInfo->dwADsType == ADSTYPE_LARGE_INTEGER)
  158. {
  159. DEBUG_OUTPUT(FULL_LOGGING,
  160. L"Adding %d values:",
  161. pAttrInfo->dwNumValues);
  162. bool bMustChangePassword = false;
  163. if (pAttrInfo->pADsValues->LargeInteger.HighPart == 0 &&
  164. pAttrInfo->pADsValues->LargeInteger.LowPart == 0)
  165. {
  166. bMustChangePassword = true;
  167. }
  168. DEBUG_OUTPUT(LEVEL8_LOGGING,
  169. L"Must change password: %s",
  170. bMustChangePassword ? g_pszYes : g_pszNo);
  171. hr = pDisplayInfo->AddValue(bMustChangePassword ? g_pszYes : g_pszNo);
  172. }
  173. } while (false);
  174. return hr;
  175. }
  176. HRESULT DisplayAccountDisabled(PCWSTR /*pszDN*/,
  177. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  178. const CDSCmdCredentialObject& /*refCredentialObject*/,
  179. _DSGetObjectTableEntry* pEntry,
  180. ARG_RECORD* pRecord,
  181. PADS_ATTR_INFO pAttrInfo,
  182. CComPtr<IDirectoryObject>& /*spDirObject*/,
  183. PDSGET_DISPLAY_INFO pDisplayInfo)
  184. {
  185. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayAccountDisabled, hr);
  186. do // false loop
  187. {
  188. //
  189. // Verify parameters
  190. //
  191. if (!pEntry ||
  192. !pRecord ||
  193. !pDisplayInfo)
  194. {
  195. ASSERT(pEntry);
  196. ASSERT(pRecord);
  197. ASSERT(pDisplayInfo);
  198. hr = E_INVALIDARG;
  199. break;
  200. }
  201. if (pAttrInfo->pADsValues && pAttrInfo->dwADsType == ADSTYPE_INTEGER)
  202. {
  203. DEBUG_OUTPUT(FULL_LOGGING,
  204. L"Adding %d values:",
  205. pAttrInfo->dwNumValues);
  206. bool bAccountDisabled = false;
  207. if (pAttrInfo->pADsValues->Integer & UF_ACCOUNTDISABLE)
  208. {
  209. bAccountDisabled = true;
  210. }
  211. DEBUG_OUTPUT(LEVEL8_LOGGING,
  212. L"Account disabled: %s",
  213. bAccountDisabled ? g_pszYes : g_pszNo);
  214. hr = pDisplayInfo->AddValue(bAccountDisabled ? g_pszYes : g_pszNo);
  215. }
  216. } while (false);
  217. return hr;
  218. }
  219. HRESULT DisplayPasswordNeverExpires(PCWSTR /*pszDN*/,
  220. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  221. const CDSCmdCredentialObject& /*refCredentialObject*/,
  222. _DSGetObjectTableEntry* pEntry,
  223. ARG_RECORD* pRecord,
  224. PADS_ATTR_INFO pAttrInfo,
  225. CComPtr<IDirectoryObject>& /*spDirObject*/,
  226. PDSGET_DISPLAY_INFO pDisplayInfo)
  227. {
  228. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayPasswordNeverExpires, hr);
  229. do // false loop
  230. {
  231. //
  232. // Verify parameters
  233. //
  234. if (!pEntry ||
  235. !pRecord ||
  236. !pDisplayInfo)
  237. {
  238. ASSERT(pEntry);
  239. ASSERT(pRecord);
  240. ASSERT(pDisplayInfo);
  241. hr = E_INVALIDARG;
  242. break;
  243. }
  244. if (pAttrInfo->pADsValues && pAttrInfo->dwADsType == ADSTYPE_INTEGER)
  245. {
  246. DEBUG_OUTPUT(FULL_LOGGING,
  247. L"Adding %d values:",
  248. pAttrInfo->dwNumValues);
  249. bool bPwdNeverExpires = false;
  250. if (pAttrInfo->pADsValues->Integer & UF_DONT_EXPIRE_PASSWD)
  251. {
  252. bPwdNeverExpires = true;
  253. }
  254. DEBUG_OUTPUT(LEVEL8_LOGGING,
  255. L"Password never expires: %s",
  256. bPwdNeverExpires ? g_pszYes : g_pszNo);
  257. hr = pDisplayInfo->AddValue(bPwdNeverExpires ? g_pszYes : g_pszNo);
  258. }
  259. } while (false);
  260. return hr;
  261. }
  262. HRESULT DisplayReversiblePassword(PCWSTR /*pszDN*/,
  263. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  264. const CDSCmdCredentialObject& /*refCredentialObject*/,
  265. _DSGetObjectTableEntry* pEntry,
  266. ARG_RECORD* pRecord,
  267. PADS_ATTR_INFO pAttrInfo,
  268. CComPtr<IDirectoryObject>& /*spDirObject*/,
  269. PDSGET_DISPLAY_INFO pDisplayInfo)
  270. {
  271. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayReversiblePassword, hr);
  272. do // false loop
  273. {
  274. //
  275. // Verify parameters
  276. //
  277. if (!pEntry ||
  278. !pRecord ||
  279. !pDisplayInfo)
  280. {
  281. ASSERT(pEntry);
  282. ASSERT(pRecord);
  283. ASSERT(pDisplayInfo);
  284. hr = E_INVALIDARG;
  285. break;
  286. }
  287. if (pAttrInfo->pADsValues && pAttrInfo->dwADsType == ADSTYPE_INTEGER)
  288. {
  289. DEBUG_OUTPUT(FULL_LOGGING,
  290. L"Adding %d values:",
  291. pAttrInfo->dwNumValues);
  292. bool bReversiblePwd = false;
  293. if (pAttrInfo->pADsValues->Integer & UF_DONT_EXPIRE_PASSWD)
  294. {
  295. bReversiblePwd = true;
  296. }
  297. DEBUG_OUTPUT(LEVEL8_LOGGING,
  298. L"Password store with reversible encryption: %s",
  299. bReversiblePwd ? g_pszYes : g_pszNo);
  300. hr = pDisplayInfo->AddValue(bReversiblePwd ? g_pszYes : g_pszNo);
  301. }
  302. } while (false);
  303. return hr;
  304. }
  305. // Constants
  306. const unsigned long DSCMD_FILETIMES_PER_MILLISECOND = 10000;
  307. const DWORD DSCMD_FILETIMES_PER_SECOND = 1000 * DSCMD_FILETIMES_PER_MILLISECOND;
  308. const DWORD DSCMD_FILETIMES_PER_MINUTE = 60 * DSCMD_FILETIMES_PER_SECOND;
  309. const __int64 DSCMD_FILETIMES_PER_HOUR = 60 * (__int64)DSCMD_FILETIMES_PER_MINUTE;
  310. const __int64 DSCMD_FILETIMES_PER_DAY = 24 * DSCMD_FILETIMES_PER_HOUR;
  311. const __int64 DSCMD_FILETIMES_PER_MONTH= 30 * DSCMD_FILETIMES_PER_DAY;
  312. HRESULT DisplayAccountExpires(PCWSTR /*pszDN*/,
  313. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  314. const CDSCmdCredentialObject& /*refCredentialObject*/,
  315. _DSGetObjectTableEntry* pEntry,
  316. ARG_RECORD* pRecord,
  317. PADS_ATTR_INFO pAttrInfo,
  318. CComPtr<IDirectoryObject>& /*spDirObject*/,
  319. PDSGET_DISPLAY_INFO pDisplayInfo)
  320. {
  321. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayAccountExpires, hr);
  322. do // false loop
  323. {
  324. //
  325. // Verify parameters
  326. //
  327. if (!pEntry ||
  328. !pRecord ||
  329. !pDisplayInfo)
  330. {
  331. ASSERT(pEntry);
  332. ASSERT(pRecord);
  333. ASSERT(pDisplayInfo);
  334. hr = E_INVALIDARG;
  335. break;
  336. }
  337. if (pAttrInfo && pAttrInfo->pADsValues)
  338. {
  339. DEBUG_OUTPUT(FULL_LOGGING,
  340. L"Adding %d values:",
  341. pAttrInfo->dwNumValues);
  342. DWORD dwValuesAdded = 0;
  343. for (DWORD dwIdx = 0; dwIdx < pAttrInfo->dwNumValues; dwIdx++)
  344. {
  345. WCHAR* pBuffer = new WCHAR[MAXSTR];
  346. if (!pBuffer)
  347. {
  348. hr = E_OUTOFMEMORY;
  349. break;
  350. }
  351. if (pAttrInfo->pADsValues[dwIdx].LargeInteger.QuadPart == 0 ||
  352. pAttrInfo->pADsValues[dwIdx].LargeInteger.QuadPart == -1 ||
  353. pAttrInfo->pADsValues[dwIdx].LargeInteger.QuadPart == 0x7FFFFFFFFFFFFFFF)
  354. {
  355. wcsncpy(pBuffer, g_pszNever, MAXSTR);
  356. hr = pDisplayInfo->AddValue(pBuffer);
  357. if (FAILED(hr))
  358. {
  359. delete[] pBuffer;
  360. pBuffer = NULL;
  361. break;
  362. }
  363. dwValuesAdded++;
  364. }
  365. else
  366. {
  367. FILETIME ftGMT; // GMT filetime
  368. FILETIME ftLocal; // Local filetime
  369. SYSTEMTIME st;
  370. SYSTEMTIME stGMT;
  371. ZeroMemory(&ftGMT, sizeof(FILETIME));
  372. ZeroMemory(&ftLocal, sizeof(FILETIME));
  373. ZeroMemory(&st, sizeof(SYSTEMTIME));
  374. ZeroMemory(&stGMT, sizeof(SYSTEMTIME));
  375. //Get Local Time in SYSTEMTIME format
  376. ftGMT.dwLowDateTime = pAttrInfo->pADsValues[dwIdx].LargeInteger.LowPart;
  377. ftGMT.dwHighDateTime = pAttrInfo->pADsValues[dwIdx].LargeInteger.HighPart;
  378. FileTimeToSystemTime(&ftGMT, &stGMT);
  379. SystemTimeToTzSpecificLocalTime(NULL, &stGMT,&st);
  380. //For Display Purpose reduce one day
  381. SystemTimeToFileTime(&st, &ftLocal );
  382. pAttrInfo->pADsValues[dwIdx].LargeInteger.LowPart = ftLocal.dwLowDateTime;
  383. pAttrInfo->pADsValues[dwIdx].LargeInteger.HighPart = ftLocal.dwHighDateTime;
  384. pAttrInfo->pADsValues[dwIdx].LargeInteger.QuadPart -= DSCMD_FILETIMES_PER_DAY;
  385. ftLocal.dwLowDateTime = pAttrInfo->pADsValues[dwIdx].LargeInteger.LowPart;
  386. ftLocal.dwHighDateTime = pAttrInfo->pADsValues[dwIdx].LargeInteger.HighPart;
  387. FileTimeToSystemTime(&ftLocal, &st);
  388. // Format the string with respect to locale
  389. if (!GetDateFormat(LOCALE_USER_DEFAULT, 0 ,
  390. &st, NULL,
  391. pBuffer, MAXSTR))
  392. {
  393. hr = GetLastError();
  394. DEBUG_OUTPUT(LEVEL5_LOGGING,
  395. L"Failed to locale string for date: hr = 0x%x",
  396. hr);
  397. }
  398. else
  399. {
  400. hr = pDisplayInfo->AddValue(pBuffer);
  401. if (FAILED(hr))
  402. {
  403. delete[] pBuffer;
  404. pBuffer = NULL;
  405. break;
  406. }
  407. dwValuesAdded++;
  408. }
  409. }
  410. delete[] pBuffer;
  411. pBuffer = NULL;
  412. }
  413. }
  414. } while (false);
  415. return hr;
  416. }
  417. HRESULT DisplayGroupScope(PCWSTR /*pszDN*/,
  418. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  419. const CDSCmdCredentialObject& /*refCredentialObject*/,
  420. _DSGetObjectTableEntry* pEntry,
  421. ARG_RECORD* pRecord,
  422. PADS_ATTR_INFO pAttrInfo,
  423. CComPtr<IDirectoryObject>& /*spDirObject*/,
  424. PDSGET_DISPLAY_INFO pDisplayInfo)
  425. {
  426. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayGroupScope, hr);
  427. do // false loop
  428. {
  429. //
  430. // Verify parameters
  431. //
  432. if (!pEntry ||
  433. !pRecord ||
  434. !pDisplayInfo)
  435. {
  436. ASSERT(pEntry);
  437. ASSERT(pRecord);
  438. ASSERT(pDisplayInfo);
  439. hr = E_INVALIDARG;
  440. break;
  441. }
  442. if (pAttrInfo->pADsValues && pAttrInfo->dwADsType == ADSTYPE_INTEGER)
  443. {
  444. DEBUG_OUTPUT(FULL_LOGGING,
  445. L"Adding %d values:",
  446. pAttrInfo->dwNumValues);
  447. if (pAttrInfo->pADsValues->Integer & GROUP_TYPE_RESOURCE_GROUP)
  448. {
  449. //
  450. // Display Domain Local
  451. //
  452. DEBUG_OUTPUT(LEVEL8_LOGGING,
  453. L"Group scope: domain local");
  454. hr = pDisplayInfo->AddValue(L"domain local");
  455. }
  456. else if (pAttrInfo->pADsValues->Integer & GROUP_TYPE_ACCOUNT_GROUP)
  457. {
  458. //
  459. // Display Global
  460. //
  461. DEBUG_OUTPUT(LEVEL8_LOGGING,
  462. L"Group scope: global");
  463. hr = pDisplayInfo->AddValue(L"global");
  464. }
  465. else if (pAttrInfo->pADsValues->Integer & GROUP_TYPE_UNIVERSAL_GROUP)
  466. {
  467. //
  468. // Display Universal
  469. //
  470. DEBUG_OUTPUT(LEVEL8_LOGGING,
  471. L"Group scope: universal");
  472. hr = pDisplayInfo->AddValue(L"universal");
  473. }
  474. else
  475. {
  476. //
  477. // Unknown group type???
  478. //
  479. DEBUG_OUTPUT(LEVEL8_LOGGING,
  480. L"Group scope: unknown???");
  481. hr = pDisplayInfo->AddValue(L"unknown");
  482. }
  483. }
  484. } while (false);
  485. return hr;
  486. }
  487. HRESULT DisplayGroupSecurityEnabled(PCWSTR /*pszDN*/,
  488. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  489. const CDSCmdCredentialObject& /*refCredentialObject*/,
  490. _DSGetObjectTableEntry* pEntry,
  491. ARG_RECORD* pRecord,
  492. PADS_ATTR_INFO pAttrInfo,
  493. CComPtr<IDirectoryObject>& /*spDirObject*/,
  494. PDSGET_DISPLAY_INFO pDisplayInfo)
  495. {
  496. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayGroupSecurityEnabled, hr);
  497. do // false loop
  498. {
  499. //
  500. // Verify parameters
  501. //
  502. if (!pEntry ||
  503. !pRecord ||
  504. !pDisplayInfo)
  505. {
  506. ASSERT(pEntry);
  507. ASSERT(pRecord);
  508. ASSERT(pDisplayInfo);
  509. hr = E_INVALIDARG;
  510. break;
  511. }
  512. if (pAttrInfo->pADsValues && pAttrInfo->dwADsType == ADSTYPE_INTEGER)
  513. {
  514. DEBUG_OUTPUT(FULL_LOGGING,
  515. L"Adding %d value:",
  516. 1);
  517. bool bSecurityEnabled = false;
  518. if (pAttrInfo->pADsValues->Integer & GROUP_TYPE_SECURITY_ENABLED)
  519. {
  520. bSecurityEnabled = true;
  521. }
  522. DEBUG_OUTPUT(LEVEL8_LOGGING,
  523. L"Group security enabled: %s",
  524. bSecurityEnabled ? g_pszYes : g_pszNo);
  525. hr = pDisplayInfo->AddValue(bSecurityEnabled ? g_pszYes : g_pszNo);
  526. }
  527. } while (false);
  528. return hr;
  529. }
  530. //+--------------------------------------------------------------------------
  531. //
  532. // Function: ConvertRIDtoDN
  533. //
  534. // Synopsis: Finds the DN for the group associated with the primary group ID
  535. //
  536. // Arguments: [pObjSID IN] : SID of the object in question
  537. // [priGroupRID IN] : primary group ID of the group to be found
  538. // [refBasePathsInfo IN] : reference to base paths info
  539. // [refCredObject IN] : reference to the credential manager object
  540. // [refsbstrdN OUT] : DN of the group
  541. //
  542. // Returns: S_OK if everthing succeeds and a group was found
  543. // S_FALSE if everthing succeeds but no group was found
  544. // E_INVALIDARG is an argument is incorrect
  545. // Anything else was a result of a failed ADSI call
  546. //
  547. // History: 24-Oct-2000 JeffJon Created
  548. //
  549. //---------------------------------------------------------------------------
  550. HRESULT ConvertRIDtoDN(PSID pObjSID,
  551. DWORD priGroupRID,
  552. CDSCmdBasePathsInfo& refBasePathsInfo,
  553. const CDSCmdCredentialObject& refCredObject,
  554. CComBSTR& refsbstrDN)
  555. {
  556. ENTER_FUNCTION_HR(LEVEL5_LOGGING, ConvertRIDtoDN, hr);
  557. //
  558. // This needs to be cleaned up no matter how we exit the false loop
  559. //
  560. PWSTR pszSearchFilter = NULL;
  561. do // false loop
  562. {
  563. //
  564. // Verify parameters
  565. //
  566. if (!pObjSID ||
  567. !priGroupRID)
  568. {
  569. ASSERT(pObjSID);
  570. ASSERT(priGroupRID);
  571. hr = E_INVALIDARG;
  572. break;
  573. }
  574. UCHAR * psaCount, i;
  575. PSID pSID = NULL;
  576. PSID_IDENTIFIER_AUTHORITY psia;
  577. DWORD rgRid[8];
  578. psaCount = GetSidSubAuthorityCount(pObjSID);
  579. if (psaCount == NULL)
  580. {
  581. hr = HRESULT_FROM_WIN32(GetLastError());
  582. DEBUG_OUTPUT(MINIMAL_LOGGING,
  583. L"GetSidSubAuthorityCount failed: hr = 0x%x",
  584. hr);
  585. break;
  586. }
  587. if (*psaCount > 8)
  588. {
  589. DEBUG_OUTPUT(MINIMAL_LOGGING,
  590. L"The count returned from GetSidSubAuthorityCount was too high: %d",
  591. *psaCount);
  592. hr = E_FAIL;
  593. break;
  594. }
  595. for (i = 0; i < (*psaCount - 1); i++)
  596. {
  597. PDWORD pRid = GetSidSubAuthority(pObjSID, (DWORD)i);
  598. if (pRid == NULL)
  599. {
  600. hr = HRESULT_FROM_WIN32(GetLastError());
  601. DEBUG_OUTPUT(MINIMAL_LOGGING,
  602. L"GetSidSubAuthority for index %i failed: hr = 0x%x",
  603. i,
  604. hr);
  605. break;
  606. }
  607. rgRid[i] = *pRid;
  608. }
  609. if (FAILED(hr))
  610. {
  611. break;
  612. }
  613. rgRid[*psaCount - 1] = priGroupRID;
  614. for (i = *psaCount; i < 8; i++)
  615. {
  616. rgRid[i] = 0;
  617. }
  618. psia = GetSidIdentifierAuthority(pObjSID);
  619. if (psia == NULL)
  620. {
  621. hr = HRESULT_FROM_WIN32(GetLastError());
  622. DEBUG_OUTPUT(MINIMAL_LOGGING,
  623. L"GetSidIdentifierAuthority failed: hr = 0x%x",
  624. hr);
  625. break;
  626. }
  627. if (!AllocateAndInitializeSid(psia, *psaCount, rgRid[0], rgRid[1],
  628. rgRid[2], rgRid[3], rgRid[4],
  629. rgRid[5], rgRid[6], rgRid[7], &pSID))
  630. {
  631. hr = HRESULT_FROM_WIN32(GetLastError());
  632. DEBUG_OUTPUT(MINIMAL_LOGGING,
  633. L"AllocateAndInitializeSid failed: hr = 0x%x",
  634. hr);
  635. break;
  636. }
  637. PWSTR rgpwzAttrNames[] = { L"ADsPath" };
  638. const WCHAR wzSearchFormat[] = L"(&(objectCategory=group)(objectSid=%s))";
  639. PWSTR pwzSID;
  640. hr = ADsEncodeBinaryData((PBYTE)pSID, GetLengthSid(pSID), &pwzSID);
  641. if (FAILED(hr))
  642. {
  643. DEBUG_OUTPUT(MINIMAL_LOGGING,
  644. L"ADsEncodeBinaryData failed: hr = 0x%x",
  645. hr);
  646. break;
  647. }
  648. pszSearchFilter = new WCHAR[wcslen(pwzSID) + wcslen(wzSearchFormat) + 1];
  649. if (!pszSearchFilter)
  650. {
  651. hr = E_OUTOFMEMORY;
  652. break;
  653. }
  654. wsprintf(pszSearchFilter, wzSearchFormat, pwzSID);
  655. FreeADsMem(pwzSID);
  656. //
  657. // Get the domain path
  658. //
  659. CComBSTR sbstrDomainDN;
  660. sbstrDomainDN = refBasePathsInfo.GetDefaultNamingContext();
  661. CComBSTR sbstrDomainPath;
  662. refBasePathsInfo.ComposePathFromDN(sbstrDomainDN, sbstrDomainPath);
  663. //
  664. // Get an IDirectorySearch interface to the domain
  665. //
  666. CComPtr<IDirectorySearch> spDirSearch;
  667. hr = DSCmdOpenObject(refCredObject,
  668. sbstrDomainPath,
  669. IID_IDirectorySearch,
  670. (void**)&spDirSearch,
  671. true);
  672. if (FAILED(hr))
  673. {
  674. break;
  675. }
  676. CDSSearch Search;
  677. hr = Search.Init(spDirSearch);
  678. if (FAILED(hr))
  679. {
  680. DEBUG_OUTPUT(MINIMAL_LOGGING,
  681. L"Failed to initialize the search object: hr = 0x%x",
  682. hr);
  683. break;
  684. }
  685. Search.SetFilterString(pszSearchFilter);
  686. Search.SetAttributeList(rgpwzAttrNames, 1);
  687. Search.SetSearchScope(ADS_SCOPE_SUBTREE);
  688. hr = Search.DoQuery();
  689. if (FAILED(hr))
  690. {
  691. DEBUG_OUTPUT(MINIMAL_LOGGING,
  692. L"Failed to run search: hr = 0x%x",
  693. hr);
  694. break;
  695. }
  696. hr = Search.GetNextRow();
  697. if (hr == S_ADS_NOMORE_ROWS)
  698. {
  699. DEBUG_OUTPUT(LEVEL5_LOGGING,
  700. L"No group was found with primaryGroupID = %d",
  701. priGroupRID);
  702. //
  703. // No object has a matching RID, the primary group must have been
  704. // deleted. Return S_FALSE to denote this condition.
  705. //
  706. hr = S_FALSE;
  707. break;
  708. }
  709. if (FAILED(hr))
  710. {
  711. break;
  712. }
  713. ADS_SEARCH_COLUMN Column;
  714. hr = Search.GetColumn(L"ADsPath", &Column);
  715. if (FAILED(hr))
  716. {
  717. DEBUG_OUTPUT(MINIMAL_LOGGING,
  718. L"Failed to get the path column: hr = 0x%x",
  719. hr);
  720. break;
  721. }
  722. if (!Column.pADsValues->CaseIgnoreString)
  723. {
  724. hr = E_FAIL;
  725. break;
  726. }
  727. refsbstrDN = Column.pADsValues->CaseIgnoreString;
  728. Search.FreeColumn(&Column);
  729. } while (false);
  730. //
  731. // Cleanup
  732. //
  733. if (pszSearchFilter)
  734. {
  735. delete[] pszSearchFilter;
  736. pszSearchFilter = NULL;
  737. }
  738. return hr;
  739. }
  740. //+--------------------------------------------------------------------------
  741. //
  742. // Function: AddMemberOfValues
  743. //
  744. // Synopsis: Retrieves the DNs of the objects to which the current object
  745. // is a member
  746. //
  747. // Arguments: [pszDN IN] : DN of object to retrieve member of
  748. // [pszClass IN] : Class of object to retrieve member of
  749. // [refBasePathsInfo IN] : reference to Base paths info object
  750. // [refCredentialObject IN] : reference to Credential management object
  751. // [pDirObject IN] : IDirectoryObject pointer to object
  752. // [pDisplayInfo IN/OUT] : Pointer to display info for this attribute
  753. // [bRecurse IN] : Should we find the memberOf for each memberOf
  754. //
  755. // Returns: S_OK if everthing succeeds
  756. // E_INVALIDARG is an argument is incorrect
  757. // Anything else was a result of a failed ADSI call
  758. //
  759. // History: 24-Oct-2000 JeffJon Created
  760. //
  761. //---------------------------------------------------------------------------
  762. HRESULT AddMemberOfValues(PCWSTR pszDN,
  763. PCWSTR pszClass,
  764. CDSCmdBasePathsInfo& refBasePathsInfo,
  765. const CDSCmdCredentialObject& refCredentialObject,
  766. IDirectoryObject* pDirObject,
  767. PDSGET_DISPLAY_INFO pDisplayInfo,
  768. CManagedStringList& refGroupsDisplayed,
  769. bool bRecurse = false)
  770. {
  771. ENTER_FUNCTION_HR(LEVEL5_LOGGING, AddMemberOfValues, hr);
  772. //
  773. // These are declared here so that we can free them if we break out of the false loop
  774. //
  775. PADS_ATTR_INFO pAttrInfo = NULL;
  776. PADS_ATTR_INFO pGCAttrInfo = NULL;
  777. PSID pObjSID = NULL;
  778. do // false loop
  779. {
  780. //
  781. // Verify parameters
  782. //
  783. if (!pszDN ||
  784. !pDisplayInfo)
  785. {
  786. ASSERT(pszDN);
  787. ASSERT(pDisplayInfo);
  788. hr = E_INVALIDARG;
  789. break;
  790. }
  791. CComPtr<IDirectoryObject> spDirObject;
  792. if (pDirObject)
  793. {
  794. //
  795. // Use the currently bound object
  796. // This should only happen on the first call.
  797. // All recursive calls should have this NULL
  798. //
  799. spDirObject = pDirObject;
  800. }
  801. else
  802. {
  803. //
  804. // We have to open the object
  805. //
  806. CComBSTR sbstrPath;
  807. refBasePathsInfo.ComposePathFromDN(pszDN, sbstrPath);
  808. hr = DSCmdOpenObject(refCredentialObject,
  809. sbstrPath,
  810. IID_IDirectoryObject,
  811. (void**)&spDirObject,
  812. true);
  813. if (FAILED(hr))
  814. {
  815. break;
  816. }
  817. }
  818. CComBSTR sbstrClass;
  819. if (!pszClass)
  820. {
  821. CComPtr<IADs> spIADs;
  822. hr = spDirObject->QueryInterface(IID_IADs, (void**)&spIADs);
  823. if (FAILED(hr))
  824. {
  825. break;
  826. }
  827. hr = spIADs->get_Class(&sbstrClass);
  828. if (FAILED(hr))
  829. {
  830. break;
  831. }
  832. }
  833. else
  834. {
  835. sbstrClass = pszClass;
  836. }
  837. //
  838. // Read the memberOf attribute and any attributes we need for that specific class
  839. //
  840. if (_wcsicmp(sbstrClass, g_pszUser) == 0 ||
  841. _wcsicmp(sbstrClass, g_pszComputer) == 0)
  842. {
  843. DEBUG_OUTPUT(FULL_LOGGING, L"Displaying membership for a group or computer");
  844. static const DWORD dwAttrCount = 3;
  845. PWSTR ppszAttrNames[] = { L"memberOf", L"primaryGroupID", L"objectSID" };
  846. DWORD dwAttrsReturned = 0;
  847. hr = spDirObject->GetObjectAttributes(ppszAttrNames,
  848. dwAttrCount,
  849. &pAttrInfo,
  850. &dwAttrsReturned);
  851. if (FAILED(hr))
  852. {
  853. DEBUG_OUTPUT(MINIMAL_LOGGING,
  854. L"GetObjectAttributes failed for class %s: hr = 0x%x",
  855. sbstrClass,
  856. hr);
  857. break;
  858. }
  859. if (pAttrInfo && dwAttrsReturned)
  860. {
  861. DWORD priGroupRID = 0;
  862. //
  863. // For each attribute returned do the appropriate thing
  864. //
  865. for (DWORD dwIdx = 0; dwIdx < dwAttrsReturned; dwIdx++)
  866. {
  867. if (_wcsicmp(pAttrInfo[dwIdx].pszAttrName, L"memberOf") == 0)
  868. {
  869. //
  870. // Add each value and recurse if necessary
  871. //
  872. for (DWORD dwValueIdx = 0; dwValueIdx < pAttrInfo[dwIdx].dwNumValues; dwValueIdx++)
  873. {
  874. if (pAttrInfo[dwIdx].pADsValues &&
  875. pAttrInfo[dwIdx].pADsValues[dwValueIdx].DNString)
  876. {
  877. if (!refGroupsDisplayed.Contains(pAttrInfo[dwIdx].pADsValues[dwValueIdx].DNString))
  878. {
  879. refGroupsDisplayed.Add(pAttrInfo[dwIdx].pADsValues[dwValueIdx].DNString);
  880. hr = pDisplayInfo->AddValue(pAttrInfo[dwIdx].pADsValues[dwValueIdx].DNString);
  881. if (FAILED(hr))
  882. {
  883. break; // value for loop
  884. }
  885. if (bRecurse)
  886. {
  887. hr = AddMemberOfValues(pAttrInfo[dwIdx].pADsValues[dwValueIdx].DNString,
  888. NULL,
  889. refBasePathsInfo,
  890. refCredentialObject,
  891. NULL,
  892. pDisplayInfo,
  893. refGroupsDisplayed,
  894. bRecurse);
  895. if (FAILED(hr))
  896. {
  897. break; // value for loop
  898. }
  899. }
  900. }
  901. }
  902. }
  903. if (FAILED(hr))
  904. {
  905. break; // attrs for loop
  906. }
  907. }
  908. else if (_wcsicmp(pAttrInfo[dwIdx].pszAttrName, L"primaryGroupID") == 0)
  909. {
  910. if (pAttrInfo[dwIdx].pADsValues)
  911. {
  912. priGroupRID = pAttrInfo[dwIdx].pADsValues->Integer;
  913. }
  914. }
  915. else if (_wcsicmp(pAttrInfo[dwIdx].pszAttrName, L"objectSID") == 0)
  916. {
  917. pObjSID = new BYTE[pAttrInfo[dwIdx].pADsValues->OctetString.dwLength];
  918. if (!pObjSID)
  919. {
  920. hr = E_OUTOFMEMORY;
  921. break; // attrs for loop
  922. }
  923. memcpy(pObjSID, pAttrInfo[dwIdx].pADsValues->OctetString.lpValue,
  924. pAttrInfo[dwIdx].pADsValues->OctetString.dwLength);
  925. }
  926. } // attrs for loop
  927. //
  928. // if we were able to retrieve the SID and the primaryGroupID,
  929. // then convert that into the DN of the group
  930. //
  931. if (pObjSID &&
  932. priGroupRID)
  933. {
  934. CComBSTR sbstrPath;
  935. hr = ConvertRIDtoDN(pObjSID,
  936. priGroupRID,
  937. refBasePathsInfo,
  938. refCredentialObject,
  939. sbstrPath);
  940. if (SUCCEEDED(hr) &&
  941. hr != S_FALSE)
  942. {
  943. CComBSTR sbstrDN;
  944. hr = CPathCracker::GetDNFromPath(sbstrPath, sbstrDN);
  945. if (SUCCEEDED(hr))
  946. {
  947. if (!refGroupsDisplayed.Contains(sbstrDN))
  948. {
  949. refGroupsDisplayed.Add(sbstrDN);
  950. hr = pDisplayInfo->AddValue(sbstrDN);
  951. if (SUCCEEDED(hr) && bRecurse)
  952. {
  953. hr = AddMemberOfValues(sbstrDN,
  954. NULL,
  955. refBasePathsInfo,
  956. refCredentialObject,
  957. NULL,
  958. pDisplayInfo,
  959. refGroupsDisplayed,
  960. bRecurse);
  961. if (FAILED(hr))
  962. {
  963. break; // false do loop
  964. }
  965. }
  966. }
  967. }
  968. }
  969. }
  970. if (FAILED(hr))
  971. {
  972. break; // false do loop
  973. }
  974. }
  975. if (pAttrInfo)
  976. {
  977. FreeADsMem(pAttrInfo);
  978. pAttrInfo = NULL;
  979. }
  980. }
  981. else if (_wcsicmp(sbstrClass, g_pszGroup) == 0)
  982. {
  983. long lGroupType = 0;
  984. hr = ReadGroupType(pszDN,
  985. refBasePathsInfo,
  986. refCredentialObject,
  987. &lGroupType);
  988. if (FAILED(hr))
  989. {
  990. DEBUG_OUTPUT(MINIMAL_LOGGING,
  991. L"Could not read group type: hr = 0x%x",
  992. hr);
  993. break;
  994. }
  995. //
  996. // All we want to do is get the memberOf attribute
  997. //
  998. DWORD dwAttrCount = 1;
  999. PWSTR ppszAttrNames[] = { L"memberOf" };
  1000. DWORD dwGCAttrsReturned = 0;
  1001. if (!(lGroupType & GROUP_TYPE_RESOURCE_GROUP))
  1002. {
  1003. //
  1004. // We also have to get its memberOf attribute from the GC if its not a local group
  1005. //
  1006. CComBSTR sbstrGCPath;
  1007. refBasePathsInfo.ComposePathFromDN(pszDN,
  1008. sbstrGCPath,
  1009. DSCMD_GC_PROVIDER);
  1010. //
  1011. // Note: we will continue on as long as we succeed
  1012. //
  1013. CComPtr<IDirectoryObject> spGCDirObject;
  1014. hr = DSCmdOpenObject(refCredentialObject,
  1015. sbstrGCPath,
  1016. IID_IDirectoryObject,
  1017. (void**)&spGCDirObject,
  1018. false);
  1019. if (SUCCEEDED(hr))
  1020. {
  1021. //
  1022. // Now get the memberOf attribute
  1023. //
  1024. hr = spGCDirObject->GetObjectAttributes(ppszAttrNames,
  1025. dwAttrCount,
  1026. &pGCAttrInfo,
  1027. &dwGCAttrsReturned);
  1028. if (FAILED(hr))
  1029. {
  1030. DEBUG_OUTPUT(LEVEL3_LOGGING,
  1031. L"Could not retrieve memberOf attribute from GC: hr = 0x%x",
  1032. hr);
  1033. hr = S_OK;
  1034. }
  1035. }
  1036. else
  1037. {
  1038. DEBUG_OUTPUT(LEVEL3_LOGGING,
  1039. L"Could not bind to object in GC: hr = 0x%x",
  1040. hr);
  1041. hr = S_OK;
  1042. }
  1043. }
  1044. DWORD dwAttrsReturned = 0;
  1045. hr = spDirObject->GetObjectAttributes(ppszAttrNames,
  1046. dwAttrCount,
  1047. &pAttrInfo,
  1048. &dwAttrsReturned);
  1049. if (FAILED(hr))
  1050. {
  1051. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1052. L"GetObjectAttributes failed for class %s: hr = 0x%x",
  1053. sbstrClass,
  1054. hr);
  1055. break;
  1056. }
  1057. if (pAttrInfo && dwAttrsReturned)
  1058. {
  1059. bool bFirstPass = true;
  1060. ASSERT(dwAttrsReturned == 1);
  1061. ASSERT(_wcsicmp(pAttrInfo->pszAttrName, L"memberOf") == 0);
  1062. //
  1063. // Add each value and recurse if necessary
  1064. //
  1065. for (DWORD dwValueIdx = 0; dwValueIdx < pAttrInfo->dwNumValues; dwValueIdx++)
  1066. {
  1067. bool bExistsInGCList = false;
  1068. if (pAttrInfo->pADsValues &&
  1069. pAttrInfo->pADsValues[dwValueIdx].DNString)
  1070. {
  1071. if (pGCAttrInfo && dwGCAttrsReturned)
  1072. {
  1073. //
  1074. // Only add if it wasn't in the GC list
  1075. //
  1076. for (DWORD dwGCValueIdx = 0; dwGCValueIdx < pGCAttrInfo->dwNumValues; dwGCValueIdx++)
  1077. {
  1078. if (_wcsicmp(pAttrInfo->pADsValues[dwValueIdx].DNString,
  1079. pGCAttrInfo->pADsValues[dwGCValueIdx].DNString) == 0)
  1080. {
  1081. bExistsInGCList = true;
  1082. if (!bFirstPass)
  1083. {
  1084. break; // gc value for
  1085. }
  1086. }
  1087. //
  1088. // Add all the GC values on the first pass and recurse if necessary
  1089. //
  1090. if (bFirstPass)
  1091. {
  1092. if (!refGroupsDisplayed.Contains(pGCAttrInfo->pADsValues[dwGCValueIdx].DNString))
  1093. {
  1094. refGroupsDisplayed.Add(pGCAttrInfo->pADsValues[dwGCValueIdx].DNString);
  1095. hr = pDisplayInfo->AddValue(pGCAttrInfo->pADsValues[dwGCValueIdx].DNString);
  1096. //
  1097. // We will ignore failures with the GC list
  1098. //
  1099. if (bRecurse)
  1100. {
  1101. hr = AddMemberOfValues(pGCAttrInfo->pADsValues[dwGCValueIdx].DNString,
  1102. NULL,
  1103. refBasePathsInfo,
  1104. refCredentialObject,
  1105. NULL,
  1106. pDisplayInfo,
  1107. refGroupsDisplayed,
  1108. bRecurse);
  1109. }
  1110. }
  1111. }
  1112. }
  1113. bFirstPass = false;
  1114. }
  1115. //
  1116. // If it doesn't exist in the GC list then add it.
  1117. //
  1118. if (!bExistsInGCList)
  1119. {
  1120. if (!refGroupsDisplayed.Contains(pAttrInfo->pADsValues[dwValueIdx].DNString))
  1121. {
  1122. refGroupsDisplayed.Add(pAttrInfo->pADsValues[dwValueIdx].DNString);
  1123. hr = pDisplayInfo->AddValue(pAttrInfo->pADsValues[dwValueIdx].DNString);
  1124. if (FAILED(hr))
  1125. {
  1126. break; // value for loop
  1127. }
  1128. if (bRecurse)
  1129. {
  1130. hr = AddMemberOfValues(pAttrInfo->pADsValues[dwValueIdx].DNString,
  1131. NULL,
  1132. refBasePathsInfo,
  1133. refCredentialObject,
  1134. NULL,
  1135. pDisplayInfo,
  1136. refGroupsDisplayed,
  1137. bRecurse);
  1138. if (FAILED(hr))
  1139. {
  1140. break; // value for loop
  1141. }
  1142. }
  1143. }
  1144. }
  1145. }
  1146. } // value for loop
  1147. if (FAILED(hr))
  1148. {
  1149. break; // false do loop
  1150. }
  1151. }
  1152. }
  1153. else
  1154. {
  1155. DEBUG_OUTPUT(MINIMAL_LOGGING, L"Unknown class type: %s", sbstrClass);
  1156. ASSERT(false);
  1157. hr = E_INVALIDARG;
  1158. break;
  1159. }
  1160. } while (false);
  1161. //
  1162. // Cleanup
  1163. //
  1164. if (pAttrInfo)
  1165. {
  1166. FreeADsMem(pAttrInfo);
  1167. pAttrInfo = NULL;
  1168. }
  1169. if (pGCAttrInfo)
  1170. {
  1171. FreeADsMem(pGCAttrInfo);
  1172. pGCAttrInfo = NULL;
  1173. }
  1174. if (pObjSID)
  1175. {
  1176. delete[] pObjSID;
  1177. pObjSID = NULL;
  1178. }
  1179. return hr;
  1180. }
  1181. HRESULT DisplayUserMemberOf(PCWSTR pszDN,
  1182. CDSCmdBasePathsInfo& refBasePathsInfo,
  1183. const CDSCmdCredentialObject& refCredentialObject,
  1184. _DSGetObjectTableEntry* pEntry,
  1185. ARG_RECORD* pCommandArgs,
  1186. PADS_ATTR_INFO pAttrInfo,
  1187. CComPtr<IDirectoryObject>& spDirObject,
  1188. PDSGET_DISPLAY_INFO pDisplayInfo)
  1189. {
  1190. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayUserMemberOf, hr);
  1191. do // false loop
  1192. {
  1193. //
  1194. // Verify parameters
  1195. //
  1196. if (!pszDN ||
  1197. !pEntry ||
  1198. !pCommandArgs ||
  1199. !pAttrInfo ||
  1200. !pDisplayInfo)
  1201. {
  1202. ASSERT(pEntry);
  1203. ASSERT(pCommandArgs);
  1204. ASSERT(pDisplayInfo);
  1205. hr = E_INVALIDARG;
  1206. break;
  1207. }
  1208. //
  1209. // This list is used to keep from going into infinite recursion
  1210. // if there is circular group membership
  1211. //
  1212. CManagedStringList groupsDisplayed;
  1213. hr = AddMemberOfValues(pszDN,
  1214. g_pszUser,
  1215. refBasePathsInfo,
  1216. refCredentialObject,
  1217. spDirObject,
  1218. pDisplayInfo,
  1219. groupsDisplayed,
  1220. (pCommandArgs[eUserExpand].bDefined != 0));
  1221. } while (false);
  1222. return hr;
  1223. }
  1224. HRESULT DisplayComputerMemberOf(PCWSTR pszDN,
  1225. CDSCmdBasePathsInfo& refBasePathsInfo,
  1226. const CDSCmdCredentialObject& refCredentialObject,
  1227. _DSGetObjectTableEntry* pEntry,
  1228. ARG_RECORD* pCommandArgs,
  1229. PADS_ATTR_INFO /*pAttrInfo*/,
  1230. CComPtr<IDirectoryObject>& spDirObject,
  1231. PDSGET_DISPLAY_INFO pDisplayInfo)
  1232. {
  1233. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayComputerMemberOf, hr);
  1234. do // false loop
  1235. {
  1236. //
  1237. // Verify parameters
  1238. //
  1239. if (!pEntry ||
  1240. !pCommandArgs ||
  1241. !pDisplayInfo)
  1242. {
  1243. ASSERT(pEntry);
  1244. ASSERT(pCommandArgs);
  1245. ASSERT(pDisplayInfo);
  1246. hr = E_INVALIDARG;
  1247. break;
  1248. }
  1249. //
  1250. // This list is used to keep from going into infinite recursion
  1251. // if there is circular group membership
  1252. //
  1253. CManagedStringList groupsDisplayed;
  1254. hr = AddMemberOfValues(pszDN,
  1255. g_pszComputer,
  1256. refBasePathsInfo,
  1257. refCredentialObject,
  1258. spDirObject,
  1259. pDisplayInfo,
  1260. groupsDisplayed,
  1261. (pCommandArgs[eComputerExpand].bDefined != 0));
  1262. } while (false);
  1263. return hr;
  1264. }
  1265. HRESULT DisplayGroupMemberOf(PCWSTR pszDN,
  1266. CDSCmdBasePathsInfo& refBasePathsInfo,
  1267. const CDSCmdCredentialObject& refCredentialObject,
  1268. _DSGetObjectTableEntry* pEntry,
  1269. ARG_RECORD* pCommandArgs,
  1270. PADS_ATTR_INFO /*pAttrInfo*/,
  1271. CComPtr<IDirectoryObject>& spDirObject,
  1272. PDSGET_DISPLAY_INFO pDisplayInfo)
  1273. {
  1274. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayGroupMemberOf, hr);
  1275. do // false loop
  1276. {
  1277. //
  1278. // Verify parameters
  1279. //
  1280. if (!pEntry ||
  1281. !pCommandArgs ||
  1282. !pDisplayInfo)
  1283. {
  1284. ASSERT(pEntry);
  1285. ASSERT(pCommandArgs);
  1286. ASSERT(pDisplayInfo);
  1287. hr = E_INVALIDARG;
  1288. break;
  1289. }
  1290. //
  1291. // This list is used to keep from going into infinite recursion
  1292. // if there is circular group membership
  1293. //
  1294. CManagedStringList groupsDisplayed;
  1295. hr = AddMemberOfValues(pszDN,
  1296. g_pszGroup,
  1297. refBasePathsInfo,
  1298. refCredentialObject,
  1299. spDirObject,
  1300. pDisplayInfo,
  1301. groupsDisplayed,
  1302. (pCommandArgs[eGroupExpand].bDefined != 0));
  1303. } while (false);
  1304. return hr;
  1305. }
  1306. HRESULT DisplayGrandparentRDN(PCWSTR pszDN,
  1307. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  1308. const CDSCmdCredentialObject& /*refCredentialObject*/,
  1309. _DSGetObjectTableEntry* /*pEntry*/,
  1310. ARG_RECORD* /*pCommandArgs*/,
  1311. PADS_ATTR_INFO /*pAttrInfo*/,
  1312. CComPtr<IDirectoryObject>& /*spDirObject*/,
  1313. PDSGET_DISPLAY_INFO pDisplayInfo)
  1314. {
  1315. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayGrandparentRDN, hr);
  1316. do // false loop
  1317. {
  1318. //
  1319. // Verify parameters
  1320. //
  1321. if (!pszDN ||
  1322. !pDisplayInfo)
  1323. {
  1324. ASSERT(pszDN);
  1325. ASSERT(pDisplayInfo);
  1326. hr = E_INVALIDARG;
  1327. break;
  1328. }
  1329. CComBSTR sbstrSiteName;
  1330. CPathCracker pathCracker;
  1331. hr = pathCracker.Set(const_cast<PWSTR>(pszDN), ADS_SETTYPE_DN);
  1332. if (FAILED(hr))
  1333. {
  1334. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1335. L"IADsPathname::Set failed: hr = 0x%x",
  1336. hr);
  1337. break;
  1338. }
  1339. hr = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  1340. if (FAILED(hr))
  1341. {
  1342. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1343. L"IADsPathname::SetDisplayType failed: hr = 0x%x",
  1344. hr);
  1345. break;
  1346. }
  1347. hr = pathCracker.GetElement(2, &sbstrSiteName);
  1348. if (FAILED(hr))
  1349. {
  1350. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1351. L"IADsPathname::GetElement failed: hr = 0x%x",
  1352. hr);
  1353. break;
  1354. }
  1355. hr = pDisplayInfo->AddValue(sbstrSiteName);
  1356. } while (false);
  1357. return hr;
  1358. }
  1359. HRESULT IsServerGCDisplay(PCWSTR pszDN,
  1360. CDSCmdBasePathsInfo& refBasePathsInfo,
  1361. const CDSCmdCredentialObject& refCredentialObject,
  1362. _DSGetObjectTableEntry* /*pEntry*/,
  1363. ARG_RECORD* /*pCommandArgs*/,
  1364. PADS_ATTR_INFO /*pAttrInfo*/,
  1365. CComPtr<IDirectoryObject>& /*spDirObject*/,
  1366. PDSGET_DISPLAY_INFO pDisplayInfo)
  1367. {
  1368. ENTER_FUNCTION_HR(LEVEL5_LOGGING, IsServerGCDisplay, hr);
  1369. do // false loop
  1370. {
  1371. //
  1372. // Verify parameters
  1373. //
  1374. if (!pszDN ||
  1375. !pDisplayInfo)
  1376. {
  1377. ASSERT(pszDN);
  1378. ASSERT(pDisplayInfo);
  1379. hr = E_INVALIDARG;
  1380. break;
  1381. }
  1382. //
  1383. // Compose the path to the NTDS settings object from the server DN
  1384. //
  1385. CComBSTR sbstrNTDSSettingsDN;
  1386. sbstrNTDSSettingsDN = L"CN=NTDS Settings,";
  1387. sbstrNTDSSettingsDN += pszDN;
  1388. CComBSTR sbstrNTDSSettingsPath;
  1389. refBasePathsInfo.ComposePathFromDN(sbstrNTDSSettingsDN, sbstrNTDSSettingsPath);
  1390. CComPtr<IADs> spADs;
  1391. hr = DSCmdOpenObject(refCredentialObject,
  1392. sbstrNTDSSettingsPath,
  1393. IID_IADs,
  1394. (void**)&spADs,
  1395. true);
  1396. if (FAILED(hr))
  1397. {
  1398. break;
  1399. }
  1400. CComVariant var;
  1401. hr = spADs->Get(L"options", &var);
  1402. if (FAILED(hr))
  1403. {
  1404. DEBUG_OUTPUT(LEVEL5_LOGGING,
  1405. L"Failed to get the options: hr = 0x%x",
  1406. hr);
  1407. break;
  1408. }
  1409. ASSERT(var.vt == VT_I4);
  1410. bool bGC = false;
  1411. if (var.lVal & 0x1)
  1412. {
  1413. bGC = true;
  1414. }
  1415. DEBUG_OUTPUT(LEVEL8_LOGGING,
  1416. L"Server is GC: %s",
  1417. bGC ? g_pszYes : g_pszNo);
  1418. hr = pDisplayInfo->AddValue(bGC ? g_pszYes : g_pszNo);
  1419. } while (false);
  1420. return hr;
  1421. }
  1422. HRESULT FindSiteSettingsOptions(IDirectoryObject* pDirectoryObj,
  1423. DWORD& refOptions)
  1424. {
  1425. ENTER_FUNCTION_HR(LEVEL5_LOGGING, FindSiteSettingsOptions, hr);
  1426. do // false loop
  1427. {
  1428. //
  1429. // Verify parameters
  1430. //
  1431. if (!pDirectoryObj)
  1432. {
  1433. ASSERT(pDirectoryObj);
  1434. hr = E_INVALIDARG;
  1435. break;
  1436. }
  1437. CComPtr<IDirectorySearch> spSearch;
  1438. hr = pDirectoryObj->QueryInterface(IID_IDirectorySearch, (void**)&spSearch);
  1439. if (FAILED(hr))
  1440. {
  1441. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1442. L"QI for IDirectorySearch failed: hr = 0x%x",
  1443. hr);
  1444. break;
  1445. }
  1446. CDSSearch Search;
  1447. hr = Search.Init(spSearch);
  1448. if (FAILED(hr))
  1449. {
  1450. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1451. L"CDSSearch::Init failed: hr = 0x%x",
  1452. hr);
  1453. break;
  1454. }
  1455. PWSTR pszSearchFilter = L"(objectClass=nTDSSiteSettings)";
  1456. Search.SetFilterString(pszSearchFilter);
  1457. PWSTR rgpwzAttrNames[] = { L"options" };
  1458. Search.SetAttributeList(rgpwzAttrNames, 1);
  1459. Search.SetSearchScope(ADS_SCOPE_ONELEVEL);
  1460. hr = Search.DoQuery();
  1461. if (FAILED(hr))
  1462. {
  1463. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1464. L"Failed to run search: hr = 0x%x",
  1465. hr);
  1466. break;
  1467. }
  1468. hr = Search.GetNextRow();
  1469. if (hr == S_ADS_NOMORE_ROWS)
  1470. {
  1471. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1472. L"No rows found!");
  1473. hr = E_FAIL;
  1474. break;
  1475. }
  1476. ADS_SEARCH_COLUMN Column;
  1477. hr = Search.GetColumn(L"options", &Column);
  1478. if (FAILED(hr))
  1479. {
  1480. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1481. L"Failed to get the options column: hr = 0x%x",
  1482. hr);
  1483. break;
  1484. }
  1485. if (Column.dwADsType != ADSTYPE_INTEGER ||
  1486. Column.dwNumValues == 0 ||
  1487. !Column.pADsValues)
  1488. {
  1489. Search.FreeColumn(&Column);
  1490. hr = E_FAIL;
  1491. break;
  1492. }
  1493. refOptions = Column.pADsValues->Integer;
  1494. Search.FreeColumn(&Column);
  1495. } while (false);
  1496. return hr;
  1497. }
  1498. HRESULT IsAutotopologyEnabledSite(PCWSTR /*pszDN*/,
  1499. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  1500. const CDSCmdCredentialObject& /*refCredentialObject*/,
  1501. _DSGetObjectTableEntry* pEntry,
  1502. ARG_RECORD* pCommandArgs,
  1503. PADS_ATTR_INFO /*pAttrInfo*/,
  1504. CComPtr<IDirectoryObject>& spDirObject,
  1505. PDSGET_DISPLAY_INFO pDisplayInfo)
  1506. {
  1507. ENTER_FUNCTION_HR(LEVEL5_LOGGING, IsAutotopologyEnabledSite, hr);
  1508. bool bAutoTopDisabled = false;
  1509. do // false loop
  1510. {
  1511. //
  1512. // Verify parameters
  1513. //
  1514. if (!pEntry ||
  1515. !pCommandArgs ||
  1516. !pDisplayInfo)
  1517. {
  1518. ASSERT(pEntry);
  1519. ASSERT(pCommandArgs);
  1520. ASSERT(pDisplayInfo);
  1521. hr = E_INVALIDARG;
  1522. break;
  1523. }
  1524. //
  1525. // Get the options attribute from the nTDSSiteSettings object under the site object
  1526. //
  1527. DWORD dwOptions = 0;
  1528. hr = FindSiteSettingsOptions(spDirObject,
  1529. dwOptions);
  1530. if (FAILED(hr))
  1531. {
  1532. break;
  1533. }
  1534. //
  1535. // See if the intersite autotopology is disabled
  1536. //
  1537. if (dwOptions & NTDSSETTINGS_OPT_IS_INTER_SITE_AUTO_TOPOLOGY_DISABLED)
  1538. {
  1539. bAutoTopDisabled = true;
  1540. }
  1541. } while (false);
  1542. //
  1543. // Add the value for display
  1544. //
  1545. DEBUG_OUTPUT(LEVEL8_LOGGING,
  1546. L"Autotopology: %s",
  1547. bAutoTopDisabled ? g_pszNo : g_pszYes);
  1548. pDisplayInfo->AddValue(bAutoTopDisabled ? g_pszNo : g_pszYes);
  1549. return hr;
  1550. }
  1551. HRESULT IsCacheGroupsEnabledSite(PCWSTR /*pszDN*/,
  1552. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  1553. const CDSCmdCredentialObject& /*refCredentialObject*/,
  1554. _DSGetObjectTableEntry* pEntry,
  1555. ARG_RECORD* pCommandArgs,
  1556. PADS_ATTR_INFO /*pAttrInfo*/,
  1557. CComPtr<IDirectoryObject>& spDirObject,
  1558. PDSGET_DISPLAY_INFO pDisplayInfo)
  1559. {
  1560. ENTER_FUNCTION_HR(LEVEL5_LOGGING, IsCacheGroupsEnabledSite, hr);
  1561. bool bCacheGroupsEnabled = false;
  1562. do // false loop
  1563. {
  1564. //
  1565. // Verify parameters
  1566. //
  1567. if (!pEntry ||
  1568. !pCommandArgs ||
  1569. !pDisplayInfo)
  1570. {
  1571. ASSERT(pEntry);
  1572. ASSERT(pCommandArgs);
  1573. ASSERT(pDisplayInfo);
  1574. hr = E_INVALIDARG;
  1575. break;
  1576. }
  1577. //
  1578. // Get the options attribute from the nTDSSiteSettings object under the site object
  1579. //
  1580. DWORD dwOptions = 0;
  1581. hr = FindSiteSettingsOptions(spDirObject,
  1582. dwOptions);
  1583. if (FAILED(hr))
  1584. {
  1585. break;
  1586. }
  1587. //
  1588. // See if groups caching is enabled
  1589. //
  1590. if (dwOptions & NTDSSETTINGS_OPT_IS_GROUP_CACHING_ENABLED)
  1591. {
  1592. bCacheGroupsEnabled = true;
  1593. }
  1594. } while (false);
  1595. //
  1596. // Add the value for display
  1597. //
  1598. DEBUG_OUTPUT(LEVEL8_LOGGING,
  1599. L"Cache groups enabled: %s",
  1600. bCacheGroupsEnabled ? g_pszYes : g_pszNo);
  1601. pDisplayInfo->AddValue(bCacheGroupsEnabled ? g_pszYes : g_pszNo);
  1602. return hr;
  1603. }
  1604. HRESULT FindSiteSettingsPreferredGCSite(IDirectoryObject* pDirectoryObj,
  1605. CComBSTR& refsbstrGC)
  1606. {
  1607. ENTER_FUNCTION_HR(LEVEL5_LOGGING, FindSiteSettingsPreferredGCSite, hr);
  1608. do // false loop
  1609. {
  1610. //
  1611. // Verify parameters
  1612. //
  1613. if (!pDirectoryObj)
  1614. {
  1615. ASSERT(pDirectoryObj);
  1616. hr = E_INVALIDARG;
  1617. break;
  1618. }
  1619. CComPtr<IDirectorySearch> spSearch;
  1620. hr = pDirectoryObj->QueryInterface(IID_IDirectorySearch, (void**)&spSearch);
  1621. if (FAILED(hr))
  1622. {
  1623. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1624. L"QI for IDirectorySearch failed: hr = 0x%x",
  1625. hr);
  1626. break;
  1627. }
  1628. CDSSearch Search;
  1629. hr = Search.Init(spSearch);
  1630. if (FAILED(hr))
  1631. {
  1632. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1633. L"CDSSearch::Init failed: hr = 0x%x",
  1634. hr);
  1635. break;
  1636. }
  1637. PWSTR pszSearchFilter = L"(objectClass=nTDSSiteSettings)";
  1638. Search.SetFilterString(pszSearchFilter);
  1639. PWSTR rgpwzAttrNames[] = { L"msDS-Preferred-GC-Site" };
  1640. Search.SetAttributeList(rgpwzAttrNames, 1);
  1641. Search.SetSearchScope(ADS_SCOPE_ONELEVEL);
  1642. hr = Search.DoQuery();
  1643. if (FAILED(hr))
  1644. {
  1645. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1646. L"Failed to run search: hr = 0x%x",
  1647. hr);
  1648. break;
  1649. }
  1650. hr = Search.GetNextRow();
  1651. if (hr == S_ADS_NOMORE_ROWS)
  1652. {
  1653. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1654. L"No rows found!");
  1655. hr = E_FAIL;
  1656. break;
  1657. }
  1658. ADS_SEARCH_COLUMN Column;
  1659. hr = Search.GetColumn(L"msDS-Preferred-GC-Site", &Column);
  1660. if (FAILED(hr))
  1661. {
  1662. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1663. L"Failed to get the msDS-Preferred-GC-Site column: hr = 0x%x",
  1664. hr);
  1665. break;
  1666. }
  1667. if (Column.dwADsType != ADSTYPE_DN_STRING ||
  1668. Column.dwNumValues == 0 ||
  1669. !Column.pADsValues)
  1670. {
  1671. Search.FreeColumn(&Column);
  1672. hr = E_FAIL;
  1673. break;
  1674. }
  1675. refsbstrGC = Column.pADsValues->DNString;
  1676. Search.FreeColumn(&Column);
  1677. } while (false);
  1678. return hr;
  1679. }
  1680. HRESULT DisplayPreferredGC(PCWSTR /*pszDN*/,
  1681. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  1682. const CDSCmdCredentialObject& /*refCredentialObject*/,
  1683. _DSGetObjectTableEntry* pEntry,
  1684. ARG_RECORD* pCommandArgs,
  1685. PADS_ATTR_INFO /*pAttrInfo*/,
  1686. CComPtr<IDirectoryObject>& spDirObject,
  1687. PDSGET_DISPLAY_INFO pDisplayInfo)
  1688. {
  1689. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayPreferredGC, hr);
  1690. CComBSTR sbstrGC;
  1691. do // false loop
  1692. {
  1693. //
  1694. // Verify parameters
  1695. //
  1696. if (!pEntry ||
  1697. !pCommandArgs ||
  1698. !pDisplayInfo)
  1699. {
  1700. ASSERT(pEntry);
  1701. ASSERT(pCommandArgs);
  1702. ASSERT(pDisplayInfo);
  1703. hr = E_INVALIDARG;
  1704. break;
  1705. }
  1706. //
  1707. // Get the msDS-Preferred-GC-Site attribute from the nTDSSiteSettings
  1708. // object under the site object
  1709. //
  1710. hr = FindSiteSettingsPreferredGCSite(spDirObject,
  1711. sbstrGC);
  1712. if (FAILED(hr))
  1713. {
  1714. break;
  1715. }
  1716. } while (false);
  1717. //
  1718. // Add the value for display
  1719. //
  1720. DEBUG_OUTPUT(LEVEL8_LOGGING,
  1721. L"Preferred GC Site: %s",
  1722. (!sbstrGC) ? g_pszNotConfigured : sbstrGC);
  1723. pDisplayInfo->AddValue((!sbstrGC) ? g_pszNotConfigured : sbstrGC);
  1724. return hr;
  1725. }