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

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