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.

1603 lines
52 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000
  5. //
  6. // File: dsquery.cpp
  7. //
  8. // Contents: Defines the main function DSQUERY
  9. // command line utility
  10. //
  11. // History: 06-Sep-2000 hiteshr Created
  12. //
  13. //
  14. //--------------------------------------------------------------------------
  15. #include "pch.h"
  16. #include "cstrings.h"
  17. #include "usage.h"
  18. #include "querytable.h"
  19. #include "querybld.h"
  20. #include "dsquery.h"
  21. #include "query.h"
  22. #include "resource.h"
  23. #include "output.h"
  24. #include <dscmn.h>
  25. #include "Ntdsapi.h"
  26. //
  27. //Structure Defined to Store Global Values at one place.
  28. //
  29. typedef struct _GlobalInfo
  30. {
  31. ADS_SCOPEENUM scope; //Scope of query
  32. DSQUERY_OUTPUT_FORMAT outputFormat; //Output Format
  33. }GLOBAL_INFO,*PGLOBAL_INFO;
  34. bool g_bQuiet = false;
  35. int g_iQueryLimit = 100;
  36. bool g_bDeafultLimit = true;
  37. DSQUERY_COMMAND_ENUM g_eGC = (DSQUERY_COMMAND_ENUM)-1;
  38. //
  39. // Forward Function Declarations
  40. //
  41. HRESULT DoQueryValidation(PARG_RECORD pCommandArgs,
  42. PDSQueryObjectTableEntry pObjectEntry,
  43. PGLOBAL_INFO pcommon_info);
  44. HRESULT DoQuery(PARG_RECORD pCommandArgs,
  45. PDSQueryObjectTableEntry pObjectEntry,
  46. PGLOBAL_INFO pcommon_info);
  47. HRESULT GetAttributesToFetch(IN PGLOBAL_INFO pcommon_info,
  48. IN PARG_RECORD pCommandArgs,
  49. IN PDSQueryObjectTableEntry pObjectEntry,
  50. OUT LPWSTR **ppszAttributes,
  51. OUT DWORD * pCount);
  52. VOID FreeAttributesToFetch( IN LPWSTR *ppszAttributes,
  53. IN DWORD dwCount);
  54. HRESULT GetSearchRoot(IN IN PDSQueryObjectTableEntry pObjectEntry,
  55. IN PARG_RECORD pCommandArgs,
  56. IN CDSCmdBasePathsInfo& refBasePathsInfo,
  57. OUT CComBSTR& refsbstrDN,
  58. OUT BOOL *pbSearchAtForestRoot,
  59. OUT BOOL *pbSearchAtGC);
  60. HRESULT GetSearchObject(IN IN PDSQueryObjectTableEntry pObjectEntry,
  61. IN CDSCmdBasePathsInfo& refBasePathsInfo,
  62. IN PARG_RECORD pCommandArgs,
  63. IN CDSCmdCredentialObject& refCredentialObject,
  64. IN CComBSTR& refsbstrDN,
  65. IN BOOL bSearchAtForestRoot,
  66. IN BOOL bSearchAtGC,
  67. OUT CComPtr<IDirectorySearch>& refspSearchObject);
  68. BOOL
  69. TranslateNameFromDnToDns(const CComBSTR& bstrInputDN,
  70. CComBSTR& bstrOutputDNS);
  71. HRESULT GetGCIndex(PDSQueryObjectTableEntry pObjectEntry, int& nCommandEnum);
  72. //
  73. //Main Function
  74. //
  75. int __cdecl _tmain( VOID )
  76. {
  77. int argc = 0;
  78. LPTOKEN pToken = NULL;
  79. HRESULT hr = S_OK;
  80. PARG_RECORD pNewCommandArgs = 0;
  81. //
  82. // False loop
  83. //
  84. do
  85. {
  86. //
  87. // Initialize COM
  88. //
  89. hr = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  90. if (FAILED(hr))
  91. {
  92. DisplayErrorMessage(g_pszDSCommandName,
  93. NULL,
  94. hr);
  95. break;
  96. }
  97. //Get CommandLine Input
  98. DWORD dwErr = GetCommandInput(&argc,&pToken);
  99. hr = HRESULT_FROM_WIN32(dwErr);
  100. if (FAILED(hr))
  101. {
  102. DisplayErrorMessage(g_pszDSCommandName,
  103. NULL,
  104. hr);
  105. break;
  106. }
  107. if(argc == 1)
  108. {
  109. //
  110. // Display the error message and then break out of the false loop
  111. //
  112. DisplayMessage(USAGE_DSQUERY,TRUE);
  113. hr = E_INVALIDARG;
  114. break;
  115. }
  116. if(argc == 2)
  117. {
  118. if(IsTokenHelpSwitch(pToken + 1))
  119. {
  120. hr = S_OK;
  121. DisplayMessage(USAGE_DSQUERY,TRUE);
  122. break;
  123. }
  124. }
  125. //
  126. // Find which object table entry to use from
  127. // the second command line argument
  128. //
  129. PDSQueryObjectTableEntry pObjectEntry = NULL;
  130. UINT idx = 0;
  131. PWSTR pszObjectType = (pToken+1)->GetToken();
  132. while (true)
  133. {
  134. pObjectEntry = g_DSObjectTable[idx++];
  135. if (!pObjectEntry)
  136. {
  137. break;
  138. }
  139. //Security Review:Both strings are null terminated.
  140. if (0 == _wcsicmp(pObjectEntry->pszCommandLineObjectType, pszObjectType))
  141. {
  142. break;
  143. }
  144. }
  145. if (!pObjectEntry)
  146. {
  147. //
  148. // Display the error message and then break out of the false loop
  149. //
  150. hr = E_INVALIDARG;
  151. if (FAILED(hr))
  152. {
  153. DisplayErrorMessage(g_pszDSCommandName,
  154. NULL,
  155. hr,
  156. IDS_INVALID_OBJECTTYPE);
  157. }
  158. break;
  159. }
  160. //
  161. // Now that we have the correct table entry, merge the command line table
  162. // for this object with the common commands
  163. //
  164. hr = MergeArgCommand(DSQUERY_COMMON_COMMANDS,
  165. pObjectEntry->pParserTable,
  166. &pNewCommandArgs);
  167. if (FAILED(hr))
  168. {
  169. DisplayErrorMessage(g_pszDSCommandName,
  170. NULL,
  171. hr);
  172. break;
  173. }
  174. //
  175. //Parse the Input
  176. //
  177. PARSE_ERROR Error;
  178. if(!ParseCmd(g_pszDSCommandName,
  179. pNewCommandArgs,
  180. argc-1,
  181. pToken+1,
  182. pObjectEntry->pUsageTable,
  183. &Error,
  184. TRUE))
  185. {
  186. //ParseCmd did not display any error. Error should
  187. //be handled here. Check DisplayParseError for the
  188. //cases where Error is not shown by ParseCmd
  189. if(!Error.MessageShown)
  190. {
  191. hr = E_INVALIDARG;
  192. DisplayErrorMessage(g_pszDSCommandName,
  193. NULL,
  194. hr);
  195. break;
  196. }
  197. if(Error.ErrorSource == ERROR_FROM_PARSER
  198. && Error.Error == PARSE_ERROR_HELP_SWITCH)
  199. {
  200. hr = S_OK;
  201. break;
  202. }
  203. hr = E_INVALIDARG;
  204. break;
  205. }
  206. //
  207. // Check to see if we are doing debug spew
  208. //
  209. #ifdef DBG
  210. bool bDebugging = pNewCommandArgs[eCommDebug].bDefined &&
  211. pNewCommandArgs[eCommDebug].nValue;
  212. if (bDebugging)
  213. {
  214. ENABLE_DEBUG_OUTPUT(pNewCommandArgs[eCommDebug].nValue);
  215. }
  216. #else
  217. DISABLE_DEBUG_OUTPUT();
  218. #endif
  219. // Get the GC switch (if supported)
  220. int nCommandEnum = -1;
  221. if (FAILED(GetGCIndex(pObjectEntry, nCommandEnum)))
  222. {
  223. // An object type is missing in GetGCIndex
  224. if(!Error.MessageShown)
  225. {
  226. hr = E_INVALIDARG;
  227. DisplayErrorMessage(g_pszDSCommandName,
  228. NULL,
  229. hr);
  230. break;
  231. }
  232. }
  233. g_eGC = (DSQUERY_COMMAND_ENUM) nCommandEnum;
  234. //
  235. // Set the global quiet flag
  236. //
  237. g_bQuiet = pNewCommandArgs[eCommQuiet].bDefined &&
  238. pNewCommandArgs[eCommQuiet].bValue;
  239. //
  240. //
  241. //
  242. if(pNewCommandArgs[eCommLimit].bDefined)
  243. {
  244. g_iQueryLimit = pNewCommandArgs[eCommLimit].nValue;
  245. g_bDeafultLimit = false;
  246. }
  247. GLOBAL_INFO common_info;
  248. common_info.scope = ADS_SCOPE_SUBTREE;
  249. common_info.outputFormat = DSQUERY_OUTPUT_DN;
  250. //
  251. // Do extra validation like switch dependency check etc.
  252. // Also collect Query Scope and Output format
  253. //
  254. hr = DoQueryValidation(pNewCommandArgs,
  255. pObjectEntry,
  256. &common_info);
  257. if (FAILED(hr))
  258. break;
  259. //
  260. // Command line parsing succeeded
  261. //
  262. hr = DoQuery(pNewCommandArgs,
  263. pObjectEntry,
  264. &common_info);
  265. if(FAILED(hr))
  266. break;
  267. } while (false); //False Loop
  268. //
  269. //Do the CleanUp
  270. //
  271. //
  272. // Free the memory associated with the command values
  273. //
  274. if(pNewCommandArgs)
  275. FreeCmd(pNewCommandArgs);
  276. //
  277. // Free the tokens
  278. //
  279. if (pToken)
  280. {
  281. delete[] pToken;
  282. pToken = 0;
  283. }
  284. //
  285. // Uninitialize COM
  286. //
  287. CoUninitialize();
  288. return hr;
  289. }
  290. //+--------------------------------------------------------------------------
  291. //
  292. // Function: DoQueryValidation
  293. //
  294. // Synopsis: Checks to be sure that command line switches that are mutually
  295. // exclusive are not both present and those that are dependent are
  296. // both presetn, and other validations which cannot be done by parser.
  297. //
  298. // Arguments: [pCommandArgs - IN] : the command line argument structure used
  299. // to retrieve the values for each switch
  300. // [pObjectEntry - IN] : pointer to the object table entry for the
  301. // object type that will be queryied
  302. // [pcommon_info - OUT]: gets scope and output format info
  303. //
  304. // Returns: HRESULT : S_OK if everything succeeded
  305. // E_INVALIDARG if the object entry wasn't found
  306. //
  307. // History: 25-Sep-2000 hiteshr Created
  308. //
  309. //---------------------------------------------------------------------------
  310. HRESULT DoQueryValidation(IN PARG_RECORD pCommandArgs,
  311. IN PDSQueryObjectTableEntry pObjectEntry,
  312. OUT PGLOBAL_INFO pcommon_info)
  313. {
  314. ENTER_FUNCTION_HR(MINIMAL_LOGGING, DoQueryValidation, hr);
  315. if (!pCommandArgs || !pObjectEntry || !pcommon_info)
  316. {
  317. ASSERT(pCommandArgs);
  318. ASSERT(pObjectEntry);
  319. ASSERT(pcommon_info);
  320. hr = E_INVALIDARG;
  321. return hr;
  322. }
  323. // Check to be sure the server and domain switches
  324. // are mutually exclusive
  325. if (pCommandArgs[eCommServer].bDefined &&
  326. pCommandArgs[eCommDomain].bDefined)
  327. {
  328. hr = E_INVALIDARG;
  329. DisplayErrorMessage(g_pszDSCommandName,
  330. NULL,
  331. hr);
  332. return hr;
  333. }
  334. //
  335. //Validate OutputFormat for "dsquery objectType"
  336. //
  337. //Security Review:Both strings are null terminated.
  338. if(_wcsicmp(pObjectEntry->pszCommandLineObjectType,g_pszStar))
  339. {
  340. DEBUG_OUTPUT(MINIMAL_LOGGING, L"dsquery <objectType> processing will be performed");
  341. if(pCommandArgs[eCommOutputFormat].bDefined &&
  342. pCommandArgs[eCommOutputFormat].strValue)
  343. {
  344. //
  345. //ppValidOutput contains the validoutput type for a
  346. //given object type
  347. //
  348. ASSERT(pObjectEntry->ppValidOutput);
  349. BOOL bMatch = FALSE;
  350. for(UINT i = 0; i < pObjectEntry->dwOutputCount; ++i)
  351. {
  352. //Security Review:Both strings are null terminated.
  353. if(_wcsicmp(pCommandArgs[eCommOutputFormat].strValue,
  354. pObjectEntry->ppValidOutput[i]->pszOutputFormat) == 0 )
  355. {
  356. bMatch = TRUE;
  357. pcommon_info->outputFormat = pObjectEntry->ppValidOutput[i]->outputFormat;
  358. break;
  359. }
  360. }
  361. if(!bMatch)
  362. {
  363. hr = E_INVALIDARG;
  364. DisplayErrorMessage(g_pszDSCommandName,
  365. NULL,
  366. hr,
  367. IDS_INVALID_OUTPUT);
  368. return hr;
  369. }
  370. }
  371. //
  372. //default output format is DN
  373. //
  374. else
  375. pcommon_info->outputFormat = DSQUERY_OUTPUT_DN;
  376. }
  377. else
  378. {
  379. //
  380. //-o is invalid switch form dsquery *, but since its
  381. //common for all other objects its kept in common table
  382. //and we do the special casing for dsquery *
  383. //
  384. if(pCommandArgs[eCommOutputFormat].bDefined &&
  385. pCommandArgs[eCommOutputFormat].strValue)
  386. {
  387. hr = E_INVALIDARG;
  388. DisplayErrorMessage(g_pszDSCommandName,
  389. NULL,
  390. hr,
  391. IDS_O_NOT_FOR_STAR);
  392. return hr;
  393. }
  394. DEBUG_OUTPUT(MINIMAL_LOGGING, L"dsquery * processing will be performed");
  395. if(pCommandArgs[eStarAttrsOnly].bDefined)
  396. pcommon_info->outputFormat = DSQUERY_OUTPUT_ATTRONLY;
  397. else
  398. pcommon_info->outputFormat = DSQUERY_OUTPUT_ATTR;
  399. }
  400. //
  401. //Validate Scope string.
  402. //default scope is subtree.
  403. //
  404. pcommon_info->scope = ADS_SCOPE_SUBTREE;
  405. if(pObjectEntry->nScopeID != -1)
  406. {
  407. if( pCommandArgs[pObjectEntry->nScopeID].bDefined &&
  408. pCommandArgs[pObjectEntry->nScopeID].strValue )
  409. {
  410. LPCWSTR pszScope = pCommandArgs[pObjectEntry->nScopeID].strValue;
  411. //Security Review:Both strings are null terminated.
  412. if( _wcsicmp(pszScope,g_pszSubTree) == 0 )
  413. {
  414. DEBUG_OUTPUT(MINIMAL_LOGGING, L"scope = subtree");
  415. pcommon_info->scope = ADS_SCOPE_SUBTREE;
  416. }
  417. else if( _wcsicmp(pszScope,g_pszOneLevel) == 0 )
  418. {
  419. DEBUG_OUTPUT(MINIMAL_LOGGING, L"scope = onelevel");
  420. pcommon_info->scope = ADS_SCOPE_ONELEVEL;
  421. }
  422. else if( _wcsicmp(pszScope,g_pszBase) == 0 )
  423. {
  424. DEBUG_OUTPUT(MINIMAL_LOGGING, L"scope = base");
  425. pcommon_info->scope = ADS_SCOPE_BASE;
  426. }
  427. else
  428. {
  429. DEBUG_OUTPUT(MINIMAL_LOGGING, L"Unknown scope = %s", pszScope);
  430. hr = E_INVALIDARG;
  431. DisplayErrorMessage(g_pszDSCommandName,
  432. NULL,
  433. hr,
  434. IDS_ERROR_SCOPE);
  435. return hr;
  436. }
  437. }
  438. }
  439. //
  440. //if startnode is forestroot, only valid scope is ADS_SCOPE_SUBTREE
  441. //NTRAID#NTBUG9-382511-2001/05/14-hiteshr
  442. //
  443. if(pCommandArgs[eCommStartNode].bDefined &&
  444. pCommandArgs[eCommStartNode].strValue)
  445. {
  446. //Security Review:Both strings are null terminated.
  447. if((_wcsicmp(pCommandArgs[eCommStartNode].strValue, g_pszForestRoot) == 0 )
  448. && (pcommon_info->scope != ADS_SCOPE_SUBTREE))
  449. {
  450. DEBUG_OUTPUT(MINIMAL_LOGGING, L"Startnode is forestroot, Scope must be SubTree");
  451. hr = E_INVALIDARG;
  452. DisplayErrorMessage(g_pszDSCommandName,
  453. NULL,
  454. hr,
  455. IDS_FOREST_SEARCH_SCOPE);
  456. return hr;
  457. }
  458. if((_wcsicmp(pCommandArgs[eCommStartNode].strValue, g_pszForestRoot) == 0 )
  459. && _wcsicmp(pObjectEntry->pszCommandLineObjectType, g_pszQuota) == 0)
  460. {
  461. DEBUG_OUTPUT(MINIMAL_LOGGING, L"A Startnode of forestroot is not allowed for quotas");
  462. hr = E_INVALIDARG;
  463. DisplayErrorMessage(g_pszDSCommandName,
  464. NULL,
  465. hr,
  466. IDS_FOREST_SEARCH_SCOPE_QUOTAS);
  467. return hr;
  468. }
  469. }
  470. //
  471. //Limit must be 0 or greater
  472. //
  473. if(pCommandArgs[eCommLimit].bDefined)
  474. {
  475. if(pCommandArgs[eCommLimit].nValue < 0)
  476. {
  477. hr = E_INVALIDARG;
  478. DisplayErrorMessage(g_pszDSCommandName,
  479. NULL,
  480. hr,
  481. IDS_ERROR_LIMIT);
  482. return hr;
  483. }
  484. }
  485. //
  486. //Forestwide Search implies the -GC switch so define it if it isn't already
  487. //
  488. if(pCommandArgs[eCommStartNode].bDefined &&
  489. pCommandArgs[eCommStartNode].strValue )
  490. {
  491. //Security Review:Both strings are null terminated.
  492. if(_wcsicmp(pCommandArgs[eCommStartNode].strValue,g_pszForestRoot) == 0)
  493. {
  494. // partitions and quotas don't support forestRoot so
  495. // g_eGC will be valid unless there is an upstream bug
  496. // so this ASSERT will catch that in private tests
  497. ASSERT(g_eGC != -1);
  498. if(!(pCommandArgs[g_eGC].bDefined &&
  499. pCommandArgs[g_eGC].bValue))
  500. {
  501. pCommandArgs[g_eGC].bDefined = TRUE;
  502. pCommandArgs[g_eGC].bValue = TRUE;
  503. }
  504. }
  505. }
  506. //
  507. //For dsquery server, if none of the -domain, -forest, -site is
  508. //specified, then define -domain as its default
  509. //
  510. //Security Review:Both strings are null terminated.
  511. if(!_wcsicmp(pObjectEntry->pszCommandLineObjectType,g_pszServer))
  512. {
  513. //
  514. //Value is assigned in DoQuery function
  515. //
  516. if(!pCommandArgs[eServerDomain].bDefined &&
  517. !pCommandArgs[eServerForest].bDefined &&
  518. !pCommandArgs[eServerSite].bDefined)
  519. {
  520. pCommandArgs[eServerDomain].bDefined = TRUE;
  521. }
  522. }
  523. return hr;
  524. }
  525. //+--------------------------------------------------------------------------
  526. //
  527. // Function: DoQuery
  528. //
  529. // Synopsis: Does the query
  530. // Arguments: [pCommandArgs - IN] : the command line argument structure used
  531. // to retrieve the values for each switch
  532. // [pObjectEntry - IN] : pointer to the object table entry for the
  533. // object type that will be modified
  534. // [pcommon_info - IN] : scope and outputformat info
  535. //
  536. // Returns: HRESULT : S_OK if everything succeeded
  537. // E_INVALIDARG if the object entry wasn't found
  538. // Anything else is a failure code from an ADSI call
  539. //
  540. // History: 25-Sep-2000 hiteshr Created
  541. //
  542. //---------------------------------------------------------------------------
  543. HRESULT DoQuery(PARG_RECORD pCommandArgs,
  544. PDSQueryObjectTableEntry pObjectEntry,
  545. PGLOBAL_INFO pcommon_info)
  546. {
  547. ENTER_FUNCTION_HR(MINIMAL_LOGGING, DoQuery, hr);
  548. if (!pCommandArgs || !pObjectEntry || !pcommon_info)
  549. {
  550. ASSERT(pCommandArgs);
  551. ASSERT(pObjectEntry);
  552. ASSERT(pcommon_info);
  553. hr = E_INVALIDARG;
  554. return hr;
  555. }
  556. CDSCmdCredentialObject credentialObject;
  557. if (pCommandArgs[eCommUserName].bDefined)
  558. {
  559. credentialObject.SetUsername(pCommandArgs[eCommUserName].strValue);
  560. credentialObject.SetUsingCredentials(true);
  561. }
  562. if (pCommandArgs[eCommPassword].bDefined)
  563. {
  564. //Security Review:pCommandArgs[eCommPassword].strValue is encrypted.
  565. //Decrypt pCommandArgs[eCommPassword].strValue and then pass it to the
  566. //credentialObject.SetPassword.
  567. //See NTRAID#NTBUG9-571544-2000/11/13-hiteshr
  568. credentialObject.SetEncryptedPassword(&pCommandArgs[eCommPassword].encryptedDataBlob);
  569. credentialObject.SetUsingCredentials(true);
  570. }
  571. // If this is something that supports the GC switch then do the next check
  572. if(g_eGC != -1)
  573. {
  574. //if -GC and -s flags are specified together than server must be
  575. //GC.
  576. if(pCommandArgs[g_eGC].bDefined &&
  577. pCommandArgs[g_eGC].bValue &&
  578. pCommandArgs[eCommServer].bDefined &&
  579. pCommandArgs[eCommServer].strValue)
  580. {
  581. if(!IsServerGC(pCommandArgs[eCommServer].strValue,credentialObject))
  582. {
  583. hr = E_INVALIDARG;
  584. DisplayErrorMessage(g_pszDSCommandName,
  585. NULL,
  586. hr,
  587. IDS_SEVER_NOT_GC);
  588. return hr;
  589. }
  590. }
  591. }
  592. //
  593. // Initialize the base paths info from the command line args
  594. //
  595. CDSCmdBasePathsInfo basePathsInfo;
  596. if (pCommandArgs[eCommServer].bDefined)
  597. {
  598. hr = basePathsInfo.InitializeFromName(credentialObject,
  599. pCommandArgs[eCommServer].strValue,
  600. true);
  601. }
  602. else if (pCommandArgs[eCommDomain].bDefined)
  603. {
  604. hr = basePathsInfo.InitializeFromName(credentialObject,
  605. pCommandArgs[eCommDomain].strValue,
  606. false);
  607. }
  608. else
  609. {
  610. hr = basePathsInfo.InitializeFromName(credentialObject, NULL, false);
  611. }
  612. if (FAILED(hr))
  613. {
  614. DisplayErrorMessage(g_pszDSCommandName,
  615. NULL,
  616. hr);
  617. return hr;
  618. }
  619. //
  620. //Check if to search GC and get the search root path
  621. //
  622. BOOL bSearchAtGC = FALSE;
  623. BOOL bSearchAtForestRoot = FALSE;
  624. CComBSTR sbstrObjectDN;
  625. hr = GetSearchRoot(pObjectEntry,
  626. pCommandArgs,
  627. basePathsInfo,
  628. sbstrObjectDN,
  629. &bSearchAtForestRoot,
  630. &bSearchAtGC);
  631. if (FAILED(hr))
  632. {
  633. //Error is displayed in the function itself.
  634. return hr;
  635. }
  636. DEBUG_OUTPUT(MINIMAL_LOGGING, L"start node = %s", sbstrObjectDN);
  637. //
  638. //Build The Filter For Query
  639. //
  640. CComBSTR strSubSiteSuffix;
  641. PVOID pParam = NULL;
  642. //Security Review:Both strings are null terminated.
  643. if (_wcsicmp(pObjectEntry->pszObjectClass, g_pszSubnet) == 0)
  644. {
  645. GetSiteContainerPath(basePathsInfo, strSubSiteSuffix);
  646. pParam = (PVOID)&strSubSiteSuffix;
  647. }
  648. CComBSTR strLDAPFilter;
  649. hr = BuildQueryFilter(pCommandArgs,
  650. pObjectEntry,
  651. basePathsInfo,
  652. credentialObject,
  653. pParam,
  654. strLDAPFilter);
  655. if (FAILED(hr))
  656. {
  657. DisplayErrorMessage(g_pszDSCommandName,
  658. NULL,
  659. hr);
  660. return hr;
  661. }
  662. //
  663. //Create The IDirectorySearchObject
  664. //
  665. CComPtr<IDirectorySearch> spSearchObject;
  666. hr = GetSearchObject(pObjectEntry,
  667. basePathsInfo,
  668. pCommandArgs,
  669. credentialObject,
  670. sbstrObjectDN,
  671. bSearchAtForestRoot,
  672. bSearchAtGC,
  673. spSearchObject);
  674. if (FAILED(hr))
  675. {
  676. //Error is displayed in the function itself.
  677. return hr;
  678. }
  679. //
  680. //Get the arributes to fetch
  681. //
  682. LPWSTR *ppszAttributes = NULL;
  683. DWORD dwCountAttr = 0;
  684. hr = GetAttributesToFetch(pcommon_info,
  685. pCommandArgs,
  686. pObjectEntry,
  687. &ppszAttributes,
  688. &dwCountAttr);
  689. if (FAILED(hr))
  690. {
  691. DisplayErrorMessage(g_pszDSCommandName,
  692. NULL,
  693. hr);
  694. return hr;
  695. }
  696. //
  697. //Lets Query Now
  698. //
  699. CDSSearch searchObject;
  700. hr = searchObject.Init(spSearchObject);
  701. if (FAILED(hr))
  702. {
  703. DEBUG_OUTPUT(MINIMAL_LOGGING,
  704. L"Initializing search object failed: hr = 0x%x",
  705. hr);
  706. FreeAttributesToFetch(ppszAttributes, dwCountAttr);
  707. DisplayErrorMessage(g_pszDSCommandName,
  708. NULL,
  709. hr);
  710. return hr;
  711. }
  712. searchObject.SetFilterString(strLDAPFilter);
  713. searchObject.SetSearchScope(pcommon_info->scope);
  714. searchObject.SetAttributeList(ppszAttributes,dwCountAttr?dwCountAttr:-1);
  715. hr = searchObject.DoQuery();
  716. if(FAILED(hr))
  717. {
  718. DEBUG_OUTPUT(MINIMAL_LOGGING, L"DoQuery failed hr = 0x%x", hr);
  719. FreeAttributesToFetch(ppszAttributes,dwCountAttr);
  720. DisplayErrorMessage(g_pszDSCommandName,
  721. NULL,
  722. hr);
  723. return hr;
  724. }
  725. //
  726. //Find out the display format for dsquery *
  727. //It can be either List or Table
  728. //
  729. BOOL bListFormat = TRUE;
  730. if(pcommon_info->outputFormat == DSQUERY_OUTPUT_ATTR)
  731. {
  732. //
  733. //If all attributes are to be displayed, only List Format is valid
  734. //If attributes to fetch are specified at commandline, Table is default format.
  735. if(dwCountAttr &&
  736. !pCommandArgs[eStarList].bDefined)
  737. bListFormat = FALSE;
  738. }
  739. bool bUseStandardOutput = true;
  740. if (pCommandArgs[eCommObjectType].bDefined &&
  741. _wcsicmp(pCommandArgs[eCommObjectType].strValue, g_pszServer) == 0)
  742. //Security Review:Both strings are null terminated.
  743. {
  744. //
  745. // "dsquery server" requires additional processing if either the
  746. // -isgc or the -hasfsmo switch is specified
  747. //
  748. if ((pCommandArgs[eServerIsGC].bDefined && pCommandArgs[eServerIsGC].bValue) ||
  749. (pCommandArgs[eServerHasFSMO].bDefined && pCommandArgs[eServerHasFSMO].strValue)||
  750. (pCommandArgs[eServerDomain].bDefined && pCommandArgs[eServerDomain].strValue))
  751. {
  752. bUseStandardOutput = false;
  753. hr = DsQueryServerOutput(pcommon_info->outputFormat,
  754. ppszAttributes,
  755. dwCountAttr,
  756. searchObject,
  757. credentialObject,
  758. basePathsInfo,
  759. pCommandArgs);
  760. if (FAILED(hr))
  761. {
  762. DisplayErrorMessage(g_pszDSCommandName,
  763. NULL,
  764. hr);
  765. }
  766. }
  767. }
  768. if (bUseStandardOutput)
  769. {
  770. //
  771. //Output the result of search
  772. //
  773. hr = DsQueryOutput(pcommon_info->outputFormat,
  774. ppszAttributes,
  775. dwCountAttr,
  776. &searchObject,
  777. bListFormat);
  778. if (FAILED(hr))
  779. {
  780. DisplayErrorMessage(g_pszDSCommandName,
  781. NULL,
  782. hr);
  783. }
  784. }
  785. FreeAttributesToFetch(ppszAttributes,dwCountAttr);
  786. return hr;
  787. }
  788. //+--------------------------------------------------------------------------
  789. //
  790. // Function: GetAttributesToFetch
  791. //
  792. // Synopsis: Make an array of attributes to fetch.
  793. // Arguments: [pcommon_info - IN] : outputformat and scope info
  794. // [ppszAttributes - OUT] : array of attributes to fetch
  795. // [pCount - OUT] : count of attributes in array
  796. //
  797. // Returns: HRESULT : S_OK if everything succeeded
  798. // E_INVALIDARG if the object entry wasn't found
  799. // Anything else is a failure code from an ADSI call
  800. //
  801. // History: 25-Sep-2000 hiteshr Created
  802. //
  803. //---------------------------------------------------------------------------
  804. HRESULT GetAttributesToFetch(IN PGLOBAL_INFO pcommon_info,
  805. IN PARG_RECORD pCommandArgs,
  806. IN PDSQueryObjectTableEntry pObjectEntry,
  807. OUT LPWSTR **ppszAttributes,
  808. OUT DWORD * pCount)
  809. {
  810. ENTER_FUNCTION_HR(MINIMAL_LOGGING, GetAttributesToFetch, hr);
  811. if(!pcommon_info || !pCommandArgs || !pObjectEntry)
  812. {
  813. ASSERT(pcommon_info);
  814. ASSERT(pCommandArgs);
  815. ASSERT(pObjectEntry);
  816. hr = E_INVALIDARG;
  817. return hr;
  818. }
  819. if(pcommon_info->outputFormat == DSQUERY_OUTPUT_ATTR ||
  820. pcommon_info->outputFormat == DSQUERY_OUTPUT_ATTRONLY)
  821. {
  822. if(pCommandArgs[eStarAttr].bDefined)
  823. {
  824. //
  825. //If input is "*", fetch all attributes
  826. //
  827. //Security Review:Both strings are null terminated.
  828. if(wcscmp(pCommandArgs[eStarAttr].strValue,L"*") == 0 )
  829. {
  830. *ppszAttributes = NULL;
  831. *pCount = 0;
  832. return hr;
  833. }
  834. LPWSTR *ppszTemp = NULL;
  835. UINT argc = 0;
  836. ParseNullSeparatedString(pCommandArgs[eStarAttr].strValue,
  837. &ppszTemp,
  838. &argc);
  839. LPWSTR *ppszAttr = (LPWSTR *)LocalAlloc(LPTR,argc*sizeof(LPCTSTR));
  840. if(!ppszAttr)
  841. {
  842. hr = E_OUTOFMEMORY;
  843. return hr;
  844. }
  845. for(UINT i = 0; i < argc; ++i)
  846. {
  847. if(FAILED(LocalCopyString(ppszAttr+i, ppszTemp[i])))
  848. {
  849. LocalFree(ppszAttr);
  850. hr = E_OUTOFMEMORY;
  851. return hr;
  852. }
  853. }
  854. *ppszAttributes = ppszAttr;
  855. *pCount = argc;
  856. if(ppszTemp)
  857. LocalFree(ppszTemp);
  858. hr = S_OK;
  859. return hr;
  860. }
  861. }
  862. LPCWSTR pszAttr = NULL;
  863. if(pcommon_info->outputFormat == DSQUERY_OUTPUT_ATTR)
  864. {
  865. //
  866. //If eStarAttr is not defined, Fetch only DN
  867. pcommon_info->outputFormat = DSQUERY_OUTPUT_DN;
  868. if(_wcsicmp(pObjectEntry->pszCommandLineObjectType, g_pszPartition) == 0)
  869. pszAttr = g_szAttrNCName;
  870. else
  871. pszAttr = g_szAttrDistinguishedName;
  872. }
  873. else if(pcommon_info->outputFormat == DSQUERY_OUTPUT_ATTRONLY)
  874. pszAttr = g_szAttrDistinguishedName;
  875. else if(pcommon_info->outputFormat == DSQUERY_OUTPUT_DN)
  876. {
  877. if(_wcsicmp(pObjectEntry->pszCommandLineObjectType, g_pszPartition) == 0)
  878. pszAttr = g_szAttrNCName;
  879. else
  880. pszAttr = g_szAttrDistinguishedName;
  881. }
  882. else if(pcommon_info->outputFormat == DSQUERY_OUTPUT_UPN)
  883. pszAttr = g_szAttrUserPrincipalName;
  884. else if(pcommon_info->outputFormat == DSQUERY_OUTPUT_SAMID)
  885. pszAttr = g_szAttrSamAccountName;
  886. else if(pcommon_info->outputFormat == DSQUERY_OUTPUT_RDN)
  887. pszAttr = g_szAttrRDN;
  888. //
  889. // Always include the DN in the search results as well. It is quite useful.
  890. //
  891. size_t entries = 2;
  892. //Security Review:Both strings are null terminated.
  893. if (_wcsicmp(pObjectEntry->pszObjectClass, g_pszServer) == 0)
  894. {
  895. //
  896. // Add an addition space for the serverReference
  897. ++entries;
  898. }
  899. LPWSTR *ppszAttr = (LPWSTR *)LocalAlloc(LPTR,sizeof(LPWSTR) * entries);
  900. if(!ppszAttr)
  901. {
  902. hr = E_OUTOFMEMORY;
  903. return hr;
  904. }
  905. //Security Review:Correct buffer size is passed.
  906. ZeroMemory(ppszAttr, sizeof(LPWSTR) * entries);
  907. if(FAILED(LocalCopyString(ppszAttr,pszAttr)))
  908. {
  909. LocalFree(ppszAttr);
  910. hr = E_OUTOFMEMORY;
  911. return hr;
  912. }
  913. //
  914. // Always include the DN in the search results as well. It is quite useful.
  915. //
  916. if (FAILED(LocalCopyString(&(ppszAttr[1]), g_szAttrDistinguishedName)))
  917. {
  918. LocalFree(ppszAttr);
  919. hr = E_OUTOFMEMORY;
  920. return hr;
  921. }
  922. //Security Review:Both strings are null terminated.
  923. if (_wcsicmp(pObjectEntry->pszObjectClass, g_pszServer) == 0)
  924. {
  925. ASSERT(entries >= 3);
  926. if (FAILED(LocalCopyString(&(ppszAttr[2]), g_szAttrServerReference)))
  927. {
  928. LocalFree(ppszAttr);
  929. hr = E_OUTOFMEMORY;
  930. return hr;
  931. }
  932. }
  933. *ppszAttributes = ppszAttr;
  934. *pCount = static_cast<DWORD>(entries);
  935. return hr;
  936. }
  937. //+--------------------------------------------------------------------------
  938. //
  939. // Function: FreeAttributesToFetch
  940. //
  941. // Synopsis: Function to free memory allocated by GetAttributesToFetch
  942. // Arguments: [dwszAttributes - in] : array of attributes to fetch
  943. // [dwCount - in] : count of attributes in array
  944. //
  945. // Returns: HRESULT : S_OK if everything succeeded
  946. // E_INVALIDARG if the object entry wasn't found
  947. // Anything else is a failure code from an ADSI call
  948. //
  949. // History: 25-Sep-2000 hiteshr Created
  950. //
  951. //---------------------------------------------------------------------------
  952. VOID FreeAttributesToFetch( IN LPWSTR *ppszAttributes,
  953. IN DWORD dwCount)
  954. {
  955. while(dwCount)
  956. {
  957. LocalFree(ppszAttributes[--dwCount]);
  958. }
  959. LocalFree(ppszAttributes);
  960. }
  961. //+--------------------------------------------------------------------------
  962. //
  963. // Function: GetSearchRoot
  964. //
  965. // Synopsis: Builds the path to the root of the search as determined by
  966. // the parameters passed in from the command line.
  967. //
  968. // Arguments: [pObjectEntry - IN] : pointer to the object table entry for the
  969. // object type that will be modified
  970. // [pCommandArgs IN] : the table of the command line input
  971. // [refBasePathsInfo IN] : reference to the base paths info
  972. // [refsbstrDN OUT] : reference to a CComBSTR that will
  973. // receive the DN at which to start
  974. // the search
  975. // [pbSearchAtForestRoot] :Set to true is startnode is equal to
  976. // forestroot
  977. //
  978. // Returns: HRESULT
  979. //
  980. // History: 24-April-2001 hiteshr Created
  981. //
  982. //---------------------------------------------------------------------------
  983. HRESULT GetSearchRoot(IN IN PDSQueryObjectTableEntry pObjectEntry,
  984. IN PARG_RECORD pCommandArgs,
  985. IN CDSCmdBasePathsInfo& refBasePathsInfo,
  986. OUT CComBSTR& refsbstrDN,
  987. OUT BOOL *pbSearchAtForestRoot,
  988. OUT BOOL *pbSearchAtGC)
  989. {
  990. if(!pCommandArgs ||
  991. !pObjectEntry ||
  992. !pbSearchAtForestRoot ||
  993. !pbSearchAtGC)
  994. {
  995. return E_POINTER;
  996. }
  997. PWSTR pszInputDN = NULL;
  998. // If GC switch isn't supported then set to false
  999. // otherwise check to see if it has been passed
  1000. if(g_eGC == -1)
  1001. {
  1002. *pbSearchAtGC = FALSE;
  1003. }
  1004. else
  1005. {
  1006. if(pCommandArgs[g_eGC].bDefined &&
  1007. pCommandArgs[g_eGC].bValue)
  1008. {
  1009. DEBUG_OUTPUT(LEVEL5_LOGGING, L"Searching the GC");
  1010. *pbSearchAtGC = TRUE;
  1011. }
  1012. }
  1013. //
  1014. //Get the starting node
  1015. //
  1016. if(pCommandArgs[eCommStartNode].bDefined &&
  1017. pCommandArgs[eCommStartNode].strValue )
  1018. {
  1019. pszInputDN = pCommandArgs[eCommStartNode].strValue;
  1020. //Security Review:Both strings are null terminated.
  1021. if(_wcsicmp(pszInputDN,g_pszDomainRoot) == 0)
  1022. {
  1023. refsbstrDN = refBasePathsInfo.GetDefaultNamingContext();
  1024. }
  1025. //Security Review:Both strings are null terminated.
  1026. else if(_wcsicmp(pszInputDN,g_pszForestRoot) == 0)
  1027. {
  1028. *pbSearchAtForestRoot = TRUE;
  1029. }
  1030. else
  1031. {
  1032. //
  1033. //DN is entered
  1034. //
  1035. refsbstrDN = pszInputDN;
  1036. }
  1037. }
  1038. else
  1039. {
  1040. //Security Review:Both strings are null terminated.
  1041. if (_wcsicmp(pObjectEntry->pszObjectClass, g_pszServer) == 0)
  1042. {
  1043. if (pCommandArgs[eServerDomain].bDefined &&
  1044. !pCommandArgs[eServerDomain].strValue)
  1045. {
  1046. PWSTR pszName = 0;
  1047. CComBSTR bstrDomainName = refBasePathsInfo.GetDefaultNamingContext();
  1048. HRESULT hr = CrackName(bstrDomainName,
  1049. &pszName,
  1050. GET_DNS_DOMAIN_NAME,
  1051. NULL);
  1052. if (FAILED(hr))
  1053. {
  1054. DEBUG_OUTPUT(LEVEL3_LOGGING,
  1055. L"Failed to crack the DN into a domain name: hr = 0x%x",
  1056. hr);
  1057. DisplayErrorMessage(g_pszDSCommandName,
  1058. NULL,
  1059. hr);
  1060. return hr;
  1061. }
  1062. pCommandArgs[eServerDomain].strValue = pszName;
  1063. }
  1064. //
  1065. // Get the base path that corresponds with the scope
  1066. //
  1067. GetServerSearchRoot(pCommandArgs,
  1068. refBasePathsInfo,
  1069. refsbstrDN);
  1070. }
  1071. //Security Review:Both strings are null terminated.
  1072. else if (_wcsicmp(pObjectEntry->pszObjectClass, g_pszSite) == 0)
  1073. {
  1074. //
  1075. // Scope is the configuration container
  1076. //
  1077. refsbstrDN = refBasePathsInfo.GetConfigurationNamingContext();
  1078. }
  1079. //Security Review:Both strings are null terminated.
  1080. else if (_wcsicmp(pObjectEntry->pszObjectClass, g_pszSubnet) == 0)
  1081. {
  1082. //
  1083. // Get the base path that corresponds with the scope
  1084. //
  1085. GetSubnetSearchRoot(refBasePathsInfo,
  1086. refsbstrDN);
  1087. }
  1088. else if (_wcsicmp(pObjectEntry->pszCommandLineObjectType, g_pszPartition) == 0)
  1089. {
  1090. // For partitions, search from Configuration
  1091. refsbstrDN = L"CN=Partitions,";
  1092. refsbstrDN += refBasePathsInfo.GetConfigurationNamingContext();
  1093. }
  1094. else
  1095. {
  1096. //
  1097. //default is Domain DN
  1098. //
  1099. refsbstrDN = refBasePathsInfo.GetDefaultNamingContext();
  1100. }
  1101. }
  1102. return S_OK;
  1103. }
  1104. HRESULT GetSearchObject(IN IN PDSQueryObjectTableEntry pObjectEntry,
  1105. IN CDSCmdBasePathsInfo& refBasePathsInfo,
  1106. IN PARG_RECORD pCommandArgs,
  1107. IN CDSCmdCredentialObject& refCredentialObject,
  1108. IN CComBSTR& refsbstrDN,
  1109. IN BOOL bSearchAtForestRoot,
  1110. IN BOOL bSearchAtGC,
  1111. OUT CComPtr<IDirectorySearch>& refspSearchObject)
  1112. {
  1113. ENTER_FUNCTION_HR(MINIMAL_LOGGING, GetSearchObject, hr);
  1114. if(!pObjectEntry || !pCommandArgs)
  1115. return E_POINTER;
  1116. //
  1117. //Rules for determining where to search.
  1118. //if -s server is given always search at server
  1119. //if -gc is given search at gc.
  1120. //if startnode is forestroot, search at gc. so -gc is implicit here.
  1121. //if startnode is forestroot, and -s server is provided, server must
  1122. //be gc.
  1123. //if -s server and -gc are given, server must be gc. This check is
  1124. //done in DoQueryValidation
  1125. //
  1126. if(!bSearchAtForestRoot)
  1127. {
  1128. CComBSTR sbstrObjectPath;
  1129. bool bBindToServer = true;
  1130. //
  1131. //Search at GC
  1132. //
  1133. if(bSearchAtGC)
  1134. {
  1135. //
  1136. //Change the provider in sbstrObjectPath from LDAP to GC
  1137. //
  1138. CComPtr<IADsPathname> spPathNameObject;
  1139. //Security Review:CLSCTX_INPROC_SERVER is passed. This is fine.
  1140. hr = CoCreateInstance(CLSID_Pathname,
  1141. NULL,
  1142. CLSCTX_INPROC_SERVER,
  1143. IID_IADsPathname,
  1144. (LPVOID*)&spPathNameObject);
  1145. if (FAILED(hr))
  1146. {
  1147. DisplayErrorMessage(g_pszDSCommandName,
  1148. NULL,
  1149. hr);
  1150. return hr;
  1151. }
  1152. //Set Provider to GC
  1153. hr = spPathNameObject->Set(CComBSTR(L"GC"), ADS_SETTYPE_PROVIDER);
  1154. ASSERT(SUCCEEDED(hr));
  1155. //Set the DN
  1156. hr = spPathNameObject->Set(refsbstrDN, ADS_SETTYPE_DN);
  1157. ASSERT(SUCCEEDED(hr));
  1158. //If server name present, search there. Server must be GC, check
  1159. //already done DoQueryValidation.
  1160. if(pCommandArgs[eCommServer].bDefined &&
  1161. pCommandArgs[eCommServer].strValue)
  1162. {
  1163. //Convert DN to adsi path with GC provider
  1164. hr = spPathNameObject->Set(CComBSTR(pCommandArgs[eCommServer].strValue), ADS_SETTYPE_SERVER);
  1165. //
  1166. //server name in path
  1167. //
  1168. bBindToServer = true;
  1169. }
  1170. else
  1171. {
  1172. //
  1173. //No server name in path
  1174. //
  1175. bBindToServer = false;
  1176. }
  1177. hr = spPathNameObject->Retrieve(bBindToServer ? ADS_FORMAT_X500 : ADS_FORMAT_X500_NO_SERVER,
  1178. &sbstrObjectPath);
  1179. ASSERT(SUCCEEDED(hr));
  1180. }
  1181. else
  1182. {
  1183. //
  1184. // Convert the DN to an ADSI path
  1185. //
  1186. refBasePathsInfo.ComposePathFromDN(refsbstrDN, sbstrObjectPath);
  1187. //Security Review:Both strings are null terminated.
  1188. if((_wcsicmp(pObjectEntry->pszObjectClass, g_pszUser) == 0 &&
  1189. pCommandArgs[eUserInactive].bDefined) ||
  1190. //Security Review:Both strings are null terminated.
  1191. (_wcsicmp(pObjectEntry->pszObjectClass, g_pszComputer) == 0 &&
  1192. pCommandArgs[eComputerInactive].bDefined))
  1193. {
  1194. INT nDomainBehaviorVersion = 0;
  1195. CComPtr<IADs> spDomain;
  1196. CComBSTR sbstrBasePath;
  1197. refBasePathsInfo.ComposePathFromDN(refBasePathsInfo.GetDefaultNamingContext(),
  1198. sbstrBasePath);
  1199. hr = DSCmdOpenObject(refCredentialObject,
  1200. sbstrBasePath,
  1201. IID_IADs,
  1202. (void**)&spDomain,
  1203. bBindToServer);
  1204. if (SUCCEEDED(hr))
  1205. {
  1206. CComVariant varVer;
  1207. hr = spDomain->GetInfo();
  1208. if(SUCCEEDED(hr))
  1209. {
  1210. CComBSTR bstrVer = L"msDS-Behavior-Version";
  1211. hr = spDomain->Get(bstrVer, &varVer);
  1212. if(SUCCEEDED(hr))
  1213. {
  1214. ASSERT(varVer.vt == VT_I4);
  1215. nDomainBehaviorVersion = static_cast<UINT>(varVer.lVal);
  1216. }
  1217. }
  1218. }
  1219. if(nDomainBehaviorVersion == 0)
  1220. {
  1221. DEBUG_OUTPUT(LEVEL3_LOGGING,
  1222. L"DomainBehaviorVersion is 0.");
  1223. hr = E_INVALIDARG;
  1224. DisplayErrorMessage(g_pszDSCommandName,
  1225. NULL,
  1226. hr,
  1227. IDS_FILTER_LAST_LOGON_VERSION);
  1228. return hr;
  1229. }
  1230. }
  1231. }
  1232. hr = DSCmdOpenObject(refCredentialObject,
  1233. sbstrObjectPath,
  1234. IID_IDirectorySearch,
  1235. (void**)&refspSearchObject,
  1236. bBindToServer);
  1237. if (FAILED(hr))
  1238. {
  1239. DisplayErrorMessage(g_pszDSCommandName,
  1240. NULL,
  1241. hr);
  1242. return hr;
  1243. }
  1244. }
  1245. else
  1246. {
  1247. CComBSTR bstrSearchRoot = L"GC://";
  1248. bool bBindToServer = false;
  1249. //If server name is provided search there
  1250. if(pCommandArgs[eCommServer].bDefined &&
  1251. pCommandArgs[eCommServer].strValue)
  1252. {
  1253. bstrSearchRoot += pCommandArgs[eCommServer].strValue;
  1254. bBindToServer = true;
  1255. }
  1256. else
  1257. {
  1258. //Get RootDse
  1259. CComPtr<IADs> spRootDSE = refBasePathsInfo.GetRootDSE();
  1260. //Get name of forest
  1261. VARIANT Default;
  1262. VariantInit(&Default);
  1263. hr = spRootDSE->Get (CComBSTR(L"rootDomainNamingContext"), &Default);
  1264. if(FAILED(hr))
  1265. {
  1266. DisplayErrorMessage(g_pszDSCommandName,
  1267. NULL,
  1268. hr);
  1269. return hr;
  1270. }
  1271. ASSERT(Default.vt == VT_BSTR);
  1272. CComBSTR bstrForestDN = Default.bstrVal;
  1273. ::VariantClear(&Default);
  1274. //Convert DN to dns path
  1275. CComBSTR bstrForestDNS;
  1276. if(!TranslateNameFromDnToDns(bstrForestDN,
  1277. bstrForestDNS))
  1278. {
  1279. hr = E_FAIL;
  1280. DisplayErrorMessage(g_pszDSCommandName,
  1281. NULL,
  1282. hr);
  1283. return hr;
  1284. }
  1285. bBindToServer = false;
  1286. bstrSearchRoot += bstrForestDNS;
  1287. }
  1288. //BIND to GC to search entire forest
  1289. hr = DSCmdOpenObject(refCredentialObject,
  1290. bstrSearchRoot,
  1291. IID_IDirectorySearch,
  1292. (void**)&refspSearchObject,
  1293. bBindToServer);
  1294. if (FAILED(hr))
  1295. {
  1296. DisplayErrorMessage(g_pszDSCommandName,
  1297. NULL,
  1298. hr);
  1299. return hr;
  1300. }
  1301. }
  1302. return hr;
  1303. }
  1304. BOOL
  1305. TranslateNameFromDnToDns(const CComBSTR& bstrInputDN,
  1306. CComBSTR& bstrOutputDNS)
  1307. {
  1308. if(bstrInputDN.Length() == 0)
  1309. return FALSE;
  1310. bstrOutputDNS.Empty();
  1311. LPCWSTR pstrName = bstrInputDN;
  1312. PDS_NAME_RESULT pResult = NULL;
  1313. if( DS_NAME_NO_ERROR
  1314. == DsCrackNames(NULL,
  1315. DS_NAME_FLAG_SYNTACTICAL_ONLY,
  1316. DS_FQDN_1779_NAME,
  1317. DS_CANONICAL_NAME,
  1318. 1,
  1319. (LPWSTR*)(&pstrName),
  1320. &pResult))
  1321. {
  1322. if(pResult &&
  1323. pResult->cItems == 1 &&
  1324. pResult->rItems[0].status == DS_NAME_NO_ERROR &&
  1325. pResult->rItems[0].pDomain)
  1326. {
  1327. bstrOutputDNS = pResult->rItems[0].pDomain;
  1328. }
  1329. if(pResult)
  1330. {
  1331. DsFreeNameResult(pResult);
  1332. }
  1333. }
  1334. return !!bstrOutputDNS.Length();
  1335. }
  1336. //+--------------------------------------------------------------------------
  1337. //
  1338. // Function: GetGCIndex
  1339. //
  1340. // Synopsis: Performs a lookup to determine which enum value is holding
  1341. // the GC (if any). This was necessary removing -gc from common
  1342. //
  1343. // Arguments: [pObjectEntry IN] : ObjectEntry from the parser
  1344. // [nCommandEnum OUT] : Enum value of the object, else -1
  1345. //
  1346. // Returns: HRESULT : S_OK if everything succeeded
  1347. // E_INVALIDARG
  1348. //
  1349. // Remarks:
  1350. //
  1351. //
  1352. // History: 10-Sep-2002 ronmart Created
  1353. //
  1354. //---------------------------------------------------------------------------
  1355. HRESULT GetGCIndex(PDSQueryObjectTableEntry pObjectEntry, int& nCommandEnum)
  1356. {
  1357. HRESULT hr = S_OK;
  1358. do // false loop
  1359. {
  1360. // Init nCommandEnum to an error value by default
  1361. nCommandEnum = -1;
  1362. if(NULL == pObjectEntry)
  1363. {
  1364. hr = E_INVALIDARG;
  1365. break;
  1366. }
  1367. // Get a pointer to the object class for readability
  1368. PCWSTR pszCommandLineObjectType = pObjectEntry->pszCommandLineObjectType;
  1369. // Now compare each object type against the specified
  1370. // object class to see what the enum index is
  1371. if(0 == lstrcmpi(pszCommandLineObjectType, g_pszStar))
  1372. {
  1373. nCommandEnum = eStarGC;
  1374. break;
  1375. }
  1376. else if(0 == lstrcmpi(pszCommandLineObjectType, g_pszOU))
  1377. {
  1378. nCommandEnum = eOUGC;
  1379. break;
  1380. }
  1381. else if(0 == lstrcmpi(pszCommandLineObjectType, g_pszUser))
  1382. {
  1383. nCommandEnum = eUserGC;
  1384. break;
  1385. }
  1386. else if(0 == lstrcmpi(pszCommandLineObjectType, g_pszContact))
  1387. {
  1388. nCommandEnum = eContactGC;
  1389. break;
  1390. }
  1391. else if(0 == lstrcmpi(pszCommandLineObjectType, g_pszComputer))
  1392. {
  1393. nCommandEnum = eComputerGC;
  1394. break;
  1395. }
  1396. else if(0 == lstrcmpi(pszCommandLineObjectType, g_pszGroup))
  1397. {
  1398. nCommandEnum = eGroupGC;
  1399. break;
  1400. }
  1401. else if(0 == lstrcmpi(pszCommandLineObjectType, g_pszServer))
  1402. {
  1403. nCommandEnum = eServerGC;
  1404. break;
  1405. }
  1406. else if(0 == lstrcmpi(pszCommandLineObjectType, g_pszSite))
  1407. {
  1408. nCommandEnum = eSiteGC;
  1409. break;
  1410. }
  1411. else if(0 == lstrcmpi(pszCommandLineObjectType,g_pszSubnet))
  1412. {
  1413. nCommandEnum = eSubnetGC;
  1414. break;
  1415. }
  1416. else if(0 == lstrcmpi(pszCommandLineObjectType, g_pszQuota))
  1417. {
  1418. nCommandEnum = -1; // -gc not supported
  1419. break;
  1420. }
  1421. else if(0 == lstrcmpi(pszCommandLineObjectType, g_pszPartition))
  1422. {
  1423. nCommandEnum = -1; // -gc not supported
  1424. break;
  1425. }
  1426. else
  1427. {
  1428. hr = E_FAIL;
  1429. // If you get here, then you've added a new object
  1430. // to cstrings.* without adding it to the
  1431. // if statement. This should only happen
  1432. // when testing a new object for the first time
  1433. // without a corresponding check above.
  1434. ASSERT(FALSE);
  1435. break;
  1436. }
  1437. } while(false);
  1438. return hr;
  1439. }