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.

1838 lines
62 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000
  5. //
  6. // File: output.cpp
  7. //
  8. // Contents: Defines the functions which displays the query output
  9. // History: 05-OCT-2000 hiteshr Created
  10. //
  11. //
  12. //--------------------------------------------------------------------------
  13. #include "pch.h"
  14. #include "cstrings.h"
  15. #include "usage.h"
  16. #include "querytable.h"
  17. #include "querybld.h"
  18. #include "dsquery.h"
  19. #include "query.h"
  20. #include "resource.h"
  21. #include "stdlib.h"
  22. #include "output.h"
  23. #include "sddl.h"
  24. #include <dscmn.h>
  25. //
  26. // list was causing unused formal parameter warnings when compiling with /W4
  27. //
  28. #pragma warning(disable : 4100)
  29. #include <list>
  30. #pragma warning(default : 4100)
  31. HRESULT GetStringFromADs(IN const ADSVALUE *pValues,
  32. IN ADSTYPE dwADsType,
  33. OUT LPWSTR* ppBuffer,
  34. IN PCWSTR pszAttrName);
  35. HRESULT OutputFetchAttr(IN LPWSTR * ppszAttributes,
  36. IN DWORD cAttributes,
  37. IN CDSSearch *pSearch,
  38. IN BOOL bListFormat);
  39. HRESULT OutputAllAttr(IN CDSSearch *pSearch, BOOL bAttrOnly);
  40. HRESULT OutputSingleAttr(IN LPWSTR * ppszAttributes,
  41. IN DWORD cAttributes,
  42. IN CDSSearch *pSearch);
  43. BOOL IsQueryLimitReached(int iResultsDisplayed)
  44. {
  45. if(g_iQueryLimit != 0)
  46. {
  47. if(iResultsDisplayed == g_iQueryLimit)
  48. {
  49. if(!g_bQuiet)
  50. {
  51. if(g_bDeafultLimit)
  52. WriteStringIDToStandardErr(IDS_DEFAULT_QUERY_LIMIT_REACHED);
  53. else
  54. WriteStringIDToStandardErr(IDS_QUERY_LIMIT_REACHED);
  55. }
  56. return TRUE;
  57. }
  58. }
  59. return FALSE;
  60. }
  61. HRESULT LocalCopyString(LPTSTR* ppResult, LPCTSTR pString)
  62. {
  63. if ( !ppResult || !pString )
  64. return E_INVALIDARG;
  65. //pString is NULL terminated.
  66. *ppResult = (LPTSTR)LocalAlloc(LPTR, (wcslen(pString)+1)*sizeof(WCHAR) );
  67. if ( !*ppResult )
  68. return E_OUTOFMEMORY;
  69. //Correct buffer is allocated above.
  70. lstrcpy(*ppResult, pString);
  71. return S_OK; // success
  72. }
  73. //+--------------------------------------------------------------------------
  74. //
  75. // Function: DisplayList
  76. //
  77. // Synopsis: Dispalys a name and value in list format.
  78. // Arguments: [szName - IN] : name of the attribute
  79. // [szValue - IN]: value of the attribute
  80. // [bShowAttribute - IN] : if true the attribute name will be
  81. // prepended to the output
  82. //
  83. //
  84. // History: 05-OCT-2000 hiteshr Created
  85. // 13-Dec-2000 JeffJon Modified - Added the bShowAttribute flag
  86. // so that the caller can determine whether
  87. // or not to show the attribute name
  88. //
  89. //---------------------------------------------------------------------------
  90. VOID DisplayList(LPCWSTR szName, LPCWSTR szValue, bool bShowAttribute = true)
  91. {
  92. if(!szName)
  93. return;
  94. CComBSTR strTemp;
  95. if (bShowAttribute)
  96. {
  97. strTemp = szName;
  98. strTemp += L": ";
  99. }
  100. if(szValue)
  101. strTemp += szValue;
  102. DisplayOutput(strTemp);
  103. }
  104. //+--------------------------------------------------------------------------
  105. //
  106. // Function: DsQueryOutput
  107. //
  108. // Synopsis: This functions outputs the query results.
  109. //
  110. // Arguments: [outputFormat IN] Output format specified at commandline.
  111. // [ppszAttributes IN] List of attributes fetched by query
  112. // [cAttributes,IN] Number of arributes in above array
  113. // [*pSeach,IN] Search Object which has queryhandle
  114. // [bListFormat IN] Is Output to shown in List Format.
  115. // This is valid for "dsquery *" only.
  116. // Returns: HRESULT : S_OK if everything succeeded
  117. // E_INVALIDARG
  118. // Anything else is a failure code from an ADSI call
  119. //
  120. // History: 25-Sep-2000 hiteshr Created
  121. //
  122. //---------------------------------------------------------------------------
  123. HRESULT DsQueryOutput( IN DSQUERY_OUTPUT_FORMAT outputFormat,
  124. IN LPWSTR * ppszAttributes,
  125. IN DWORD cAttributes,
  126. IN CDSSearch *pSearch,
  127. IN BOOL bListFormat )
  128. {
  129. ENTER_FUNCTION_HR(FULL_LOGGING, DsQueryOutput, hr);
  130. if(!pSearch)
  131. {
  132. ASSERT(FALSE);
  133. hr = E_INVALIDARG;
  134. return hr;
  135. }
  136. if(outputFormat == DSQUERY_OUTPUT_ATTRONLY)
  137. {
  138. hr = OutputAllAttr(pSearch, TRUE);
  139. return hr;
  140. }
  141. else if(outputFormat == DSQUERY_OUTPUT_ATTR)
  142. {
  143. //
  144. //Attributes to display were specified at command line
  145. //
  146. if(cAttributes)
  147. {
  148. hr = OutputFetchAttr(ppszAttributes,
  149. cAttributes,
  150. pSearch,
  151. bListFormat);
  152. return hr;
  153. }
  154. else
  155. {
  156. //
  157. //No attributes were specified at commandline Display All the attributes.
  158. //
  159. hr = OutputAllAttr(pSearch, FALSE);
  160. return hr;
  161. }
  162. }
  163. else
  164. {
  165. //
  166. //Do the output for "dsquery objecttype"
  167. //
  168. hr = OutputSingleAttr(ppszAttributes,
  169. cAttributes,
  170. pSearch);
  171. return hr;
  172. }
  173. }
  174. //+--------------------------------------------------------------------------
  175. //
  176. // Function: GetServerSearchRoot
  177. //
  178. // Synopsis: Builds the path to the root of the search as determined by
  179. // the parameters passed in from the command line.
  180. //
  181. // Arguments: [pCommandArgs IN] : the table of the command line input
  182. // [refBasePathsInfo IN] : reference to the base paths info
  183. // [refsbstrDN OUT] : reference to a CComBSTR that will
  184. // receive the DN at which to start
  185. // the search
  186. //
  187. // Returns: SERVER_QUERY_SCOPE : a value from the enumeration that represents
  188. // the scope that will be searched
  189. //
  190. // History: 11-Dec-2000 JeffJon Created
  191. //
  192. //---------------------------------------------------------------------------
  193. DWORD GetServerSearchRoot(IN PARG_RECORD pCommandArgs,
  194. IN CDSCmdBasePathsInfo& refBasePathsInfo,
  195. OUT CComBSTR& refsbstrDN)
  196. {
  197. ENTER_FUNCTION(LEVEL3_LOGGING, GetServerSearchRoot);
  198. DWORD scope = SERVER_QUERY_SCOPE_FOREST;
  199. CComBSTR sbstrRootDN = L"CN=Sites,";
  200. sbstrRootDN += refBasePathsInfo.GetConfigurationNamingContext();
  201. do // false loop
  202. {
  203. //
  204. // Validate parameters
  205. //
  206. if (!pCommandArgs)
  207. {
  208. ASSERT(pCommandArgs);
  209. break;
  210. }
  211. if (pCommandArgs[eServerSite].bDefined &&
  212. pCommandArgs[eServerSite].strValue)
  213. {
  214. DEBUG_OUTPUT(FULL_LOGGING,
  215. L"Using the site as the root of the search: %s",
  216. pCommandArgs[eServerSite].strValue);
  217. //
  218. // Prepend the named site container to the current root
  219. //
  220. CComBSTR sbstrTemp = L"CN=";
  221. sbstrTemp += pCommandArgs[eServerSite].strValue;
  222. sbstrTemp += L",";
  223. sbstrTemp += sbstrRootDN;
  224. sbstrRootDN = sbstrTemp;
  225. DEBUG_OUTPUT(FULL_LOGGING,
  226. L"scope = SERVER_QUERY_SCOPE_SITE");
  227. scope = SERVER_QUERY_SCOPE_SITE;
  228. }
  229. else
  230. {
  231. DEBUG_OUTPUT(FULL_LOGGING,
  232. L"scope = SERVER_QUERY_SCOPE_FOREST");
  233. scope = SERVER_QUERY_SCOPE_FOREST;
  234. }
  235. if (pCommandArgs[eServerDomain].bDefined &&
  236. pCommandArgs[eServerDomain].strValue)
  237. {
  238. DEBUG_OUTPUT(FULL_LOGGING,
  239. L"scope |= SERVER_QUERY_SCOPE_DOMAIN");
  240. scope |= SERVER_QUERY_SCOPE_DOMAIN;
  241. }
  242. refsbstrDN = sbstrRootDN;
  243. DEBUG_OUTPUT(LEVEL3_LOGGING,
  244. L"search root = %s",
  245. refsbstrDN);
  246. DEBUG_OUTPUT(LEVEL3_LOGGING,
  247. L"search scope = 0x%x",
  248. scope);
  249. } while (false);
  250. return scope;
  251. }
  252. //+--------------------------------------------------------------------------
  253. //
  254. // Function: GetSubnetSearchRoot
  255. //
  256. // Synopsis: Builds search root path for Subnet. Its always
  257. // cn=subnet,cn=site in configuration container
  258. //
  259. // Arguments: [refBasePathsInfo IN] : reference to the base paths info
  260. // [refsbstrDN OUT] : reference to a CComBSTR that will
  261. // receive the DN at which to start
  262. // the search
  263. //
  264. // Returns: HRESULT
  265. //
  266. // History: 24-April-2001 hiteshr Created
  267. //
  268. //---------------------------------------------------------------------------
  269. VOID GetSubnetSearchRoot(IN CDSCmdBasePathsInfo& refBasePathsInfo,
  270. OUT CComBSTR& refsbstrDN)
  271. {
  272. ENTER_FUNCTION(LEVEL3_LOGGING, GetSubnetSearchRoot);
  273. refsbstrDN = L"CN=subnets,CN=Sites,";
  274. refsbstrDN += refBasePathsInfo.GetConfigurationNamingContext();
  275. return;
  276. }
  277. //+--------------------------------------------------------------------------
  278. //
  279. // Function: GetSiteContainerPath
  280. //
  281. // Synopsis: Returns the DN for site container in Configuration
  282. // container
  283. //
  284. // Arguments: [refBasePathsInfo IN] : reference to the base paths info
  285. // [refsbstrDN OUT] : reference to a CComBSTR that will
  286. // receive the DN
  287. //
  288. // Returns: HRESULT
  289. //
  290. // History: 24-April-2001 hiteshr Created
  291. //
  292. //---------------------------------------------------------------------------
  293. VOID GetSiteContainerPath(IN CDSCmdBasePathsInfo& refBasePathsInfo,
  294. OUT CComBSTR& refSubSiteSuffix)
  295. {
  296. ENTER_FUNCTION(LEVEL3_LOGGING, GetSubnetSearchRoot);
  297. refSubSiteSuffix = L"CN=Sites,";
  298. refSubSiteSuffix += refBasePathsInfo.GetConfigurationNamingContext();
  299. return;
  300. }
  301. //+--------------------------------------------------------------------------
  302. //
  303. // Function: GetGCList
  304. //
  305. // Synopsis: Does a search from the passed in path looking for GCs
  306. //
  307. // Arguments: [pszSearchRootPath IN] : the path to the root of the search
  308. // [refCredObject IN] : reference to the credential object
  309. // [refGCList OUT] : reference to an STL list that will
  310. // take the DNs of the GCs
  311. //
  312. //
  313. // Returns: HRESULT : S_OK if everything succeeded
  314. // E_INVALIDARG
  315. // Anything else is a failure code from an ADSI call
  316. //
  317. // Remarks: Caller must free all strings added to the list by calling
  318. // SysFreeString()
  319. //
  320. // History: 08-Dec-2000 JeffJon Created
  321. //
  322. //---------------------------------------------------------------------------
  323. HRESULT GetGCList( IN PCWSTR pszSearchRootPath,
  324. IN const CDSCmdCredentialObject& refCredObject,
  325. OUT std::list<BSTR>& refGCList)
  326. {
  327. ENTER_FUNCTION_HR(LEVEL3_LOGGING, GetGCList, hr);
  328. do // false loop
  329. {
  330. //
  331. // Verify parameters
  332. //
  333. if (!pszSearchRootPath)
  334. {
  335. ASSERT(pszSearchRootPath);
  336. hr = E_INVALIDARG;
  337. break;
  338. }
  339. //
  340. // Search for NTDSDSA objects that have the options bit set for a GC
  341. //
  342. CDSSearch gcSearchObj;
  343. hr = gcSearchObj.Init(pszSearchRootPath,
  344. refCredObject);
  345. if (FAILED(hr))
  346. {
  347. break;
  348. }
  349. //
  350. // Prepare the search object
  351. //
  352. PWSTR ppszAttrs[] = { L"distinguishedName" };
  353. DWORD dwAttrCount = sizeof(ppszAttrs)/sizeof(PCWSTR);
  354. PWSTR pszGCFilter = L"(&(objectClass=nTDSDSA)(options:LDAP_MATCHING_RULE_BIT_AND_W:=1))";
  355. gcSearchObj.SetFilterString(pszGCFilter);
  356. gcSearchObj.SetSearchScope(ADS_SCOPE_SUBTREE);
  357. gcSearchObj.SetAttributeList(ppszAttrs, dwAttrCount);
  358. hr = gcSearchObj.DoQuery();
  359. if (FAILED(hr))
  360. {
  361. DEBUG_OUTPUT(LEVEL3_LOGGING,
  362. L"Failed to search for NTDSDSA objects that are GCs: hr = 0x%x",
  363. hr);
  364. break;
  365. }
  366. while (SUCCEEDED(hr))
  367. {
  368. hr = gcSearchObj.GetNextRow();
  369. if (FAILED(hr))
  370. {
  371. DEBUG_OUTPUT(LEVEL3_LOGGING,
  372. L"GetNextRow() failed: hr = 0x%x",
  373. hr);
  374. break;
  375. }
  376. if (hr == S_ADS_NOMORE_ROWS)
  377. {
  378. hr = S_OK;
  379. break;
  380. }
  381. ADS_SEARCH_COLUMN column;
  382. //Security Review:Correct Buffer size is passed.
  383. ZeroMemory(&column, sizeof(ADS_SEARCH_COLUMN));
  384. hr = gcSearchObj.GetColumn(ppszAttrs[0], &column);
  385. if (FAILED(hr))
  386. {
  387. DEBUG_OUTPUT(LEVEL3_LOGGING,
  388. L"Failed to get column %s",
  389. ppszAttrs[0]);
  390. break;
  391. }
  392. //Security Review:Done
  393. ASSERT(0 == _wcsicmp(column.pszAttrName, ppszAttrs[0]));
  394. if (column.dwNumValues == 1 &&
  395. column.pADsValues)
  396. {
  397. //
  398. // Since the server is really the parent of the NTDSDSA object,
  399. // get the server DN and add it to the list
  400. //
  401. CComBSTR sbstrParentDN;
  402. hr = CPathCracker::GetParentDN(column.pADsValues->DNString,
  403. sbstrParentDN);
  404. if (SUCCEEDED(hr))
  405. {
  406. refGCList.push_back(sbstrParentDN.Copy());
  407. DEBUG_OUTPUT(FULL_LOGGING,
  408. L"GC found: %s",
  409. column.pADsValues->DNString);
  410. }
  411. else
  412. {
  413. DEBUG_OUTPUT(LEVEL3_LOGGING,
  414. L"Failed to get the parent DN from the NTDSDSA DN: %s",
  415. column.pADsValues->DNString);
  416. break;
  417. }
  418. }
  419. else
  420. {
  421. DEBUG_OUTPUT(LEVEL3_LOGGING,
  422. L"The column has no values!");
  423. }
  424. hr = gcSearchObj.FreeColumn(&column);
  425. ASSERT(SUCCEEDED(hr));
  426. }
  427. } while (false);
  428. return hr;
  429. }
  430. //+--------------------------------------------------------------------------
  431. //
  432. // Function: GetFSMOList
  433. //
  434. // Synopsis: Does a search from the passed in path looking for the FSMO
  435. // role owners
  436. //
  437. // Arguments: [pszSearchRootPath IN] : the path to the root of the search
  438. // [refBasePathsInfo IN] : reference to the base paths info
  439. // [refCredObject IN] : reference to the credential object
  440. // [pszFSMOArg IN] : the value of the -hasfsmo arg
  441. // [refFSMOList OUT] : reference to the search object that
  442. // will hold the results
  443. //
  444. //
  445. // Returns: HRESULT : S_OK if everything succeeded
  446. // E_INVALIDARG
  447. // Anything else is a failure code from an ADSI call
  448. //
  449. // Remarks: Caller must free all strings added to the list by calling
  450. // SysFreeString()
  451. //
  452. // History: 11-Dec-2000 JeffJon Created
  453. //
  454. //---------------------------------------------------------------------------
  455. HRESULT GetFSMOList( IN PCWSTR pszSearchRootPath,
  456. IN CDSCmdBasePathsInfo& refBasePathsInfo,
  457. IN const CDSCmdCredentialObject& refCredObject,
  458. IN PCWSTR pszFSMOArg,
  459. OUT std::list<BSTR>& refFSMOList)
  460. {
  461. ENTER_FUNCTION_HR(LEVEL3_LOGGING, GetFSMOList, hr);
  462. do // false loop
  463. {
  464. //
  465. // Verify parameters
  466. //
  467. if (!pszSearchRootPath ||
  468. !pszFSMOArg)
  469. {
  470. ASSERT(pszSearchRootPath);
  471. hr = E_INVALIDARG;
  472. break;
  473. }
  474. FSMO_TYPE fsmoType = SCHEMA_FSMO;
  475. //Security Reivew: Both strings are null terminated.
  476. if (0 == _wcsicmp(pszFSMOArg, g_pszSchema))
  477. {
  478. DEBUG_OUTPUT(LEVEL3_LOGGING,
  479. L"Searching for the schema FSMO holder");
  480. fsmoType = SCHEMA_FSMO;
  481. }
  482. //Security Reivew: Both strings are null terminated.
  483. else if (0 == _wcsicmp(pszFSMOArg, g_pszName))
  484. {
  485. DEBUG_OUTPUT(LEVEL3_LOGGING,
  486. L"Searching for the domain naming master FSMO holder");
  487. fsmoType = DOMAIN_NAMING_FSMO;
  488. }
  489. //Security Reivew: Both strings are null terminated.
  490. else if (0 == _wcsicmp(pszFSMOArg, g_pszInfr))
  491. {
  492. DEBUG_OUTPUT(LEVEL3_LOGGING,
  493. L"Searching for the infrastructure FSMO holder");
  494. fsmoType = INFRASTUCTURE_FSMO;
  495. }
  496. //Security Reivew: Both strings are null terminated.
  497. else if (0 == _wcsicmp(pszFSMOArg, g_pszPDC))
  498. {
  499. DEBUG_OUTPUT(LEVEL3_LOGGING,
  500. L"Searching for the PDC FSMO holder");
  501. fsmoType = PDC_FSMO;
  502. }
  503. //Security Reivew: Both strings are null terminated.
  504. else if (0 == _wcsicmp(pszFSMOArg, g_pszRID))
  505. {
  506. DEBUG_OUTPUT(LEVEL3_LOGGING,
  507. L"Searching for the RID FSMO holder");
  508. fsmoType = RID_POOL_FSMO;
  509. }
  510. else
  511. {
  512. DEBUG_OUTPUT(LEVEL3_LOGGING,
  513. L"Unknown FSMO was passed in: %s",
  514. pszFSMOArg);
  515. hr = E_INVALIDARG;
  516. break;
  517. }
  518. CComBSTR sbstrServerDN;
  519. hr = FindFSMOOwner(refBasePathsInfo,
  520. refCredObject,
  521. fsmoType,
  522. sbstrServerDN);
  523. if (FAILED(hr))
  524. {
  525. break;
  526. }
  527. refFSMOList.push_back(sbstrServerDN.Copy());
  528. } while (false);
  529. return hr;
  530. }
  531. //+--------------------------------------------------------------------------
  532. //
  533. // Function: IsObjectValidInAllLists
  534. //
  535. // Synopsis: Determines if the passed in DN exists in the other lists
  536. //
  537. // Arguments: [pszDN IN] : DN to search for in the lists
  538. // [refGCList IN] : reference to the list of GCs found
  539. // [bUseGCList IN] : if true refGCList will be used to validate DN
  540. // [refFSMOList IN] : reference to the list of FSMO holders found
  541. // [bUseFSMOList IN] : if true refFSMOList will be used to validate DN
  542. //
  543. // Returns: bool : true if the object is in all valid lists
  544. // false otherwise
  545. //
  546. // History: 12-Dec-2000 JeffJon Created
  547. //
  548. //---------------------------------------------------------------------------
  549. bool IsObjectValidInAllLists(IN PCWSTR pszComputerDN,
  550. IN PCWSTR pszDN,
  551. IN DWORD scope,
  552. IN PCWSTR pszDomain,
  553. IN const std::list<BSTR>& refGCList,
  554. IN bool bUseGCList,
  555. IN const std::list<BSTR>& refFSMOList,
  556. IN bool bUseFSMOList)
  557. {
  558. ENTER_FUNCTION(LEVEL3_LOGGING, IsObjectValidInAllLists);
  559. bool bReturn = false;
  560. PWSTR pszName = 0;
  561. do // false loop
  562. {
  563. //
  564. // Validate parameters
  565. //
  566. if (!pszDN ||
  567. !pszComputerDN)
  568. {
  569. ASSERT(pszDN);
  570. ASSERT(pszComputerDN);
  571. return false;
  572. }
  573. bool bFoundInGCList = false;
  574. bool bFoundInFSMOList = false;
  575. DEBUG_OUTPUT(LEVEL7_LOGGING,
  576. L"Searching for %s",
  577. pszDN);
  578. if (scope & SERVER_QUERY_SCOPE_DOMAIN)
  579. {
  580. if (!pszDomain)
  581. {
  582. //
  583. // If no domain was specified there is no way we could find a match
  584. //
  585. DEBUG_OUTPUT(LEVEL3_LOGGING,
  586. L"The scope is domain but no domain argument was specified!");
  587. bReturn = false;
  588. break;
  589. }
  590. DEBUG_OUTPUT(FULL_LOGGING,
  591. L"Looking for domain: %s",
  592. pszDomain);
  593. //
  594. // Use CrackName to get the domain name from the DN
  595. //
  596. HRESULT hr = CrackName(const_cast<PTSTR>(pszComputerDN),
  597. &pszName,
  598. GET_DNS_DOMAIN_NAME,
  599. NULL);
  600. if (FAILED(hr))
  601. {
  602. DEBUG_OUTPUT(LEVEL3_LOGGING,
  603. L"Failed to crack the DN into a domain name: hr = 0x%x",
  604. hr);
  605. bReturn = false;
  606. break;
  607. }
  608. //Both names are null terminated.
  609. if (0 != _wcsicmp(pszName, pszDomain))
  610. {
  611. DEBUG_OUTPUT(LEVEL3_LOGGING,
  612. L"Domain names don't match");
  613. bReturn = false;
  614. break;
  615. }
  616. }
  617. if (bUseGCList)
  618. {
  619. DEBUG_OUTPUT(LEVEL3_LOGGING,
  620. L"Searching through GC list...");
  621. std::list<PWSTR>::iterator itr;
  622. for (itr = refGCList.begin(); itr != refGCList.end(); ++itr)
  623. {
  624. //Both names are null terminated.
  625. if (0 == _wcsicmp(*itr, pszDN))
  626. {
  627. bFoundInGCList = true;
  628. break;
  629. }
  630. }
  631. }
  632. if (bUseFSMOList)
  633. {
  634. DEBUG_OUTPUT(LEVEL3_LOGGING,
  635. L"Searching through FSMO list...");
  636. std::list<PWSTR>::iterator itr;
  637. for (itr = refFSMOList.begin(); itr != refFSMOList.end(); ++itr)
  638. {
  639. DEBUG_OUTPUT(FULL_LOGGING,
  640. L"Comparing: %s and %s",
  641. *itr,
  642. pszDN);
  643. //Both names are null terminated.
  644. if (0 == _wcsicmp(*itr, pszDN))
  645. {
  646. bFoundInFSMOList = true;
  647. break;
  648. }
  649. }
  650. }
  651. bReturn = ((bUseGCList && bFoundInGCList) || !bUseGCList) &&
  652. ((bUseFSMOList && bFoundInFSMOList) || !bUseFSMOList);
  653. } while (false);
  654. if(pszName)
  655. LocalFree(pszName);
  656. if (bReturn)
  657. {
  658. DEBUG_OUTPUT(LEVEL3_LOGGING,
  659. L"%s is a valid result",
  660. pszDN);
  661. }
  662. else
  663. {
  664. DEBUG_OUTPUT(LEVEL3_LOGGING,
  665. L"%s is NOT a valid result",
  666. pszDN);
  667. }
  668. return bReturn;
  669. }
  670. //+--------------------------------------------------------------------------
  671. //
  672. // Function: OutputValidSearchResult
  673. //
  674. // Synopsis: Determines if the passed in DN exists in the other lists
  675. //
  676. // Arguments: [refSearchObject - IN] : reference to the object that performed
  677. // the search
  678. // [ppszAttributes - IN] : list of attributes to be displayed
  679. // [cAttributes - IN] : count of attributes in ppszAttributes
  680. //
  681. // Returns:
  682. //
  683. // History: 12-Dec-2000 JeffJon Created
  684. //
  685. //---------------------------------------------------------------------------
  686. void OutputValidSearchResult(IN DSQUERY_OUTPUT_FORMAT outputFormat,
  687. IN CDSSearch& refSearchObject,
  688. IN PWSTR* ppszAttributes,
  689. IN DWORD cAttributes)
  690. {
  691. ENTER_FUNCTION(LEVEL5_LOGGING, OutputValidSearchResult);
  692. HRESULT hr = S_OK;
  693. if (!ppszAttributes ||
  694. cAttributes == 0)
  695. {
  696. ASSERT(cAttributes > 0);
  697. ASSERT(ppszAttributes);
  698. return;
  699. }
  700. //
  701. // Output in list format, note that we are only displaying one attribute
  702. // The first attribute in the array must be the one we want to display
  703. //
  704. ADS_SEARCH_COLUMN ColumnData;
  705. hr = refSearchObject.GetColumn(ppszAttributes[0], &ColumnData);
  706. if(SUCCEEDED(hr))
  707. {
  708. ADSVALUE *pValues = ColumnData.pADsValues;
  709. for( DWORD j = 0; j < ColumnData.dwNumValues && pValues; ++j )
  710. {
  711. LPWSTR pBuffer = NULL;
  712. hr = GetStringFromADs(pValues,
  713. ColumnData.dwADsType,
  714. &pBuffer,
  715. ppszAttributes[0]);
  716. if(SUCCEEDED(hr))
  717. {
  718. CComBSTR sbstrTemp;
  719. if (outputFormat == DSQUERY_OUTPUT_DN)
  720. {
  721. sbstrTemp = L"\"";
  722. sbstrTemp += pBuffer;
  723. sbstrTemp += L"\"";
  724. }
  725. else
  726. {
  727. sbstrTemp = pBuffer;
  728. }
  729. DisplayList(ppszAttributes[0], sbstrTemp, false);
  730. delete pBuffer;
  731. pBuffer = NULL;
  732. }
  733. ++pValues;
  734. }
  735. refSearchObject.FreeColumn(&ColumnData);
  736. }
  737. }
  738. //+--------------------------------------------------------------------------
  739. //
  740. // Function: DsQueryServerOutput
  741. //
  742. // Synopsis: This functions outputs the query results for server object.
  743. //
  744. // Arguments: [outputFormat IN] Output format specified at commandline.
  745. // [ppszAttributes IN] List of attributes fetched by query
  746. // [cAttributes,IN] Number of arributes in above array
  747. // [refServerSearch,IN]reference to the search Object
  748. // [refBasePathsInfo IN] reference to the base paths info
  749. // [pCommandArgs,IN] The pointer to the commands table
  750. //
  751. // Returns: HRESULT : S_OK if everything succeeded
  752. // E_INVALIDARG
  753. // Anything else is a failure code from an ADSI call
  754. //
  755. // History: 08-Dec-2000 JeffJon Created
  756. //
  757. //---------------------------------------------------------------------------
  758. HRESULT DsQueryServerOutput( IN DSQUERY_OUTPUT_FORMAT outputFormat,
  759. IN LPWSTR* ppszAttributes,
  760. IN DWORD cAttributes,
  761. IN CDSSearch& refServerSearch,
  762. IN const CDSCmdCredentialObject& refCredObject,
  763. IN CDSCmdBasePathsInfo& refBasePathsInfo,
  764. IN PARG_RECORD pCommandArgs)
  765. {
  766. ENTER_FUNCTION_HR(LEVEL3_LOGGING, DsQueryServerOutput, hr);
  767. std::list<BSTR> gcList;
  768. std::list<BSTR> fsmoList;
  769. do // false loop
  770. {
  771. //
  772. // Validate parameters
  773. //
  774. if (!ppszAttributes ||
  775. !pCommandArgs)
  776. {
  777. ASSERT(ppszAttributes);
  778. ASSERT(pCommandArgs);
  779. hr = E_INVALIDARG;
  780. break;
  781. }
  782. //
  783. // Determine the scope that should be used
  784. //
  785. CComBSTR sbstrSearchRootDN;
  786. DWORD scope = GetServerSearchRoot(pCommandArgs,
  787. refBasePathsInfo,
  788. sbstrSearchRootDN);
  789. CComBSTR sbstrSearchRootPath;
  790. refBasePathsInfo.ComposePathFromDN(sbstrSearchRootDN, sbstrSearchRootPath);
  791. //
  792. // Build the list of GCs if needed
  793. //
  794. bool bUseGCSearchResults = false;
  795. if (pCommandArgs[eServerIsGC].bDefined &&
  796. pCommandArgs[eServerIsGC].bValue)
  797. {
  798. hr = GetGCList(sbstrSearchRootPath,
  799. refCredObject,
  800. gcList);
  801. if (FAILED(hr))
  802. {
  803. break;
  804. }
  805. //
  806. // If we didn't get any values then there is no reason to continue
  807. // since we won't have anything that matches the -isgc flag
  808. //
  809. if (gcList.size() < 1)
  810. {
  811. break;
  812. }
  813. bUseGCSearchResults = true;
  814. }
  815. //
  816. // Build the list of FSMO owners if needed
  817. //
  818. bool bUseFSMOSearchResults = false;
  819. if (pCommandArgs[eServerHasFSMO].bDefined &&
  820. pCommandArgs[eServerHasFSMO].strValue)
  821. {
  822. hr = GetFSMOList(sbstrSearchRootPath,
  823. refBasePathsInfo,
  824. refCredObject,
  825. pCommandArgs[eServerHasFSMO].strValue,
  826. fsmoList);
  827. if (FAILED(hr))
  828. {
  829. break;
  830. }
  831. bUseFSMOSearchResults = true;
  832. }
  833. //
  834. // See if we need to filter on domain
  835. //
  836. bool bUseDomainFiltering = false;
  837. if (pCommandArgs[eServerDomain].bDefined &&
  838. pCommandArgs[eServerDomain].strValue)
  839. {
  840. bUseDomainFiltering = true;
  841. }
  842. if (!bUseGCSearchResults &&
  843. !bUseFSMOSearchResults &&
  844. !bUseDomainFiltering)
  845. {
  846. hr = DsQueryOutput(outputFormat,
  847. ppszAttributes,
  848. cAttributes,
  849. &refServerSearch,
  850. true);
  851. }
  852. else
  853. {
  854. //
  855. // Either -isgc or -hasfsmo was specified so we have to take the intersection
  856. // of the lists of objects found in each search to use as output
  857. //
  858. while (SUCCEEDED(hr))
  859. {
  860. hr = refServerSearch.GetNextRow();
  861. if (FAILED(hr))
  862. {
  863. break;
  864. }
  865. if (hr == S_ADS_NOMORE_ROWS)
  866. {
  867. hr = S_OK;
  868. break;
  869. }
  870. ADS_SEARCH_COLUMN computerColumn;
  871. //Security Review:Correct Buffer size is passed.
  872. ZeroMemory(&computerColumn, sizeof(ADS_SEARCH_COLUMN));
  873. //
  874. // Get the DN
  875. //
  876. hr = refServerSearch.GetColumn((PWSTR)g_szAttrServerReference, &computerColumn);
  877. if (FAILED(hr))
  878. {
  879. DEBUG_OUTPUT(LEVEL3_LOGGING,
  880. L"Failed to get the server reference for a column: hr = 0x%x",
  881. hr);
  882. DEBUG_OUTPUT(LEVEL3_LOGGING,
  883. L"continuing...");
  884. hr = S_OK;
  885. continue;
  886. }
  887. ADS_SEARCH_COLUMN serverColumn;
  888. //Security Review:Correct Buffer size is passed.
  889. ZeroMemory(&serverColumn, sizeof(ADS_SEARCH_COLUMN));
  890. hr = refServerSearch.GetColumn((PWSTR)g_szAttrDistinguishedName, &serverColumn);
  891. if (FAILED(hr))
  892. {
  893. DEBUG_OUTPUT(LEVEL3_LOGGING,
  894. L"Failed to get the distinguishedName for a column: hr = 0x%x",
  895. hr);
  896. DEBUG_OUTPUT(LEVEL3_LOGGING,
  897. L"continuing...");
  898. hr = S_OK;
  899. continue;
  900. }
  901. if (computerColumn.dwNumValues == 1 &&
  902. computerColumn.pADsValues &&
  903. serverColumn.dwNumValues == 1 &&
  904. serverColumn.pADsValues)
  905. {
  906. //
  907. // Search the lists and determine if the DN exists in all the lists
  908. //
  909. bool bValidEntry = IsObjectValidInAllLists(computerColumn.pADsValues->DNString,
  910. serverColumn.pADsValues->DNString,
  911. scope,
  912. pCommandArgs[eServerDomain].strValue,
  913. gcList,
  914. bUseGCSearchResults,
  915. fsmoList,
  916. bUseFSMOSearchResults);
  917. if (bValidEntry)
  918. {
  919. //
  920. // Output this server object since it matches all search criteria
  921. //
  922. OutputValidSearchResult(outputFormat,
  923. refServerSearch,
  924. ppszAttributes,
  925. cAttributes);
  926. }
  927. }
  928. hr = refServerSearch.FreeColumn(&computerColumn);
  929. ASSERT(SUCCEEDED(hr));
  930. }
  931. }
  932. } while (false);
  933. std::list<BSTR>::iterator gcItr;
  934. for (gcItr = gcList.begin(); gcItr != gcList.end(); ++gcItr)
  935. {
  936. // Prefast will bark at this but it is correct. The container
  937. // is filled with BSTRs which need to be freed using SysFreeString
  938. SysFreeString(*gcItr);
  939. }
  940. std::list<BSTR>::iterator fsmoItr;
  941. for (fsmoItr = fsmoList.begin(); fsmoItr != fsmoList.end(); ++fsmoItr)
  942. {
  943. // Prefast will bark at this but it is correct. The container
  944. // is filled with BSTRs which need to be freed using SysFreeString
  945. SysFreeString(*fsmoItr);
  946. }
  947. return hr;
  948. }
  949. //+--------------------------------------------------------------------------
  950. //
  951. // Function: OutputFetchAttr
  952. //
  953. // Synopsis: Dispalys the fetched attributes in either list or table format
  954. // Arguments: [ppszAttributes - IN] : Array containing list of attributes to display
  955. // [cAttributes - IN]: Count of attributes in ppszAttributes
  956. // [pSearch - IN]: pointer to search object
  957. // [bListFormat - IN]: List or Table format
  958. // Returns HRESULT S_OK if Successful
  959. // E_INVALIDARG
  960. // Anything else is a failure code from an ADSI call
  961. //
  962. //
  963. // History: 05-OCT-2000 hiteshr Created
  964. //
  965. //---------------------------------------------------------------------------
  966. HRESULT OutputFetchAttr(IN LPWSTR * ppszAttributes,
  967. IN DWORD cAttributes,
  968. IN CDSSearch *pSearch,
  969. IN BOOL bListFormat)
  970. {
  971. ENTER_FUNCTION_HR(FULL_LOGGING, OutputFetchAttr, hr);
  972. if(bListFormat)
  973. {
  974. //
  975. //Display in list format
  976. //
  977. int cListDisplayed = 0;
  978. while(TRUE)
  979. {
  980. hr = pSearch->GetNextRow();
  981. if(IsQueryLimitReached(cListDisplayed))
  982. break;
  983. if(hr == S_ADS_NOMORE_ROWS || FAILED(hr))
  984. break;
  985. bool bShowAttributes = false;
  986. if (cAttributes > 1)
  987. {
  988. bShowAttributes = true;
  989. }
  990. for(DWORD i = 0; i < cAttributes; ++i)
  991. {
  992. ADS_SEARCH_COLUMN ColumnData;
  993. hr = pSearch->GetColumn(ppszAttributes[i], &ColumnData);
  994. if(SUCCEEDED(hr))
  995. {
  996. ADSVALUE *pValues = ColumnData.pADsValues;
  997. for( DWORD j = 0; j < ColumnData.dwNumValues; ++j )
  998. {
  999. LPWSTR pBuffer = NULL;
  1000. hr = GetStringFromADs(pValues,
  1001. ColumnData.dwADsType,
  1002. &pBuffer,
  1003. ppszAttributes[i]);
  1004. if(SUCCEEDED(hr))
  1005. {
  1006. DisplayList(ppszAttributes[i], pBuffer, bShowAttributes);
  1007. delete pBuffer;
  1008. pBuffer = NULL;
  1009. }
  1010. ++pValues;
  1011. }
  1012. pSearch->FreeColumn(&ColumnData);
  1013. }
  1014. else if(hr == E_ADS_COLUMN_NOT_SET)
  1015. DisplayList(ppszAttributes[i], L"", bShowAttributes);
  1016. }
  1017. cListDisplayed++;
  1018. }
  1019. if(hr == S_ADS_NOMORE_ROWS)
  1020. hr = S_OK;
  1021. return hr;
  1022. }
  1023. else
  1024. {
  1025. //
  1026. //Display in table format
  1027. //
  1028. //
  1029. //format will use first 80 rows to calculate column width
  1030. //
  1031. CFormatInfo format;
  1032. LONG sampleSize = 80;
  1033. //
  1034. //sampleSize should be lessthan or equal to QueryLimit
  1035. //
  1036. if(g_iQueryLimit != 0 && (sampleSize > g_iQueryLimit))
  1037. sampleSize = g_iQueryLimit;
  1038. LONG cRow = 0;
  1039. hr = format.Init(sampleSize,cAttributes,ppszAttributes);
  1040. if(FAILED(hr))
  1041. return hr;
  1042. //
  1043. //Display in table format
  1044. //
  1045. while(TRUE)
  1046. {
  1047. //
  1048. //we have reached sampleSize, so display column headers and
  1049. //display all the sample rows.
  1050. //
  1051. if(cRow == sampleSize)
  1052. {
  1053. format.DisplayHeaders();
  1054. format.DisplayAllRows();
  1055. }
  1056. hr = pSearch->GetNextRow();
  1057. //We are done
  1058. if(hr == S_ADS_NOMORE_ROWS || FAILED(hr))
  1059. break;
  1060. //
  1061. //Check if we have reached querylimit
  1062. //
  1063. if(IsQueryLimitReached(cRow))
  1064. break;
  1065. //
  1066. //Fetch columns
  1067. //
  1068. for( DWORD i = 0; i < cAttributes; ++i )
  1069. {
  1070. ADS_SEARCH_COLUMN ColumnData;
  1071. hr = pSearch->GetColumn(ppszAttributes[i], &ColumnData);
  1072. CComBSTR strValue;
  1073. if(SUCCEEDED(hr))
  1074. {
  1075. strValue = "";
  1076. ADSVALUE *pValues = ColumnData.pADsValues;
  1077. for( DWORD j = 0; j < ColumnData.dwNumValues; ++j )
  1078. {
  1079. LPWSTR pBuffer = NULL;
  1080. hr = GetStringFromADs(pValues,
  1081. ColumnData.dwADsType,
  1082. &pBuffer,
  1083. ppszAttributes[i]);
  1084. //
  1085. //In table format multiple values are shown separated by ;
  1086. //
  1087. if(SUCCEEDED(hr))
  1088. {
  1089. strValue += pBuffer;
  1090. delete pBuffer;
  1091. pBuffer = NULL;
  1092. if(ColumnData.dwNumValues > 1)
  1093. {
  1094. strValue += L";";
  1095. }
  1096. }
  1097. ++pValues;
  1098. }
  1099. pSearch->FreeColumn(&ColumnData);
  1100. }
  1101. if(SUCCEEDED(hr) || hr == E_ADS_COLUMN_NOT_SET)
  1102. {
  1103. if(cRow < sampleSize)
  1104. {
  1105. //
  1106. //Cache this value in format and use it to calculate column width
  1107. //
  1108. format.Set(cRow,i,strValue);
  1109. }
  1110. else
  1111. {
  1112. //
  1113. //Display the column value
  1114. //
  1115. format.DisplayColumn(i,strValue);
  1116. if(i == (cAttributes - 1))
  1117. format.NewLine();
  1118. }
  1119. }
  1120. }
  1121. ++cRow;
  1122. }//End of while loop
  1123. if(hr == S_ADS_NOMORE_ROWS)
  1124. hr = S_OK;
  1125. if(cRow && (cRow < sampleSize))
  1126. {
  1127. //
  1128. //if total number of rows is less that sample size they are not
  1129. //displayed yet. Display them
  1130. //
  1131. format.DisplayHeaders();
  1132. format.DisplayAllRows();
  1133. }
  1134. return hr;
  1135. }
  1136. }
  1137. //+--------------------------------------------------------------------------
  1138. //
  1139. // Function: OutputSingleAttr
  1140. //
  1141. // Synopsis: Displays the single attribute which user has asked for.
  1142. // Arguments: [ppszAttributes - IN] : Array containing list of attributes to display
  1143. // [cAttributes - IN]: Count of attributes in ppszAttributes. Should be 1
  1144. // [pSearch - IN]: pointer to search object
  1145. // Returns HRESULT S_OK if Successful
  1146. // E_INVALIDARG
  1147. // Anything else is a failure code from an ADSI call
  1148. //
  1149. //
  1150. // History: 05-OCT-2000 hiteshr Created
  1151. //
  1152. //---------------------------------------------------------------------------
  1153. HRESULT OutputSingleAttr(IN LPWSTR * ppszAttributes,
  1154. IN DWORD cAttributes,
  1155. IN CDSSearch *pSearch)
  1156. {
  1157. ENTER_FUNCTION_HR(FULL_LOGGING, OutputSingleAttr, hr);
  1158. if(!ppszAttributes || !cAttributes || !pSearch)
  1159. {
  1160. ASSERT(FALSE);
  1161. hr = E_INVALIDARG;
  1162. return hr;
  1163. }
  1164. ASSERT(cAttributes > 0);
  1165. LONG cRow = 0;
  1166. while(TRUE)
  1167. {
  1168. hr = pSearch->GetNextRow();
  1169. //We are done
  1170. if(hr == S_ADS_NOMORE_ROWS || FAILED(hr))
  1171. break;
  1172. //
  1173. //Check if we have reached querylimit
  1174. //
  1175. if(IsQueryLimitReached(cRow))
  1176. break;
  1177. ADS_SEARCH_COLUMN ColumnData;
  1178. hr = pSearch->GetColumn(ppszAttributes[0], &ColumnData);
  1179. if(SUCCEEDED(hr))
  1180. {
  1181. LPWSTR pBuffer = NULL;
  1182. hr = GetStringFromADs(ColumnData.pADsValues,
  1183. ColumnData.dwADsType,
  1184. &pBuffer,
  1185. ppszAttributes[0]);
  1186. if(SUCCEEDED(hr))
  1187. {
  1188. //Display the output enclosed in Double Quotes
  1189. CComBSTR strTemp;
  1190. strTemp = L"\"" ;
  1191. strTemp += pBuffer;
  1192. strTemp += L"\"";
  1193. DisplayOutput(strTemp);
  1194. delete pBuffer;
  1195. pBuffer = NULL;
  1196. }
  1197. pSearch->FreeColumn(&ColumnData);
  1198. }
  1199. else if(hr == E_ADS_COLUMN_NOT_SET)
  1200. {
  1201. //
  1202. //If Attribute is not set display ""
  1203. //
  1204. DisplayOutput(L"\"\"");
  1205. }
  1206. //
  1207. //Increment number of Row displayed
  1208. //
  1209. cRow++;
  1210. }//End of while loop
  1211. if(hr == S_ADS_NOMORE_ROWS)
  1212. hr = S_OK;
  1213. return hr;
  1214. }
  1215. //+--------------------------------------------------------------------------
  1216. //
  1217. // Function: OutputAllAttr
  1218. //
  1219. // Synopsis: Displays all the attributes.
  1220. // Arguments: [pSearch - IN]: pointer to search object
  1221. // [bAttrOnly - IN]: display attributes names only
  1222. // Returns HRESULT S_OK if Successful
  1223. // E_INVALIDARG
  1224. // Anything else is a failure code from an ADSI
  1225. // call
  1226. //
  1227. //
  1228. // History: 05-OCT-2000 hiteshr Created
  1229. //
  1230. //---------------------------------------------------------------------------
  1231. HRESULT OutputAllAttr(IN CDSSearch *pSearch, BOOL bAttrOnly)
  1232. {
  1233. ENTER_FUNCTION_HR(FULL_LOGGING, OutputAllAttr, hr);
  1234. if(!pSearch)
  1235. {
  1236. ASSERT(FALSE);
  1237. hr = E_INVALIDARG;
  1238. return hr;
  1239. }
  1240. LONG cRow = 0;
  1241. while(TRUE)
  1242. {
  1243. hr = pSearch->GetNextRow();
  1244. //We are done
  1245. if(hr == S_ADS_NOMORE_ROWS || FAILED(hr))
  1246. break;
  1247. //
  1248. //Check if we reached querylimit
  1249. //
  1250. if(IsQueryLimitReached(cRow))
  1251. break;
  1252. LPWSTR pszColumnName;
  1253. BOOL bColumnNameDisplayed = FALSE;
  1254. //
  1255. //Get the name of next column which has value
  1256. //
  1257. while(pSearch->GetNextColumnName(&pszColumnName) != S_ADS_NOMORE_COLUMNS)
  1258. {
  1259. WCHAR szBuffer[MAXSTR];
  1260. if(bAttrOnly)
  1261. {
  1262. //Security Review:Replace with strsafe api
  1263. //NTRAID#NTBUG9-573989-2002/03/12-hiteshr
  1264. //Its fine to truncate.
  1265. hr = StringCchPrintf(szBuffer,MAXSTR, L"%ws ", pszColumnName);
  1266. if(SUCCEEDED(hr))
  1267. {
  1268. DisplayOutputNoNewline(szBuffer);
  1269. bColumnNameDisplayed = TRUE;
  1270. }
  1271. }
  1272. else
  1273. {
  1274. ADS_SEARCH_COLUMN ColumnData;
  1275. hr = pSearch->GetColumn(pszColumnName, &ColumnData);
  1276. if(SUCCEEDED(hr))
  1277. {
  1278. ADSVALUE *pValues = ColumnData.pADsValues;
  1279. for( DWORD j = 0; j < ColumnData.dwNumValues; ++j )
  1280. {
  1281. LPWSTR pBuffer = NULL;
  1282. hr = GetStringFromADs(pValues,
  1283. ColumnData.dwADsType,
  1284. &pBuffer,
  1285. pszColumnName);
  1286. if(SUCCEEDED(hr))
  1287. {
  1288. DisplayList(pszColumnName, pBuffer);
  1289. delete pBuffer;
  1290. pBuffer = NULL;
  1291. }
  1292. ++pValues;
  1293. }
  1294. pSearch->FreeColumn(&ColumnData);
  1295. }
  1296. else if(hr == E_ADS_COLUMN_NOT_SET)
  1297. DisplayList(pszColumnName, L"");
  1298. }
  1299. pSearch->FreeColumnName(pszColumnName);
  1300. }
  1301. if(bAttrOnly)
  1302. {
  1303. if(bColumnNameDisplayed)
  1304. {
  1305. DisplayOutputNoNewline(L"\r\n");
  1306. cRow++;
  1307. }
  1308. }
  1309. else
  1310. cRow++;
  1311. }//End of while loop
  1312. if(hr == S_ADS_NOMORE_ROWS)
  1313. hr = S_OK;
  1314. return hr;
  1315. }
  1316. //+--------------------------------------------------------------------------
  1317. //
  1318. // Function: GetStringFromADs
  1319. //
  1320. // Synopsis: Converts Value into string depending upon type
  1321. // Arguments: [pValues - IN]: Value to be converted to string
  1322. // [dwADsType-IN]: ADSTYPE of pValue
  1323. // [pBuffer - OUT]:Output buffer which gets the string
  1324. // [dwBufferLen-IN]:Size of output buffer
  1325. // [pszAttrName-IN]:Name of the attribute being formatted
  1326. // Returns HRESULT S_OK if Successful
  1327. // E_INVALIDARG
  1328. // Anything else is a failure code from an ADSI
  1329. // call
  1330. //
  1331. //
  1332. // History: 05-OCT-2000 hiteshr Created
  1333. //
  1334. //---------------------------------------------------------------------------
  1335. HRESULT GetStringFromADs(IN const ADSVALUE *pValues,
  1336. IN ADSTYPE dwADsType,
  1337. OUT LPWSTR* ppBuffer,
  1338. IN PCWSTR pszAttrName)
  1339. {
  1340. HRESULT hr = S_OK;
  1341. if(!pValues || !ppBuffer)
  1342. {
  1343. ASSERT(FALSE);
  1344. return E_INVALIDARG;
  1345. }
  1346. if( dwADsType == ADSTYPE_INVALID )
  1347. {
  1348. return E_INVALIDARG;
  1349. }
  1350. switch( dwADsType )
  1351. {
  1352. case ADSTYPE_DN_STRING :
  1353. {
  1354. CComBSTR sbstrOutputDN;
  1355. hr = GetOutputDN( &sbstrOutputDN, pValues->DNString );
  1356. if (FAILED(hr))
  1357. return hr;
  1358. UINT length = sbstrOutputDN.Length();
  1359. *ppBuffer = new WCHAR[length + 1];
  1360. if (!(*ppBuffer))
  1361. {
  1362. hr = E_OUTOFMEMORY;
  1363. return hr;
  1364. }
  1365. //Security Review:Correct Buffer size is passed.
  1366. ZeroMemory(*ppBuffer, (length + 1) * sizeof(WCHAR));
  1367. //Security Review:wcsncpy will copy length char
  1368. //lenght + 1 is already set to zero so we are fine.
  1369. wcsncpy(*ppBuffer, (BSTR)sbstrOutputDN, length);
  1370. }
  1371. break;
  1372. case ADSTYPE_CASE_EXACT_STRING :
  1373. {
  1374. //Security Review:This is null terminated.
  1375. size_t length = wcslen(pValues->CaseExactString);
  1376. *ppBuffer = new WCHAR[length + 1];
  1377. if (!(*ppBuffer))
  1378. {
  1379. hr = E_OUTOFMEMORY;
  1380. return hr;
  1381. }
  1382. //Security Review:Correct Buffer size is passed.
  1383. ZeroMemory(*ppBuffer, (length + 1) * sizeof(WCHAR));
  1384. //Security Review:wcsncpy will copy length char
  1385. //lenght + 1 is already set to zero so we are fine.
  1386. wcsncpy(*ppBuffer ,pValues->CaseExactString, length);
  1387. }
  1388. break;
  1389. case ADSTYPE_CASE_IGNORE_STRING:
  1390. {
  1391. size_t length = wcslen(pValues->CaseIgnoreString);
  1392. *ppBuffer = new WCHAR[length + 1];
  1393. if (!(*ppBuffer))
  1394. {
  1395. hr = E_OUTOFMEMORY;
  1396. return hr;
  1397. }
  1398. //Security Review:Correct Buffer size is passed.
  1399. ZeroMemory(*ppBuffer, (length + 1) * sizeof(WCHAR));
  1400. //Security Review:wcsncpy will copy length char
  1401. //lenght + 1 is already set to zero so we are fine.
  1402. wcsncpy(*ppBuffer ,pValues->CaseIgnoreString, length);
  1403. }
  1404. break;
  1405. case ADSTYPE_PRINTABLE_STRING :
  1406. {
  1407. //Security Review:Null terminated string.
  1408. size_t length = wcslen(pValues->PrintableString);
  1409. *ppBuffer = new WCHAR[length + 1];
  1410. if (!(*ppBuffer))
  1411. {
  1412. hr = E_OUTOFMEMORY;
  1413. return hr;
  1414. }
  1415. //Security Review:Correct Buffer size is passed.
  1416. ZeroMemory(*ppBuffer, (length + 1) * sizeof(WCHAR));
  1417. //Security Review:wcsncpy will copy length char
  1418. //lenght + 1 is already set to zero so we are fine.
  1419. wcsncpy(*ppBuffer ,pValues->PrintableString, length);
  1420. }
  1421. break;
  1422. case ADSTYPE_NUMERIC_STRING :
  1423. {
  1424. //Security Review:Null terminated string.
  1425. size_t length = wcslen(pValues->NumericString);
  1426. *ppBuffer = new WCHAR[length + 1];
  1427. if (!(*ppBuffer))
  1428. {
  1429. hr = E_OUTOFMEMORY;
  1430. return hr;
  1431. }
  1432. //Security Review:Correct Buffer size is passed.
  1433. ZeroMemory(*ppBuffer, (length + 1) * sizeof(WCHAR));
  1434. //Security Review:wcsncpy will copy length char
  1435. //lenght + 1 is already set to zero so we are fine.
  1436. wcsncpy(*ppBuffer ,pValues->NumericString, length);
  1437. }
  1438. break;
  1439. case ADSTYPE_OBJECT_CLASS :
  1440. {
  1441. //Security Review:Null terminated string.
  1442. size_t length = wcslen(pValues->ClassName);
  1443. *ppBuffer = new WCHAR[length + 1];
  1444. if (!(*ppBuffer))
  1445. {
  1446. hr = E_OUTOFMEMORY;
  1447. return hr;
  1448. }
  1449. //Security Review:Correct Buffer size is passed.
  1450. ZeroMemory(*ppBuffer, (length + 1) * sizeof(WCHAR));
  1451. //Security Review:wcsncpy will copy length char
  1452. //length + 1 is already set to zero so we are fine.
  1453. wcsncpy(*ppBuffer ,pValues->ClassName, length);
  1454. }
  1455. break;
  1456. case ADSTYPE_BOOLEAN :
  1457. {
  1458. size_t length = 0;
  1459. if (pValues->Boolean)
  1460. {
  1461. length = wcslen(L"TRUE");
  1462. *ppBuffer = new WCHAR[length + 1];
  1463. }
  1464. else
  1465. {
  1466. length = wcslen(L"FALSE");
  1467. *ppBuffer = new WCHAR[length + 1];
  1468. }
  1469. if (!(*ppBuffer))
  1470. {
  1471. hr = E_OUTOFMEMORY;
  1472. return hr;
  1473. }
  1474. //Security Review:Correct Buffer size is passed.
  1475. ZeroMemory(*ppBuffer, (length + 1) * sizeof(WCHAR));
  1476. //Security Review:Replace with strsafe api
  1477. //NTRAID#NTBUG9-573989-2002/03/12-hiteshr
  1478. hr = StringCchPrintf(*ppBuffer ,length + 1,L"%s", ((DWORD)pValues->Boolean) ? L"TRUE" : L"FALSE");
  1479. if(FAILED(hr))
  1480. {
  1481. delete[] *ppBuffer;
  1482. *ppBuffer = NULL;
  1483. return hr;
  1484. }
  1485. }
  1486. break;
  1487. case ADSTYPE_INTEGER :
  1488. // Just allocate too much...
  1489. *ppBuffer = new WCHAR[MAXSTR];
  1490. if (!(*ppBuffer))
  1491. {
  1492. hr = E_OUTOFMEMORY;
  1493. return hr;
  1494. }
  1495. //Security Review:Correct Buffer size is passed.
  1496. ZeroMemory(*ppBuffer, MAXSTR * sizeof(WCHAR));
  1497. //Security Review:Replace with strsafe api
  1498. //NTRAID#NTBUG9-573989-2002/03/12-hiteshr
  1499. hr = StringCchPrintf(*ppBuffer,MAXSTR ,L"%d", (DWORD) pValues->Integer);
  1500. if(FAILED(hr))
  1501. {
  1502. delete[] *ppBuffer;
  1503. *ppBuffer = NULL;
  1504. return hr;
  1505. }
  1506. break;
  1507. case ADSTYPE_OCTET_STRING :
  1508. {
  1509. // I am just going to limit the buffer to MAXSTR.
  1510. // It will be a rare occasion when someone wants
  1511. // to look at a binary string that is not a GUID
  1512. // or a SID.
  1513. *ppBuffer = new WCHAR[MAXSTR];
  1514. if (!(*ppBuffer))
  1515. {
  1516. hr = E_OUTOFMEMORY;
  1517. return hr;
  1518. }
  1519. //Security Review:Correct Buffer size is passed.
  1520. ZeroMemory(*ppBuffer, MAXSTR * sizeof(WCHAR));
  1521. //
  1522. //Special case objectguid and objectsid and sid history attribute
  1523. //
  1524. //Security Review:pszAttrName is null terminated
  1525. if(pszAttrName && !_wcsicmp(pszAttrName, L"objectguid"))
  1526. {
  1527. GUID *pguid = (GUID*)pValues->OctetString.lpValue;
  1528. StringFromGUID2(*pguid,(LPOLESTR)*ppBuffer,MAXSTR);
  1529. break;
  1530. }
  1531. //Security Review:pszAttrName is null terminated
  1532. if(pszAttrName && (!_wcsicmp(pszAttrName, L"objectsid") || !_wcsicmp(pszAttrName, L"sidhistory")))
  1533. {
  1534. LPWSTR pszSid = NULL;
  1535. PSID pSid = (PSID)pValues->OctetString.lpValue;
  1536. if(ConvertSidToStringSid(pSid, &pszSid))
  1537. {
  1538. LocalFree(pszSid);
  1539. //Security Review:
  1540. //NTRAID#NTBUG9-574198-2002/03/12-hiteshr
  1541. //Its fine to truncate
  1542. hr = StringCchCopy(*ppBuffer,MAXSTR,pszSid);
  1543. if(FAILED(hr))
  1544. {
  1545. delete[] *ppBuffer;
  1546. *ppBuffer = NULL;
  1547. return hr;
  1548. }
  1549. break;
  1550. }
  1551. }
  1552. for ( DWORD idx=0; idx<pValues->OctetString.dwLength; idx++)
  1553. {
  1554. BYTE b = ((BYTE *)pValues->OctetString.lpValue)[idx];
  1555. //Security Review:Replace with strsafe api
  1556. //NTRAID#NTBUG9-573989-2002/03/12-hiteshr
  1557. WCHAR sOctet[128];
  1558. hr = StringCchPrintf(sOctet,128,L"0x%02x ", b);
  1559. if(FAILED(hr))
  1560. {
  1561. delete[] *ppBuffer;
  1562. *ppBuffer = NULL;
  1563. return hr;
  1564. }
  1565. if(FAILED(StringCchCat(*ppBuffer,MAXSTR,sOctet)))
  1566. {
  1567. //We are truncating the string. We will display only
  1568. //MAXSTR -1 chars.
  1569. break;
  1570. }
  1571. }
  1572. }
  1573. break;
  1574. case ADSTYPE_LARGE_INTEGER :
  1575. {
  1576. CComBSTR strLarge;
  1577. LARGE_INTEGER li = pValues->LargeInteger;
  1578. litow(li, strLarge);
  1579. UINT length = strLarge.Length();
  1580. *ppBuffer = new WCHAR[length + 1];
  1581. if (!(*ppBuffer))
  1582. {
  1583. hr = E_OUTOFMEMORY;
  1584. return hr;
  1585. }
  1586. //Security Review:Correct Buffer size is passed.
  1587. ZeroMemory(*ppBuffer, (length + 1) * sizeof(WCHAR));
  1588. //Security Review:wcsncpy will copy length char
  1589. //length + 1 is already set to zero so we are fine.
  1590. wcsncpy(*ppBuffer,strLarge,length);
  1591. }
  1592. break;
  1593. case ADSTYPE_UTC_TIME :
  1594. // The longest date can be 20 characters including the NULL
  1595. *ppBuffer = new WCHAR[20];
  1596. if (!(*ppBuffer))
  1597. {
  1598. hr = E_OUTOFMEMORY;
  1599. return hr;
  1600. }
  1601. //Security Review:Correct Buffer size is passed.
  1602. ZeroMemory(*ppBuffer, sizeof(WCHAR) * 20);
  1603. //Security Review:Replace with strsafe api
  1604. //NTRAID#NTBUG9-573989-2002/03/12-hiteshr
  1605. hr = StringCchPrintf(*ppBuffer,20,
  1606. L"%02d/%02d/%04d %02d:%02d:%02d", pValues->UTCTime.wMonth, pValues->UTCTime.wDay, pValues->UTCTime.wYear,
  1607. pValues->UTCTime.wHour, pValues->UTCTime.wMinute, pValues->UTCTime.wSecond
  1608. );
  1609. //This should never fail
  1610. if(FAILED(hr))
  1611. {
  1612. ASSERT(FALSE);
  1613. delete[] *ppBuffer;
  1614. *ppBuffer = NULL;
  1615. return hr;
  1616. }
  1617. break;
  1618. case ADSTYPE_NT_SECURITY_DESCRIPTOR: // I use the ACLEditor instead
  1619. {
  1620. if((pValues->SecurityDescriptor).lpValue)
  1621. {
  1622. LPWSTR pszSD = NULL;
  1623. ULONG lLen = 0;
  1624. if(ConvertSecurityDescriptorToStringSecurityDescriptor(
  1625. (PSECURITY_DESCRIPTOR )((pValues->SecurityDescriptor).lpValue),
  1626. SDDL_REVISION_1,
  1627. OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION|SACL_SECURITY_INFORMATION,
  1628. &pszSD,
  1629. &lLen))
  1630. {
  1631. if(pszSD)
  1632. {
  1633. //pszSD is null terminated.
  1634. size_t length = wcslen(pszSD);
  1635. *ppBuffer = new WCHAR[length + 1];
  1636. if (!(*ppBuffer))
  1637. {
  1638. hr = E_OUTOFMEMORY;
  1639. return hr;
  1640. }
  1641. //Security Review:Correct Buffer size is passed.
  1642. ZeroMemory(*ppBuffer, sizeof(WCHAR) * (length+1));
  1643. //Security Review:wcsncpy will copy length char
  1644. //length + 1 is already set to zero so we are fine.
  1645. wcsncpy(*ppBuffer,pszSD,length);
  1646. LocalFree(pszSD);
  1647. }
  1648. }
  1649. }
  1650. }
  1651. break;
  1652. default :
  1653. break;
  1654. }
  1655. return S_OK;
  1656. }