Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3180 lines
99 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 "resource.h"
  22. #include <lmaccess.h> // UF_* for userAccountControl flags
  23. #include <ntsam.h> // GROUP_TYPE_*
  24. #include <ntdsapi.h> // NTDSSETTINGS_OPT_*
  25. #include <msxml.h> // For XML_GetNodeText and GetTopObjectUsage
  26. //
  27. // Almost all of these functions are of type PGETDISPLAYSTRINGFUNC as defined in
  28. // gettable.h
  29. //
  30. #ifdef ADS_OPTION_QUOTA
  31. #pragma message("ADS_OPTION_QUOTA is now defined, so display.cpp needs to be updated to support it")
  32. #pragma warning(error : 1);
  33. #else
  34. #pragma message("ADS_OPTION_QUOTA is not defined, so using 5 instead")
  35. //
  36. // until the global definition is published, define it on my own so I'm not blocked
  37. //
  38. #define ADS_OPTION_QUOTA 5
  39. #endif
  40. //+--------------------------------------------------------------------------
  41. //
  42. // Function: XML_GetNodeText
  43. //
  44. // Synopsis: This code was taken from admin\snapin\dsadmin\xmlutil.cpp
  45. // on 8/29/02. Given an XML node of type NODE_TEXT, it
  46. // returns its value into a CComBSTR
  47. //
  48. // Arguments: [pXDN - IN]: The node to extract the text value from
  49. // [refBstr - OUT]: The node text if successful, else unchanged
  50. //
  51. // Returns: HRESULT : S_OK if everything succeeded
  52. // Anything else is a failure code from XML
  53. // or E_INVALIDARG
  54. //
  55. // History: 29-Aug-2002 RonMart Created
  56. //
  57. //---------------------------------------------------------------------------
  58. HRESULT XML_GetNodeText(IN IXMLDOMNode* pXDN, OUT CComBSTR& refBstr)
  59. {
  60. ENTER_FUNCTION_HR(LEVEL5_LOGGING, XML_GetNodeText, hr);
  61. ASSERT(pXDN != NULL);
  62. // assume the given node has a child node
  63. CComPtr<IXMLDOMNode> spName;
  64. hr = pXDN->get_firstChild(&spName);
  65. if (FAILED(hr))
  66. {
  67. // unexpected failure
  68. return hr;
  69. }
  70. // if no children, the api returns S_FALSE
  71. if (spName == NULL)
  72. {
  73. return hr;
  74. }
  75. // got now a valid pointer,
  76. // check if this is the valid node type
  77. DOMNodeType nodeType = NODE_INVALID;
  78. hr = spName->get_nodeType(&nodeType);
  79. ASSERT(hr == S_OK);
  80. ASSERT(nodeType == NODE_TEXT);
  81. if (nodeType != NODE_TEXT)
  82. {
  83. ASSERT(FALSE);
  84. return E_INVALIDARG;
  85. }
  86. // it is of type text
  87. // retrieve the node value into a variant
  88. CComVariant val;
  89. hr = pXDN->get_nodeTypedValue(&val);
  90. if (FAILED(hr))
  91. {
  92. // unexpected failure
  93. ASSERT(FALSE);
  94. return hr;
  95. }
  96. if (val.vt != VT_BSTR)
  97. {
  98. ASSERT(FALSE);
  99. return E_INVALIDARG;
  100. }
  101. // got the text value
  102. refBstr = val.bstrVal;
  103. return hr;
  104. }
  105. //+--------------------------------------------------------------------------
  106. //
  107. // Function: GetNT4NameOrSidString
  108. //
  109. // Synopsis: Called by GetTopObjectUsage on failure, this first does
  110. // a LookupAccountSid and tries to get the NT4 style name.
  111. // If that succeeds, then it tries to get the DN using that.
  112. // If no DN is returned, then the NT4 style name (if it exists)
  113. // or the SID string will be returned.
  114. //
  115. // Arguments: [bstrSid - IN]: Sid string to resolve
  116. // [lpszDN - OUT]: Returns the DN, NT4 name or Sid string.
  117. // Use LocalFree when done.
  118. //
  119. // Returns: HRESULT : S_OK if everything succeeded
  120. //
  121. // History: 11-Oct-2002 RonMart Created
  122. //
  123. //---------------------------------------------------------------------------
  124. HRESULT GetNT4NameOrSidString(IN CComBSTR& bstrSid, OUT LPWSTR* lpszDN)
  125. {
  126. ENTER_FUNCTION_HR(LEVEL5_LOGGING, GetNT4NameOrSidString, hr);
  127. LPWSTR lpszName = NULL;
  128. LPWSTR lpszDomain = NULL;
  129. PSID pSid = NULL;
  130. do
  131. {
  132. //
  133. // Verify parameters
  134. //
  135. if (!lpszDN)
  136. {
  137. hr = E_INVALIDARG;
  138. break;
  139. }
  140. // Convert the Sid String to a Sid so we can lookup the account
  141. if(!ConvertStringSidToSid(bstrSid, &pSid))
  142. {
  143. hr = E_FAIL;
  144. ASSERT(FALSE);
  145. break;
  146. }
  147. DWORD cchName = 0;
  148. DWORD cchDomainName = 0;
  149. SID_NAME_USE sUse = SidTypeInvalid;
  150. // Call once to get the buffer sizes
  151. if(!LookupAccountSid(NULL,
  152. pSid,
  153. lpszName,
  154. &cchName,
  155. lpszDomain,
  156. &cchDomainName,
  157. &sUse))
  158. {
  159. // If it fails, then deleted account so return
  160. // the sid string
  161. DWORD cchBufSize = SysStringLen(bstrSid) + 1;
  162. // Alloc the return buffer
  163. *lpszDN = (LPWSTR) LocalAlloc(LPTR,
  164. cchBufSize * sizeof(WCHAR));
  165. if(NULL == *lpszDN)
  166. {
  167. ASSERT(FALSE);
  168. hr = E_OUTOFMEMORY;
  169. break;
  170. }
  171. hr = StringCchCopy(*lpszDN, cchName, bstrSid.m_str);
  172. }
  173. if(cchName < 1 || cchDomainName < 1)
  174. {
  175. ASSERT(FALSE);
  176. E_UNEXPECTED;
  177. break;
  178. }
  179. lpszName = (LPWSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
  180. cchName * sizeof(WCHAR));
  181. if(NULL == lpszName)
  182. {
  183. ASSERT(FALSE);
  184. E_OUTOFMEMORY;
  185. break;
  186. }
  187. lpszDomain = (LPWSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
  188. cchDomainName * sizeof(WCHAR));
  189. if(NULL == lpszDomain)
  190. {
  191. ASSERT(FALSE);
  192. E_OUTOFMEMORY;
  193. break;
  194. }
  195. // Get the name
  196. if(!LookupAccountSid(NULL,
  197. pSid,
  198. lpszName,
  199. &cchName,
  200. lpszDomain,
  201. &cchDomainName,
  202. &sUse))
  203. {
  204. ASSERT(FALSE);
  205. E_FAIL;
  206. break;
  207. }
  208. // Grow the buffer to hold both the domain and name
  209. DWORD chBufSize = (cchName + cchDomainName + 2);
  210. LPWSTR lpszNew = (LPWSTR) HeapReAlloc(GetProcessHeap(), 0,
  211. lpszDomain, chBufSize * sizeof(WCHAR));
  212. if (NULL == lpszNew)
  213. {
  214. ASSERT(FALSE);
  215. hr = E_OUTOFMEMORY;
  216. break;
  217. }
  218. lpszDomain = lpszNew;
  219. // Merge the domain & account name
  220. hr = StringCchCat(lpszDomain, chBufSize, L"\\");
  221. if (FAILED(hr))
  222. {
  223. break;
  224. }
  225. hr = StringCchCat(lpszDomain, chBufSize, lpszName);
  226. if (FAILED(hr))
  227. {
  228. break;
  229. }
  230. // Try one more time to get the DN
  231. hr = ConvertTrusteeToDN(NULL, lpszDomain, lpszDN);
  232. // If this failed, then return the NT4 name
  233. if (FAILED(hr))
  234. {
  235. // Alloc the return buffer
  236. *lpszDN = (LPWSTR) LocalAlloc(LPTR,
  237. chBufSize * sizeof(WCHAR));
  238. if(NULL == *lpszDN)
  239. {
  240. ASSERT(FALSE);
  241. hr = E_OUTOFMEMORY;
  242. break;
  243. }
  244. // Return the NT4 name
  245. hr = StringCchCopy(*lpszDN, chBufSize, lpszDomain);
  246. // If we still fail, then give up and abort
  247. if(FAILED(hr))
  248. {
  249. ASSERT(FALSE);
  250. LocalFree(*lpszDN);
  251. *lpszDN = NULL;
  252. break;
  253. }
  254. }
  255. } while (0);
  256. if(pSid)
  257. LocalFree(pSid);
  258. if(lpszName)
  259. HeapFree(GetProcessHeap(), 0, lpszName);
  260. if(lpszDomain)
  261. HeapFree(GetProcessHeap(), 0, lpszDomain);
  262. return hr;
  263. }
  264. //+--------------------------------------------------------------------------
  265. //
  266. // Function: GetTopObjectUsage
  267. //
  268. // Synopsis: This code takes the XML block returned from a
  269. // msDS-TopQuotaUsage attribute and extracts the trustee name
  270. // DN and the quotaUsed value
  271. //
  272. // Arguments: [pXDN - IN]: The node to extract the text value from
  273. // [lpszDomain - IN]:Domain to query or NULL for local
  274. // [lpszDN - OUT]: Returns the DN. Use LocalFree when done
  275. // [refBstr - OUT]: The node text if successful, else unchanged
  276. //
  277. // Returns: HRESULT : S_OK if everything succeeded
  278. // Anything else is a failure code from XML
  279. // or E_INVALIDARG
  280. //
  281. // History: 29-Aug-2002 RonMart Created
  282. //
  283. //---------------------------------------------------------------------------
  284. HRESULT GetTopObjectUsage(IN CComBSTR& bstrXML, IN LPCWSTR lpszDomain,
  285. OUT LPWSTR* lpszDN, OUT CComBSTR& bstrQuotaUsed)
  286. {
  287. ENTER_FUNCTION_HR(LEVEL5_LOGGING, GetTopObjectUsage, hr);
  288. // Create an XML document
  289. CComPtr<IXMLDOMDocument> pXMLDoc;
  290. hr = pXMLDoc.CoCreateInstance(CLSID_DOMDocument);
  291. if (FAILED(hr))
  292. {
  293. DEBUG_OUTPUT(MINIMAL_LOGGING,
  294. L"CoCreateInstance(CLSID_DOMDocument) failed: hr = 0x%x",
  295. hr);
  296. return hr;
  297. }
  298. do
  299. {
  300. //
  301. // Verify parameters
  302. //
  303. if (!lpszDN)
  304. {
  305. hr = E_INVALIDARG;
  306. break;
  307. }
  308. // Load the XML text
  309. VARIANT_BOOL isSuccessful;
  310. hr = pXMLDoc->loadXML(bstrXML, &isSuccessful);
  311. // If it failed for any reason, then abort
  312. if (FAILED(hr) || (isSuccessful == FALSE))
  313. {
  314. DEBUG_OUTPUT(MINIMAL_LOGGING,
  315. L"loadXML failed: hr = 0x%x",
  316. hr);
  317. break;
  318. }
  319. // Get the SID string node
  320. CComPtr<IXMLDOMNode> pSidNode;
  321. hr = pXMLDoc->selectSingleNode(CComBSTR(L"MS_DS_TOP_QUOTA_USAGE/ownerSID"), &pSidNode);
  322. if (FAILED (hr))
  323. {
  324. DEBUG_OUTPUT(MINIMAL_LOGGING,
  325. L"selectSingleNode('MS_DS_TOP_QUOTA_USAGE/ownerSID') failed: hr = 0x%x",
  326. hr);
  327. break;
  328. }
  329. // Extract the sid string
  330. CComBSTR bstrSID;
  331. hr = XML_GetNodeText(pSidNode, bstrSID);
  332. if(FAILED(hr))
  333. {
  334. break;
  335. }
  336. // Convert the sid string into a DN (into the return buffer)
  337. hr = ConvertTrusteeToDN(lpszDomain, bstrSID, lpszDN);
  338. if (FAILED (hr))
  339. {
  340. // If we couldn't get the DN then get the NT4 name
  341. // from the string sid and try again to get either the
  342. // DN, the NT4 name or last resort return the sid string
  343. hr = GetNT4NameOrSidString(bstrSID, lpszDN);
  344. if(FAILED(hr))
  345. {
  346. ASSERT(FALSE);
  347. break;
  348. }
  349. }
  350. // Get the quotaUsed node
  351. CComPtr<IXMLDOMNode> pQuotaUsedNode;
  352. hr = pXMLDoc->selectSingleNode(CComBSTR(L"MS_DS_TOP_QUOTA_USAGE/quotaUsed"), &pQuotaUsedNode);
  353. if (FAILED (hr))
  354. {
  355. DEBUG_OUTPUT(MINIMAL_LOGGING,
  356. L"selectSingleNode('MS_DS_TOP_QUOTA_USAGE/quotaUsed') failed: hr = 0x%x",
  357. hr);
  358. break;
  359. }
  360. // Extract the value as text (into the return buffer)
  361. hr = XML_GetNodeText(pQuotaUsedNode, bstrQuotaUsed);
  362. if (FAILED(hr))
  363. {
  364. return hr;
  365. }
  366. } while (0);
  367. return hr;
  368. }
  369. HRESULT DisplayTopObjOwner(PCWSTR /*pszDN*/,//pszDN will be the dn of the server (from config) or the partition dn
  370. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  371. const CDSCmdCredentialObject& /*refCredentialObject*/,
  372. _DSGetObjectTableEntry* pEntry,
  373. ARG_RECORD* pRecord,
  374. PADS_ATTR_INFO pAttrInfo,
  375. CComPtr<IDirectoryObject>& /*spDirObject*/,
  376. PDSGET_DISPLAY_INFO pDisplayInfo)
  377. {
  378. ENTER_FUNCTION_HR(MINIMAL_LOGGING, DisplayTopObjOwner, hr);
  379. LPWSTR lpszDN = NULL;
  380. do // false loop
  381. {
  382. //
  383. // Verify parameters
  384. //
  385. if (!pEntry ||
  386. !pRecord ||
  387. !pAttrInfo ||
  388. !pDisplayInfo)
  389. {
  390. hr = E_INVALIDARG;
  391. break;
  392. }
  393. // These callback functions weren't designed for the headers
  394. // to be changed, so two values must be stuck in one column entry
  395. // Since this is always going to be a one column table, this should
  396. // be acceptable
  397. pDisplayInfo->AddValue(L"Account DN\tObjects Owned");
  398. // If values returned in dsget's GetObjectAttributes
  399. if (pAttrInfo && pAttrInfo->pADsValues)
  400. {
  401. DEBUG_OUTPUT(FULL_LOGGING,
  402. L"Examining %d values:",
  403. pAttrInfo->dwNumValues);
  404. // For each of the values found in dsget's GetObjectAttributes
  405. for (DWORD dwIdx = 0; dwIdx < pAttrInfo->dwNumValues; dwIdx++)
  406. {
  407. WCHAR* pBuffer = 0;
  408. // The top object usage will be a single XML string
  409. hr = GetStringFromADs(&(pAttrInfo->pADsValues[dwIdx]),
  410. pAttrInfo->dwADsType,
  411. &pBuffer,
  412. pAttrInfo->pszAttrName);
  413. // If we got it then parse it
  414. if (SUCCEEDED(hr))
  415. {
  416. // Extract the trustee name and quota value
  417. CComBSTR bstrXML(pBuffer);
  418. CComBSTR bstrQuotaUsed;
  419. delete[] pBuffer;
  420. pBuffer = NULL;
  421. hr = GetTopObjectUsage(bstrXML, NULL, &lpszDN, bstrQuotaUsed);
  422. if (FAILED(hr) || (hr == S_FALSE))
  423. {
  424. if(hr == S_FALSE)
  425. continue; // skip failures due to invalid sid bug in AD
  426. else
  427. break; // FAIL if not the known invalid sid
  428. }
  429. // How big are the return strings plus the tab char
  430. size_t size = (lstrlen(lpszDN) +
  431. bstrQuotaUsed.Length()+2) *
  432. sizeof(WCHAR);
  433. // Create a buffer to hold the value to display
  434. PWSTR pszValue = (PWSTR) LocalAlloc(LPTR, size);
  435. if(NULL == pszValue)
  436. {
  437. LocalFree(lpszDN);
  438. hr = E_OUTOFMEMORY;
  439. break;
  440. }
  441. // Format the two columns
  442. hr = StringCbPrintf(pszValue, size, L"%s\t%s",
  443. lpszDN, bstrQuotaUsed.m_str);
  444. // Done with this now (if FAILED(hr)), so free it
  445. LocalFree(lpszDN);
  446. lpszDN = NULL;
  447. // If the format failed
  448. if(FAILED(hr))
  449. {
  450. break;
  451. }
  452. // Add the string to display
  453. hr = pDisplayInfo->AddValue(pszValue);
  454. }
  455. }
  456. }
  457. } while (false);
  458. if(lpszDN != NULL)
  459. LocalFree(lpszDN);
  460. return hr;
  461. }
  462. //+--------------------------------------------------------------------------
  463. //
  464. // Function: AddValuesToDisplayInfo
  465. //
  466. // Synopsis: Adds the values a variant array of BSTR's (or single BSTR)
  467. // to the displayInfo
  468. //
  469. // Arguments: [refvar - IN]: A variant that contains either a BSTR or
  470. // an array of BSTR's
  471. //
  472. // [pDisplayInfo - IN]: Display object to add to
  473. //
  474. // Returns: HRESULT : S_OK if everything succeeded
  475. // E_UNEXPECTED in most failure cases
  476. // Anything else is a failure code from call that
  477. // returns a hr
  478. //
  479. // Note: This code was derrived from admin\snapin\adsiedit\common.cpp
  480. //
  481. // History: 29-Aug-2002 RonMart Created
  482. //
  483. //---------------------------------------------------------------------------
  484. HRESULT AddValuesToDisplayInfo(VARIANT& refvar, PDSGET_DISPLAY_INFO pDisplayInfo)
  485. {
  486. ENTER_FUNCTION_HR(MINIMAL_LOGGING, AddValuesToDisplayInfo, hr);
  487. long start = 0;
  488. long end = 0;
  489. // If a single value comes back
  490. if ( !(V_VT(&refvar) & VT_ARRAY) )
  491. {
  492. // and it is not a BSTR then abort
  493. if ( V_VT(&refvar) != VT_BSTR )
  494. {
  495. return E_UNEXPECTED;
  496. }
  497. // Add the value to the displayInfo
  498. return pDisplayInfo->AddValue(V_BSTR(&refvar));
  499. }
  500. // Otherwise it is a SafeArray so get the array
  501. SAFEARRAY *saAttributes = V_ARRAY( &refvar );
  502. // Verify array returned
  503. if(NULL == saAttributes)
  504. return E_UNEXPECTED;
  505. // Figure out the dimensions of the array.
  506. hr = SafeArrayGetLBound( saAttributes, 1, &start );
  507. if( FAILED(hr) )
  508. return hr;
  509. hr = SafeArrayGetUBound( saAttributes, 1, &end );
  510. if( FAILED(hr) )
  511. return hr;
  512. // Search the array elements and abort if a match is found
  513. CComVariant SingleResult;
  514. for ( long idx = start; (idx <= end); idx++ )
  515. {
  516. hr = SafeArrayGetElement( saAttributes, &idx, &SingleResult );
  517. if( FAILED(hr) )
  518. {
  519. return hr;
  520. }
  521. if ( V_VT(&SingleResult) != VT_BSTR )
  522. {
  523. // If not BSTR then go to the next element
  524. continue;
  525. }
  526. // Add the value to the displayInfo
  527. hr = pDisplayInfo->AddValue(V_BSTR(&SingleResult));
  528. if( FAILED(hr) )
  529. {
  530. return hr;
  531. }
  532. }
  533. return hr;
  534. }
  535. HRESULT DisplayPartitions(PCWSTR pszDN,
  536. CDSCmdBasePathsInfo& refBasePathsInfo,
  537. const CDSCmdCredentialObject& refCredentialObject,
  538. _DSGetObjectTableEntry* /*pEntry*/,
  539. ARG_RECORD* /*pRecord*/,
  540. PADS_ATTR_INFO /*pAttrInfo*/,
  541. CComPtr<IDirectoryObject>& /*spDirObject*/,
  542. PDSGET_DISPLAY_INFO pDisplayInfo)
  543. {
  544. ENTER_FUNCTION_HR(MINIMAL_LOGGING, DisplayPartitions, hr);
  545. do // false loop
  546. {
  547. // Verify parameters
  548. if (!pszDN ||
  549. !pDisplayInfo)
  550. {
  551. hr = E_INVALIDARG;
  552. break;
  553. }
  554. // Compose the path to the NTDS settings object from the server DN
  555. CComBSTR sbstrNTDSSettingsDN;
  556. sbstrNTDSSettingsDN = L"CN=NTDS Settings,";
  557. sbstrNTDSSettingsDN += pszDN;
  558. CComBSTR sbstrNTDSSettingsPath;
  559. refBasePathsInfo.ComposePathFromDN(sbstrNTDSSettingsDN, sbstrNTDSSettingsPath);
  560. // Bind to it
  561. CComPtr<IADs> spADs;
  562. hr = DSCmdOpenObject(refCredentialObject,
  563. sbstrNTDSSettingsPath,
  564. IID_IADs,
  565. (void**)&spADs,
  566. true);
  567. if (FAILED(hr))
  568. {
  569. break;
  570. }
  571. // Get the partitions bstr array (per Brett Shirley)
  572. // 705146 ronmart 2002/09/18 .NET Server domains use msDS-hasMasterNCs
  573. CComVariant var;
  574. hr = spADs->Get(CComBSTR(L"msDS-hasMasterNCs"), &var);
  575. if (FAILED(hr))
  576. {
  577. DEBUG_OUTPUT(LEVEL5_LOGGING,
  578. L"Failed to get msDS-hasMasterNCs: hr = 0x%x",
  579. hr);
  580. // 705146 ronmart 2002/09/18 W2k Server domains use hasMasterNCs
  581. hr = spADs->Get(CComBSTR(L"hasMasterNCs"), &var);
  582. if (FAILED(hr))
  583. {
  584. DEBUG_OUTPUT(LEVEL5_LOGGING,
  585. L"Failed to get hasMasterNCs: hr = 0x%x",
  586. hr);
  587. break;
  588. }
  589. }
  590. // Add the array values to the displayInfo
  591. hr = AddValuesToDisplayInfo(var, pDisplayInfo);
  592. if (FAILED(hr))
  593. {
  594. break;
  595. }
  596. } while (false);
  597. return hr;
  598. }
  599. HRESULT DisplayQuotaInfoFunc(PCWSTR pszDN,
  600. CDSCmdBasePathsInfo& refBasePathsInfo,
  601. const CDSCmdCredentialObject& refCredentialObject,
  602. _DSGetObjectTableEntry* pEntry,
  603. ARG_RECORD* pRecord,
  604. PADS_ATTR_INFO /*pAttrInfo*/,
  605. CComPtr<IDirectoryObject>& /*spDirObject*/,
  606. PDSGET_DISPLAY_INFO pDisplayInfo)
  607. {
  608. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayQuotaInfoFunc, hr);
  609. LPWSTR lpszSid = NULL;
  610. PWSTR pszPartitionDN = NULL;
  611. PSID pSid = NULL;
  612. do // false loop
  613. {
  614. //
  615. // Verify parameters
  616. //
  617. if (!pEntry ||
  618. !pRecord ||
  619. !pDisplayInfo ||
  620. !pszDN)
  621. {
  622. hr = E_INVALIDARG;
  623. break;
  624. }
  625. // Get a pointer to the object entry for readability
  626. PCWSTR pszCommandLineObjectType = pEntry->pszCommandLineObjectType;
  627. // NTRAID#NTBUG9-765440-2003/01/17-ronmart-dsget user/group -qlimit -qused
  628. // not returning values
  629. PCWSTR pszAttrName = NULL;
  630. DSGET_COMMAND_ENUM ePart;
  631. if(0 == _wcsicmp(pszCommandLineObjectType, g_pszUser))
  632. {
  633. ePart = eUserPart;
  634. // NTRAID#NTBUG9-765440-2003/01/17-ronmart-dsget user/group -qlimit
  635. // -qused not returning values
  636. if(0 == _wcsicmp(pDisplayInfo->GetDisplayName(), g_pszArg1UserQLimit))
  637. {
  638. pszAttrName = g_pszAttrmsDSQuotaEffective;
  639. }
  640. else if(0 == _wcsicmp(pDisplayInfo->GetDisplayName(), g_pszArg1UserQuotaUsed))
  641. {
  642. pszAttrName = g_pszAttrmsDSQuotaUsed;
  643. }
  644. else
  645. {
  646. hr = E_INVALIDARG;
  647. DEBUG_OUTPUT(FULL_LOGGING,
  648. L"Unable to determine quota attribute name.");
  649. break;
  650. }
  651. }
  652. else if(0 == _wcsicmp(pszCommandLineObjectType, g_pszGroup))
  653. {
  654. ePart = eGroupPart;
  655. // NTRAID#NTBUG9-765440-2003/01/17-ronmart-dsget user/group -qlimit
  656. // -qused not returning values
  657. if(0 == _wcsicmp(pDisplayInfo->GetDisplayName(), g_pszArg1GroupQLimit))
  658. {
  659. pszAttrName = g_pszAttrmsDSQuotaEffective;
  660. }
  661. else if(0 == _wcsicmp(pDisplayInfo->GetDisplayName(), g_pszArg1GroupQuotaUsed))
  662. {
  663. pszAttrName = g_pszAttrmsDSQuotaUsed;
  664. }
  665. else
  666. {
  667. hr = E_INVALIDARG;
  668. DEBUG_OUTPUT(FULL_LOGGING,
  669. L"Unable to determine quota attribute name.");
  670. break;
  671. }
  672. }
  673. else if(0 == _wcsicmp(pszCommandLineObjectType, g_pszComputer))
  674. {
  675. ePart = eComputerPart;
  676. // NTRAID#NTBUG9-765440-2003/01/17-ronmart-dsget user/group -qlimit
  677. // -qused not returning values
  678. if(0 == _wcsicmp(pDisplayInfo->GetDisplayName(), g_pszArg1ComputerQLimit))
  679. {
  680. pszAttrName = g_pszAttrmsDSQuotaEffective;
  681. }
  682. else if(0 == _wcsicmp(pDisplayInfo->GetDisplayName(), g_pszArg1ComputerQuotaUsed))
  683. {
  684. pszAttrName = g_pszAttrmsDSQuotaUsed;
  685. }
  686. else
  687. {
  688. hr = E_INVALIDARG;
  689. DEBUG_OUTPUT(FULL_LOGGING,
  690. L"Unable to determine quota attribute name.");
  691. break;
  692. }
  693. }
  694. else
  695. {
  696. hr = E_INVALIDARG;
  697. // TODO: This may cause a duplicate error message
  698. DisplayErrorMessage(g_pszDSCommandName,
  699. pszDN,
  700. hr,
  701. IDS_ERRMSG_PART_MISSING);
  702. break;
  703. }
  704. // Validate the partition and get the quotas container DN
  705. hr = GetQuotaContainerDN(refBasePathsInfo, refCredentialObject,
  706. pRecord[ePart].strValue, &pszPartitionDN);
  707. if(FAILED(hr))
  708. {
  709. // TODO: This may cause a duplicate error message
  710. DisplayErrorMessage(g_pszDSCommandName,
  711. pRecord[ePart].strValue,
  712. hr,
  713. IDS_ERRMSG_INVALID_PART);
  714. break;
  715. }
  716. // Get a path that accounts for -domain or -server
  717. CComBSTR sbstrObjectPath;
  718. refBasePathsInfo.ComposePathFromDN(pszPartitionDN, sbstrObjectPath,
  719. DSCMD_LDAP_PROVIDER);
  720. // Build a variant array of the value to look up
  721. CComVariant varArrayQuotaParams;
  722. LPWSTR pszAttrs[] = { (LPWSTR) pszAttrName };
  723. DWORD dwNumber = 1;
  724. hr = ADsBuildVarArrayStr( pszAttrs, dwNumber, &varArrayQuotaParams );
  725. if(FAILED(hr))
  726. {
  727. break;
  728. }
  729. CComPtr<IADs> spADsContainer;
  730. CComPtr<IADsObjectOptions> spADsObjectOptions;
  731. // Get the SID from the DN
  732. hr = GetDNSid(pszDN,
  733. refBasePathsInfo,
  734. refCredentialObject,
  735. &pSid);
  736. if(FAILED(hr))
  737. {
  738. break;
  739. }
  740. if(!ConvertSidToStringSid(pSid, &lpszSid))
  741. {
  742. DEBUG_OUTPUT(MINIMAL_LOGGING,
  743. L"ConvertSidToStringSid failure: GetLastError = 0x%08x, %s",
  744. GetLastError());
  745. break;
  746. }
  747. // Bind to the quotas container for the given partition
  748. hr = DSCmdOpenObject(refCredentialObject,
  749. sbstrObjectPath,
  750. IID_IADs,
  751. (void**)&spADsContainer,
  752. false);
  753. if (FAILED(hr) || (spADsContainer.p == 0))
  754. {
  755. ASSERT( !!spADsContainer );
  756. DEBUG_OUTPUT(MINIMAL_LOGGING,
  757. L"DsCmdOpenObject failure: hr = 0x%08x, %s", hr);
  758. break;
  759. }
  760. // Get a object options pointer
  761. hr = spADsContainer->QueryInterface(IID_IADsObjectOptions,
  762. (void**)&spADsObjectOptions);
  763. if (FAILED(hr) || (spADsObjectOptions.p == 0))
  764. {
  765. ASSERT( !!spADsObjectOptions );
  766. DEBUG_OUTPUT(MINIMAL_LOGGING,
  767. L"QI for IID_IADsObjectOptions failed: hr = 0x%08x, %s",
  768. hr);
  769. break;
  770. }
  771. // Quota values are obtained by setting the ADS_OPTION_QUOTA value
  772. // to the SID string of the trustee who you want to inquire about
  773. // and then calling GetInfoEx to update the property cache with
  774. // the computed values
  775. CComVariant vntSID(lpszSid);
  776. hr = spADsObjectOptions->SetOption(ADS_OPTION_QUOTA, vntSID);
  777. if(FAILED(hr))
  778. {
  779. DEBUG_OUTPUT(MINIMAL_LOGGING,
  780. L"SetOption(ADS_OPTION_QUOTA,sid) failure: hr = 0x%08x", hr);
  781. break;
  782. }
  783. // Done with the sid string, so free it
  784. LocalFree(lpszSid);
  785. lpszSid= NULL;
  786. // Update the property cache
  787. hr = spADsContainer->GetInfoEx(varArrayQuotaParams, 0);
  788. if (FAILED(hr))
  789. {
  790. DEBUG_OUTPUT(MINIMAL_LOGGING,
  791. L"GetInfoEx failure: hr = 0x%08x", hr);
  792. break;
  793. }
  794. // Get the requested attribute from the quota container
  795. CComVariant var;
  796. hr = spADsContainer->Get(CComBSTR(pszAttrName), &var);
  797. if (FAILED(hr))
  798. {
  799. DEBUG_OUTPUT(MINIMAL_LOGGING,
  800. L"Failed to retrieve %s: hr = 0x%x",
  801. pszAttrName, hr);
  802. hr = E_UNEXPECTED;
  803. break;
  804. }
  805. // Add the value to the display info
  806. var.ChangeType(VT_BSTR);
  807. hr = pDisplayInfo->AddValue(V_BSTR(&var));
  808. if (FAILED(hr))
  809. {
  810. break;
  811. }
  812. } while (false);
  813. if(pSid)
  814. LocalFree(pSid);
  815. if(pszPartitionDN)
  816. LocalFree(pszPartitionDN);
  817. if(lpszSid)
  818. LocalFree(lpszSid);
  819. return hr;
  820. }
  821. HRESULT DisplayUserFromSidFunc(PCWSTR /*pszDN*/,
  822. CDSCmdBasePathsInfo& refBasePathsInfo,
  823. const CDSCmdCredentialObject& /*refCredentialObject*/,
  824. _DSGetObjectTableEntry* /*pEntry*/,
  825. ARG_RECORD* /*pRecord*/,
  826. PADS_ATTR_INFO pAttrInfo,
  827. CComPtr<IDirectoryObject>& /*spDirObject*/,
  828. PDSGET_DISPLAY_INFO pDisplayInfo)
  829. {
  830. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayUserFromSidFunc, hr);
  831. LPWSTR lpszName = NULL;
  832. LPWSTR lpszDomain = NULL;
  833. do // false loop
  834. {
  835. //
  836. // Verify parameters
  837. //
  838. if (!pAttrInfo ||
  839. !pDisplayInfo)
  840. {
  841. hr = E_INVALIDARG;
  842. break;
  843. }
  844. if (pAttrInfo && pAttrInfo->pADsValues)
  845. {
  846. DEBUG_OUTPUT(FULL_LOGGING,
  847. L"Adding %d values:",
  848. pAttrInfo->dwNumValues);
  849. DWORD dwValuesAdded = 0;
  850. for (DWORD dwIdx = 0; dwIdx < pAttrInfo->dwNumValues; dwIdx++)
  851. {
  852. DWORD cchName = 0;
  853. DWORD cchDomainName = 0;
  854. SID_NAME_USE sUse = SidTypeInvalid;
  855. if(pAttrInfo->dwADsType != ADSTYPE_OCTET_STRING)
  856. {
  857. // Wrong attribute requested in gettable.cpp
  858. hr = E_INVALIDARG;
  859. break;
  860. }
  861. // Call once to get the buffer sizes
  862. LookupAccountSid(refBasePathsInfo.GetServerName(),
  863. (PSID)pAttrInfo->pADsValues[dwIdx].OctetString.lpValue,
  864. lpszName,
  865. &cchName,
  866. lpszDomain,
  867. &cchDomainName,
  868. &sUse);
  869. if(cchName < 1 || cchDomainName < 1)
  870. {
  871. E_UNEXPECTED;
  872. break;
  873. }
  874. lpszName = (LPWSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
  875. cchName * sizeof(WCHAR));
  876. if(NULL == lpszName)
  877. {
  878. E_OUTOFMEMORY;
  879. break;
  880. }
  881. lpszDomain = (LPWSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
  882. cchDomainName * sizeof(WCHAR));
  883. if(NULL == lpszDomain)
  884. {
  885. E_OUTOFMEMORY;
  886. break;
  887. }
  888. // Get the SAM name
  889. if(!LookupAccountSid(refBasePathsInfo.GetServerName(),
  890. (PSID)pAttrInfo->pADsValues[dwIdx].OctetString.lpValue,
  891. lpszName,
  892. &cchName,
  893. lpszDomain,
  894. &cchDomainName,
  895. &sUse))
  896. {
  897. E_FAIL;
  898. break;
  899. }
  900. DWORD chBufSize = (cchName + cchDomainName + 2);
  901. LPWSTR lpszNew = (LPWSTR) HeapReAlloc(GetProcessHeap(), 0,
  902. lpszDomain, chBufSize * sizeof(WCHAR));
  903. if (NULL == lpszNew)
  904. {
  905. hr = E_OUTOFMEMORY;
  906. break;
  907. }
  908. lpszDomain = lpszNew;
  909. // Merge the domain & account name and add the value
  910. // to the display info
  911. hr = StringCchCat(lpszDomain, chBufSize, L"\\");
  912. if (FAILED(hr))
  913. {
  914. break;
  915. }
  916. hr = StringCchCat(lpszDomain, chBufSize, lpszName);
  917. if (FAILED(hr))
  918. {
  919. break;
  920. }
  921. hr = pDisplayInfo->AddValue(lpszDomain);
  922. if (FAILED(hr))
  923. {
  924. break;
  925. }
  926. // Release and reset everything for the next iteration
  927. HeapFree(GetProcessHeap(), 0, lpszName);
  928. HeapFree(GetProcessHeap(), 0, lpszDomain);
  929. lpszName = NULL;
  930. lpszDomain = NULL;
  931. cchName = 0;
  932. cchDomainName = 0;
  933. sUse = SidTypeInvalid;
  934. dwValuesAdded++;
  935. }
  936. }
  937. } while (false);
  938. if(lpszName)
  939. HeapFree(GetProcessHeap(), 0, lpszName);
  940. if(lpszDomain)
  941. HeapFree(GetProcessHeap(), 0, lpszDomain);
  942. return hr;
  943. }
  944. HRESULT CommonDisplayStringFunc(PCWSTR /*pszDN*/,
  945. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  946. const CDSCmdCredentialObject& /*refCredentialObject*/,
  947. _DSGetObjectTableEntry* pEntry,
  948. ARG_RECORD* pRecord,
  949. PADS_ATTR_INFO pAttrInfo,
  950. CComPtr<IDirectoryObject>& /*spDirObject*/,
  951. PDSGET_DISPLAY_INFO pDisplayInfo)
  952. {
  953. ENTER_FUNCTION_HR(LEVEL5_LOGGING, CommonDisplayStringFunc, hr);
  954. do // false loop
  955. {
  956. //
  957. // Verify parameters
  958. //
  959. if (!pEntry ||
  960. !pRecord ||
  961. !pDisplayInfo)
  962. {
  963. ASSERT(pEntry);
  964. ASSERT(pRecord);
  965. ASSERT(pDisplayInfo);
  966. hr = E_INVALIDARG;
  967. break;
  968. }
  969. if (pAttrInfo && pAttrInfo->pADsValues)
  970. {
  971. DEBUG_OUTPUT(FULL_LOGGING,
  972. L"Adding %d values:",
  973. pAttrInfo->dwNumValues);
  974. DWORD dwValuesAdded = 0;
  975. for (DWORD dwIdx = 0; dwIdx < pAttrInfo->dwNumValues; dwIdx++)
  976. {
  977. WCHAR* pBuffer = 0;
  978. hr = GetStringFromADs(&(pAttrInfo->pADsValues[dwIdx]),
  979. pAttrInfo->dwADsType,
  980. &pBuffer,
  981. pAttrInfo->pszAttrName);
  982. if (SUCCEEDED(hr))
  983. {
  984. hr = pDisplayInfo->AddValue(pBuffer);
  985. if (FAILED(hr))
  986. {
  987. delete[] pBuffer;
  988. pBuffer = NULL;
  989. break;
  990. }
  991. delete[] pBuffer;
  992. pBuffer = NULL;
  993. dwValuesAdded++;
  994. }
  995. }
  996. }
  997. } while (false);
  998. return hr;
  999. }
  1000. HRESULT DisplayCanChangePassword(PCWSTR pszDN,
  1001. CDSCmdBasePathsInfo& refBasePathsInfo,
  1002. const CDSCmdCredentialObject& refCredentialObject,
  1003. _DSGetObjectTableEntry* pEntry,
  1004. ARG_RECORD* pRecord,
  1005. PADS_ATTR_INFO /*pAttrInfo*/,
  1006. CComPtr<IDirectoryObject>& /*spDirObject*/,
  1007. PDSGET_DISPLAY_INFO pDisplayInfo)
  1008. {
  1009. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayCanChangePassword, hr);
  1010. do // false loop
  1011. {
  1012. //
  1013. // Verify parameters
  1014. //
  1015. if (!pszDN ||
  1016. !pEntry ||
  1017. !pRecord ||
  1018. !pDisplayInfo)
  1019. {
  1020. ASSERT(pszDN);
  1021. ASSERT(pEntry);
  1022. ASSERT(pRecord);
  1023. ASSERT(pDisplayInfo);
  1024. hr = E_INVALIDARG;
  1025. break;
  1026. }
  1027. bool bCanChangePassword = false;
  1028. hr = EvaluateCanChangePasswordAces(pszDN,
  1029. refBasePathsInfo,
  1030. refCredentialObject,
  1031. bCanChangePassword);
  1032. if (FAILED(hr))
  1033. {
  1034. break;
  1035. }
  1036. DEBUG_OUTPUT(LEVEL8_LOGGING,
  1037. L"Can change password: %s",
  1038. bCanChangePassword ? g_pszYes : g_pszNo);
  1039. hr = pDisplayInfo->AddValue(bCanChangePassword ? g_pszYes : g_pszNo);
  1040. } while (false);
  1041. return hr;
  1042. }
  1043. HRESULT DisplayMustChangePassword(PCWSTR /*pszDN*/,
  1044. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  1045. const CDSCmdCredentialObject& /*refCredentialObject*/,
  1046. _DSGetObjectTableEntry* pEntry,
  1047. ARG_RECORD* pRecord,
  1048. PADS_ATTR_INFO pAttrInfo,
  1049. CComPtr<IDirectoryObject>& /*spDirObject*/,
  1050. PDSGET_DISPLAY_INFO pDisplayInfo)
  1051. {
  1052. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayMustChangePassword, hr);
  1053. do // false loop
  1054. {
  1055. //
  1056. // Verify parameters
  1057. //
  1058. if (!pEntry ||
  1059. !pRecord ||
  1060. !pDisplayInfo)
  1061. {
  1062. ASSERT(pEntry);
  1063. ASSERT(pRecord);
  1064. ASSERT(pDisplayInfo);
  1065. hr = E_INVALIDARG;
  1066. break;
  1067. }
  1068. if (pAttrInfo->pADsValues && pAttrInfo->dwADsType == ADSTYPE_LARGE_INTEGER)
  1069. {
  1070. DEBUG_OUTPUT(FULL_LOGGING,
  1071. L"Adding %d values:",
  1072. pAttrInfo->dwNumValues);
  1073. bool bMustChangePassword = false;
  1074. if (pAttrInfo->pADsValues->LargeInteger.HighPart == 0 &&
  1075. pAttrInfo->pADsValues->LargeInteger.LowPart == 0)
  1076. {
  1077. bMustChangePassword = true;
  1078. }
  1079. DEBUG_OUTPUT(LEVEL8_LOGGING,
  1080. L"Must change password: %s",
  1081. bMustChangePassword ? g_pszYes : g_pszNo);
  1082. hr = pDisplayInfo->AddValue(bMustChangePassword ? g_pszYes : g_pszNo);
  1083. }
  1084. } while (false);
  1085. return hr;
  1086. }
  1087. HRESULT DisplayAccountDisabled(PCWSTR /*pszDN*/,
  1088. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  1089. const CDSCmdCredentialObject& /*refCredentialObject*/,
  1090. _DSGetObjectTableEntry* pEntry,
  1091. ARG_RECORD* pRecord,
  1092. PADS_ATTR_INFO pAttrInfo,
  1093. CComPtr<IDirectoryObject>& /*spDirObject*/,
  1094. PDSGET_DISPLAY_INFO pDisplayInfo)
  1095. {
  1096. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayAccountDisabled, hr);
  1097. do // false loop
  1098. {
  1099. //
  1100. // Verify parameters
  1101. //
  1102. if (!pEntry ||
  1103. !pRecord ||
  1104. !pDisplayInfo)
  1105. {
  1106. ASSERT(pEntry);
  1107. ASSERT(pRecord);
  1108. ASSERT(pDisplayInfo);
  1109. hr = E_INVALIDARG;
  1110. break;
  1111. }
  1112. if (pAttrInfo->pADsValues && pAttrInfo->dwADsType == ADSTYPE_INTEGER)
  1113. {
  1114. DEBUG_OUTPUT(FULL_LOGGING,
  1115. L"Adding %d values:",
  1116. pAttrInfo->dwNumValues);
  1117. bool bAccountDisabled = false;
  1118. if (pAttrInfo->pADsValues->Integer & UF_ACCOUNTDISABLE)
  1119. {
  1120. bAccountDisabled = true;
  1121. }
  1122. DEBUG_OUTPUT(LEVEL8_LOGGING,
  1123. L"Account disabled: %s",
  1124. bAccountDisabled ? g_pszYes : g_pszNo);
  1125. hr = pDisplayInfo->AddValue(bAccountDisabled ? g_pszYes : g_pszNo);
  1126. }
  1127. } while (false);
  1128. return hr;
  1129. }
  1130. HRESULT DisplayPasswordNeverExpires(PCWSTR /*pszDN*/,
  1131. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  1132. const CDSCmdCredentialObject& /*refCredentialObject*/,
  1133. _DSGetObjectTableEntry* pEntry,
  1134. ARG_RECORD* pRecord,
  1135. PADS_ATTR_INFO pAttrInfo,
  1136. CComPtr<IDirectoryObject>& /*spDirObject*/,
  1137. PDSGET_DISPLAY_INFO pDisplayInfo)
  1138. {
  1139. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayPasswordNeverExpires, hr);
  1140. do // false loop
  1141. {
  1142. //
  1143. // Verify parameters
  1144. //
  1145. if (!pEntry ||
  1146. !pRecord ||
  1147. !pDisplayInfo)
  1148. {
  1149. ASSERT(pEntry);
  1150. ASSERT(pRecord);
  1151. ASSERT(pDisplayInfo);
  1152. hr = E_INVALIDARG;
  1153. break;
  1154. }
  1155. if (pAttrInfo->pADsValues && pAttrInfo->dwADsType == ADSTYPE_INTEGER)
  1156. {
  1157. DEBUG_OUTPUT(FULL_LOGGING,
  1158. L"Adding %d values:",
  1159. pAttrInfo->dwNumValues);
  1160. bool bPwdNeverExpires = false;
  1161. if (pAttrInfo->pADsValues->Integer & UF_DONT_EXPIRE_PASSWD)
  1162. {
  1163. bPwdNeverExpires = true;
  1164. }
  1165. DEBUG_OUTPUT(LEVEL8_LOGGING,
  1166. L"Password never expires: %s",
  1167. bPwdNeverExpires ? g_pszYes : g_pszNo);
  1168. hr = pDisplayInfo->AddValue(bPwdNeverExpires ? g_pszYes : g_pszNo);
  1169. }
  1170. } while (false);
  1171. return hr;
  1172. }
  1173. HRESULT DisplayReversiblePassword(PCWSTR /*pszDN*/,
  1174. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  1175. const CDSCmdCredentialObject& /*refCredentialObject*/,
  1176. _DSGetObjectTableEntry* pEntry,
  1177. ARG_RECORD* pRecord,
  1178. PADS_ATTR_INFO pAttrInfo,
  1179. CComPtr<IDirectoryObject>& /*spDirObject*/,
  1180. PDSGET_DISPLAY_INFO pDisplayInfo)
  1181. {
  1182. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayReversiblePassword, hr);
  1183. do // false loop
  1184. {
  1185. //
  1186. // Verify parameters
  1187. //
  1188. if (!pEntry ||
  1189. !pRecord ||
  1190. !pDisplayInfo)
  1191. {
  1192. ASSERT(pEntry);
  1193. ASSERT(pRecord);
  1194. ASSERT(pDisplayInfo);
  1195. hr = E_INVALIDARG;
  1196. break;
  1197. }
  1198. if (pAttrInfo->pADsValues && pAttrInfo->dwADsType == ADSTYPE_INTEGER)
  1199. {
  1200. DEBUG_OUTPUT(FULL_LOGGING,
  1201. L"Adding %d values:",
  1202. pAttrInfo->dwNumValues);
  1203. bool bReversiblePwd = false;
  1204. if (pAttrInfo->pADsValues->Integer & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)
  1205. {
  1206. bReversiblePwd = true;
  1207. }
  1208. DEBUG_OUTPUT(LEVEL8_LOGGING,
  1209. L"Password store with reversible encryption: %s",
  1210. bReversiblePwd ? g_pszYes : g_pszNo);
  1211. hr = pDisplayInfo->AddValue(bReversiblePwd ? g_pszYes : g_pszNo);
  1212. }
  1213. } while (false);
  1214. return hr;
  1215. }
  1216. // Constants
  1217. const unsigned long DSCMD_FILETIMES_PER_MILLISECOND = 10000;
  1218. const DWORD DSCMD_FILETIMES_PER_SECOND = 1000 * DSCMD_FILETIMES_PER_MILLISECOND;
  1219. const DWORD DSCMD_FILETIMES_PER_MINUTE = 60 * DSCMD_FILETIMES_PER_SECOND;
  1220. const __int64 DSCMD_FILETIMES_PER_HOUR = 60 * (__int64)DSCMD_FILETIMES_PER_MINUTE;
  1221. const __int64 DSCMD_FILETIMES_PER_DAY = 24 * DSCMD_FILETIMES_PER_HOUR;
  1222. const __int64 DSCMD_FILETIMES_PER_MONTH= 30 * DSCMD_FILETIMES_PER_DAY;
  1223. HRESULT DisplayAccountExpires(PCWSTR /*pszDN*/,
  1224. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  1225. const CDSCmdCredentialObject& /*refCredentialObject*/,
  1226. _DSGetObjectTableEntry* pEntry,
  1227. ARG_RECORD* pRecord,
  1228. PADS_ATTR_INFO pAttrInfo,
  1229. CComPtr<IDirectoryObject>& /*spDirObject*/,
  1230. PDSGET_DISPLAY_INFO pDisplayInfo)
  1231. {
  1232. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayAccountExpires, hr);
  1233. do // false loop
  1234. {
  1235. //
  1236. // Verify parameters
  1237. //
  1238. if (!pEntry ||
  1239. !pRecord ||
  1240. !pDisplayInfo)
  1241. {
  1242. ASSERT(pEntry);
  1243. ASSERT(pRecord);
  1244. ASSERT(pDisplayInfo);
  1245. hr = E_INVALIDARG;
  1246. break;
  1247. }
  1248. if (pAttrInfo && pAttrInfo->pADsValues)
  1249. {
  1250. DEBUG_OUTPUT(FULL_LOGGING,
  1251. L"Adding %d values:",
  1252. pAttrInfo->dwNumValues);
  1253. DWORD dwValuesAdded = 0;
  1254. for (DWORD dwIdx = 0; dwIdx < pAttrInfo->dwNumValues; dwIdx++)
  1255. {
  1256. WCHAR* pBuffer = new WCHAR[MAXSTR+1];
  1257. if (!pBuffer)
  1258. {
  1259. hr = E_OUTOFMEMORY;
  1260. break;
  1261. }
  1262. ZeroMemory(pBuffer, (MAXSTR+1) * sizeof(WCHAR));
  1263. if (pAttrInfo->pADsValues[dwIdx].LargeInteger.QuadPart == 0 ||
  1264. pAttrInfo->pADsValues[dwIdx].LargeInteger.QuadPart == -1 ||
  1265. pAttrInfo->pADsValues[dwIdx].LargeInteger.QuadPart == 0x7FFFFFFFFFFFFFFF)
  1266. {
  1267. //Security Review: if g_pszNever is greater or equal to MAXSTR,
  1268. //buffer is not null terminated.Bug 574385
  1269. wcsncpy(pBuffer, g_pszNever, MAXSTR); //Change pBuffer size to MAXSTR+1, yanggao
  1270. hr = pDisplayInfo->AddValue(pBuffer);
  1271. if (FAILED(hr))
  1272. {
  1273. delete[] pBuffer;
  1274. pBuffer = NULL;
  1275. break;
  1276. }
  1277. dwValuesAdded++;
  1278. }
  1279. else
  1280. {
  1281. FILETIME ftGMT; // GMT filetime
  1282. FILETIME ftLocal; // Local filetime
  1283. SYSTEMTIME st;
  1284. SYSTEMTIME stGMT;
  1285. ZeroMemory(&ftGMT, sizeof(FILETIME));
  1286. ZeroMemory(&ftLocal, sizeof(FILETIME));
  1287. ZeroMemory(&st, sizeof(SYSTEMTIME));
  1288. ZeroMemory(&stGMT, sizeof(SYSTEMTIME));
  1289. //Get Local Time in SYSTEMTIME format
  1290. ftGMT.dwLowDateTime = pAttrInfo->pADsValues[dwIdx].LargeInteger.LowPart;
  1291. ftGMT.dwHighDateTime = pAttrInfo->pADsValues[dwIdx].LargeInteger.HighPart;
  1292. FileTimeToSystemTime(&ftGMT, &stGMT);
  1293. SystemTimeToTzSpecificLocalTime(NULL, &stGMT,&st);
  1294. //For Display Purpose reduce one day
  1295. SystemTimeToFileTime(&st, &ftLocal );
  1296. pAttrInfo->pADsValues[dwIdx].LargeInteger.LowPart = ftLocal.dwLowDateTime;
  1297. pAttrInfo->pADsValues[dwIdx].LargeInteger.HighPart = ftLocal.dwHighDateTime;
  1298. pAttrInfo->pADsValues[dwIdx].LargeInteger.QuadPart -= DSCMD_FILETIMES_PER_DAY;
  1299. ftLocal.dwLowDateTime = pAttrInfo->pADsValues[dwIdx].LargeInteger.LowPart;
  1300. ftLocal.dwHighDateTime = pAttrInfo->pADsValues[dwIdx].LargeInteger.HighPart;
  1301. FileTimeToSystemTime(&ftLocal, &st);
  1302. // Format the string with respect to locale
  1303. if (!GetDateFormat(LOCALE_USER_DEFAULT, 0 ,
  1304. &st, NULL,
  1305. pBuffer, MAXSTR))
  1306. {
  1307. hr = GetLastError();
  1308. DEBUG_OUTPUT(LEVEL5_LOGGING,
  1309. L"Failed to locale string for date: hr = 0x%x",
  1310. hr);
  1311. }
  1312. else
  1313. {
  1314. hr = pDisplayInfo->AddValue(pBuffer);
  1315. if (FAILED(hr))
  1316. {
  1317. delete[] pBuffer;
  1318. pBuffer = NULL;
  1319. break;
  1320. }
  1321. dwValuesAdded++;
  1322. }
  1323. }
  1324. delete[] pBuffer;
  1325. pBuffer = NULL;
  1326. }
  1327. }
  1328. } while (false);
  1329. return hr;
  1330. }
  1331. HRESULT DisplayGroupScope(PCWSTR /*pszDN*/,
  1332. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  1333. const CDSCmdCredentialObject& /*refCredentialObject*/,
  1334. _DSGetObjectTableEntry* pEntry,
  1335. ARG_RECORD* pRecord,
  1336. PADS_ATTR_INFO pAttrInfo,
  1337. CComPtr<IDirectoryObject>& /*spDirObject*/,
  1338. PDSGET_DISPLAY_INFO pDisplayInfo)
  1339. {
  1340. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayGroupScope, hr);
  1341. do // false loop
  1342. {
  1343. //
  1344. // Verify parameters
  1345. //
  1346. if (!pEntry ||
  1347. !pRecord ||
  1348. !pDisplayInfo)
  1349. {
  1350. ASSERT(pEntry);
  1351. ASSERT(pRecord);
  1352. ASSERT(pDisplayInfo);
  1353. hr = E_INVALIDARG;
  1354. break;
  1355. }
  1356. if (pAttrInfo->pADsValues && pAttrInfo->dwADsType == ADSTYPE_INTEGER)
  1357. {
  1358. DEBUG_OUTPUT(FULL_LOGGING,
  1359. L"Adding %d values:",
  1360. pAttrInfo->dwNumValues);
  1361. if (pAttrInfo->pADsValues->Integer & GROUP_TYPE_RESOURCE_GROUP)
  1362. {
  1363. //
  1364. // Display Domain Local
  1365. //
  1366. DEBUG_OUTPUT(LEVEL8_LOGGING,
  1367. L"Group scope: domain local");
  1368. hr = pDisplayInfo->AddValue(L"domain local");
  1369. }
  1370. else if (pAttrInfo->pADsValues->Integer & GROUP_TYPE_ACCOUNT_GROUP)
  1371. {
  1372. //
  1373. // Display Global
  1374. //
  1375. DEBUG_OUTPUT(LEVEL8_LOGGING,
  1376. L"Group scope: global");
  1377. hr = pDisplayInfo->AddValue(L"global");
  1378. }
  1379. else if (pAttrInfo->pADsValues->Integer & GROUP_TYPE_UNIVERSAL_GROUP)
  1380. {
  1381. //
  1382. // Display Universal
  1383. //
  1384. DEBUG_OUTPUT(LEVEL8_LOGGING,
  1385. L"Group scope: universal");
  1386. hr = pDisplayInfo->AddValue(L"universal");
  1387. }
  1388. else if (pAttrInfo->pADsValues->Integer & GROUP_TYPE_APP_BASIC_GROUP)
  1389. {
  1390. //
  1391. // AZ basic group
  1392. //
  1393. DEBUG_OUTPUT(LEVEL8_LOGGING,
  1394. L"Group scope: app basic group");
  1395. CComBSTR sbstrBasicGroup;
  1396. bool result = sbstrBasicGroup.LoadString(::GetModuleHandle(NULL), IDS_APP_BASIC_GROUP);
  1397. ASSERT(result);
  1398. hr = pDisplayInfo->AddValue(sbstrBasicGroup);
  1399. }
  1400. else if (pAttrInfo->pADsValues->Integer & GROUP_TYPE_APP_QUERY_GROUP)
  1401. {
  1402. //
  1403. // AZ basic group
  1404. //
  1405. DEBUG_OUTPUT(LEVEL8_LOGGING,
  1406. L"Group scope: app query group");
  1407. CComBSTR sbstrQueryGroup;
  1408. bool result = sbstrQueryGroup.LoadString(::GetModuleHandle(NULL), IDS_APP_QUERY_GROUP);
  1409. ASSERT(result);
  1410. hr = pDisplayInfo->AddValue(sbstrQueryGroup);
  1411. }
  1412. else
  1413. {
  1414. //
  1415. // Unknown group type???
  1416. //
  1417. DEBUG_OUTPUT(LEVEL8_LOGGING,
  1418. L"Group scope: unknown???");
  1419. hr = pDisplayInfo->AddValue(L"unknown");
  1420. }
  1421. }
  1422. } while (false);
  1423. return hr;
  1424. }
  1425. HRESULT DisplayGroupSecurityEnabled(PCWSTR /*pszDN*/,
  1426. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  1427. const CDSCmdCredentialObject& /*refCredentialObject*/,
  1428. _DSGetObjectTableEntry* pEntry,
  1429. ARG_RECORD* pRecord,
  1430. PADS_ATTR_INFO pAttrInfo,
  1431. CComPtr<IDirectoryObject>& /*spDirObject*/,
  1432. PDSGET_DISPLAY_INFO pDisplayInfo)
  1433. {
  1434. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayGroupSecurityEnabled, hr);
  1435. do // false loop
  1436. {
  1437. //
  1438. // Verify parameters
  1439. //
  1440. if (!pEntry ||
  1441. !pRecord ||
  1442. !pDisplayInfo)
  1443. {
  1444. ASSERT(pEntry);
  1445. ASSERT(pRecord);
  1446. ASSERT(pDisplayInfo);
  1447. hr = E_INVALIDARG;
  1448. break;
  1449. }
  1450. if (pAttrInfo->pADsValues && pAttrInfo->dwADsType == ADSTYPE_INTEGER)
  1451. {
  1452. DEBUG_OUTPUT(FULL_LOGGING,
  1453. L"Adding %d value:",
  1454. 1);
  1455. bool bSecurityEnabled = false;
  1456. if (pAttrInfo->pADsValues->Integer & GROUP_TYPE_SECURITY_ENABLED)
  1457. {
  1458. bSecurityEnabled = true;
  1459. }
  1460. DEBUG_OUTPUT(LEVEL8_LOGGING,
  1461. L"Group security enabled: %s",
  1462. bSecurityEnabled ? g_pszYes : g_pszNo);
  1463. hr = pDisplayInfo->AddValue(bSecurityEnabled ? g_pszYes : g_pszNo);
  1464. }
  1465. } while (false);
  1466. return hr;
  1467. }
  1468. //+--------------------------------------------------------------------------
  1469. //
  1470. // Function: ConvertRIDtoDN
  1471. //
  1472. // Synopsis: Finds the DN for the group associated with the primary group ID
  1473. //
  1474. // Arguments: [pObjSID IN] : SID of the object in question
  1475. // [priGroupRID IN] : primary group ID of the group to be found
  1476. // [refBasePathsInfo IN] : reference to base paths info
  1477. // [refCredObject IN] : reference to the credential manager object
  1478. // [refsbstrdN OUT] : DN of the group
  1479. //
  1480. // Returns: S_OK if everthing succeeds and a group was found
  1481. // S_FALSE if everthing succeeds but no group was found
  1482. // E_INVALIDARG is an argument is incorrect
  1483. // Anything else was a result of a failed ADSI call
  1484. //
  1485. // History: 24-Oct-2000 JeffJon Created
  1486. //
  1487. //---------------------------------------------------------------------------
  1488. HRESULT ConvertRIDtoDN(PSID pObjSID,
  1489. DWORD priGroupRID,
  1490. CDSCmdBasePathsInfo& refBasePathsInfo,
  1491. const CDSCmdCredentialObject& refCredObject,
  1492. CComBSTR& refsbstrDN)
  1493. {
  1494. ENTER_FUNCTION_HR(LEVEL5_LOGGING, ConvertRIDtoDN, hr);
  1495. //
  1496. // This needs to be cleaned up no matter how we exit the false loop
  1497. //
  1498. PWSTR pszSearchFilter = NULL;
  1499. do // false loop
  1500. {
  1501. //
  1502. // Verify parameters
  1503. //
  1504. if (!pObjSID ||
  1505. !priGroupRID)
  1506. {
  1507. ASSERT(pObjSID);
  1508. ASSERT(priGroupRID);
  1509. hr = E_INVALIDARG;
  1510. break;
  1511. }
  1512. UCHAR * psaCount, i;
  1513. PSID pSID = NULL;
  1514. PSID_IDENTIFIER_AUTHORITY psia;
  1515. DWORD rgRid[8];
  1516. psaCount = GetSidSubAuthorityCount(pObjSID);
  1517. if (psaCount == NULL)
  1518. {
  1519. DWORD _dwErr = GetLastError();
  1520. hr = HRESULT_FROM_WIN32( _dwErr );
  1521. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1522. L"GetSidSubAuthorityCount failed: hr = 0x%x",
  1523. hr);
  1524. break;
  1525. }
  1526. if (*psaCount > 8)
  1527. {
  1528. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1529. L"The count returned from GetSidSubAuthorityCount was too high: %d",
  1530. *psaCount);
  1531. hr = E_FAIL;
  1532. break;
  1533. }
  1534. for (i = 0; i < (*psaCount - 1); i++)
  1535. {
  1536. PDWORD pRid = GetSidSubAuthority(pObjSID, (DWORD)i);
  1537. if (pRid == NULL)
  1538. {
  1539. DWORD _dwErr = GetLastError();
  1540. hr = HRESULT_FROM_WIN32( _dwErr );
  1541. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1542. L"GetSidSubAuthority for index %i failed: hr = 0x%x",
  1543. i,
  1544. hr);
  1545. break;
  1546. }
  1547. rgRid[i] = *pRid;
  1548. }
  1549. if (FAILED(hr))
  1550. {
  1551. break;
  1552. }
  1553. rgRid[*psaCount - 1] = priGroupRID;
  1554. for (i = *psaCount; i < 8; i++)
  1555. {
  1556. rgRid[i] = 0;
  1557. }
  1558. psia = GetSidIdentifierAuthority(pObjSID);
  1559. if (psia == NULL)
  1560. {
  1561. DWORD _dwErr = GetLastError();
  1562. hr = HRESULT_FROM_WIN32( _dwErr );
  1563. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1564. L"GetSidIdentifierAuthority failed: hr = 0x%x",
  1565. hr);
  1566. break;
  1567. }
  1568. //Security Review:This is fine.
  1569. if (!AllocateAndInitializeSid(psia, *psaCount, rgRid[0], rgRid[1],
  1570. rgRid[2], rgRid[3], rgRid[4],
  1571. rgRid[5], rgRid[6], rgRid[7], &pSID))
  1572. {
  1573. DWORD _dwErr = GetLastError();
  1574. hr = HRESULT_FROM_WIN32( _dwErr );
  1575. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1576. L"AllocateAndInitializeSid failed: hr = 0x%x",
  1577. hr);
  1578. break;
  1579. }
  1580. PWSTR rgpwzAttrNames[] = { L"ADsPath" };
  1581. const WCHAR wzSearchFormat[] = L"(&(objectCategory=group)(objectSid=%1))";
  1582. PWSTR pwzSID;
  1583. hr = ADsEncodeBinaryData((PBYTE)pSID, GetLengthSid(pSID), &pwzSID);
  1584. if (FAILED(hr))
  1585. {
  1586. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1587. L"ADsEncodeBinaryData failed: hr = 0x%x",
  1588. hr);
  1589. break;
  1590. }
  1591. PVOID apv[1] = { pwzSID };
  1592. // generate the filter
  1593. DWORD characterCount =
  1594. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
  1595. | FORMAT_MESSAGE_FROM_STRING
  1596. | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1597. wzSearchFormat,
  1598. 0,
  1599. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  1600. (PTSTR)&pszSearchFilter,
  1601. 0,
  1602. (va_list*)apv);
  1603. FreeADsMem(pwzSID);
  1604. if (!characterCount)
  1605. {
  1606. DWORD error = ::GetLastError();
  1607. hr = HRESULT_FROM_WIN32(error);
  1608. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1609. L"FormatMessage failed to build filter string: hr = 0x%x",
  1610. hr);
  1611. break;
  1612. }
  1613. DEBUG_OUTPUT(FULL_LOGGING,
  1614. L"Query filter = %s",
  1615. pszSearchFilter);
  1616. //
  1617. // Get the domain path
  1618. //
  1619. CComBSTR sbstrDomainDN;
  1620. sbstrDomainDN = refBasePathsInfo.GetDefaultNamingContext();
  1621. CComBSTR sbstrDomainPath;
  1622. refBasePathsInfo.ComposePathFromDN(sbstrDomainDN, sbstrDomainPath);
  1623. //
  1624. // Get an IDirectorySearch interface to the domain
  1625. //
  1626. CComPtr<IDirectorySearch> spDirSearch;
  1627. hr = DSCmdOpenObject(refCredObject,
  1628. sbstrDomainPath,
  1629. IID_IDirectorySearch,
  1630. (void**)&spDirSearch,
  1631. true);
  1632. if (FAILED(hr))
  1633. {
  1634. break;
  1635. }
  1636. CDSSearch Search;
  1637. hr = Search.Init(spDirSearch);
  1638. if (FAILED(hr))
  1639. {
  1640. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1641. L"Failed to initialize the search object: hr = 0x%x",
  1642. hr);
  1643. break;
  1644. }
  1645. Search.SetFilterString(pszSearchFilter);
  1646. Search.SetAttributeList(rgpwzAttrNames, 1);
  1647. Search.SetSearchScope(ADS_SCOPE_SUBTREE);
  1648. hr = Search.DoQuery();
  1649. if (FAILED(hr))
  1650. {
  1651. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1652. L"Failed to run search: hr = 0x%x",
  1653. hr);
  1654. break;
  1655. }
  1656. hr = Search.GetNextRow();
  1657. if (hr == S_ADS_NOMORE_ROWS)
  1658. {
  1659. DEBUG_OUTPUT(LEVEL5_LOGGING,
  1660. L"No group was found with primaryGroupID = %d",
  1661. priGroupRID);
  1662. //
  1663. // No object has a matching RID, the primary group must have been
  1664. // deleted. Return S_FALSE to denote this condition.
  1665. //
  1666. hr = S_FALSE;
  1667. break;
  1668. }
  1669. if (FAILED(hr))
  1670. {
  1671. break;
  1672. }
  1673. ADS_SEARCH_COLUMN Column;
  1674. hr = Search.GetColumn(L"ADsPath", &Column);
  1675. if (FAILED(hr))
  1676. {
  1677. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1678. L"Failed to get the path column: hr = 0x%x",
  1679. hr);
  1680. break;
  1681. }
  1682. if (!Column.pADsValues->CaseIgnoreString)
  1683. {
  1684. hr = E_FAIL;
  1685. break;
  1686. }
  1687. refsbstrDN = Column.pADsValues->CaseIgnoreString;
  1688. Search.FreeColumn(&Column);
  1689. } while (false);
  1690. //
  1691. // Cleanup
  1692. //
  1693. if (pszSearchFilter)
  1694. {
  1695. LocalFree(pszSearchFilter);
  1696. pszSearchFilter = NULL;
  1697. }
  1698. return hr;
  1699. }
  1700. //+--------------------------------------------------------------------------
  1701. //
  1702. // Function: AddMembershipValues
  1703. //
  1704. // Synopsis: Retrieves the DNs of the objects to which the current object
  1705. // is a member
  1706. //
  1707. // Arguments: [pszDN IN] : DN of object to retrieve member of
  1708. // [refBasePathsInfo IN] : reference to Base paths info object
  1709. // [refCredentialObject IN] : reference to Credential management object
  1710. // [pDisplayInfo IN/OUT] : Pointer to display info for this attribute
  1711. // [bMemberOf IN] : Should we look for memberOf or members
  1712. // [bRecurse IN] : Should we find the membership for each object returned
  1713. //
  1714. // Returns: S_OK if everthing succeeds
  1715. // E_INVALIDARG is an argument is incorrect
  1716. // Anything else was a result of a failed ADSI call
  1717. //
  1718. // History: 24-Oct-2000 JeffJon Created
  1719. //
  1720. //---------------------------------------------------------------------------
  1721. HRESULT AddMembershipValues(PCWSTR pszDN,
  1722. CDSCmdBasePathsInfo& refBasePathsInfo,
  1723. const CDSCmdCredentialObject& refCredentialObject,
  1724. PDSGET_DISPLAY_INFO pDisplayInfo,
  1725. bool bMemberOf = true,
  1726. bool bRecurse = false)
  1727. {
  1728. ENTER_FUNCTION_HR(LEVEL5_LOGGING, AddMembershipValues, hr);
  1729. //
  1730. // These are declared here so that we can free them if we break out of the false loop
  1731. //
  1732. PADS_ATTR_INFO pAttrInfo = NULL;
  1733. PADS_ATTR_INFO pGCAttrInfo = NULL;
  1734. PSID pObjSID = NULL;
  1735. do // false loop
  1736. {
  1737. //
  1738. // Verify parameters
  1739. //
  1740. if (!pszDN ||
  1741. !pDisplayInfo)
  1742. {
  1743. ASSERT(pszDN);
  1744. ASSERT(pDisplayInfo);
  1745. hr = E_INVALIDARG;
  1746. break;
  1747. }
  1748. CManagedStringList groupsDisplayed;
  1749. CManagedStringList membersToDisplay;
  1750. membersToDisplay.Add(pszDN);
  1751. CManagedStringEntry* pCurrent = membersToDisplay.Pop();
  1752. while (pCurrent)
  1753. {
  1754. //
  1755. // We have to open the object
  1756. //
  1757. CComPtr<IDirectoryObject> spDirObject;
  1758. CComBSTR sbstrPath;
  1759. refBasePathsInfo.ComposePathFromDN(pCurrent->sbstrValue, sbstrPath);
  1760. hr = DSCmdOpenObject(refCredentialObject,
  1761. sbstrPath,
  1762. IID_IDirectoryObject,
  1763. (void**)&spDirObject,
  1764. true);
  1765. if (FAILED(hr))
  1766. {
  1767. if (pCurrent)
  1768. {
  1769. delete pCurrent;
  1770. pCurrent = 0;
  1771. }
  1772. pCurrent = membersToDisplay.Pop();
  1773. continue;
  1774. }
  1775. CComBSTR sbstrClass;
  1776. CComPtr<IADs> spIADs;
  1777. hr = spDirObject->QueryInterface(IID_IADs, (void**)&spIADs);
  1778. if (FAILED(hr))
  1779. {
  1780. if (pCurrent)
  1781. {
  1782. delete pCurrent;
  1783. pCurrent = 0;
  1784. }
  1785. pCurrent = membersToDisplay.Pop();
  1786. continue;
  1787. }
  1788. hr = spIADs->get_Class(&sbstrClass);
  1789. if (FAILED(hr))
  1790. {
  1791. if (pCurrent)
  1792. {
  1793. delete pCurrent;
  1794. pCurrent = 0;
  1795. }
  1796. pCurrent = membersToDisplay.Pop();
  1797. continue;
  1798. }
  1799. //
  1800. // Read the memberOf attribute and any attributes we need for that specific class
  1801. //
  1802. //This is fine. Both are null terminated.
  1803. if (_wcsicmp(sbstrClass, g_pszUser) == 0 ||
  1804. _wcsicmp(sbstrClass, g_pszComputer) == 0)
  1805. {
  1806. if (!bMemberOf)
  1807. {
  1808. // Don't want to show memberOf info if we are looking for members
  1809. if (pCurrent)
  1810. {
  1811. delete pCurrent;
  1812. pCurrent = 0;
  1813. }
  1814. pCurrent = membersToDisplay.Pop();
  1815. continue;
  1816. }
  1817. DEBUG_OUTPUT(FULL_LOGGING, L"Displaying membership for a user or computer");
  1818. static const DWORD dwAttrCount = 3;
  1819. PWSTR ppszAttrNames[] = { L"memberOf", L"primaryGroupID", L"objectSID" };
  1820. DWORD dwAttrsReturned = 0;
  1821. hr = spDirObject->GetObjectAttributes(ppszAttrNames,
  1822. dwAttrCount,
  1823. &pAttrInfo,
  1824. &dwAttrsReturned);
  1825. if (FAILED(hr))
  1826. {
  1827. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1828. L"GetObjectAttributes failed for class %s: hr = 0x%x",
  1829. sbstrClass,
  1830. hr);
  1831. if (pCurrent)
  1832. {
  1833. delete pCurrent;
  1834. pCurrent = 0;
  1835. }
  1836. pCurrent = membersToDisplay.Pop();
  1837. continue;
  1838. }
  1839. if (pAttrInfo && dwAttrsReturned)
  1840. {
  1841. DWORD priGroupRID = 0;
  1842. //
  1843. // For each attribute returned do the appropriate thing
  1844. //
  1845. for (DWORD dwIdx = 0; dwIdx < dwAttrsReturned; dwIdx++)
  1846. {
  1847. //Security Review:This is fine.
  1848. if (_wcsicmp(pAttrInfo[dwIdx].pszAttrName, L"memberOf") == 0)
  1849. {
  1850. //
  1851. // Add each value and recurse if necessary
  1852. //
  1853. for (DWORD dwValueIdx = 0; dwValueIdx < pAttrInfo[dwIdx].dwNumValues; dwValueIdx++)
  1854. {
  1855. if (pAttrInfo[dwIdx].pADsValues &&
  1856. pAttrInfo[dwIdx].pADsValues[dwValueIdx].DNString)
  1857. {
  1858. if (!groupsDisplayed.Contains(pAttrInfo[dwIdx].pADsValues[dwValueIdx].DNString))
  1859. {
  1860. DEBUG_OUTPUT(LEVEL8_LOGGING,
  1861. L"Adding group to display: %s",
  1862. pAttrInfo[dwIdx].pADsValues[dwValueIdx].DNString);
  1863. groupsDisplayed.Add(pAttrInfo[dwIdx].pADsValues[dwValueIdx].DNString);
  1864. hr = pDisplayInfo->AddValue(GetQuotedDN(pAttrInfo[dwIdx].pADsValues[dwValueIdx].DNString));
  1865. if (FAILED(hr))
  1866. {
  1867. break; // value for loop
  1868. }
  1869. if (bRecurse)
  1870. {
  1871. DEBUG_OUTPUT(LEVEL8_LOGGING,
  1872. L"Adding group for recursion: %s",
  1873. pAttrInfo[dwIdx].pADsValues[dwValueIdx].DNString);
  1874. membersToDisplay.Add(pAttrInfo[dwIdx].pADsValues[dwValueIdx].DNString);
  1875. }
  1876. }
  1877. }
  1878. }
  1879. if (FAILED(hr))
  1880. {
  1881. break; // attrs for loop
  1882. }
  1883. }
  1884. //Security Review:Both are null terminated.
  1885. else if (_wcsicmp(pAttrInfo[dwIdx].pszAttrName, L"primaryGroupID") == 0)
  1886. {
  1887. if (pAttrInfo[dwIdx].pADsValues)
  1888. {
  1889. priGroupRID = pAttrInfo[dwIdx].pADsValues->Integer;
  1890. }
  1891. }
  1892. //Security Review:Both are null terminated.
  1893. else if (_wcsicmp(pAttrInfo[dwIdx].pszAttrName, L"objectSID") == 0)
  1894. {
  1895. pObjSID = new BYTE[pAttrInfo[dwIdx].pADsValues->OctetString.dwLength];
  1896. if (!pObjSID)
  1897. {
  1898. hr = E_OUTOFMEMORY;
  1899. break; // attrs for loop
  1900. }
  1901. //Security Review:This is fine.
  1902. memcpy(pObjSID, pAttrInfo[dwIdx].pADsValues->OctetString.lpValue,
  1903. pAttrInfo[dwIdx].pADsValues->OctetString.dwLength);
  1904. }
  1905. } // attrs for loop
  1906. //
  1907. // if we were able to retrieve the SID and the primaryGroupID,
  1908. // then convert that into the DN of the group
  1909. //
  1910. if (pObjSID &&
  1911. priGroupRID)
  1912. {
  1913. CComBSTR sbstrPath;
  1914. hr = ConvertRIDtoDN(pObjSID,
  1915. priGroupRID,
  1916. refBasePathsInfo,
  1917. refCredentialObject,
  1918. sbstrPath);
  1919. if (SUCCEEDED(hr) &&
  1920. hr != S_FALSE)
  1921. {
  1922. CComBSTR sbstrDN;
  1923. hr = CPathCracker::GetDNFromPath(sbstrPath, sbstrDN);
  1924. if (SUCCEEDED(hr))
  1925. {
  1926. if (!groupsDisplayed.Contains(sbstrDN))
  1927. {
  1928. groupsDisplayed.Add(sbstrDN);
  1929. hr = pDisplayInfo->AddValue(GetQuotedDN(sbstrDN));
  1930. if (SUCCEEDED(hr) && bRecurse)
  1931. {
  1932. membersToDisplay.Add(sbstrDN);
  1933. }
  1934. }
  1935. }
  1936. }
  1937. if (pObjSID)
  1938. {
  1939. delete[] pObjSID;
  1940. pObjSID = 0;
  1941. }
  1942. }
  1943. }
  1944. if (pAttrInfo)
  1945. {
  1946. FreeADsMem(pAttrInfo);
  1947. pAttrInfo = NULL;
  1948. }
  1949. if (FAILED(hr))
  1950. {
  1951. if (pCurrent)
  1952. {
  1953. delete pCurrent;
  1954. pCurrent = 0;
  1955. }
  1956. pCurrent = membersToDisplay.Pop();
  1957. continue; // while loop
  1958. }
  1959. }
  1960. //Security Review:Both are null terminated.
  1961. else if (_wcsicmp(sbstrClass, g_pszGroup) == 0)
  1962. {
  1963. long lGroupType = 0;
  1964. hr = ReadGroupType(pszDN,
  1965. refBasePathsInfo,
  1966. refCredentialObject,
  1967. &lGroupType);
  1968. if (FAILED(hr))
  1969. {
  1970. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1971. L"Could not read group type: hr = 0x%x",
  1972. hr);
  1973. // Continue on even if we failed to read the group type
  1974. // The worst thing we do is query the GC for memberOf
  1975. }
  1976. //
  1977. // All we want to do is get the memberOf attribute
  1978. //
  1979. DWORD dwAttrCount = 1;
  1980. PWSTR ppszAttrNames[1];
  1981. ppszAttrNames[0] = (bMemberOf) ? L"memberOf" : L"member";
  1982. DWORD dwGCAttrsReturned = 0;
  1983. if (!(lGroupType & GROUP_TYPE_RESOURCE_GROUP))
  1984. {
  1985. //
  1986. // We also have to get its memberOf attribute from the GC if its not a local group
  1987. //
  1988. CComBSTR sbstrGCPath;
  1989. refBasePathsInfo.ComposePathFromDN(pszDN,
  1990. sbstrGCPath,
  1991. DSCMD_GC_PROVIDER);
  1992. //
  1993. // Note: we will continue on as long as we succeed
  1994. //
  1995. CComPtr<IDirectoryObject> spGCDirObject;
  1996. hr = DSCmdOpenObject(refCredentialObject,
  1997. sbstrGCPath,
  1998. IID_IDirectoryObject,
  1999. (void**)&spGCDirObject,
  2000. false);
  2001. if (SUCCEEDED(hr))
  2002. {
  2003. //
  2004. // Now get the memberOf attribute
  2005. //
  2006. hr = spGCDirObject->GetObjectAttributes(ppszAttrNames,
  2007. dwAttrCount,
  2008. &pGCAttrInfo,
  2009. &dwGCAttrsReturned);
  2010. if (FAILED(hr))
  2011. {
  2012. DEBUG_OUTPUT(LEVEL3_LOGGING,
  2013. L"Could not retrieve memberOf attribute from GC: hr = 0x%x",
  2014. hr);
  2015. hr = S_OK;
  2016. }
  2017. }
  2018. else
  2019. {
  2020. DEBUG_OUTPUT(LEVEL3_LOGGING,
  2021. L"Could not bind to object in GC: hr = 0x%x",
  2022. hr);
  2023. hr = S_OK;
  2024. }
  2025. }
  2026. DWORD dwAttrsReturned = 0;
  2027. hr = spDirObject->GetObjectAttributes(ppszAttrNames,
  2028. dwAttrCount,
  2029. &pAttrInfo,
  2030. &dwAttrsReturned);
  2031. if (FAILED(hr))
  2032. {
  2033. DEBUG_OUTPUT(MINIMAL_LOGGING,
  2034. L"GetObjectAttributes failed for class %s: hr = 0x%x",
  2035. sbstrClass,
  2036. hr);
  2037. if (pCurrent)
  2038. {
  2039. delete pCurrent;
  2040. pCurrent = 0;
  2041. }
  2042. pCurrent = membersToDisplay.Pop();
  2043. continue;
  2044. }
  2045. if (pAttrInfo && dwAttrsReturned)
  2046. {
  2047. bool bFirstPass = true;
  2048. ASSERT(pAttrInfo);
  2049. ASSERT(pAttrInfo->dwNumValues);
  2050. ASSERT(dwAttrsReturned == 1);
  2051. //
  2052. // Add each value and recurse if necessary
  2053. //
  2054. for (DWORD dwValueIdx = 0; dwValueIdx < pAttrInfo->dwNumValues; dwValueIdx++)
  2055. {
  2056. bool bExistsInGCList = false;
  2057. if (pAttrInfo->pADsValues &&
  2058. pAttrInfo->pADsValues[dwValueIdx].DNString)
  2059. {
  2060. if (pGCAttrInfo && dwGCAttrsReturned)
  2061. {
  2062. //
  2063. // Only add if it wasn't in the GC list
  2064. //
  2065. for (DWORD dwGCValueIdx = 0; dwGCValueIdx < pGCAttrInfo->dwNumValues; dwGCValueIdx++)
  2066. {
  2067. if (_wcsicmp(pAttrInfo->pADsValues[dwValueIdx].DNString,
  2068. pGCAttrInfo->pADsValues[dwGCValueIdx].DNString) == 0)
  2069. {
  2070. bExistsInGCList = true;
  2071. if (!bFirstPass)
  2072. {
  2073. break; // gc value for
  2074. }
  2075. }
  2076. //
  2077. // Add all the GC values on the first pass and recurse if necessary
  2078. //
  2079. if (bFirstPass)
  2080. {
  2081. if (!groupsDisplayed.Contains(pGCAttrInfo->pADsValues[dwGCValueIdx].DNString))
  2082. {
  2083. groupsDisplayed.Add(pGCAttrInfo->pADsValues[dwGCValueIdx].DNString);
  2084. hr = pDisplayInfo->AddValue(GetQuotedDN(pGCAttrInfo->pADsValues[dwGCValueIdx].DNString));
  2085. //
  2086. // We will ignore failures with the GC list
  2087. //
  2088. if (bRecurse)
  2089. {
  2090. membersToDisplay.Add(pGCAttrInfo->pADsValues[dwGCValueIdx].DNString);
  2091. }
  2092. }
  2093. }
  2094. }
  2095. bFirstPass = false;
  2096. FreeADsMem(pGCAttrInfo);
  2097. pGCAttrInfo = 0;
  2098. }
  2099. //
  2100. // If it doesn't exist in the GC list then add it.
  2101. //
  2102. if (!bExistsInGCList)
  2103. {
  2104. if (!groupsDisplayed.Contains(pAttrInfo->pADsValues[dwValueIdx].DNString))
  2105. {
  2106. groupsDisplayed.Add(pAttrInfo->pADsValues[dwValueIdx].DNString);
  2107. hr = pDisplayInfo->AddValue(GetQuotedDN(pAttrInfo->pADsValues[dwValueIdx].DNString));
  2108. if (FAILED(hr))
  2109. {
  2110. break; // value for loop
  2111. }
  2112. if (bRecurse)
  2113. {
  2114. membersToDisplay.Add(pAttrInfo->pADsValues[dwValueIdx].DNString);
  2115. }
  2116. }
  2117. }
  2118. }
  2119. } // value for loop
  2120. FreeADsMem(pAttrInfo);
  2121. pAttrInfo = 0;
  2122. if (FAILED(hr))
  2123. {
  2124. if (pCurrent)
  2125. {
  2126. delete pCurrent;
  2127. pCurrent = 0;
  2128. }
  2129. pCurrent = membersToDisplay.Pop();
  2130. continue; // while loop
  2131. }
  2132. }
  2133. }
  2134. else
  2135. {
  2136. DEBUG_OUTPUT(MINIMAL_LOGGING, L"Unknown class type: %s", sbstrClass);
  2137. ASSERT(false);
  2138. hr = E_INVALIDARG;
  2139. break;
  2140. }
  2141. delete pCurrent;
  2142. pCurrent = membersToDisplay.Pop();
  2143. }
  2144. if (pCurrent)
  2145. {
  2146. delete pCurrent;
  2147. pCurrent = 0;
  2148. }
  2149. } while (false);
  2150. return hr;
  2151. }
  2152. HRESULT DisplayGroupMembers(PCWSTR pszDN,
  2153. CDSCmdBasePathsInfo& refBasePathsInfo,
  2154. const CDSCmdCredentialObject& refCredentialObject,
  2155. _DSGetObjectTableEntry* /*pEntry*/,
  2156. ARG_RECORD* pCommandArgs,
  2157. PADS_ATTR_INFO /*pAttrInfo*/,
  2158. CComPtr<IDirectoryObject>& /*spDirObject*/,
  2159. PDSGET_DISPLAY_INFO pDisplayInfo)
  2160. {
  2161. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayGroupMembers, hr);
  2162. do // false loop
  2163. {
  2164. //
  2165. // Verify parameters
  2166. //
  2167. if (!pszDN ||
  2168. !pCommandArgs ||
  2169. !pDisplayInfo)
  2170. {
  2171. ASSERT(pszDN);
  2172. ASSERT(pCommandArgs);
  2173. ASSERT(pDisplayInfo);
  2174. hr = E_INVALIDARG;
  2175. break;
  2176. }
  2177. hr = AddMembershipValues(pszDN,
  2178. refBasePathsInfo,
  2179. refCredentialObject,
  2180. pDisplayInfo,
  2181. false,
  2182. (pCommandArgs[eGroupExpand].bDefined != 0));
  2183. } while (false);
  2184. return hr;
  2185. }
  2186. HRESULT DisplayUserMemberOf(PCWSTR pszDN,
  2187. CDSCmdBasePathsInfo& refBasePathsInfo,
  2188. const CDSCmdCredentialObject& refCredentialObject,
  2189. _DSGetObjectTableEntry* /*pEntry*/,
  2190. ARG_RECORD* pCommandArgs,
  2191. PADS_ATTR_INFO /*pAttrInfo*/,
  2192. CComPtr<IDirectoryObject>& /*spDirObject*/,
  2193. PDSGET_DISPLAY_INFO pDisplayInfo)
  2194. {
  2195. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayUserMemberOf, hr);
  2196. do // false loop
  2197. {
  2198. //
  2199. // Verify parameters
  2200. //
  2201. if (!pszDN ||
  2202. !pCommandArgs ||
  2203. !pDisplayInfo)
  2204. {
  2205. ASSERT(pCommandArgs);
  2206. ASSERT(pDisplayInfo);
  2207. hr = E_INVALIDARG;
  2208. break;
  2209. }
  2210. hr = AddMembershipValues(pszDN,
  2211. refBasePathsInfo,
  2212. refCredentialObject,
  2213. pDisplayInfo,
  2214. true,
  2215. (pCommandArgs[eUserExpand].bDefined != 0));
  2216. } while (false);
  2217. return hr;
  2218. }
  2219. HRESULT DisplayComputerMemberOf(PCWSTR pszDN,
  2220. CDSCmdBasePathsInfo& refBasePathsInfo,
  2221. const CDSCmdCredentialObject& refCredentialObject,
  2222. _DSGetObjectTableEntry* /*pEntry*/,
  2223. ARG_RECORD* pCommandArgs,
  2224. PADS_ATTR_INFO /*pAttrInfo*/,
  2225. CComPtr<IDirectoryObject>& /*spDirObject*/,
  2226. PDSGET_DISPLAY_INFO pDisplayInfo)
  2227. {
  2228. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayComputerMemberOf, hr);
  2229. do // false loop
  2230. {
  2231. //
  2232. // Verify parameters
  2233. //
  2234. if (!pszDN ||
  2235. !pCommandArgs ||
  2236. !pDisplayInfo)
  2237. {
  2238. ASSERT(pszDN);
  2239. ASSERT(pCommandArgs);
  2240. ASSERT(pDisplayInfo);
  2241. hr = E_INVALIDARG;
  2242. break;
  2243. }
  2244. hr = AddMembershipValues(pszDN,
  2245. refBasePathsInfo,
  2246. refCredentialObject,
  2247. pDisplayInfo,
  2248. true,
  2249. (pCommandArgs[eComputerExpand].bDefined != 0));
  2250. } while (false);
  2251. return hr;
  2252. }
  2253. HRESULT DisplayGroupMemberOf(PCWSTR pszDN,
  2254. CDSCmdBasePathsInfo& refBasePathsInfo,
  2255. const CDSCmdCredentialObject& refCredentialObject,
  2256. _DSGetObjectTableEntry* /*pEntry*/,
  2257. ARG_RECORD* pCommandArgs,
  2258. PADS_ATTR_INFO /*pAttrInfo*/,
  2259. CComPtr<IDirectoryObject>& /*spDirObject*/,
  2260. PDSGET_DISPLAY_INFO pDisplayInfo)
  2261. {
  2262. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayGroupMemberOf, hr);
  2263. do // false loop
  2264. {
  2265. //
  2266. // Verify parameters
  2267. //
  2268. if (!pszDN ||
  2269. !pCommandArgs ||
  2270. !pDisplayInfo)
  2271. {
  2272. ASSERT(pszDN);
  2273. ASSERT(pCommandArgs);
  2274. ASSERT(pDisplayInfo);
  2275. hr = E_INVALIDARG;
  2276. break;
  2277. }
  2278. hr = AddMembershipValues(pszDN,
  2279. refBasePathsInfo,
  2280. refCredentialObject,
  2281. pDisplayInfo,
  2282. true,
  2283. (pCommandArgs[eGroupExpand].bDefined != 0));
  2284. } while (false);
  2285. return hr;
  2286. }
  2287. HRESULT DisplayGrandparentRDN(PCWSTR pszDN,
  2288. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  2289. const CDSCmdCredentialObject& /*refCredentialObject*/,
  2290. _DSGetObjectTableEntry* /*pEntry*/,
  2291. ARG_RECORD* /*pCommandArgs*/,
  2292. PADS_ATTR_INFO /*pAttrInfo*/,
  2293. CComPtr<IDirectoryObject>& /*spDirObject*/,
  2294. PDSGET_DISPLAY_INFO pDisplayInfo)
  2295. {
  2296. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayGrandparentRDN, hr);
  2297. do // false loop
  2298. {
  2299. //
  2300. // Verify parameters
  2301. //
  2302. if (!pszDN ||
  2303. !pDisplayInfo)
  2304. {
  2305. ASSERT(pszDN);
  2306. ASSERT(pDisplayInfo);
  2307. hr = E_INVALIDARG;
  2308. break;
  2309. }
  2310. CComBSTR sbstrSiteName;
  2311. CPathCracker pathCracker;
  2312. hr = pathCracker.Set(CComBSTR(pszDN), ADS_SETTYPE_DN);
  2313. if (FAILED(hr))
  2314. {
  2315. DEBUG_OUTPUT(MINIMAL_LOGGING,
  2316. L"IADsPathname::Set failed: hr = 0x%x",
  2317. hr);
  2318. break;
  2319. }
  2320. hr = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  2321. if (FAILED(hr))
  2322. {
  2323. DEBUG_OUTPUT(MINIMAL_LOGGING,
  2324. L"IADsPathname::SetDisplayType failed: hr = 0x%x",
  2325. hr);
  2326. break;
  2327. }
  2328. hr = pathCracker.GetElement(2, &sbstrSiteName);
  2329. if (FAILED(hr))
  2330. {
  2331. DEBUG_OUTPUT(MINIMAL_LOGGING,
  2332. L"IADsPathname::GetElement failed: hr = 0x%x",
  2333. hr);
  2334. break;
  2335. }
  2336. hr = pDisplayInfo->AddValue(sbstrSiteName);
  2337. } while (false);
  2338. return hr;
  2339. }
  2340. HRESULT DisplayObjectAttributeAsRDN(PCWSTR /*pszDN*/,
  2341. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  2342. const CDSCmdCredentialObject& /*refCredentialObject*/,
  2343. _DSGetObjectTableEntry* pEntry,
  2344. ARG_RECORD* pRecord,
  2345. PADS_ATTR_INFO pAttrInfo,
  2346. CComPtr<IDirectoryObject>& /*spDirObject*/,
  2347. PDSGET_DISPLAY_INFO pDisplayInfo)
  2348. {
  2349. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayObjectAttributeAsRDN, hr);
  2350. do // false loop
  2351. {
  2352. //
  2353. // Verify parameters
  2354. //
  2355. if (!pEntry ||
  2356. !pRecord ||
  2357. !pDisplayInfo)
  2358. {
  2359. ASSERT(pEntry);
  2360. ASSERT(pRecord);
  2361. ASSERT(pDisplayInfo);
  2362. hr = E_INVALIDARG;
  2363. break;
  2364. }
  2365. if (pAttrInfo && pAttrInfo->pADsValues)
  2366. {
  2367. DEBUG_OUTPUT(FULL_LOGGING,
  2368. L"Adding %d values:",
  2369. pAttrInfo->dwNumValues);
  2370. ASSERT(pAttrInfo->dwADsType == ADSTYPE_DN_STRING);
  2371. // Add only the RDN value of the attribute to the output
  2372. CPathCracker pathCracker;
  2373. hr = pathCracker.Set(CComBSTR(pAttrInfo->pADsValues->DNString), ADS_SETTYPE_DN);
  2374. if (SUCCEEDED(hr))
  2375. {
  2376. hr = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  2377. ASSERT(SUCCEEDED(hr));
  2378. CComBSTR sbstrRDN;
  2379. hr = pathCracker.Retrieve(ADS_FORMAT_LEAF, &sbstrRDN);
  2380. if (SUCCEEDED(hr))
  2381. {
  2382. hr = pDisplayInfo->AddValue(sbstrRDN);
  2383. }
  2384. }
  2385. }
  2386. } while (false);
  2387. return hr;
  2388. }
  2389. HRESULT IsServerGCDisplay(PCWSTR pszDN,
  2390. CDSCmdBasePathsInfo& refBasePathsInfo,
  2391. const CDSCmdCredentialObject& refCredentialObject,
  2392. _DSGetObjectTableEntry* /*pEntry*/,
  2393. ARG_RECORD* /*pCommandArgs*/,
  2394. PADS_ATTR_INFO /*pAttrInfo*/,
  2395. CComPtr<IDirectoryObject>& /*spDirObject*/,
  2396. PDSGET_DISPLAY_INFO pDisplayInfo)
  2397. {
  2398. ENTER_FUNCTION_HR(LEVEL5_LOGGING, IsServerGCDisplay, hr);
  2399. do // false loop
  2400. {
  2401. //
  2402. // Verify parameters
  2403. //
  2404. if (!pszDN ||
  2405. !pDisplayInfo)
  2406. {
  2407. ASSERT(pszDN);
  2408. ASSERT(pDisplayInfo);
  2409. hr = E_INVALIDARG;
  2410. break;
  2411. }
  2412. //
  2413. // Compose the path to the NTDS settings object from the server DN
  2414. //
  2415. CComBSTR sbstrNTDSSettingsDN;
  2416. sbstrNTDSSettingsDN = L"CN=NTDS Settings,";
  2417. sbstrNTDSSettingsDN += pszDN;
  2418. CComBSTR sbstrNTDSSettingsPath;
  2419. refBasePathsInfo.ComposePathFromDN(sbstrNTDSSettingsDN, sbstrNTDSSettingsPath);
  2420. CComPtr<IADs> spADs;
  2421. hr = DSCmdOpenObject(refCredentialObject,
  2422. sbstrNTDSSettingsPath,
  2423. IID_IADs,
  2424. (void**)&spADs,
  2425. true);
  2426. if (FAILED(hr))
  2427. {
  2428. break;
  2429. }
  2430. bool bGC = false;
  2431. CComVariant var;
  2432. hr = spADs->Get(CComBSTR(L"options"), &var);
  2433. if (FAILED(hr))
  2434. {
  2435. DEBUG_OUTPUT(LEVEL5_LOGGING,
  2436. L"Failed to get the options: hr = 0x%x",
  2437. hr);
  2438. }
  2439. else
  2440. {
  2441. ASSERT(var.vt == VT_I4);
  2442. if (var.lVal & SERVER_IS_GC_BIT)
  2443. {
  2444. bGC = true;
  2445. }
  2446. }
  2447. DEBUG_OUTPUT(LEVEL8_LOGGING,
  2448. L"Server is GC: %s",
  2449. bGC ? g_pszYes : g_pszNo);
  2450. hr = pDisplayInfo->AddValue(bGC ? g_pszYes : g_pszNo);
  2451. } while (false);
  2452. return hr;
  2453. }
  2454. HRESULT FindSiteSettingsOptions(IDirectoryObject* pDirectoryObj,
  2455. DWORD& refOptions)
  2456. {
  2457. ENTER_FUNCTION_HR(LEVEL5_LOGGING, FindSiteSettingsOptions, hr);
  2458. do // false loop
  2459. {
  2460. //
  2461. // Verify parameters
  2462. //
  2463. if (!pDirectoryObj)
  2464. {
  2465. ASSERT(pDirectoryObj);
  2466. hr = E_INVALIDARG;
  2467. break;
  2468. }
  2469. CComPtr<IDirectorySearch> spSearch;
  2470. hr = pDirectoryObj->QueryInterface(IID_IDirectorySearch, (void**)&spSearch);
  2471. if (FAILED(hr))
  2472. {
  2473. DEBUG_OUTPUT(MINIMAL_LOGGING,
  2474. L"QI for IDirectorySearch failed: hr = 0x%x",
  2475. hr);
  2476. break;
  2477. }
  2478. CDSSearch Search;
  2479. hr = Search.Init(spSearch);
  2480. if (FAILED(hr))
  2481. {
  2482. DEBUG_OUTPUT(MINIMAL_LOGGING,
  2483. L"CDSSearch::Init failed: hr = 0x%x",
  2484. hr);
  2485. break;
  2486. }
  2487. PWSTR pszSearchFilter = L"(objectClass=nTDSSiteSettings)";
  2488. Search.SetFilterString(pszSearchFilter);
  2489. PWSTR rgpwzAttrNames[] = { L"options" };
  2490. Search.SetAttributeList(rgpwzAttrNames, 1);
  2491. Search.SetSearchScope(ADS_SCOPE_ONELEVEL);
  2492. hr = Search.DoQuery();
  2493. if (FAILED(hr))
  2494. {
  2495. DEBUG_OUTPUT(MINIMAL_LOGGING,
  2496. L"Failed to run search: hr = 0x%x",
  2497. hr);
  2498. break;
  2499. }
  2500. hr = Search.GetNextRow();
  2501. if (hr == S_ADS_NOMORE_ROWS)
  2502. {
  2503. DEBUG_OUTPUT(MINIMAL_LOGGING,
  2504. L"No rows found!");
  2505. hr = E_FAIL;
  2506. break;
  2507. }
  2508. ADS_SEARCH_COLUMN Column;
  2509. hr = Search.GetColumn(L"options", &Column);
  2510. if (FAILED(hr))
  2511. {
  2512. DEBUG_OUTPUT(MINIMAL_LOGGING,
  2513. L"Failed to get the options column: hr = 0x%x",
  2514. hr);
  2515. break;
  2516. }
  2517. if (Column.dwADsType != ADSTYPE_INTEGER ||
  2518. Column.dwNumValues == 0 ||
  2519. !Column.pADsValues)
  2520. {
  2521. Search.FreeColumn(&Column);
  2522. hr = E_FAIL;
  2523. break;
  2524. }
  2525. refOptions = Column.pADsValues->Integer;
  2526. Search.FreeColumn(&Column);
  2527. } while (false);
  2528. return hr;
  2529. }
  2530. HRESULT IsAutotopologyEnabledSite(PCWSTR /*pszDN*/,
  2531. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  2532. const CDSCmdCredentialObject& /*refCredentialObject*/,
  2533. _DSGetObjectTableEntry* pEntry,
  2534. ARG_RECORD* pCommandArgs,
  2535. PADS_ATTR_INFO /*pAttrInfo*/,
  2536. CComPtr<IDirectoryObject>& spDirObject,
  2537. PDSGET_DISPLAY_INFO pDisplayInfo)
  2538. {
  2539. ENTER_FUNCTION_HR(LEVEL5_LOGGING, IsAutotopologyEnabledSite, hr);
  2540. bool bAutoTopDisabled = false;
  2541. do // false loop
  2542. {
  2543. //
  2544. // Verify parameters
  2545. //
  2546. if (!pEntry ||
  2547. !pCommandArgs ||
  2548. !pDisplayInfo)
  2549. {
  2550. ASSERT(pEntry);
  2551. ASSERT(pCommandArgs);
  2552. ASSERT(pDisplayInfo);
  2553. hr = E_INVALIDARG;
  2554. break;
  2555. }
  2556. //
  2557. // Get the options attribute from the nTDSSiteSettings object under the site object
  2558. //
  2559. DWORD dwOptions = 0;
  2560. hr = FindSiteSettingsOptions(spDirObject,
  2561. dwOptions);
  2562. if (FAILED(hr))
  2563. {
  2564. break;
  2565. }
  2566. //
  2567. // See if the intersite autotopology is disabled
  2568. //
  2569. if (dwOptions & NTDSSETTINGS_OPT_IS_INTER_SITE_AUTO_TOPOLOGY_DISABLED)
  2570. {
  2571. bAutoTopDisabled = true;
  2572. }
  2573. } while (false);
  2574. //
  2575. // Add the value for display
  2576. //
  2577. DEBUG_OUTPUT(LEVEL8_LOGGING,
  2578. L"Autotopology: %s",
  2579. bAutoTopDisabled ? g_pszNo : g_pszYes);
  2580. pDisplayInfo->AddValue(bAutoTopDisabled ? g_pszNo : g_pszYes);
  2581. return hr;
  2582. }
  2583. HRESULT IsCacheGroupsEnabledSite(PCWSTR /*pszDN*/,
  2584. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  2585. const CDSCmdCredentialObject& /*refCredentialObject*/,
  2586. _DSGetObjectTableEntry* pEntry,
  2587. ARG_RECORD* pCommandArgs,
  2588. PADS_ATTR_INFO /*pAttrInfo*/,
  2589. CComPtr<IDirectoryObject>& spDirObject,
  2590. PDSGET_DISPLAY_INFO pDisplayInfo)
  2591. {
  2592. ENTER_FUNCTION_HR(LEVEL5_LOGGING, IsCacheGroupsEnabledSite, hr);
  2593. bool bCacheGroupsEnabled = false;
  2594. do // false loop
  2595. {
  2596. //
  2597. // Verify parameters
  2598. //
  2599. if (!pEntry ||
  2600. !pCommandArgs ||
  2601. !pDisplayInfo)
  2602. {
  2603. ASSERT(pEntry);
  2604. ASSERT(pCommandArgs);
  2605. ASSERT(pDisplayInfo);
  2606. hr = E_INVALIDARG;
  2607. break;
  2608. }
  2609. //
  2610. // Get the options attribute from the nTDSSiteSettings object under the site object
  2611. //
  2612. DWORD dwOptions = 0;
  2613. hr = FindSiteSettingsOptions(spDirObject,
  2614. dwOptions);
  2615. if (FAILED(hr))
  2616. {
  2617. break;
  2618. }
  2619. //
  2620. // See if groups caching is enabled
  2621. //
  2622. if (dwOptions & NTDSSETTINGS_OPT_IS_GROUP_CACHING_ENABLED)
  2623. {
  2624. bCacheGroupsEnabled = true;
  2625. }
  2626. } while (false);
  2627. //
  2628. // Add the value for display
  2629. //
  2630. DEBUG_OUTPUT(LEVEL8_LOGGING,
  2631. L"Cache groups enabled: %s",
  2632. bCacheGroupsEnabled ? g_pszYes : g_pszNo);
  2633. pDisplayInfo->AddValue(bCacheGroupsEnabled ? g_pszYes : g_pszNo);
  2634. return hr;
  2635. }
  2636. HRESULT FindSiteSettingsPreferredGCSite(IDirectoryObject* pDirectoryObj,
  2637. CComBSTR& refsbstrGC)
  2638. {
  2639. ENTER_FUNCTION_HR(LEVEL5_LOGGING, FindSiteSettingsPreferredGCSite, hr);
  2640. do // false loop
  2641. {
  2642. //
  2643. // Verify parameters
  2644. //
  2645. if (!pDirectoryObj)
  2646. {
  2647. ASSERT(pDirectoryObj);
  2648. hr = E_INVALIDARG;
  2649. break;
  2650. }
  2651. CComPtr<IDirectorySearch> spSearch;
  2652. hr = pDirectoryObj->QueryInterface(IID_IDirectorySearch, (void**)&spSearch);
  2653. if (FAILED(hr))
  2654. {
  2655. DEBUG_OUTPUT(MINIMAL_LOGGING,
  2656. L"QI for IDirectorySearch failed: hr = 0x%x",
  2657. hr);
  2658. break;
  2659. }
  2660. CDSSearch Search;
  2661. hr = Search.Init(spSearch);
  2662. if (FAILED(hr))
  2663. {
  2664. DEBUG_OUTPUT(MINIMAL_LOGGING,
  2665. L"CDSSearch::Init failed: hr = 0x%x",
  2666. hr);
  2667. break;
  2668. }
  2669. PWSTR pszSearchFilter = L"(objectClass=nTDSSiteSettings)";
  2670. Search.SetFilterString(pszSearchFilter);
  2671. PWSTR rgpwzAttrNames[] = { L"msDS-Preferred-GC-Site" };
  2672. Search.SetAttributeList(rgpwzAttrNames, 1);
  2673. Search.SetSearchScope(ADS_SCOPE_ONELEVEL);
  2674. hr = Search.DoQuery();
  2675. if (FAILED(hr))
  2676. {
  2677. DEBUG_OUTPUT(MINIMAL_LOGGING,
  2678. L"Failed to run search: hr = 0x%x",
  2679. hr);
  2680. break;
  2681. }
  2682. hr = Search.GetNextRow();
  2683. if (hr == S_ADS_NOMORE_ROWS)
  2684. {
  2685. DEBUG_OUTPUT(MINIMAL_LOGGING,
  2686. L"No rows found!");
  2687. hr = E_FAIL;
  2688. break;
  2689. }
  2690. ADS_SEARCH_COLUMN Column;
  2691. hr = Search.GetColumn(L"msDS-Preferred-GC-Site", &Column);
  2692. if (FAILED(hr))
  2693. {
  2694. DEBUG_OUTPUT(MINIMAL_LOGGING,
  2695. L"Failed to get the msDS-Preferred-GC-Site column: hr = 0x%x",
  2696. hr);
  2697. break;
  2698. }
  2699. if (Column.dwADsType != ADSTYPE_DN_STRING ||
  2700. Column.dwNumValues == 0 ||
  2701. !Column.pADsValues)
  2702. {
  2703. Search.FreeColumn(&Column);
  2704. hr = E_FAIL;
  2705. break;
  2706. }
  2707. refsbstrGC = Column.pADsValues->DNString;
  2708. Search.FreeColumn(&Column);
  2709. } while (false);
  2710. return hr;
  2711. }
  2712. HRESULT DisplayPreferredGC(PCWSTR /*pszDN*/,
  2713. CDSCmdBasePathsInfo& /*refBasePathsInfo*/,
  2714. const CDSCmdCredentialObject& /*refCredentialObject*/,
  2715. _DSGetObjectTableEntry* pEntry,
  2716. ARG_RECORD* pCommandArgs,
  2717. PADS_ATTR_INFO /*pAttrInfo*/,
  2718. CComPtr<IDirectoryObject>& spDirObject,
  2719. PDSGET_DISPLAY_INFO pDisplayInfo)
  2720. {
  2721. ENTER_FUNCTION_HR(LEVEL5_LOGGING, DisplayPreferredGC, hr);
  2722. CComBSTR sbstrGC;
  2723. do // false loop
  2724. {
  2725. //
  2726. // Verify parameters
  2727. //
  2728. if (!pEntry ||
  2729. !pCommandArgs ||
  2730. !pDisplayInfo)
  2731. {
  2732. ASSERT(pEntry);
  2733. ASSERT(pCommandArgs);
  2734. ASSERT(pDisplayInfo);
  2735. hr = E_INVALIDARG;
  2736. break;
  2737. }
  2738. //
  2739. // Get the msDS-Preferred-GC-Site attribute from the nTDSSiteSettings
  2740. // object under the site object
  2741. //
  2742. hr = FindSiteSettingsPreferredGCSite(spDirObject,
  2743. sbstrGC);
  2744. if (FAILED(hr))
  2745. {
  2746. break;
  2747. }
  2748. } while (false);
  2749. //
  2750. // Add the value for display
  2751. //
  2752. DEBUG_OUTPUT(LEVEL8_LOGGING,
  2753. L"Preferred GC Site: %s",
  2754. (!sbstrGC) ? g_pszNotConfigured : sbstrGC);
  2755. pDisplayInfo->AddValue((!sbstrGC) ? g_pszNotConfigured : sbstrGC);
  2756. return hr;
  2757. }