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.

1569 lines
54 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000
  5. //
  6. // File: dsAdd.cpp
  7. //
  8. // Contents: Defines the main function and parser tables for the DSAdd
  9. // command line utility
  10. //
  11. // History: 22-Sep-2000 JeffJon Created
  12. //
  13. //
  14. //--------------------------------------------------------------------------
  15. #include "pch.h"
  16. #include "cstrings.h"
  17. #include "usage.h"
  18. #include "addtable.h"
  19. #include "resource.h"
  20. #include "query.h"
  21. //
  22. // Function Declarations
  23. //
  24. HRESULT DoAddValidation(PARG_RECORD pCommandArgs, BOOL& bErrorShown);
  25. HRESULT DoAdd(PARG_RECORD pCommandArgs, PDSOBJECTTABLEENTRY pObjectEntry,
  26. DSADD_COMMAND_ENUM eObjectDNorName);
  27. HRESULT CreateQuotaName(IN CDSCmdBasePathsInfo& basePathsInfo,
  28. IN CDSCmdCredentialObject& credentialObject,
  29. IN LPCWSTR lpszRDN,
  30. OUT CComBSTR& bstrRDN);
  31. HRESULT DoQuotaValidation(IN PARG_RECORD pCommandArgs,
  32. IN PDSOBJECTTABLEENTRY pObjectEntry,
  33. IN CDSCmdBasePathsInfo& basePathsInfo,
  34. IN CDSCmdCredentialObject& credentialObject,
  35. IN LPCWSTR lpszPartitionDN,
  36. OUT PWSTR* pszNewQuotaDN);
  37. HRESULT GetObjectDNIndex(PDSOBJECTTABLEENTRY pObjectEntry,
  38. int& nCommandEnum);
  39. HRESULT IsQuotaAcctPresent( IN LPWSTR lpszTrusteeDN,
  40. IN PCWSTR pszSearchRootPath,
  41. IN CDSCmdBasePathsInfo& basePathsInfo,
  42. IN const CDSCmdCredentialObject& refCredObject,
  43. OUT bool& bFound);
  44. int __cdecl _tmain( VOID )
  45. {
  46. int argc;
  47. LPTOKEN pToken = NULL;
  48. HRESULT hr = S_OK;
  49. //
  50. // Initialize COM
  51. //
  52. hr = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  53. if (FAILED(hr))
  54. {
  55. DisplayErrorMessage(g_pszDSCommandName,
  56. NULL,
  57. hr);
  58. return hr;
  59. }
  60. if( !GetCommandInput(&argc,&pToken) )
  61. {
  62. PARG_RECORD pNewCommandArgs = 0;
  63. //
  64. // False loop
  65. //
  66. do
  67. {
  68. if(argc == 1)
  69. {
  70. //
  71. // Display the error message and then break out of the false loop
  72. //
  73. DisplayMessage(USAGE_DSADD,TRUE);
  74. hr = E_INVALIDARG;
  75. break;
  76. }
  77. if(argc == 2)
  78. {
  79. if(IsTokenHelpSwitch(pToken + 1))
  80. {
  81. hr = S_OK;
  82. DisplayMessage(USAGE_DSADD,TRUE);
  83. break;
  84. }
  85. }
  86. //
  87. // Find which object table entry to use from
  88. // the second command line argument
  89. //
  90. PDSOBJECTTABLEENTRY pObjectEntry = NULL;
  91. UINT idx = 0;
  92. while (true)
  93. {
  94. pObjectEntry = g_DSObjectTable[idx];
  95. if (!pObjectEntry)
  96. {
  97. break;
  98. }
  99. PWSTR pszObjectType = (pToken+1)->GetToken();
  100. if (0 == _wcsicmp(pObjectEntry->pszCommandLineObjectType, pszObjectType))
  101. {
  102. break;
  103. }
  104. idx++;
  105. }
  106. if (!pObjectEntry)
  107. {
  108. //
  109. // Display the error message and then break out of the false loop
  110. //
  111. DisplayMessage(USAGE_DSADD);
  112. hr = E_INVALIDARG;
  113. break;
  114. }
  115. //
  116. // Now that we have the correct table entry, merge the command line table
  117. // for this object with the common commands
  118. //
  119. hr = MergeArgCommand(DSADD_COMMON_COMMANDS,
  120. pObjectEntry->pParserTable,
  121. &pNewCommandArgs);
  122. if (FAILED(hr))
  123. {
  124. //
  125. // Display the error message and then break out of the false loop
  126. //
  127. DisplayErrorMessage(g_pszDSCommandName, L"", hr);
  128. break;
  129. }
  130. if (!pNewCommandArgs)
  131. {
  132. //
  133. // Display the usage text and then break out of the false loop
  134. //
  135. DisplayMessage(pObjectEntry->nUsageID);
  136. hr = E_FAIL;
  137. break;
  138. }
  139. PARSE_ERROR Error;
  140. if(!ParseCmd(g_pszDSCommandName,
  141. pNewCommandArgs,
  142. argc-1,
  143. pToken+1,
  144. pObjectEntry->nUsageID,
  145. &Error,
  146. TRUE))
  147. {
  148. //ParseCmd did not display any error. Error should
  149. //be handled here. Check DisplayParseError for the
  150. //cases where Error is not shown by ParseCmd
  151. if(!Error.MessageShown)
  152. {
  153. hr = E_INVALIDARG;
  154. DisplayErrorMessage(g_pszDSCommandName,
  155. NULL,
  156. hr);
  157. break;
  158. }
  159. if(Error.ErrorSource == ERROR_FROM_PARSER
  160. && Error.Error == PARSE_ERROR_HELP_SWITCH)
  161. {
  162. hr = S_OK;
  163. break;
  164. }
  165. hr = E_INVALIDARG;
  166. break;
  167. }
  168. else
  169. {
  170. //
  171. // Check to see if we are doing debug spew
  172. //
  173. #ifdef DBG
  174. bool bDebugging = pNewCommandArgs[eCommDebug].bDefined &&
  175. pNewCommandArgs[eCommDebug].nValue;
  176. if (bDebugging)
  177. {
  178. ENABLE_DEBUG_OUTPUT(pNewCommandArgs[eCommDebug].nValue);
  179. }
  180. #else
  181. DISABLE_DEBUG_OUTPUT();
  182. #endif
  183. // Get the Command Enum value based on the object type to
  184. // deal with the -part switch for quotas which doesn't
  185. // use the common object dn
  186. int nCommandEnum = -1;
  187. if (FAILED(GetObjectDNIndex(pObjectEntry, nCommandEnum))
  188. || (nCommandEnum == -1))
  189. {
  190. // An object type is missing in GetObjectDNIndex
  191. if(!Error.MessageShown)
  192. {
  193. hr = E_INVALIDARG;
  194. DisplayErrorMessage(g_pszDSCommandName,
  195. NULL,
  196. hr);
  197. break;
  198. }
  199. }
  200. DSADD_COMMAND_ENUM eObjectDNorName = (DSADD_COMMAND_ENUM) nCommandEnum;
  201. //
  202. // Be sure that mutually exclusive and dependent switches are correct
  203. //
  204. BOOL bErrorShown = FALSE;
  205. hr = DoAddValidation(pNewCommandArgs, bErrorShown);
  206. if (FAILED(hr))
  207. {
  208. if (!bErrorShown)
  209. {
  210. DisplayErrorMessage(g_pszDSCommandName,
  211. pNewCommandArgs[eObjectDNorName].strValue,
  212. hr);
  213. }
  214. break;
  215. }
  216. //
  217. // Command line parsing succeeded
  218. //
  219. hr = DoAdd(pNewCommandArgs, pObjectEntry, eObjectDNorName);
  220. }
  221. } while (false);
  222. //
  223. // Free the memory associated with the command values
  224. //
  225. if (pNewCommandArgs)
  226. {
  227. FreeCmd(pNewCommandArgs);
  228. }
  229. //
  230. // Free the tokens
  231. //
  232. if (pToken)
  233. {
  234. delete[] pToken;
  235. pToken = 0;
  236. }
  237. }
  238. //
  239. // Uninitialize COM
  240. //
  241. ::CoUninitialize();
  242. return hr;
  243. }
  244. //+--------------------------------------------------------------------------
  245. //
  246. // Function: DoGroupValidation
  247. //
  248. // Synopsis: Checks to be sure that command line switches for a group that
  249. // are mutually exclusive are not both present and those that
  250. // are dependent are both present
  251. //
  252. // Arguments: [pCommandArgs - IN] : the command line argument structure used
  253. // to retrieve the values for each switch
  254. //
  255. // Returns: HRESULT : S_OK if everything succeeded
  256. // E_INVALIDARG if the object entry wasn't found
  257. // Anything else is a failure code from an ADSI call
  258. //
  259. // History: 04-Oct-2000 JeffJon Created
  260. //
  261. //---------------------------------------------------------------------------
  262. HRESULT DoGroupValidation(PARG_RECORD pCommandArgs)
  263. {
  264. HRESULT hr = S_OK;
  265. do // false loop
  266. {
  267. //
  268. // Set the group scope to default (global) if not given
  269. //
  270. if (!pCommandArgs[eGroupScope].bDefined ||
  271. !pCommandArgs[eGroupScope].strValue)
  272. {
  273. size_t nScopeLen = _tcslen(g_bstrGroupScopeGlobal);
  274. pCommandArgs[eGroupScope].strValue = (LPWSTR)LocalAlloc(LPTR, (nScopeLen+2) * sizeof(WCHAR) );
  275. if (!pCommandArgs[eGroupScope].strValue)
  276. {
  277. DEBUG_OUTPUT(MINIMAL_LOGGING, L"Failed to allocate space for pCommandArgs[eGroupScope].strValue");
  278. hr = E_OUTOFMEMORY;
  279. break;
  280. }
  281. _tcscpy(pCommandArgs[eGroupScope].strValue, g_bstrGroupScopeGlobal);
  282. pCommandArgs[eGroupScope].bDefined = TRUE;
  283. }
  284. //
  285. // Set the group security to default (yes) if not given
  286. //
  287. if (!pCommandArgs[eGroupSecgrp].bDefined)
  288. {
  289. pCommandArgs[eGroupSecgrp].bValue = TRUE;
  290. pCommandArgs[eGroupSecgrp].bDefined = TRUE;
  291. //
  292. // Need to change the type to bool so that FreeCmd doesn't
  293. // try to free the string when the value is true
  294. //
  295. pCommandArgs[eGroupSecgrp].fType = ARG_TYPE_BOOL;
  296. }
  297. } while (false);
  298. return hr;
  299. }
  300. //+--------------------------------------------------------------------------
  301. //
  302. // Function: DoAddValidation
  303. //
  304. // Synopsis: Checks to be sure that command line switches that are mutually
  305. // exclusive are not both present and those that are dependent are
  306. // both presetn
  307. //
  308. // Arguments: [pCommandArgs - IN] : the command line argument structure used
  309. // to retrieve the values for each switch
  310. // [bErrorShown - OUT] : set to true if an error was shown
  311. //
  312. // Returns: HRESULT : S_OK if everything succeeded
  313. // E_INVALIDARG if the object entry wasn't found
  314. // Anything else is a failure code from an ADSI call
  315. //
  316. // History: 22-Sep-2000 JeffJon Created
  317. //
  318. //---------------------------------------------------------------------------
  319. HRESULT DoAddValidation(PARG_RECORD pCommandArgs, BOOL& bErrorShown)
  320. {
  321. ENTER_FUNCTION_HR(MINIMAL_LOGGING, DoAddValidation, hr);
  322. do // false loop
  323. {
  324. // Check to be sure the server and domain switches
  325. // are mutually exclusive
  326. if (pCommandArgs[eCommServer].bDefined &&
  327. pCommandArgs[eCommDomain].bDefined)
  328. {
  329. hr = E_INVALIDARG;
  330. DisplayErrorMessage(g_pszDSCommandName, 0, hr, IDS_NO_SERVER_AND_DOMAIN);
  331. bErrorShown = TRUE;
  332. break;
  333. }
  334. //
  335. // Check the user switches
  336. //
  337. PWSTR pszObjectType = NULL;
  338. if (!pCommandArgs[eCommObjectType].bDefined &&
  339. !pCommandArgs[eCommObjectType].strValue)
  340. {
  341. hr = E_INVALIDARG;
  342. break;
  343. }
  344. pszObjectType = pCommandArgs[eCommObjectType].strValue;
  345. if (0 == _wcsicmp(g_pszUser, pszObjectType))
  346. {
  347. //
  348. // Set the default for user must change password if the value wasn't specified
  349. //
  350. if (!pCommandArgs[eUserMustchpwd].bDefined)
  351. {
  352. pCommandArgs[eUserMustchpwd].bDefined = TRUE;
  353. pCommandArgs[eUserMustchpwd].bValue = FALSE;
  354. }
  355. //
  356. // Can't have user must change password if user can change password is no
  357. //
  358. if ((pCommandArgs[eUserMustchpwd].bDefined &&
  359. pCommandArgs[eUserMustchpwd].bValue) &&
  360. (pCommandArgs[eUserCanchpwd].bDefined &&
  361. !pCommandArgs[eUserCanchpwd].bValue))
  362. {
  363. DEBUG_OUTPUT(MINIMAL_LOGGING, L"User must change password and user can change password = false was supplied");
  364. hr = E_INVALIDARG;
  365. break;
  366. }
  367. // Before checking the password check to see if the user defined the -disabled switch.
  368. // If not, then set the -disabled value to TRUE if password is not defined and FALSE if
  369. // the password was defined
  370. if (!pCommandArgs[eUserDisabled].bDefined)
  371. {
  372. if (pCommandArgs[eUserPwd].bDefined)
  373. {
  374. pCommandArgs[eUserDisabled].bValue = FALSE;
  375. }
  376. else
  377. {
  378. pCommandArgs[eUserDisabled].bValue = TRUE;
  379. }
  380. pCommandArgs[eUserDisabled].bDefined = TRUE;
  381. // NTRAID#NTBUG9-707037-2002/09/24-ronmart-The following
  382. // is required to avoid an AV in FreeCmd which will
  383. // think this flag is a string (because that is how it
  384. // is defined in addtable.cpp) and therefore try to call
  385. // LocalFree on a NULL pointer.
  386. pCommandArgs[eUserDisabled].fType= ARG_TYPE_BOOL;
  387. }
  388. if (!pCommandArgs[eUserPwd].bDefined)
  389. {
  390. pCommandArgs[eUserPwd].bDefined = TRUE;
  391. // This must be allocated with LocalAlloc so that FreeCmd doesn't assert
  392. // Passwords in ARGRECORD should be in encrypted format.
  393. WCHAR szTemp[] = L"";
  394. hr = EncryptPasswordString(szTemp,&(pCommandArgs[eUserPwd].encryptedDataBlob));
  395. if(FAILED(hr))
  396. break;
  397. }
  398. // Always define Password Not Required to be false so that we unset the bit
  399. pCommandArgs[eUserPwdNotReqd].bDefined = TRUE;
  400. pCommandArgs[eUserPwdNotReqd].bValue = FALSE;
  401. }
  402. else if (0 == _wcsicmp(g_pszGroup, pszObjectType))
  403. {
  404. hr = DoGroupValidation(pCommandArgs);
  405. break;
  406. }
  407. } while (false);
  408. return hr;
  409. }
  410. //+--------------------------------------------------------------------------
  411. //
  412. // Function: DoQuotaValidation
  413. //
  414. // Synopsis: Validates input and fixes up the objectDN (via
  415. // GetQuotaContainerDN) to make sure DoAdd has a valid quota DN
  416. //
  417. // Arguments: [pCommandArgs - IN] : the command line argument structure
  418. // used to retrieve the values for each
  419. // switch
  420. // [pObjectEntry - IN] : pointer to the object table entry for
  421. // the object type that will be modified
  422. // [basePathsInfo - IN]: DSAdd's CDSCmdBasePathsInfo object
  423. // for getting the RootDSE and Schema
  424. // [credentialObject - IN]: DSAdd's creditials object used for
  425. // binding to other objects
  426. // [lpszPartitionDN - IN]: The -part DN
  427. // [pszNewQuotaDN - OUT]: Return the munged new quota dn
  428. //
  429. // Returns: HRESULT : S_OK if everything succeeded
  430. // E_UNEXPECTED in most failure cases
  431. // E_OUTOFMEMORY if a LocalAlloc fails
  432. // Anything else is a failure code from an ADSI call
  433. //
  434. // History: 12-Aug-2002 RonMart Created
  435. //
  436. //---------------------------------------------------------------------------
  437. HRESULT DoQuotaValidation(IN PARG_RECORD pCommandArgs,
  438. IN PDSOBJECTTABLEENTRY pObjectEntry,
  439. IN CDSCmdBasePathsInfo& basePathsInfo,
  440. IN CDSCmdCredentialObject& credentialObject,
  441. IN LPCWSTR lpszPartitionDN,
  442. OUT PWSTR* pszNewQuotaDN)
  443. {
  444. ENTER_FUNCTION_HR(MINIMAL_LOGGING, DoQuotaValidation, hr);
  445. LPWSTR lpszTrusteeDN = NULL;
  446. PWSTR pszQuotaDN = NULL;
  447. do // false loop
  448. {
  449. //
  450. // Verify parameters
  451. //
  452. if (!pCommandArgs || !pObjectEntry || !lpszPartitionDN ||
  453. !basePathsInfo.IsInitialized())
  454. {
  455. ASSERT(pCommandArgs);
  456. ASSERT(pObjectEntry);
  457. ASSERT(lpszPartitionDN);
  458. ASSERT(basePathsInfo.IsInitialized());
  459. hr = E_INVALIDARG;
  460. break;
  461. }
  462. // Convert pCommandArgs[eQuotaAcct] into a DN
  463. hr = ConvertTrusteeToDN(NULL,
  464. pCommandArgs[eQuotaAcct].strValue,
  465. &lpszTrusteeDN);
  466. if(FAILED(hr))
  467. {
  468. // 702224 - If the acct doesn't exist or has been deleted then
  469. // give the user a clue as to what went wrong. - ronmart
  470. hr = E_INVALIDARG;
  471. DisplayErrorMessage(g_pszDSCommandName, 0, hr, IDS_MSG_INVALID_ACCT_ERROR);
  472. break;
  473. }
  474. // If RDN not provided, then come up with a reasonable default
  475. // (NT4 name is the default for now)
  476. if (!pCommandArgs[eQuotaRDN].bDefined)
  477. {
  478. LPWSTR lpszNT4 = NULL;
  479. hr = ConvertTrusteeToNT4Name(NULL,
  480. pCommandArgs[eQuotaAcct].strValue, &lpszNT4);
  481. if(FAILED(hr))
  482. {
  483. hr = E_UNEXPECTED;
  484. break;
  485. }
  486. // strValue is null, so set it to the new NT4 name
  487. // The parser will free this memory
  488. pCommandArgs[eQuotaRDN].strValue = lpszNT4;
  489. // Mark as defined now that we've assigned it
  490. pCommandArgs[eQuotaRDN].bDefined = TRUE;
  491. }
  492. // Verify partition DN is actually a partition then
  493. // munge the partition and account name into objectDN.
  494. hr = GetQuotaContainerDN(basePathsInfo,
  495. credentialObject,
  496. lpszPartitionDN,
  497. &pszQuotaDN);
  498. if (FAILED(hr))
  499. {
  500. break;
  501. }
  502. CComBSTR bstrQuotaDN(pszQuotaDN);
  503. // See if this user has created a quota in this partition already
  504. bool bFound = false;
  505. CComBSTR sbstrSearchPath;
  506. basePathsInfo.ComposePathFromDN(bstrQuotaDN, sbstrSearchPath,
  507. DSCMD_LDAP_PROVIDER);
  508. hr = IsQuotaAcctPresent(lpszTrusteeDN, sbstrSearchPath,
  509. basePathsInfo, credentialObject, bFound);
  510. if (FAILED(hr))
  511. {
  512. DEBUG_OUTPUT(MINIMAL_LOGGING,
  513. L"IsQuotaAcctPresent failed [%s] hr = 0x%08x",
  514. bstrQuotaDN, hr);
  515. hr = E_UNEXPECTED;
  516. break;
  517. }
  518. if(bFound)
  519. {
  520. // TODO: Should spew a clear message to the user
  521. DEBUG_OUTPUT(MINIMAL_LOGGING,
  522. L"Quota already exists for [%s]", lpszTrusteeDN);
  523. hr = E_INVALIDARG;
  524. break;
  525. }
  526. // Add the resolved quota DN to pathcracker for merge with the RDN
  527. CPathCracker pathcracker;
  528. hr = pathcracker.Set( bstrQuotaDN, ADS_SETTYPE_DN );
  529. if (FAILED(hr))
  530. {
  531. DEBUG_OUTPUT(MINIMAL_LOGGING,
  532. L"pathcracker Set.failure: [%s] hr = 0x%08x",
  533. bstrQuotaDN, hr);
  534. hr = E_UNEXPECTED;
  535. break;
  536. }
  537. CComBSTR bstrRDN;
  538. hr = CreateQuotaName(basePathsInfo, credentialObject,
  539. pCommandArgs[eQuotaRDN].strValue, bstrRDN);
  540. if(FAILED(hr))
  541. {
  542. break;
  543. }
  544. hr = pathcracker.AddLeafElement( bstrRDN );
  545. if (FAILED(hr))
  546. {
  547. DEBUG_OUTPUT(MINIMAL_LOGGING,
  548. L"pathcracker.AddLeafElement failure: [%s] hr = 0x%08x",
  549. bstrRDN, hr);
  550. hr = E_UNEXPECTED;
  551. break;
  552. }
  553. // Get the new resolved DN in the format of <RDN>,CN=NTDS Quotas,<Partition DN>
  554. CComBSTR bstrNewDN;
  555. hr = pathcracker.Retrieve( ADS_FORMAT_X500_DN, &bstrNewDN );
  556. if (FAILED(hr))
  557. {
  558. DEBUG_OUTPUT(MINIMAL_LOGGING,
  559. L"pathcracker.Retrieve failure: hr = 0x%08x",
  560. hr);
  561. hr = E_UNEXPECTED;
  562. break;
  563. }
  564. // Alloc the return string to hold the munged name
  565. *pszNewQuotaDN = (PWSTR) LocalAlloc(LPTR, SysStringByteLen(bstrNewDN)
  566. + sizeof(WCHAR));
  567. if(NULL == *pszNewQuotaDN)
  568. {
  569. hr = E_OUTOFMEMORY;
  570. break;
  571. }
  572. // Copy the resolved DN into the new objectDN string
  573. lstrcpy(*pszNewQuotaDN, bstrNewDN);
  574. } while(false);
  575. if(pszQuotaDN)
  576. LocalFree(pszQuotaDN);
  577. if(lpszTrusteeDN)
  578. LocalFree(lpszTrusteeDN);
  579. return hr;
  580. }
  581. //+--------------------------------------------------------------------------
  582. //
  583. // Function: DoAdd
  584. //
  585. // Synopsis: Finds the appropriate object in the object table and fills in
  586. // the attribute values and then creates the object
  587. //
  588. // Arguments: [pCommandArgs - IN] : the command line argument structure used
  589. // to retrieve the values for each switch
  590. // [pObjectEntry - IN] : pointer to the object table entry for the
  591. // object type that will be modified
  592. //
  593. // Returns: HRESULT : S_OK if everything succeeded
  594. // E_INVALIDARG if the object entry wasn't found
  595. // Anything else is a failure code from an ADSI call
  596. //
  597. // History: 22-Sep-2000 JeffJon Created
  598. //
  599. //---------------------------------------------------------------------------
  600. HRESULT DoAdd(PARG_RECORD pCommandArgs, PDSOBJECTTABLEENTRY pObjectEntry,
  601. DSADD_COMMAND_ENUM eObjectDNorName)
  602. {
  603. ENTER_FUNCTION_HR(MINIMAL_LOGGING, DoAdd, hr);
  604. PADS_ATTR_INFO pCreateAttrs = NULL;
  605. PADS_ATTR_INFO pPostCreateAttrs = NULL;
  606. do // false loop
  607. {
  608. if (!pCommandArgs || !pObjectEntry)
  609. {
  610. ASSERT(pCommandArgs && pObjectEntry);
  611. hr = E_INVALIDARG;
  612. break;
  613. }
  614. CDSCmdCredentialObject credentialObject;
  615. if (pCommandArgs[eCommUserName].bDefined)
  616. {
  617. credentialObject.SetUsername(pCommandArgs[eCommUserName].strValue);
  618. credentialObject.SetUsingCredentials(true);
  619. }
  620. if (pCommandArgs[eCommPassword].bDefined)
  621. {
  622. credentialObject.SetEncryptedPassword(&pCommandArgs[eCommPassword].encryptedDataBlob);
  623. credentialObject.SetUsingCredentials(true);
  624. }
  625. //
  626. // Initialize the base paths info from the command line args
  627. //
  628. CDSCmdBasePathsInfo basePathsInfo;
  629. if (pCommandArgs[eCommServer].bDefined)
  630. {
  631. hr = basePathsInfo.InitializeFromName(credentialObject,
  632. pCommandArgs[eCommServer].strValue,
  633. true);
  634. }
  635. else if (pCommandArgs[eCommDomain].bDefined)
  636. {
  637. hr = basePathsInfo.InitializeFromName(credentialObject,
  638. pCommandArgs[eCommDomain].strValue,
  639. false);
  640. }
  641. else
  642. {
  643. hr = basePathsInfo.InitializeFromName(credentialObject, NULL, false);
  644. }
  645. if (FAILED(hr))
  646. {
  647. //
  648. // Display error message and return
  649. //
  650. DisplayErrorMessage(g_pszDSCommandName, NULL, hr);
  651. break;
  652. }
  653. //
  654. // The DNs or Names should be given as a \0 separated list
  655. // So parse it and loop through each object
  656. //
  657. UINT nStrings = 0;
  658. PWSTR* ppszArray = NULL;
  659. ParseNullSeparatedString(pCommandArgs[eObjectDNorName].strValue,
  660. &ppszArray,
  661. &nStrings);
  662. if (nStrings < 1 ||
  663. !ppszArray)
  664. {
  665. //
  666. // Display the usage text and then fail
  667. //
  668. hr = E_INVALIDARG;
  669. DisplayErrorMessage(g_pszDSCommandName, 0, hr);
  670. break;
  671. }
  672. // If quota object then look at first DN and munge it
  673. if(0 == lstrcmpi(pObjectEntry->pszCommandLineObjectType, g_pszQuota))
  674. {
  675. // Multiple DN's not supported for dsadd quota at this time, so err
  676. if(nStrings > 1)
  677. {
  678. CComBSTR sbstrErrMsg;
  679. sbstrErrMsg.LoadString(::GetModuleHandle(NULL),
  680. IDS_MSG_MULTIPLE_PARTITIONS_ERROR);
  681. hr = E_INVALIDARG;
  682. // Display an error
  683. DisplayErrorMessage(g_pszDSCommandName,
  684. NULL,
  685. hr,
  686. sbstrErrMsg);
  687. break;
  688. }
  689. PWSTR pszNewDN = NULL;
  690. hr = DoQuotaValidation(pCommandArgs, pObjectEntry, basePathsInfo,
  691. credentialObject, ppszArray[0], &pszNewDN);
  692. if(FAILED(hr))
  693. break;
  694. // Replace the first element in the array with the new DN
  695. ppszArray[0] = pszNewDN;
  696. }
  697. // Make sure all the DNs actually have DN syntax
  698. bool bContinue = pCommandArgs[eCommContinue].bDefined &&
  699. pCommandArgs[eCommContinue].bValue;
  700. UINT nValidDNs = ValidateDNSyntax(ppszArray, nStrings);
  701. if (nValidDNs < nStrings && !bContinue)
  702. {
  703. hr = E_ADS_BAD_PATHNAME;
  704. DisplayErrorMessage(g_pszDSCommandName, 0, hr);
  705. break;
  706. }
  707. DWORD dwCount = pObjectEntry->dwAttributeCount;
  708. //
  709. // Allocate the creation ADS_ATTR_INFO
  710. // Add an extra attribute for the object class
  711. //
  712. pCreateAttrs = new ADS_ATTR_INFO[dwCount + 1];
  713. if (!pCreateAttrs)
  714. {
  715. //
  716. // Display error message and return
  717. //
  718. DisplayErrorMessage(g_pszDSCommandName, NULL, E_OUTOFMEMORY);
  719. hr = E_OUTOFMEMORY;
  720. break;
  721. }
  722. //
  723. // Allocate the post create ADS_ATTR_INFO
  724. //
  725. pPostCreateAttrs = new ADS_ATTR_INFO[dwCount];
  726. if (!pPostCreateAttrs)
  727. {
  728. //
  729. // Display error message and return
  730. //
  731. DisplayErrorMessage(g_pszDSCommandName, NULL, E_OUTOFMEMORY);
  732. hr = E_OUTOFMEMORY;
  733. break;
  734. }
  735. //
  736. // Loop through each of the objects
  737. //
  738. for (UINT nNameIdx = 0; nNameIdx < nStrings; nNameIdx++)
  739. {
  740. do // false loop
  741. {
  742. //
  743. // Get the objects DN
  744. //
  745. PWSTR pszObjectDN = ppszArray[nNameIdx];
  746. if (!pszObjectDN)
  747. {
  748. //
  749. // Display an error message and then fail
  750. //
  751. hr = E_INVALIDARG;
  752. DisplayErrorMessage(g_pszDSCommandName, 0, hr);
  753. break; // this breaks out of the false loop
  754. }
  755. DEBUG_OUTPUT(MINIMAL_LOGGING, L"Object DN = %s", pszObjectDN);
  756. CComBSTR sbstrObjectPath;
  757. basePathsInfo.ComposePathFromDN(pszObjectDN, sbstrObjectPath);
  758. //
  759. // Now that we have the table entry loop through the other command line
  760. // args and see which ones can be applied
  761. //
  762. DWORD dwCreateAttributeCount = 0;
  763. DEBUG_OUTPUT(MINIMAL_LOGGING, L"Starting processing DS_ATTRIBUTE_ONCREATE attributes");
  764. for (DWORD dwIdx = 0; dwIdx < dwCount; dwIdx++)
  765. {
  766. ASSERT(pObjectEntry->pAttributeTable[dwIdx]->pEvalFunc);
  767. UINT nAttributeIdx = pObjectEntry->pAttributeTable[dwIdx]->nAttributeID;
  768. if (pCommandArgs[nAttributeIdx].bDefined ||
  769. pObjectEntry->pAttributeTable[dwIdx]->dwFlags & DS_ATTRIBUTE_REQUIRED)
  770. {
  771. //
  772. // Call the evaluation function to get the appropriate ADS_ATTR_INFO set
  773. // if this attribute entry has the DS_ATTRIBUTE_ONCREATE flag set
  774. //
  775. if ((pObjectEntry->pAttributeTable[dwIdx]->dwFlags & DS_ATTRIBUTE_ONCREATE) &&
  776. (!(pObjectEntry->pAttributeTable[dwIdx]->dwFlags & DS_ATTRIBUTE_DIRTY) ||
  777. pObjectEntry->pAttributeTable[dwIdx]->dwFlags & DS_ATTRIBUTE_NOT_REUSABLE))
  778. {
  779. PADS_ATTR_INFO pNewAttr = NULL;
  780. hr = pObjectEntry->pAttributeTable[dwIdx]->pEvalFunc(pszObjectDN,
  781. basePathsInfo,
  782. credentialObject,
  783. pObjectEntry,
  784. pCommandArgs[nAttributeIdx],
  785. dwIdx,
  786. &pNewAttr);
  787. DEBUG_OUTPUT(MINIMAL_LOGGING, L"pEvalFunc returned hr = 0x%x", hr);
  788. if (SUCCEEDED(hr) && hr != S_FALSE)
  789. {
  790. if (pNewAttr)
  791. {
  792. pCreateAttrs[dwCreateAttributeCount] = *pNewAttr;
  793. dwCreateAttributeCount++;
  794. }
  795. }
  796. else
  797. {
  798. //
  799. // Don't show an error if the eval function returned S_FALSE
  800. //
  801. if (hr != S_FALSE)
  802. {
  803. //
  804. // Display an error
  805. //
  806. DisplayErrorMessage(g_pszDSCommandName,
  807. pszObjectDN,
  808. hr);
  809. }
  810. if (hr == S_FALSE)
  811. {
  812. //
  813. // Return a generic error code so that we don't print the success message
  814. //
  815. hr = E_FAIL;
  816. }
  817. break; // this breaks out of the attribute loop
  818. }
  819. }
  820. }
  821. } // Attribute for loop
  822. //
  823. // The IDispatch interface of the new object
  824. //
  825. CComPtr<IDispatch> spDispatch;
  826. if (SUCCEEDED(hr))
  827. {
  828. //
  829. // Now that we have the attributes ready, lets create the object
  830. //
  831. //
  832. // Get the parent path of the new object
  833. //
  834. CComBSTR sbstrParentDN;
  835. hr = CPathCracker::GetParentDN(pszObjectDN, sbstrParentDN);
  836. if (FAILED(hr))
  837. {
  838. //
  839. // Display error message and return
  840. //
  841. DisplayErrorMessage(g_pszDSCommandName,
  842. pszObjectDN,
  843. hr);
  844. break; // this breaks out of the false loop
  845. }
  846. CComBSTR sbstrParentPath;
  847. basePathsInfo.ComposePathFromDN(sbstrParentDN, sbstrParentPath);
  848. //
  849. // Open the parent of the new object
  850. //
  851. CComPtr<IDirectoryObject> spDirObject;
  852. hr = DSCmdOpenObject(credentialObject,
  853. sbstrParentPath,
  854. IID_IDirectoryObject,
  855. (void**)&spDirObject,
  856. true);
  857. if (FAILED(hr))
  858. {
  859. //
  860. // Display error message and return
  861. //
  862. DisplayErrorMessage(g_pszDSCommandName,
  863. pszObjectDN,
  864. hr);
  865. break; // this breaks out of the false loop
  866. }
  867. //
  868. // Get the name of the new object
  869. //
  870. CComBSTR sbstrObjectName;
  871. hr = CPathCracker::GetObjectRDNFromDN(pszObjectDN, sbstrObjectName);
  872. if (FAILED(hr))
  873. {
  874. //
  875. // Display error message and return
  876. //
  877. DisplayErrorMessage(g_pszDSCommandName,
  878. pszObjectDN,
  879. hr);
  880. break; // this breaks out of the false loop
  881. }
  882. //
  883. // Add the object class to the attributes before creating the object
  884. //
  885. PADSVALUE pADsObjectClassValue = new ADSVALUE;
  886. if (!pADsObjectClassValue)
  887. {
  888. hr = E_OUTOFMEMORY;
  889. //
  890. // Display error message and return
  891. //
  892. DisplayErrorMessage(g_pszDSCommandName,
  893. pszObjectDN,
  894. hr);
  895. break; // this breaks out of the false loop
  896. }
  897. pADsObjectClassValue->dwType = ADSTYPE_CASE_IGNORE_STRING;
  898. pADsObjectClassValue->CaseIgnoreString = (PWSTR)pObjectEntry->pszObjectClass;
  899. DEBUG_OUTPUT(MINIMAL_LOGGING, L"New object name = %s", pObjectEntry->pszObjectClass);
  900. ADS_ATTR_INFO adsClassAttrInfo =
  901. {
  902. L"objectClass",
  903. ADS_ATTR_UPDATE,
  904. ADSTYPE_CASE_IGNORE_STRING,
  905. pADsObjectClassValue,
  906. 1
  907. };
  908. pCreateAttrs[dwCreateAttributeCount] = adsClassAttrInfo;
  909. dwCreateAttributeCount++;
  910. #ifdef DBG
  911. DEBUG_OUTPUT(FULL_LOGGING, L"Creation Attributes:");
  912. SpewAttrs(pCreateAttrs, dwCreateAttributeCount);
  913. #endif
  914. hr = spDirObject->CreateDSObject(sbstrObjectName,
  915. pCreateAttrs,
  916. dwCreateAttributeCount,
  917. &spDispatch);
  918. DEBUG_OUTPUT(MINIMAL_LOGGING, L"CreateDSObject returned hr = 0x%x", hr);
  919. if (FAILED(hr))
  920. {
  921. CComBSTR sbstrDuplicateErrorMessage;
  922. if (ERROR_OBJECT_ALREADY_EXISTS == HRESULT_CODE(hr))
  923. {
  924. if (_wcsicmp(pObjectEntry->pszObjectClass, g_pszComputer) == 0)
  925. {
  926. sbstrDuplicateErrorMessage.LoadString(::GetModuleHandle(NULL),
  927. IDS_MSG_DUPLICATE_NAME_ERROR_COMPUTER);
  928. }
  929. if (_wcsicmp(pObjectEntry->pszObjectClass, g_pszGroup) == 0)
  930. {
  931. sbstrDuplicateErrorMessage.LoadString(::GetModuleHandle(NULL),
  932. IDS_MSG_DUPLICATE_NAME_ERROR_GROUP);
  933. }
  934. }
  935. //
  936. // Display error message and return
  937. //
  938. DisplayErrorMessage(g_pszDSCommandName,
  939. pszObjectDN,
  940. hr,
  941. sbstrDuplicateErrorMessage);
  942. if (pADsObjectClassValue)
  943. {
  944. delete pADsObjectClassValue;
  945. pADsObjectClassValue = NULL;
  946. }
  947. break; // this breaks out of the false loop
  948. }
  949. if (pADsObjectClassValue)
  950. {
  951. delete pADsObjectClassValue;
  952. pADsObjectClassValue = NULL;
  953. }
  954. }
  955. if (SUCCEEDED(hr))
  956. {
  957. //
  958. // Now that we have created the object, set the attributes that are
  959. // marked for Post Create
  960. //
  961. DWORD dwPostCreateAttributeCount = 0;
  962. DEBUG_OUTPUT(MINIMAL_LOGGING, L"Starting processing DS_ATTRIBUTE_POSTCREATE attributes");
  963. for (DWORD dwIdx = 0; dwIdx < dwCount; dwIdx++)
  964. {
  965. ASSERT(pObjectEntry->pAttributeTable[dwIdx]->pEvalFunc);
  966. UINT nAttributeIdx = pObjectEntry->pAttributeTable[dwIdx]->nAttributeID;
  967. if (pCommandArgs[nAttributeIdx].bDefined ||
  968. pObjectEntry->pAttributeTable[dwIdx]->dwFlags & DS_ATTRIBUTE_REQUIRED)
  969. {
  970. //
  971. // Call the evaluation function to get the appropriate ADS_ATTR_INFO set
  972. // if this attribute entry has the DS_ATTRIBUTE_POSTCREATE flag set
  973. //
  974. if ((pObjectEntry->pAttributeTable[dwIdx]->dwFlags & DS_ATTRIBUTE_POSTCREATE) &&
  975. (!(pObjectEntry->pAttributeTable[dwIdx]->dwFlags & DS_ATTRIBUTE_DIRTY) ||
  976. pObjectEntry->pAttributeTable[dwIdx]->dwFlags & DS_ATTRIBUTE_NOT_REUSABLE))
  977. {
  978. PADS_ATTR_INFO pNewAttr = NULL;
  979. hr = pObjectEntry->pAttributeTable[dwIdx]->pEvalFunc(pszObjectDN,
  980. basePathsInfo,
  981. credentialObject,
  982. pObjectEntry,
  983. pCommandArgs[nAttributeIdx],
  984. dwIdx,
  985. &pNewAttr);
  986. DEBUG_OUTPUT(MINIMAL_LOGGING, L"pEvalFunc returned hr = 0x%x", hr);
  987. if (SUCCEEDED(hr) && hr != S_FALSE)
  988. {
  989. if (pNewAttr)
  990. {
  991. pPostCreateAttrs[dwPostCreateAttributeCount] = *pNewAttr;
  992. dwPostCreateAttributeCount++;
  993. }
  994. }
  995. else
  996. {
  997. //
  998. // Don't show an error if the eval function returned S_FALSE
  999. //
  1000. if (hr != S_FALSE)
  1001. {
  1002. //
  1003. // Load the post create message
  1004. //
  1005. CComBSTR sbstrPostCreateMessage;
  1006. sbstrPostCreateMessage.LoadString(::GetModuleHandle(NULL),
  1007. IDS_POST_CREATE_FAILURE);
  1008. //
  1009. // Display an error
  1010. //
  1011. DisplayErrorMessage(g_pszDSCommandName,
  1012. pszObjectDN,
  1013. hr,
  1014. sbstrPostCreateMessage);
  1015. }
  1016. if (hr == S_FALSE)
  1017. {
  1018. //
  1019. // Return a generic error code so that we don't print the success message
  1020. //
  1021. hr = E_FAIL;
  1022. }
  1023. break; // attribute table loop
  1024. }
  1025. }
  1026. }
  1027. } // Attribute table for loop
  1028. //
  1029. // Now set the attributes if necessary
  1030. //
  1031. if (SUCCEEDED(hr) && dwPostCreateAttributeCount > 0)
  1032. {
  1033. //
  1034. // Now that we have the attributes ready, lets set them in the DS
  1035. //
  1036. CComPtr<IDirectoryObject> spNewDirObject;
  1037. hr = spDispatch->QueryInterface(IID_IDirectoryObject, (void**)&spNewDirObject);
  1038. if (FAILED(hr))
  1039. {
  1040. //
  1041. // Display error message and return
  1042. //
  1043. DEBUG_OUTPUT(MINIMAL_LOGGING, L"QI for IDirectoryObject failed: hr = 0x%x", hr);
  1044. DisplayErrorMessage(g_pszDSCommandName,
  1045. pszObjectDN,
  1046. hr);
  1047. break; // this breaks out of the false loop
  1048. }
  1049. DEBUG_OUTPUT(MINIMAL_LOGGING, L"Setting %d attributes", dwPostCreateAttributeCount);
  1050. #ifdef DBG
  1051. DEBUG_OUTPUT(FULL_LOGGING, L"Post Creation Attributes:");
  1052. SpewAttrs(pPostCreateAttrs, dwPostCreateAttributeCount);
  1053. #endif
  1054. DWORD dwAttrsModified = 0;
  1055. hr = spNewDirObject->SetObjectAttributes(pPostCreateAttrs,
  1056. dwPostCreateAttributeCount,
  1057. &dwAttrsModified);
  1058. DEBUG_OUTPUT(MINIMAL_LOGGING, L"SetObjectAttributes returned hr = 0x%x", hr);
  1059. if (FAILED(hr))
  1060. {
  1061. //
  1062. // Display error message and return
  1063. //
  1064. DisplayErrorMessage(g_pszDSCommandName,
  1065. pszObjectDN,
  1066. hr);
  1067. break; // this breaks out of the false loop
  1068. }
  1069. }
  1070. }
  1071. } while (false);
  1072. //
  1073. // Loop through the attributes again, clearing any values for
  1074. // attribute entries that are marked DS_ATTRIBUTE_NOT_REUSABLE
  1075. //
  1076. DEBUG_OUTPUT(LEVEL5_LOGGING, L"Cleaning up memory and flags for object %d", nNameIdx);
  1077. for (DWORD dwIdx = 0; dwIdx < dwCount; dwIdx++)
  1078. {
  1079. if (pObjectEntry->pAttributeTable[dwIdx]->dwFlags & DS_ATTRIBUTE_NOT_REUSABLE)
  1080. {
  1081. if (pObjectEntry->pAttributeTable[dwIdx]->pAttrDesc &&
  1082. ((pObjectEntry->pAttributeTable[dwIdx]->pAttrDesc->dwFlags & DS_ATTRIBUTE_READ) ||
  1083. (pObjectEntry->pAttributeTable[dwIdx]->pAttrDesc->dwFlags & DS_ATTRIBUTE_DIRTY)))
  1084. {
  1085. //
  1086. // Cleanup the memory associated with the value
  1087. //
  1088. if (pObjectEntry->pAttributeTable[dwIdx]->pAttrDesc->adsAttrInfo.pADsValues)
  1089. {
  1090. delete[] pObjectEntry->pAttributeTable[dwIdx]->pAttrDesc->adsAttrInfo.pADsValues;
  1091. pObjectEntry->pAttributeTable[dwIdx]->pAttrDesc->adsAttrInfo.pADsValues = NULL;
  1092. }
  1093. //
  1094. // Cleanup the flags so that the attribute will be read for the next object
  1095. //
  1096. pObjectEntry->pAttributeTable[dwIdx]->pAttrDesc->dwFlags &= ~(DS_ATTRIBUTE_READ);
  1097. pObjectEntry->pAttributeTable[dwIdx]->pAttrDesc->dwFlags &= ~(DS_ATTRIBUTE_DIRTY);
  1098. DEBUG_OUTPUT(LEVEL5_LOGGING,
  1099. L"Flags for attribute %s = %d",
  1100. pObjectEntry->pAttributeTable[dwIdx]->pszName,
  1101. pObjectEntry->pAttributeTable[dwIdx]->pAttrDesc->dwFlags);
  1102. }
  1103. }
  1104. }
  1105. //
  1106. // Break if the continue flag is not specified
  1107. //
  1108. if (FAILED(hr) && !pCommandArgs[eCommContinue].bDefined)
  1109. {
  1110. break; // this breaks out of the name for loop
  1111. }
  1112. //
  1113. // Display the success message
  1114. //
  1115. if (SUCCEEDED(hr) && !pCommandArgs[eCommQuiet].bDefined)
  1116. {
  1117. DisplaySuccessMessage(g_pszDSCommandName,
  1118. pCommandArgs[eObjectDNorName].strValue);
  1119. }
  1120. } // Names for loop
  1121. } while (false);
  1122. //
  1123. // Cleanup
  1124. //
  1125. if (pCreateAttrs)
  1126. {
  1127. delete[] pCreateAttrs;
  1128. pCreateAttrs = NULL;
  1129. }
  1130. if (pPostCreateAttrs)
  1131. {
  1132. delete[] pPostCreateAttrs;
  1133. pPostCreateAttrs = NULL;
  1134. }
  1135. return hr;
  1136. }
  1137. //+--------------------------------------------------------------------------
  1138. //
  1139. // Function: GetObjectDNIndex
  1140. //
  1141. // Synopsis: Performs a lookup to determine which enum value is holding
  1142. // the objectDN. This was necessary for -part support for
  1143. // quotas.
  1144. //
  1145. // Arguments: [pObjectEntry IN] : ObjectEntry from the parser
  1146. // [nCommandEnum OUT] : Enum value of the object, else -1
  1147. //
  1148. // Returns: HRESULT : S_OK if everything succeeded
  1149. // E_INVALIDARG
  1150. //
  1151. // Remarks:
  1152. //
  1153. //
  1154. // History: 19-Aug-2002 ronmart Created
  1155. //
  1156. //---------------------------------------------------------------------------
  1157. HRESULT GetObjectDNIndex(PDSOBJECTTABLEENTRY pObjectEntry, int& nCommandEnum)
  1158. {
  1159. HRESULT hr = S_OK;
  1160. do // false loop
  1161. {
  1162. // Init nCommandEnum to an error value by default
  1163. nCommandEnum = -1;
  1164. if(NULL == pObjectEntry)
  1165. {
  1166. hr = E_INVALIDARG;
  1167. break;
  1168. }
  1169. // Get a pointer to the object class for readability
  1170. PCWSTR pszCommandLineObjectType = pObjectEntry->pszCommandLineObjectType;
  1171. // Now compare each object type against the specified
  1172. // object class to see what the enum index is
  1173. if(0 == lstrcmpi(pszCommandLineObjectType, g_pszUser))
  1174. {
  1175. nCommandEnum = eUserObjectDNorName;
  1176. break;
  1177. }
  1178. else if(0 == lstrcmpi(pszCommandLineObjectType, g_pszComputer))
  1179. {
  1180. nCommandEnum = eComputerObjectDNorName;
  1181. break;
  1182. }
  1183. else if(0 == lstrcmpi(pszCommandLineObjectType, g_pszGroup))
  1184. {
  1185. nCommandEnum = eGroupObjectDNorName;
  1186. break;
  1187. }
  1188. else if(0 == lstrcmpi(pszCommandLineObjectType, g_pszOU))
  1189. {
  1190. nCommandEnum = eOUObjectDNorName;
  1191. break;
  1192. }
  1193. else if(0 == lstrcmpi(pszCommandLineObjectType, g_pszQuota))
  1194. {
  1195. nCommandEnum = eQuotaPart;
  1196. break;
  1197. }
  1198. else if(0 == lstrcmpi(pszCommandLineObjectType, g_pszContact))
  1199. {
  1200. nCommandEnum = eContactObjectDNorName;
  1201. break;
  1202. }
  1203. else
  1204. {
  1205. hr = E_FAIL;
  1206. // If you get here, then you've added a new object
  1207. // to cstrings.* without adding it to the
  1208. // if statement. This should only happen
  1209. // when testing a new object for the first time
  1210. // without a corresponding check above.
  1211. ASSERT(FALSE);
  1212. break;
  1213. }
  1214. } while(false);
  1215. return hr;
  1216. }
  1217. //+--------------------------------------------------------------------------
  1218. //
  1219. // Function: IsQuotaAcctPresent
  1220. //
  1221. // Synopsis: Does a search from the passed in path looking for quotas
  1222. // on the given trustee and returns the result in bFound
  1223. //
  1224. // Arguments: [lpszTrusteeDN IN] : DN of the trustee to search the
  1225. // partition for (using sid string)
  1226. // [pszSearchRootPath IN] : the path to the root of the search
  1227. // [basePathsInfo - IN] : ldap settings
  1228. // [refCredObject IN] : reference to the credential object
  1229. // [bFound OUT] : Search result (true if found)
  1230. //
  1231. // Returns: HRESULT : S_OK if everything succeeded
  1232. // E_INVALIDARG
  1233. // Anything else is a failure code from an ADSI call
  1234. //
  1235. // Remarks:
  1236. //
  1237. //
  1238. // History: 19-Aug-2002 ronmart Created
  1239. //
  1240. //---------------------------------------------------------------------------
  1241. HRESULT IsQuotaAcctPresent( IN LPWSTR lpszTrusteeDN,
  1242. IN PCWSTR pszSearchRootPath,
  1243. IN CDSCmdBasePathsInfo& basePathsInfo,
  1244. IN const CDSCmdCredentialObject& refCredObject,
  1245. OUT bool& bFound)
  1246. {
  1247. ENTER_FUNCTION_HR(LEVEL3_LOGGING, IsQuotaAcctPresent, hr);
  1248. PSID pSid = NULL;
  1249. LPWSTR pszSid = NULL;
  1250. if(!lpszTrusteeDN || !pszSearchRootPath)
  1251. {
  1252. hr = E_INVALIDARG;
  1253. return hr;
  1254. }
  1255. do // false loop
  1256. {
  1257. //
  1258. // Verify parameters
  1259. //
  1260. if (!pszSearchRootPath || !pszSearchRootPath)
  1261. {
  1262. hr = E_INVALIDARG;
  1263. break;
  1264. }
  1265. // Get the SID
  1266. hr = GetDNSid(lpszTrusteeDN,
  1267. basePathsInfo,
  1268. refCredObject,
  1269. &pSid);
  1270. if(FAILED(hr))
  1271. {
  1272. hr = E_FAIL;
  1273. break;
  1274. }
  1275. // Convert the sid to a string
  1276. if(!ConvertSidToStringSid(pSid, &pszSid))
  1277. {
  1278. hr = E_FAIL;
  1279. break;
  1280. }
  1281. //
  1282. // Search
  1283. //
  1284. CDSSearch searchObj;
  1285. hr = searchObj.Init(pszSearchRootPath,
  1286. refCredObject);
  1287. if(FAILED(hr))
  1288. {
  1289. break;
  1290. }
  1291. //
  1292. // Prepare the search object
  1293. //
  1294. PWSTR ppszAttrs[] = { L"distinguishedName" };
  1295. DWORD dwAttrCount = sizeof(ppszAttrs)/sizeof(PWSTR);
  1296. CComBSTR bstrFilter = L"(&(objectCategory=msDS-QuotaControl)(|(msDS-QuotaTrustee=";
  1297. bstrFilter += pszSid;
  1298. bstrFilter += ")))";
  1299. searchObj.SetFilterString(bstrFilter);
  1300. searchObj.SetSearchScope(ADS_SCOPE_SUBTREE);
  1301. searchObj.SetAttributeList(ppszAttrs, dwAttrCount);
  1302. hr = searchObj.DoQuery();
  1303. if (FAILED(hr))
  1304. {
  1305. DEBUG_OUTPUT(LEVEL3_LOGGING,
  1306. L"Failed to search for users: hr = 0x%x",
  1307. hr);
  1308. break;
  1309. }
  1310. // Get the first row (will will return S_OK even if no results returned)
  1311. hr = searchObj.GetNextRow();
  1312. if (FAILED(hr))
  1313. {
  1314. bFound = false;
  1315. break;
  1316. }
  1317. // If rows then it exists, else
  1318. // not found
  1319. bFound = (hr != S_ADS_NOMORE_ROWS);
  1320. } while (false);
  1321. if(pSid)
  1322. LocalFree(pSid);
  1323. if(pszSid)
  1324. LocalFree(pszSid);
  1325. return hr;
  1326. }
  1327. //+--------------------------------------------------------------------------
  1328. //
  1329. // Function: CreateQuotaName
  1330. //
  1331. // Synopsis: Creates a RDN value using the quota control naming context
  1332. //
  1333. // Arguments: [basePathsInfo - IN] :
  1334. // [credentialObject - IN] :
  1335. // [lpszRDN - IN] : The name of the quota object
  1336. // [bstrRDN - OUT] : If successful a RDN to use
  1337. //
  1338. // Returns: HRESULT : S_OK if everything succeeded
  1339. // E_INVALIDARG if the object entry wasn't found
  1340. // Anything else is a failure code from an ADSI call
  1341. //
  1342. // History: 22-Aug-2002 ronmart Created
  1343. //
  1344. //---------------------------------------------------------------------------
  1345. HRESULT CreateQuotaName(IN CDSCmdBasePathsInfo& basePathsInfo,
  1346. IN CDSCmdCredentialObject& credentialObject,
  1347. IN LPCWSTR lpszRDN,
  1348. OUT CComBSTR& bstrRDN)
  1349. {
  1350. ENTER_FUNCTION_HR(MINIMAL_LOGGING, CreateQuotaName, hr);
  1351. do // false loop
  1352. {
  1353. if (!basePathsInfo.IsInitialized(), !lpszRDN)
  1354. {
  1355. hr = E_INVALIDARG;
  1356. break;
  1357. }
  1358. // Get the abstract schema path from the source domain
  1359. CComBSTR bstrSchemaPath = basePathsInfo.GetAbstractSchemaPath();
  1360. bstrSchemaPath += L"/msDS-QuotaControl";
  1361. // Bind to the quota control
  1362. CComPtr<IADsClass> spIADsItem;
  1363. hr = DSCmdOpenObject(credentialObject,
  1364. bstrSchemaPath,
  1365. IID_IADsClass,
  1366. (void**)&spIADsItem,
  1367. false);
  1368. if (FAILED(hr) || (spIADsItem.p == 0))
  1369. {
  1370. ASSERT( !!spIADsItem );
  1371. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1372. L"DsCmdOpenObject failure - couldn't bind to msDS-QuotaControl: 0x%08x",
  1373. hr);
  1374. break;
  1375. }
  1376. // Get the naming properties of the quota control (usually cn)
  1377. CComVariant varNamingProperties;
  1378. hr = spIADsItem->get_NamingProperties(&varNamingProperties);
  1379. if (FAILED(hr) || (V_VT(&varNamingProperties) != VT_BSTR ))
  1380. {
  1381. DEBUG_OUTPUT(MINIMAL_LOGGING,
  1382. L"get_NamingProperties failure: hr = 0x%08x",
  1383. hr);
  1384. hr = E_UNEXPECTED;
  1385. break;
  1386. }
  1387. // Build the <naming property>=<rdn> string
  1388. bstrRDN = V_BSTR(&varNamingProperties);
  1389. bstrRDN += L"=";
  1390. bstrRDN += lpszRDN;
  1391. }while(false);
  1392. return hr;
  1393. }