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.

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