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.

754 lines
22 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000
  5. //
  6. // File: dsget.cpp
  7. //
  8. // Contents: Defines the main function DSGET
  9. // command line utility
  10. //
  11. // History: 13-Oct-2000 JeffJon Created
  12. //
  13. //
  14. //--------------------------------------------------------------------------
  15. #include "pch.h"
  16. #include "cstrings.h"
  17. #include "usage.h"
  18. #include "gettable.h"
  19. #include "query.h"
  20. #include "resource.h"
  21. #include "output.h"
  22. //
  23. // Forward Function Declarations
  24. //
  25. HRESULT DoGetValidation(PARG_RECORD pCommandArgs,
  26. PDSGetObjectTableEntry pObjectEntry);
  27. HRESULT DoGet(PARG_RECORD pCommandArgs,
  28. PDSGetObjectTableEntry pObjectEntry);
  29. HRESULT GetAttributesToFetch(IN PARG_RECORD pCommandArgs,
  30. IN PDSGetObjectTableEntry pObjectEntry,
  31. OUT LPWSTR **ppszAttributes,
  32. OUT DWORD * pCount);
  33. VOID FreeAttributesToFetch( IN LPWSTR *ppszAttributes,
  34. IN DWORD dwCount);
  35. //
  36. //Main Function
  37. //
  38. int __cdecl _tmain( VOID )
  39. {
  40. int argc = 0;
  41. LPTOKEN pToken = NULL;
  42. HRESULT hr = S_OK;
  43. PARG_RECORD pNewCommandArgs = 0;
  44. //
  45. // False loop
  46. //
  47. do
  48. {
  49. //
  50. // Initialize COM
  51. //
  52. hr = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  53. if (FAILED(hr))
  54. break;
  55. //Get CommandLine Input
  56. hr = HRESULT_FROM_WIN32(GetCommandInput(&argc,&pToken));
  57. if(FAILED(hr))
  58. break;
  59. if(argc == 1)
  60. {
  61. //
  62. // Display the error message and then break out of the false loop
  63. //
  64. DisplayMessage(USAGE_DSGET);
  65. hr = E_INVALIDARG;
  66. break;
  67. }
  68. //
  69. // Find which object table entry to use from
  70. // the second command line argument
  71. //
  72. PDSGetObjectTableEntry pObjectEntry = NULL;
  73. UINT idx = 0;
  74. PWSTR pszObjectType = (pToken+1)->GetToken();
  75. while (true)
  76. {
  77. pObjectEntry = g_DSObjectTable[idx++];
  78. if (!pObjectEntry)
  79. {
  80. break;
  81. }
  82. if (0 == _wcsicmp(pObjectEntry->pszCommandLineObjectType, pszObjectType))
  83. {
  84. break;
  85. }
  86. }
  87. if (!pObjectEntry)
  88. {
  89. //
  90. // Display the error message and then break out of the false loop
  91. //
  92. DisplayMessage(USAGE_DSGET);
  93. hr = E_INVALIDARG;
  94. break;
  95. }
  96. //
  97. // Now that we have the correct table entry, merge the command line table
  98. // for this object with the common commands
  99. //
  100. hr = MergeArgCommand(DSGET_COMMON_COMMANDS,
  101. pObjectEntry->pParserTable,
  102. &pNewCommandArgs);
  103. if (FAILED(hr))
  104. break;
  105. //
  106. //Parse the Input
  107. //
  108. PARSE_ERROR Error;
  109. if(!ParseCmd(pNewCommandArgs,
  110. argc-1,
  111. pToken+1,
  112. pObjectEntry->nUsageID,
  113. &Error,
  114. TRUE))
  115. {
  116. if (Error.Error != PARSE_ERROR_HELP_SWITCH &&
  117. Error.Error != ERROR_FROM_PARSER)
  118. {
  119. //
  120. // Display the usage text and then break out of the false loop
  121. //
  122. DisplayMessage(pObjectEntry->nUsageID);
  123. }
  124. hr = E_INVALIDARG;
  125. break;
  126. }
  127. //
  128. // Check to see if we are doing debug spew
  129. //
  130. #ifdef DBG
  131. bool bDebugging = pNewCommandArgs[eCommDebug].bDefined &&
  132. pNewCommandArgs[eCommDebug].nValue;
  133. if (bDebugging)
  134. {
  135. ENABLE_DEBUG_OUTPUT(pNewCommandArgs[eCommDebug].nValue);
  136. }
  137. #else
  138. DISABLE_DEBUG_OUTPUT();
  139. #endif
  140. //
  141. // Do extra validation like switch dependency check etc.
  142. //
  143. hr = DoGetValidation(pNewCommandArgs,
  144. pObjectEntry);
  145. if (FAILED(hr))
  146. break;
  147. //
  148. // Command line parsing succeeded
  149. //
  150. hr = DoGet(pNewCommandArgs,
  151. pObjectEntry);
  152. if(FAILED(hr))
  153. break;
  154. } while (false); //False Loop
  155. //
  156. //Do the CleanUp
  157. //
  158. //
  159. // Free the memory associated with the command values
  160. //
  161. if (pNewCommandArgs)
  162. {
  163. FreeCmd(pNewCommandArgs);
  164. }
  165. //
  166. // Free the tokens
  167. //
  168. if (pToken)
  169. {
  170. delete[] pToken;
  171. pToken = 0;
  172. }
  173. //
  174. //Display Failure or Success Message
  175. //
  176. if(FAILED(hr))
  177. {
  178. DisplayErrorMessage(g_pszDSCommandName,
  179. NULL,
  180. hr);
  181. }
  182. else
  183. {
  184. DisplaySuccessMessage(g_pszDSCommandName,
  185. NULL);
  186. }
  187. //
  188. // Uninitialize COM
  189. //
  190. CoUninitialize();
  191. return hr;
  192. }
  193. //+--------------------------------------------------------------------------
  194. //
  195. // Function: DoGetValidation
  196. //
  197. // Synopsis: Checks to be sure that command line switches that are mutually
  198. // exclusive are not both present and those that are dependent are
  199. // both present, and other validations which cannot be done by parser.
  200. //
  201. // Arguments: [pCommandArgs - IN] : the command line argument structure used
  202. // to retrieve the values for each switch
  203. // [pObjectEntry - IN] : pointer to the object table entry for the
  204. // object type that will be queryied
  205. //
  206. // Returns: HRESULT : S_OK if everything succeeded
  207. // E_INVALIDARG if the object entry wasn't found
  208. //
  209. // History: 13-Oct-2000 JeffJon Created
  210. //
  211. //---------------------------------------------------------------------------
  212. HRESULT DoGetValidation(IN PARG_RECORD pCommandArgs,
  213. IN PDSGetObjectTableEntry pObjectEntry)
  214. {
  215. ENTER_FUNCTION_HR(MINIMAL_LOGGING, DoGetValidation, hr);
  216. do // false loop
  217. {
  218. if (!pCommandArgs ||
  219. !pObjectEntry)
  220. {
  221. ASSERT(pCommandArgs);
  222. ASSERT(pObjectEntry);
  223. hr = E_INVALIDARG;
  224. break;
  225. }
  226. //
  227. // Check the object type specific switches
  228. //
  229. PWSTR pszObjectType = NULL;
  230. if (!pCommandArgs[eCommObjectType].bDefined &&
  231. !pCommandArgs[eCommObjectType].strValue)
  232. {
  233. hr = E_INVALIDARG;
  234. break;
  235. }
  236. pszObjectType = pCommandArgs[eCommObjectType].strValue;
  237. UINT nMemberOfIdx = 0;
  238. UINT nExpandIdx = 0;
  239. UINT nIdxLast = 0;
  240. UINT nMembersIdx = 0;
  241. bool bMembersDefined = false;
  242. bool bMemberOfDefined = false;
  243. if (0 == _wcsicmp(g_pszUser, pszObjectType) )
  244. {
  245. nMemberOfIdx = eUserMemberOf;
  246. nExpandIdx = eUserExpand;
  247. nIdxLast = eUserLast;
  248. if (pCommandArgs[eUserMemberOf].bDefined)
  249. {
  250. bMemberOfDefined = true;
  251. }
  252. //
  253. // If nothing is defined, then define DN, SAMAccountName, and Description
  254. //
  255. bool bSomethingDefined = false;
  256. for (UINT nIdx = eCommDN; nIdx <= eUserLast; nIdx++)
  257. {
  258. if (pCommandArgs[nIdx].bDefined)
  259. {
  260. bSomethingDefined = true;
  261. break;
  262. }
  263. }
  264. if (!bSomethingDefined)
  265. {
  266. pCommandArgs[eCommDN].bDefined = TRUE;
  267. pCommandArgs[eCommDN].bValue = TRUE;
  268. pCommandArgs[eUserSamID].bDefined = TRUE;
  269. pCommandArgs[eUserSamID].bValue = TRUE;
  270. pCommandArgs[eCommDescription].bDefined = TRUE;
  271. pCommandArgs[eCommDescription].bValue = TRUE;
  272. }
  273. }
  274. else if (0 == _wcsicmp(g_pszComputer, pszObjectType) )
  275. {
  276. nMemberOfIdx = eComputerMemberOf;
  277. nExpandIdx = eComputerExpand;
  278. nIdxLast = eComputerLast;
  279. if (pCommandArgs[eComputerMemberOf].bDefined)
  280. {
  281. bMemberOfDefined = true;
  282. }
  283. }
  284. else if (0 == _wcsicmp(g_pszGroup, pszObjectType) )
  285. {
  286. nMemberOfIdx = eGroupMemberOf;
  287. nExpandIdx = eGroupExpand;
  288. nIdxLast = eGroupLast;
  289. nMembersIdx = eGroupMembers;
  290. if (pCommandArgs[eGroupMemberOf].bDefined)
  291. {
  292. bMemberOfDefined = true;
  293. }
  294. if (pCommandArgs[eGroupMembers].bDefined)
  295. {
  296. bMembersDefined = true;
  297. }
  298. //
  299. // If nothing is defined, then define DN, and Description
  300. //
  301. bool bSomethingDefined = false;
  302. for (UINT nIdx = eCommDN; nIdx <= eUserLast; nIdx++)
  303. {
  304. if (pCommandArgs[nIdx].bDefined)
  305. {
  306. bSomethingDefined = true;
  307. break;
  308. }
  309. }
  310. if (!bSomethingDefined)
  311. {
  312. pCommandArgs[eCommDN].bDefined = TRUE;
  313. pCommandArgs[eCommDN].bValue = TRUE;
  314. pCommandArgs[eCommDescription].bDefined = TRUE;
  315. pCommandArgs[eCommDescription].bValue = TRUE;
  316. }
  317. }
  318. else if (0 == _wcsicmp(g_pszOU, pszObjectType) ||
  319. 0 == _wcsicmp(g_pszContact, pszObjectType))
  320. {
  321. //
  322. // If nothing is defined, then define DN, and Description
  323. //
  324. bool bSomethingDefined = false;
  325. for (UINT nIdx = eCommDN; nIdx <= eUserLast; nIdx++)
  326. {
  327. if (pCommandArgs[nIdx].bDefined)
  328. {
  329. bSomethingDefined = true;
  330. break;
  331. }
  332. }
  333. if (!bSomethingDefined)
  334. {
  335. pCommandArgs[eCommDN].bDefined = TRUE;
  336. pCommandArgs[eCommDN].bValue = TRUE;
  337. pCommandArgs[eCommDescription].bDefined = TRUE;
  338. pCommandArgs[eCommDescription].bValue = TRUE;
  339. }
  340. }
  341. //
  342. // if the members or the memberof switch is defined
  343. //
  344. if (bMemberOfDefined ||
  345. bMembersDefined)
  346. {
  347. //
  348. // If the members switch is defined, undefine everything else
  349. // If the members switch isn't defined but the memberof switch is
  350. // undefine everything else
  351. //
  352. for (UINT nIdx = eCommDN; nIdx < nIdxLast; nIdx++)
  353. {
  354. if ((!bMembersDefined &&
  355. bMemberOfDefined &&
  356. nIdx != nMemberOfIdx &&
  357. nIdx != nExpandIdx) ||
  358. (bMembersDefined &&
  359. nIdx != nMembersIdx &&
  360. nIdx != nExpandIdx))
  361. {
  362. pCommandArgs[nIdx].bDefined = FALSE;
  363. }
  364. }
  365. //
  366. // MemberOf should always be seen in list view
  367. //
  368. pCommandArgs[eCommList].bDefined = TRUE;
  369. pCommandArgs[eCommList].bValue = TRUE;
  370. }
  371. } while (false);
  372. return hr;
  373. }
  374. //+--------------------------------------------------------------------------
  375. //
  376. // Function: DoGet
  377. //
  378. // Synopsis: Does the get
  379. // Arguments: [pCommandArgs - IN] : the command line argument structure used
  380. // to retrieve the values for each switch
  381. // [pObjectEntry - IN] : pointer to the object table entry for the
  382. // object type that will be modified
  383. //
  384. // Returns: HRESULT : S_OK if everything succeeded
  385. // E_INVALIDARG if the object entry wasn't found
  386. // Anything else is a failure code from an ADSI call
  387. //
  388. // History: 13-Oct-2000 JeffJon Created
  389. //
  390. //---------------------------------------------------------------------------
  391. HRESULT DoGet(PARG_RECORD pCommandArgs,
  392. PDSGetObjectTableEntry pObjectEntry)
  393. {
  394. ENTER_FUNCTION_HR(MINIMAL_LOGGING, DoGet, hr);
  395. do // false loop
  396. {
  397. if (!pCommandArgs ||
  398. !pObjectEntry)
  399. {
  400. ASSERT(pCommandArgs);
  401. ASSERT(pObjectEntry);
  402. hr = E_INVALIDARG;
  403. break;
  404. }
  405. CDSCmdCredentialObject credentialObject;
  406. if (pCommandArgs[eCommUserName].bDefined)
  407. {
  408. credentialObject.SetUsername(pCommandArgs[eCommUserName].strValue);
  409. credentialObject.SetUsingCredentials(true);
  410. }
  411. if (pCommandArgs[eCommPassword].bDefined)
  412. {
  413. credentialObject.SetPassword(pCommandArgs[eCommPassword].strValue);
  414. credentialObject.SetUsingCredentials(true);
  415. }
  416. //
  417. // Initialize the base paths info from the command line args
  418. //
  419. CDSCmdBasePathsInfo basePathsInfo;
  420. if (pCommandArgs[eCommServer].bDefined)
  421. {
  422. hr = basePathsInfo.InitializeFromName(credentialObject,
  423. pCommandArgs[eCommServer].strValue,
  424. true);
  425. }
  426. else if (pCommandArgs[eCommDomain].bDefined)
  427. {
  428. hr = basePathsInfo.InitializeFromName(credentialObject,
  429. pCommandArgs[eCommDomain].strValue,
  430. false);
  431. }
  432. else
  433. {
  434. hr = basePathsInfo.InitializeFromName(credentialObject, NULL, false);
  435. }
  436. if (FAILED(hr))
  437. {
  438. break;
  439. }
  440. //
  441. // The DNs or Names should be given as a \0 separated list
  442. // So parse it and loop through each object
  443. //
  444. UINT nStrings = 0;
  445. PWSTR* ppszArray = NULL;
  446. ParseNullSeparatedString(pCommandArgs[eCommObjectDNorName].strValue,
  447. &ppszArray,
  448. &nStrings);
  449. if (nStrings < 1 ||
  450. !ppszArray)
  451. {
  452. //
  453. // Display the usage text and then fail
  454. //
  455. DisplayMessage(pObjectEntry->nUsageID);
  456. hr = E_INVALIDARG;
  457. break;
  458. }
  459. //
  460. // Create the formatting object and initialize it
  461. //
  462. CFormatInfo formatInfo;
  463. hr = formatInfo.Initialize(nStrings,
  464. pCommandArgs[eCommList].bDefined != 0,
  465. pCommandArgs[eCommQuiet].bDefined != 0);
  466. if (FAILED(hr))
  467. {
  468. break;
  469. }
  470. //
  471. // Loop through each of the objects
  472. //
  473. for (UINT nNameIdx = 0; nNameIdx < nStrings; nNameIdx++)
  474. {
  475. //
  476. // Use a false do loop here so that we can break on an
  477. // error but still have the chance to determine if we
  478. // should continue the for loop if the -c option was provided
  479. //
  480. do // false loop
  481. {
  482. PWSTR pszObjectDN = ppszArray[nNameIdx];
  483. if (!pszObjectDN)
  484. {
  485. //
  486. // Display the usage text and then fail
  487. //
  488. DisplayMessage(pObjectEntry->nUsageID);
  489. hr = E_INVALIDARG;
  490. break;
  491. }
  492. DEBUG_OUTPUT(MINIMAL_LOGGING, L"Object DN = %s", pszObjectDN);
  493. CComBSTR sbstrObjectPath;
  494. basePathsInfo.ComposePathFromDN(pszObjectDN, sbstrObjectPath);
  495. CComPtr<IDirectoryObject> spObject;
  496. hr = DSCmdOpenObject(credentialObject,
  497. sbstrObjectPath,
  498. IID_IDirectoryObject,
  499. (void**)&spObject,
  500. true);
  501. if(FAILED(hr))
  502. {
  503. break;
  504. }
  505. //
  506. //Get the arributes to fetch
  507. //
  508. LPWSTR *ppszAttributes = NULL;
  509. DWORD dwCountAttr = 0;
  510. hr = GetAttributesToFetch(pCommandArgs,
  511. pObjectEntry,
  512. &ppszAttributes,
  513. &dwCountAttr);
  514. if (FAILED(hr))
  515. {
  516. break;
  517. }
  518. DEBUG_OUTPUT(MINIMAL_LOGGING,
  519. L"Calling GetObjectAttributes for %d attributes.",
  520. dwCountAttr);
  521. DWORD dwAttrsReturned = 0;
  522. PADS_ATTR_INFO pAttrInfo = NULL;
  523. hr = spObject->GetObjectAttributes(ppszAttributes,
  524. dwCountAttr,
  525. &pAttrInfo,
  526. &dwAttrsReturned);
  527. if(FAILED(hr))
  528. {
  529. DEBUG_OUTPUT(MINIMAL_LOGGING,
  530. L"GetObjectAttributes failed: hr = 0x%x",
  531. hr);
  532. FreeAttributesToFetch(ppszAttributes,dwCountAttr);
  533. break;
  534. }
  535. DEBUG_OUTPUT(LEVEL5_LOGGING,
  536. L"GetObjectAttributes succeeded: dwAttrsReturned = %d",
  537. dwAttrsReturned);
  538. //
  539. // NOTE: there may be other items to display that are not
  540. // part of the attributes fetched
  541. //
  542. /*
  543. if (dwAttrsReturned == 0 || !pAttrInfo)
  544. {
  545. break;
  546. }
  547. */
  548. //
  549. // Output the result of search
  550. //
  551. hr = DsGetOutputValuesList(pszObjectDN,
  552. basePathsInfo,
  553. credentialObject,
  554. pCommandArgs,
  555. pObjectEntry,
  556. dwAttrsReturned,
  557. pAttrInfo,
  558. spObject,
  559. formatInfo);
  560. } while (false);
  561. //
  562. // If there was a failure and the -c (continue) flag wasn't given
  563. // then stop processing names
  564. //
  565. if (FAILED(hr) &&
  566. !pCommandArgs[eCommContinue].bDefined)
  567. {
  568. break;
  569. }
  570. } // Names for loop
  571. //
  572. // Now display the results
  573. //
  574. formatInfo.Display();
  575. } while (false);
  576. return hr;
  577. }
  578. //+--------------------------------------------------------------------------
  579. //
  580. // Function: GetAttributesToFetch
  581. //
  582. // Synopsis: Make an array of attributes to fetch.
  583. // Arguments: [ppszAttributes - OUT] : array of attributes to fetch
  584. // [pCount - OUT] : count of attributes in array
  585. //
  586. // Returns: HRESULT : S_OK if everything succeeded
  587. // E_INVALIDARG if the object entry wasn't found
  588. // Anything else is a failure code from an ADSI call
  589. //
  590. // History: 25-Sep-2000 hiteshr Created
  591. //
  592. //---------------------------------------------------------------------------
  593. HRESULT GetAttributesToFetch(IN PARG_RECORD pCommandArgs,
  594. IN PDSGetObjectTableEntry pObjectEntry,
  595. OUT LPWSTR **ppszAttributes,
  596. OUT DWORD * pCount)
  597. {
  598. ENTER_FUNCTION_HR(LEVEL8_LOGGING, GetAttributesToFetch, hr);
  599. do // false loop
  600. {
  601. if(!pCommandArgs ||
  602. !pObjectEntry)
  603. {
  604. ASSERT(pCommandArgs);
  605. ASSERT(pObjectEntry);
  606. hr = E_INVALIDARG;
  607. break;
  608. }
  609. LPWSTR *ppszAttr = (LPWSTR *)LocalAlloc(LPTR, pObjectEntry->dwAttributeCount *sizeof(LPCTSTR));
  610. if(!ppszAttr)
  611. {
  612. hr = E_OUTOFMEMORY;
  613. break;
  614. }
  615. //
  616. // Loop through the attributes that are needed and copy
  617. // them into the array.
  618. //
  619. // REVIEW_JEFFON : what if there are duplicates?
  620. //
  621. DEBUG_OUTPUT(FULL_LOGGING, L"Adding attributes to list:");
  622. DWORD dwAttrCount = 0;
  623. for(DWORD i = 0; i < pObjectEntry->dwAttributeCount; i++)
  624. {
  625. if (pObjectEntry->pAttributeTable[i])
  626. {
  627. UINT nCommandEntry = pObjectEntry->pAttributeTable[i]->nAttributeID;
  628. if (pCommandArgs[nCommandEntry].bDefined)
  629. {
  630. LPWSTR pszAttr = pObjectEntry->pAttributeTable[i]->pszName;
  631. if (pszAttr)
  632. {
  633. hr = LocalCopyString(ppszAttr+dwAttrCount, pszAttr);
  634. if (FAILED(hr))
  635. {
  636. LocalFree(ppszAttr);
  637. hr = E_OUTOFMEMORY;
  638. break;
  639. }
  640. DEBUG_OUTPUT(FULL_LOGGING, L"\t%s", pszAttr);
  641. dwAttrCount++;
  642. }
  643. }
  644. }
  645. }
  646. if (SUCCEEDED(hr))
  647. {
  648. DEBUG_OUTPUT(FULL_LOGGING, L"Done adding %d attributes to list.", dwAttrCount);
  649. }
  650. *ppszAttributes = ppszAttr;
  651. *pCount = dwAttrCount;
  652. } while (false);
  653. return hr;
  654. }
  655. //+--------------------------------------------------------------------------
  656. //
  657. // Function: FreeAttributesToFetch
  658. //
  659. // Synopsis: Function to free memory allocated by GetAttributesToFetch
  660. // Arguments: [dwszAttributes - in] : array of attributes to fetch
  661. // [dwCount - in] : count of attributes in array
  662. //
  663. // Returns: HRESULT : S_OK if everything succeeded
  664. // E_INVALIDARG if the object entry wasn't found
  665. // Anything else is a failure code from an ADSI call
  666. //
  667. // History: 25-Sep-2000 hiteshr Created
  668. //
  669. //---------------------------------------------------------------------------
  670. VOID FreeAttributesToFetch( IN LPWSTR *ppszAttributes,
  671. IN DWORD dwCount)
  672. {
  673. while(dwCount)
  674. {
  675. LocalFree(ppszAttributes[--dwCount]);
  676. }
  677. LocalFree(ppszAttributes);
  678. }