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.

790 lines
26 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1999-2001 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // CClusSvcAccountConfig.cpp
  7. //
  8. // Description:
  9. // Contains the definition of the CClusSvcAccountConfig class.
  10. //
  11. // Maintained By:
  12. // David Potter (DavidP) 30-MAR-2001
  13. // Vij Vasu (Vvasu) 08-MAR-2000
  14. //
  15. //////////////////////////////////////////////////////////////////////////////
  16. //////////////////////////////////////////////////////////////////////////////
  17. // Include Files
  18. //////////////////////////////////////////////////////////////////////////////
  19. // The precompiled header.
  20. #include "Pch.h"
  21. // The header for this file
  22. #include "CClusSvcAccountConfig.h"
  23. // For the CBaseClusterAddNode class.
  24. #include "CBaseClusterAddNode.h"
  25. // For the net local group functions.
  26. #include <lmaccess.h>
  27. // For NERR_Success
  28. #include <lmerr.h>
  29. //////////////////////////////////////////////////////////////////////////////
  30. // Global Variables
  31. //////////////////////////////////////////////////////////////////////////////
  32. // Array of the names of rights to be granted to the cluster service account.
  33. static const WCHAR * const gs_rgpcszRightsArray[] = {
  34. SE_SERVICE_LOGON_NAME
  35. , SE_BACKUP_NAME
  36. , SE_RESTORE_NAME
  37. , SE_INCREASE_QUOTA_NAME
  38. , SE_INC_BASE_PRIORITY_NAME
  39. , SE_TCB_NAME
  40. };
  41. const UINT gc_uiRightsArraySize = sizeof( gs_rgpcszRightsArray ) / sizeof( gs_rgpcszRightsArray[0] );
  42. //////////////////////////////////////////////////////////////////////////////
  43. //++
  44. //
  45. // CClusSvcAccountConfig::CClusSvcAccountConfig()
  46. //
  47. // Description:
  48. // Constructor of the CClusSvcAccountConfig class
  49. //
  50. // Arguments:
  51. // pbcanParentActionIn
  52. // Pointer to the base cluster action of which this action is a part.
  53. //
  54. // Return Value:
  55. // None.
  56. //
  57. // Exceptions Thrown:
  58. // CRuntimeError
  59. // If any of the APIs fail.
  60. //
  61. // Any exceptions thrown by underlying functions
  62. //
  63. //--
  64. //////////////////////////////////////////////////////////////////////////////
  65. CClusSvcAccountConfig::CClusSvcAccountConfig(
  66. CBaseClusterAddNode * pbcanParentActionIn
  67. )
  68. : m_pbcanParentAction( pbcanParentActionIn )
  69. , m_fWasAreadyInGroup( true )
  70. , m_fRightsGrantSuccessful( false )
  71. , m_fRemoveAllRights( false )
  72. {
  73. BCATraceScope( "" );
  74. DWORD dwError = ERROR_SUCCESS;
  75. UINT uiIndex;
  76. // Indicate that action can be rolled back.
  77. SetRollbackPossible( true );
  78. do
  79. {
  80. PSID psidAdministrators = NULL;
  81. SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
  82. DWORD dwNameSize = 0;
  83. DWORD dwDomainSize = 0;
  84. SID_NAME_USE snuSidNameUse;
  85. //
  86. // Get the Admins SID
  87. //
  88. if ( AllocateAndInitializeSid(
  89. &siaNtAuthority // identifier authority
  90. , 2 // count of subauthorities
  91. , SECURITY_BUILTIN_DOMAIN_RID // subauthority 0
  92. , DOMAIN_ALIAS_RID_ADMINS // subauthority 1
  93. , 0 // subauthority 2
  94. , 0 // subauthority 3
  95. , 0 // subauthority 4
  96. , 0 // subauthority 5
  97. , 0 // subauthority 6
  98. , 0 // subauthority 7
  99. , &psidAdministrators // pointer to pointer to SID
  100. )
  101. == 0
  102. )
  103. {
  104. DWORD dwError = TW32( GetLastError() );
  105. TraceFlow1( "Error %#08x occurred trying get the Administrators group SID.", dwError );
  106. break;
  107. } // if: AllocateAndInitializeSid() failed
  108. // Assign the allocated SID to to the member variable.
  109. m_ssidAdminSid.Assign( psidAdministrators );
  110. //
  111. // Look up the administrators group name and store it.
  112. //
  113. // Find out how much space is required by the name.
  114. if ( LookupAccountSid(
  115. NULL
  116. , psidAdministrators
  117. , NULL
  118. , &dwNameSize
  119. , NULL
  120. , &dwDomainSize
  121. , &snuSidNameUse
  122. )
  123. == FALSE
  124. )
  125. {
  126. dwError = GetLastError();
  127. if ( dwError != ERROR_INSUFFICIENT_BUFFER )
  128. {
  129. TW32( dwError );
  130. TraceFlow( "LookupAccountSid() failed while querying for required buffer size." );
  131. break;
  132. } // if: something else has gone wrong.
  133. else
  134. {
  135. // This is expected.
  136. dwError = ERROR_SUCCESS;
  137. } // if: ERROR_INSUFFICIENT_BUFFER was returned.
  138. } // if: LookupAccountSid failed
  139. // Allocate memory for the admin group name and the domain name.
  140. m_sszAdminGroupName.Assign( new WCHAR[ dwNameSize ] );
  141. SmartSz sszDomainName( new WCHAR[ dwDomainSize ] );
  142. if ( m_sszAdminGroupName.FIsEmpty() || sszDomainName.FIsEmpty() )
  143. {
  144. dwError = ERROR_OUTOFMEMORY;
  145. break;
  146. } // if: there wasn't enough memory
  147. // Get the admin group name.
  148. if ( LookupAccountSid(
  149. NULL
  150. , psidAdministrators
  151. , m_sszAdminGroupName.PMem()
  152. , &dwNameSize
  153. , sszDomainName.PMem()
  154. , &dwDomainSize
  155. , &snuSidNameUse
  156. )
  157. == FALSE
  158. )
  159. {
  160. dwError = GetLastError();
  161. TraceFlow( "LookupAccountSid() failed while attempting to get the admin group name." );
  162. break;
  163. } // if: LookupAccountSid failed
  164. }
  165. while( false ); // dummy do-while loop to avoid gotos.
  166. if ( dwError != ERROR_SUCCESS )
  167. {
  168. LogMsg( "Error %#08x occurred trying to get information about the administrators group.", dwError );
  169. TraceFlow1( "Error %#08x occurred trying to get information about the administrators group. Throwing exception.", dwError );
  170. THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( dwError ), IDS_ERROR_GET_ADMIN_GROUP_INFO );
  171. } // if: something went wrong.
  172. } //*** CClusSvcAccountConfig::CClusSvcAccountConfig()
  173. //////////////////////////////////////////////////////////////////////////////
  174. //++
  175. //
  176. // CClusSvcAccountConfig::~CClusSvcAccountConfig()
  177. //
  178. // Description:
  179. // Destructor of the CClusSvcAccountConfig class.
  180. //
  181. // Arguments:
  182. // None.
  183. //
  184. // Return Value:
  185. // None.
  186. //
  187. // Exceptions Thrown:
  188. // Any exceptions thrown by underlying functions
  189. //
  190. //--
  191. //////////////////////////////////////////////////////////////////////////////
  192. CClusSvcAccountConfig::~CClusSvcAccountConfig( void )
  193. {
  194. BCATraceScope( "" );
  195. } //*** CClusSvcAccountConfig::~CClusSvcAccountConfig()
  196. //////////////////////////////////////////////////////////////////////////////
  197. //++
  198. //
  199. // void
  200. // CClusSvcAccountConfig::Commit()
  201. //
  202. // Description:
  203. // Grant the required rights to the account.
  204. //
  205. // Arguments:
  206. // None.
  207. //
  208. // Return Value:
  209. // None.
  210. //
  211. // Exceptions Thrown:
  212. // Any that are thrown by the contained actions.
  213. //
  214. //--
  215. //////////////////////////////////////////////////////////////////////////////
  216. void
  217. CClusSvcAccountConfig::Commit( void )
  218. {
  219. BCATraceScope( "" );
  220. // Call the base class commit method.
  221. BaseClass::Commit();
  222. try
  223. {
  224. // Configure the account.
  225. ConfigureAccount();
  226. } // try:
  227. catch( ... )
  228. {
  229. // If we are here, then something went wrong with the create.
  230. TraceFlow( "Caught exception during commit." );
  231. //
  232. // Cleanup anything that the failed create might have done.
  233. // Catch any exceptions thrown during Cleanup to make sure that there
  234. // is no collided unwind.
  235. //
  236. try
  237. {
  238. RevertAccount();
  239. }
  240. catch( ... )
  241. {
  242. //
  243. // The rollback of the committed action has failed.
  244. // There is nothing that we can do.
  245. // We certainly cannot rethrow this exception, since
  246. // the exception that caused the rollback is more important.
  247. //
  248. THR( E_UNEXPECTED );
  249. TraceFlow( "Caught exception during cleanup." );
  250. LogMsg( "THIS COMPUTER MAY BE IN AN INVALID STATE. An error has occurred during cleanup." );
  251. } // catch: all
  252. // Rethrow the exception thrown by commit.
  253. throw;
  254. } // catch: all
  255. // If we are here, then everything went well.
  256. SetCommitCompleted( true );
  257. } //*** CClusSvcAccountConfig::Commit()
  258. //////////////////////////////////////////////////////////////////////////////
  259. //++
  260. //
  261. // void
  262. // CClusSvcAccountConfig::Rollback()
  263. //
  264. // Description:
  265. // Roll the account back to the state it was in before we tried to
  266. // grant it the required privileges.
  267. //
  268. // Arguments:
  269. // None.
  270. //
  271. // Return Value:
  272. // None.
  273. //
  274. // Exceptions Thrown:
  275. // Any that are thrown by the underlying functions.
  276. //
  277. //--
  278. //////////////////////////////////////////////////////////////////////////////
  279. void
  280. CClusSvcAccountConfig::Rollback( void )
  281. {
  282. BCATraceScope( "" );
  283. // Call the base class rollback method.
  284. BaseClass::Rollback();
  285. // Bring the account back to its original state.
  286. RevertAccount();
  287. SetCommitCompleted( false );
  288. } //*** CClusSvcAccountConfig::Rollback()
  289. //////////////////////////////////////////////////////////////////////////////
  290. //++
  291. //
  292. // void
  293. // CClusSvcAccountConfig::ConfigureAccount()
  294. //
  295. // Description:
  296. // Grant the account that will be the cluster service account the requried
  297. // privileges.
  298. //
  299. // Arguments:
  300. // None.
  301. //
  302. // Return Value:
  303. // None.
  304. //
  305. // Exceptions Thrown:
  306. // CRuntimeError
  307. // If any of the APIs fail.
  308. //
  309. // Any that are thrown by the underlying functions.
  310. //
  311. //--
  312. //////////////////////////////////////////////////////////////////////////////
  313. void
  314. CClusSvcAccountConfig::ConfigureAccount( void )
  315. {
  316. BCATraceScope( "" );
  317. typedef CSmartResource<
  318. CHandleTrait<
  319. PLSA_UNICODE_STRING
  320. , NTSTATUS
  321. , reinterpret_cast< NTSTATUS (*)( PLSA_UNICODE_STRING ) >( LsaFreeMemory )
  322. , reinterpret_cast< PLSA_UNICODE_STRING >( NULL )
  323. >
  324. >
  325. SmartLsaUnicodeStringPtr;
  326. NTSTATUS ntStatus;
  327. PLSA_UNICODE_STRING plusAccountRights = NULL;
  328. ULONG ulOriginalRightsCount = 0;
  329. ULONG rgulToBeGrantedIndex[ gc_uiRightsArraySize ];
  330. ULONG ulIndex;
  331. ULONG ulIndexInner;
  332. DWORD dwError;
  333. CStatusReport srConfigAcct(
  334. m_pbcanParentAction->PBcaiGetInterfacePointer()
  335. , TASKID_Major_Configure_Cluster_Services
  336. , TASKID_Minor_Configuring_Cluster_Service_Account
  337. , 0, 1
  338. , IDS_TASK_CONFIG_CLUSSVC_ACCOUNT
  339. );
  340. // Send the next step of this status report.
  341. srConfigAcct.SendNextStep( S_OK );
  342. // Add the cluster service account to the local admin group.
  343. m_fWasAreadyInGroup = FChangeAdminGroupMembership(
  344. m_pbcanParentAction->PSidGetServiceAccountSID()
  345. , true
  346. );
  347. LogMsg( "Determining the rights that need to be granted to the cluster service account." );
  348. // Get the list of rights already granted to the cluster service account.
  349. ntStatus = LsaEnumerateAccountRights(
  350. m_pbcanParentAction->HGetLSAPolicyHandle()
  351. , m_pbcanParentAction->PSidGetServiceAccountSID()
  352. , &plusAccountRights
  353. , &ulOriginalRightsCount
  354. );
  355. if ( ntStatus != STATUS_SUCCESS )
  356. {
  357. //
  358. // LSA returns this error code if the account has no rights granted or denied to it
  359. // locally. This is not an error as far as we are concerned.
  360. //
  361. if ( ntStatus == STATUS_OBJECT_NAME_NOT_FOUND )
  362. {
  363. ntStatus = STATUS_SUCCESS;
  364. TraceFlow( "The account has no locally assigned rights." );
  365. m_fRemoveAllRights = true;
  366. plusAccountRights = NULL;
  367. ulOriginalRightsCount = 0;
  368. } // if: the account does not have any rights assigned locally to it.
  369. else
  370. {
  371. THR( ntStatus );
  372. LogMsg( "Error %#08x occurred trying to enumerate the cluster service account rights.", ntStatus );
  373. TraceFlow1( "Error %#08x occurred trying to enumerate the cluster service account rights. Throwing exception", ntStatus );
  374. THROW_RUNTIME_ERROR( ntStatus, IDS_ERROR_ACCOUNT_RIGHTS_CONFIG );
  375. } // else: something went wrong.
  376. } // if: LsaEnumerateAccountRights() failed
  377. // Store the account rights just enumerated in a smart pointer for automatic release.
  378. SmartLsaUnicodeStringPtr splusOriginalRights( plusAccountRights );
  379. // Initialize the count of rights to be granted.
  380. m_ulRightsToBeGrantedCount = 0;
  381. // Determine which of the rights that we are going to grant the account are already granted.
  382. for ( ulIndex = 0; ulIndex < gc_uiRightsArraySize; ++ulIndex )
  383. {
  384. bool fRightAlreadyGranted = false;
  385. for ( ulIndexInner = 0; ulIndexInner < ulOriginalRightsCount; ++ulIndexInner )
  386. {
  387. const WCHAR * pchGrantedRight = plusAccountRights[ ulIndexInner ].Buffer;
  388. USHORT usCharCount = plusAccountRights[ ulIndexInner ].Length / sizeof( *pchGrantedRight );
  389. const WCHAR * pcszToBeGrantedRight = gs_rgpcszRightsArray[ ulIndex ];
  390. // Do our own string compare since LSA_UNICODE_STRING may not be '\0' terminated.
  391. while ( ( usCharCount > 0 ) && ( *pcszToBeGrantedRight != L'\0' ) )
  392. {
  393. if ( *pchGrantedRight != *pcszToBeGrantedRight )
  394. {
  395. break;
  396. } // if: the current characters are not the same.
  397. --usCharCount;
  398. ++pcszToBeGrantedRight;
  399. ++pchGrantedRight;
  400. } // while: there are still characters to be compared
  401. // The strings are equal.
  402. if ( ( usCharCount == 0 ) && ( *pcszToBeGrantedRight == L'\0' ) )
  403. {
  404. fRightAlreadyGranted = true;
  405. break;
  406. } // if: the strings are equal
  407. } // for: loop through the list of rights already granted to the account
  408. // Is the current right already granted.
  409. if ( ! fRightAlreadyGranted )
  410. {
  411. // The current right is not already granted.
  412. rgulToBeGrantedIndex[ m_ulRightsToBeGrantedCount ] = ulIndex;
  413. // One more right to be granted.
  414. ++m_ulRightsToBeGrantedCount;
  415. } // if: the current right was not already granted
  416. } // for: loop through the list of rights that we want to grant the account
  417. //
  418. // Create an array of LSA_UNICODE_STRINGs of right names to be granted and store it in the
  419. // member variable.
  420. //
  421. m_srglusRightsToBeGrantedArray.Assign( new LSA_UNICODE_STRING[ m_ulRightsToBeGrantedCount ] );
  422. if ( m_srglusRightsToBeGrantedArray.FIsEmpty() )
  423. {
  424. LogMsg( "A memory allocation error occurred trying to grant account rights." );
  425. TraceFlow1( "Could not allocate %d bytes of memory. Throwing exception.", m_ulRightsToBeGrantedCount );
  426. THROW_RUNTIME_ERROR(
  427. E_OUTOFMEMORY
  428. , IDS_ERROR_ACCOUNT_RIGHTS_CONFIG
  429. );
  430. } // if: memory allocation failed.
  431. // Initialize the array.
  432. for ( ulIndex = 0; ulIndex < m_ulRightsToBeGrantedCount; ++ ulIndex )
  433. {
  434. ULONG ulCurrentRightIndex = rgulToBeGrantedIndex[ ulIndex ];
  435. TraceFlow1( "The '%ws' right will be granted.", gs_rgpcszRightsArray[ ulCurrentRightIndex ] );
  436. // Add it to the list of rights to be granted.
  437. InitLsaString(
  438. const_cast< WCHAR * >( gs_rgpcszRightsArray[ ulCurrentRightIndex ] )
  439. , m_srglusRightsToBeGrantedArray.PMem() + ulIndex
  440. );
  441. } // for: iterate through the list of rights that need to be granted
  442. // Grant the rights.
  443. ntStatus = THR( LsaAddAccountRights(
  444. m_pbcanParentAction->HGetLSAPolicyHandle()
  445. , m_pbcanParentAction->PSidGetServiceAccountSID()
  446. , m_srglusRightsToBeGrantedArray.PMem()
  447. , m_ulRightsToBeGrantedCount
  448. ) );
  449. if ( ntStatus != STATUS_SUCCESS )
  450. {
  451. LogMsg( "Error %#08x occurred trying to grant the cluster service account rights.", ntStatus );
  452. TraceFlow1( "Error %#08x occurred trying to grant the cluster service account rights. Throwing exception", ntStatus );
  453. THROW_RUNTIME_ERROR( ntStatus, IDS_ERROR_ACCOUNT_RIGHTS_CONFIG );
  454. } // if: LsaAddAccountRights() failed
  455. m_fRightsGrantSuccessful = true;
  456. // Send the last step of this status report.
  457. srConfigAcct.SendNextStep( S_OK );
  458. } //*** CClusSvcAccountConfig::ConfigureAccount()
  459. //////////////////////////////////////////////////////////////////////////////
  460. //++
  461. //
  462. // void
  463. // CClusSvcAccountConfig::RevertAccount()
  464. //
  465. // Description:
  466. // Bring the account back to its original state.
  467. //
  468. // Arguments:
  469. // None.
  470. //
  471. // Return Value:
  472. // None.
  473. //
  474. // Exceptions Thrown:
  475. // Any that are thrown by the underlying functions.
  476. //
  477. //--
  478. //////////////////////////////////////////////////////////////////////////////
  479. void
  480. CClusSvcAccountConfig::RevertAccount( void )
  481. {
  482. BCATraceScope( "" );
  483. // Check if we granted any rights to the service account. If we did, revoke them.
  484. if ( m_fRightsGrantSuccessful )
  485. {
  486. NTSTATUS ntStatus;
  487. // Revoke the rights.
  488. ntStatus = THR( LsaRemoveAccountRights(
  489. m_pbcanParentAction->HGetLSAPolicyHandle()
  490. , m_pbcanParentAction->PSidGetServiceAccountSID()
  491. , m_fRemoveAllRights
  492. , m_srglusRightsToBeGrantedArray.PMem()
  493. , m_ulRightsToBeGrantedCount
  494. ) );
  495. if ( ntStatus != STATUS_SUCCESS )
  496. {
  497. LogMsg( "Error %#08x occurred trying to remove the granted cluster service account rights.", ntStatus );
  498. TraceFlow1( "Error %#08x occurred trying to remove the granted the cluster service account rights. Throwing exception", ntStatus );
  499. THROW_RUNTIME_ERROR( ntStatus, IDS_ERROR_ACCOUNT_RIGHTS_CONFIG );
  500. } // if: LsaRemoveAccountRights() failed
  501. } // if: we granted the service account any rights.
  502. // Check if we added the account to the admin group. If we did, remove it.
  503. if ( ! m_fWasAreadyInGroup )
  504. {
  505. FChangeAdminGroupMembership( m_pbcanParentAction->PSidGetServiceAccountSID(), false );
  506. } // if: we added the account to the admin group.
  507. } //*** CClusSvcAccountConfig::RevertAccount()
  508. //////////////////////////////////////////////////////////////////////////////
  509. //++
  510. //
  511. // void
  512. // CClusSvcAccountConfig::InitLsaString()
  513. //
  514. // Description:
  515. // Initialize a LSA_UNICODE_STRING structure
  516. //
  517. // Arguments:
  518. // pszSourceIn
  519. // The string used to initialize the unicode string structure.
  520. //
  521. // plusUnicodeStringOut,
  522. // The output unicode string structure.
  523. //
  524. // Return Value:
  525. // None.
  526. //
  527. // Exceptions Thrown:
  528. // None.
  529. //
  530. //--
  531. //////////////////////////////////////////////////////////////////////////////
  532. void
  533. CClusSvcAccountConfig::InitLsaString(
  534. LPWSTR pszSourceIn
  535. , PLSA_UNICODE_STRING plusUnicodeStringOut
  536. )
  537. {
  538. if ( pszSourceIn == NULL )
  539. {
  540. plusUnicodeStringOut->Buffer = NULL;
  541. plusUnicodeStringOut->Length = 0;
  542. plusUnicodeStringOut->MaximumLength = 0;
  543. } // if: input string is NULL
  544. else
  545. {
  546. plusUnicodeStringOut->Buffer = pszSourceIn;
  547. plusUnicodeStringOut->Length = static_cast< USHORT >( wcslen( pszSourceIn ) * sizeof( *pszSourceIn ) );
  548. plusUnicodeStringOut->MaximumLength = static_cast< USHORT >( plusUnicodeStringOut->Length + sizeof( *pszSourceIn ) );
  549. } // else: input string is not NULL
  550. } //*** CClusSvcAccountConfig::InitLsaString()
  551. //////////////////////////////////////////////////////////////////////////////
  552. //++
  553. //
  554. // bool
  555. // CClusSvcAccountConfig::FChangeAdminGroupMembership()
  556. //
  557. // Description:
  558. // Adds/removes an account to/from the administrators group.
  559. //
  560. // Arguments:
  561. // psidAccountSidIn
  562. // Pointer to the SID the of account to add/remove to/from administrators
  563. // group.
  564. //
  565. // fAddIn
  566. // The account is added to the administrators group if this parameter
  567. // is true. The account is removed from the group otherwise.
  568. //
  569. // Return Value:
  570. // true if the accound was already present/absent in/from the group.
  571. // false otherwise.
  572. //
  573. // Exceptions Thrown:
  574. // CRuntimeError
  575. // If any of the APIs fail.
  576. //
  577. //--
  578. //////////////////////////////////////////////////////////////////////////////
  579. bool CClusSvcAccountConfig::FChangeAdminGroupMembership(
  580. PSID psidAccountSidIn
  581. , bool fAddIn
  582. )
  583. {
  584. BCATraceScope( "" );
  585. bool fWasAlreadyInGroup = false;
  586. LOCALGROUP_MEMBERS_INFO_0 lgmiLocalGroupMemberInfo;
  587. NET_API_STATUS nasStatus;
  588. lgmiLocalGroupMemberInfo.lgrmi0_sid = psidAccountSidIn;
  589. if ( fAddIn )
  590. {
  591. CStatusReport srAddAcctToAdminGroup(
  592. m_pbcanParentAction->PBcaiGetInterfacePointer()
  593. , TASKID_Major_Configure_Cluster_Services
  594. , TASKID_Minor_Make_Cluster_Service_Account_Admin
  595. , 0, 1
  596. , IDS_TASK_MAKING_CLUSSVC_ACCOUNT_ADMIN
  597. );
  598. srAddAcctToAdminGroup.SendNextStep( S_OK );
  599. nasStatus = NetLocalGroupAddMembers(
  600. NULL
  601. , m_sszAdminGroupName.PMem()
  602. , 0
  603. , reinterpret_cast< LPBYTE >( &lgmiLocalGroupMemberInfo )
  604. , 1
  605. );
  606. if ( nasStatus == ERROR_MEMBER_IN_ALIAS )
  607. {
  608. LogMsg( "The account was already a member of the admin group." );
  609. TraceFlow( "The account was already a member of the admin group." );
  610. nasStatus = NERR_Success;
  611. fWasAlreadyInGroup = true;
  612. srAddAcctToAdminGroup.SendLastStep( S_OK, IDS_TASK_CLUSSVC_ACCOUNT_ALREADY_ADMIN );
  613. } // if: the account was already a member of the admin group.
  614. else
  615. {
  616. if ( nasStatus == NERR_Success )
  617. {
  618. TraceFlow( "The account has been added to the admin group." );
  619. srAddAcctToAdminGroup.SendLastStep( S_OK );
  620. fWasAlreadyInGroup = false;
  621. } // if: everything was ok
  622. else
  623. {
  624. HRESULT hr = HRESULT_FROM_WIN32( TW32( nasStatus ) );
  625. srAddAcctToAdminGroup.SendLastStep( hr );
  626. TraceFlow( "NetLocalGroupAddMembers() returned an error." );
  627. } // else: something went wrong
  628. } // else: the account was not already a member of the admin group.
  629. } // if: the account has to be added to the admin group
  630. else
  631. {
  632. LogMsg( "The account needs to be removed from the administrators group." );
  633. TraceFlow( "The account needs to be removed from the administrators group." );
  634. nasStatus = NetLocalGroupDelMembers(
  635. NULL
  636. , m_sszAdminGroupName.PMem()
  637. , 0
  638. , reinterpret_cast< LPBYTE >( &lgmiLocalGroupMemberInfo )
  639. , 1
  640. );
  641. if ( nasStatus == ERROR_NO_SUCH_MEMBER )
  642. {
  643. LogMsg( "The account was not a member of the admin group to begin with." );
  644. TraceFlow( "The account was not a member of the admin group to begin with." );
  645. nasStatus = NERR_Success;
  646. fWasAlreadyInGroup = false;
  647. } // if: the account was not a member of the admin group.
  648. else
  649. {
  650. if ( nasStatus == NERR_Success )
  651. {
  652. TraceFlow( "The account has been deleted from the admin group." );
  653. fWasAlreadyInGroup = true;
  654. } // if: everything was ok
  655. else
  656. {
  657. TW32( nasStatus );
  658. TraceFlow( "NetLocalGroupDelMembers() returned an error." );
  659. } // else: something went wrong
  660. } // else; the account was a member of the admin group.
  661. } // else: the account has to be deleted from the admin group
  662. if ( nasStatus != ERROR_SUCCESS )
  663. {
  664. LogMsg( "Error %#08x occurred trying to change membership in administrators group.", nasStatus );
  665. TraceFlow1( "Error %#08x occurred trying to change membership in administrators group. Throwing exception.", nasStatus );
  666. THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( nasStatus ), IDS_ERROR_ADMIN_GROUP_ADD_REMOVE );
  667. } // if: something went wrong.
  668. else
  669. {
  670. LogMsg( "The account was successfully added/deleted to/from the group '%s'.", m_sszAdminGroupName.PMem() );
  671. TraceFlow1( "The account was successfully added/deleted to/from the group '%s'.", m_sszAdminGroupName.PMem() );
  672. } // else: everything was hunky-dory
  673. return fWasAlreadyInGroup;
  674. } //*** CClusSvcAccountConfig::FChangeAdminGroupMembership()