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.

814 lines
28 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1999-2000 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // CBaseClusterJoin.cpp
  7. //
  8. // Description:
  9. // Contains the definition of the CBaseClusterJoin class.
  10. //
  11. // Maintained By:
  12. // Vij Vasu (Vvasu) 08-MAR-2000
  13. //
  14. //////////////////////////////////////////////////////////////////////////////
  15. //////////////////////////////////////////////////////////////////////////////
  16. // Include Files
  17. //////////////////////////////////////////////////////////////////////////////
  18. // The precompiled header.
  19. #include "pch.h"
  20. // For various RPC functions
  21. #include <Rpcdce.h>
  22. // The header file of this class.
  23. #include "CBaseClusterJoin.h"
  24. // For the CClusNetCreate action
  25. #include "CClusNetCreate.h"
  26. // For the CClusDiskJoin class
  27. #include "CClusDiskJoin.h"
  28. // For the CClusDBJoin action
  29. #include "CClusDBJoin.h"
  30. // For the CClusSvcCreate action
  31. #include "CClusSvcCreate.h"
  32. // For the CNodeConfig action
  33. #include "CNodeConfig.h"
  34. // For the CImpersonateUser class.
  35. #include "CImpersonateUser.h"
  36. // For CsRpcGetJoinVersionData() and constants like JoinVersion_v2_0_c_ifspec
  37. #include <ClusRPC.h>
  38. // For ClRtlIsVersionCheckingDisabled()
  39. #include <ClusRTL.h>
  40. // For CLUSTER_INTERNAL_CURRENT_MAJOR_VERSION
  41. #include <ClusVerp.h>
  42. //////////////////////////////////////////////////////////////////////////////
  43. //++
  44. //
  45. // CBaseClusterJoin::CBaseClusterJoin
  46. //
  47. // Description:
  48. // Constructor of the CBaseClusterJoin class.
  49. //
  50. // This function also stores the parameters that are required to add this
  51. // node to a cluster.
  52. //
  53. // Arguments:
  54. // pbcaiInterfaceIn
  55. // Pointer to the interface class for this library.
  56. //
  57. // pcszClusterNameIn
  58. // Name of the cluster to be joined.
  59. //
  60. // pcszClusterAccountNameIn
  61. // pcszClusterAccountPwdIn
  62. // pcszClusterAccountDomainIn
  63. // Specifies the account to be used as the cluster service account.
  64. //
  65. // Return Value:
  66. // None.
  67. //
  68. // Exceptions Thrown:
  69. // CConfigError
  70. // If the OS version is incorrect or if the installation state
  71. // of the cluster binaries is wrong.
  72. //
  73. // CRuntimeError
  74. // If any of the APIs fail.
  75. //
  76. //--
  77. //////////////////////////////////////////////////////////////////////////////
  78. CBaseClusterJoin::CBaseClusterJoin(
  79. CBCAInterface * pbcaiInterfaceIn
  80. , const WCHAR * pcszClusterNameIn
  81. , const WCHAR * pcszClusterBindingStringIn
  82. , const WCHAR * pcszClusterAccountNameIn
  83. , const WCHAR * pcszClusterAccountPwdIn
  84. , const WCHAR * pcszClusterAccountDomainIn
  85. )
  86. : BaseClass(
  87. pbcaiInterfaceIn
  88. , pcszClusterNameIn
  89. , pcszClusterBindingStringIn
  90. , pcszClusterAccountNameIn
  91. , pcszClusterAccountPwdIn
  92. , pcszClusterAccountDomainIn
  93. )
  94. {
  95. BCATraceScope( "" );
  96. LogMsg( "[BC] The current cluster configuration task is: Cluster Join." );
  97. if ( ( pcszClusterBindingStringIn == NULL ) || ( *pcszClusterBindingStringIn == L'\0' ) )
  98. {
  99. LogMsg( "[BC] The cluster binding string is empty." );
  100. THROW_CONFIG_ERROR( E_INVALIDARG, IDS_ERROR_INVALID_CLUSTER_BINDINGSTRING );
  101. } // if: the cluster account is empty
  102. CStatusReport srInitJoin(
  103. PBcaiGetInterfacePointer()
  104. , TASKID_Major_Configure_Cluster_Services
  105. , TASKID_Minor_Initializing_Cluster_Join
  106. , 0, 1
  107. , IDS_TASK_JOIN_INIT
  108. );
  109. // Send the next step of this status report.
  110. srInitJoin.SendNextStep( S_OK );
  111. // Create an object of the CClusSvcAccountConfig class and store a pointer to it.
  112. // This object will be used during Commit() of this action. This object is not
  113. // added to the action list below since the cluster service account has to be
  114. // configured before the sponsor cluster can be contacted.
  115. m_spacAccountConfigAction.Assign( new CClusSvcAccountConfig( this ) );
  116. if ( m_spacAccountConfigAction.FIsEmpty() )
  117. {
  118. LogMsg( "[BC] A memory allocation error occurred trying to configure the cluster service account." );
  119. BCATraceMsg1( "A memory allocation error occurred trying to configure the cluster service account (%d bytes). Throwing exception.", sizeof( CClusSvcAccountConfig ) );
  120. THROW_RUNTIME_ERROR( E_OUTOFMEMORY, IDS_ERROR_JOIN_CLUSTER_INIT );
  121. } // if: memory allocation failed
  122. //
  123. // Create a list of actions to be performed.
  124. // The order of appending actions is significant.
  125. //
  126. // Add the action to create the ClusNet service.
  127. RalGetActionList().AppendAction( new CClusNetCreate( this ) );
  128. // Add the action to create the ClusDisk service.
  129. RalGetActionList().AppendAction( new CClusDiskJoin( this ) );
  130. // Add the action to create the cluster database.
  131. RalGetActionList().AppendAction( new CClusDBJoin( this ) );
  132. // Add the action to create the ClusSvc service.
  133. RalGetActionList().AppendAction( new CClusSvcCreate( this ) );
  134. // Add the action to perform miscellaneous tasks.
  135. RalGetActionList().AppendAction( new CNodeConfig( this ) );
  136. // Indicate if rollback is possible or not.
  137. SetRollbackPossible( m_spacAccountConfigAction->FIsRollbackPossible() && RalGetActionList().FIsRollbackPossible() );
  138. // Indicate that this node should be added to a cluster during commit.
  139. SetAction( eCONFIG_ACTION_JOIN );
  140. // Send the last step of a status report.
  141. srInitJoin.SendNextStep( S_OK );
  142. LogMsg( "[BC] Initialization for cluster join complete." );
  143. } //*** CBaseClusterJoin::CBaseClusterJoin()
  144. //////////////////////////////////////////////////////////////////////////////
  145. //++
  146. //
  147. // CBaseClusterJoin::~CBaseClusterJoin
  148. //
  149. // Description:
  150. // Destructor of the CBaseClusterJoin class
  151. //
  152. // Arguments:
  153. // None.
  154. //
  155. // Return Value:
  156. // None.
  157. //
  158. // Exceptions Thrown:
  159. // None.
  160. //
  161. //--
  162. //////////////////////////////////////////////////////////////////////////////
  163. CBaseClusterJoin::~CBaseClusterJoin() throw()
  164. {
  165. BCATraceScope( "" );
  166. } //*** CBaseClusterJoin::~CBaseClusterJoin()
  167. //////////////////////////////////////////////////////////////////////////////
  168. //++
  169. //
  170. // void
  171. // CBaseClusterJoin::Commit
  172. //
  173. // Description:
  174. // Join the cluster.
  175. //
  176. // Arguments:
  177. // None.
  178. //
  179. // Return Value:
  180. // None.
  181. //
  182. // Exceptions Thrown:
  183. // CRuntimeError
  184. // If any of the APIs fail.
  185. //
  186. // Any exceptions thrown by functions called.
  187. //
  188. //--
  189. //////////////////////////////////////////////////////////////////////////////
  190. void
  191. CBaseClusterJoin::Commit()
  192. {
  193. BCATraceScope( "" );
  194. LogMsg( "[BC] Initiating cluster join." );
  195. CStatusReport srJoiningCluster(
  196. PBcaiGetInterfacePointer()
  197. , TASKID_Major_Configure_Cluster_Services
  198. , TASKID_Minor_Joining_Node
  199. , 0, 1
  200. , IDS_TASK_JOINING_CLUSTER
  201. );
  202. // Send the next step of this status report.
  203. srJoiningCluster.SendNextStep( S_OK );
  204. try
  205. {
  206. // First configure the cluster service account - this is required to get the account token.
  207. m_spacAccountConfigAction->Commit();
  208. // Get the cluster service account token and store it for later use.
  209. {
  210. // Get the account token.
  211. HANDLE hServiceAccountToken = HGetAccountToken(
  212. RStrGetServiceAccountName().PszData()
  213. , RStrGetServiceAccountPassword().PszData()
  214. , RStrGetServiceAccountDomain().PszData()
  215. );
  216. // Store it in a member variable. This variable automatically closes the token on destruction.
  217. m_satServiceAccountToken.Assign( hServiceAccountToken );
  218. LogMsg( "[BC] Got the cluster service account token." );
  219. }
  220. //
  221. // In the scope below, the cluster service account is impersonated, so that we can communicate with the
  222. // sponsor cluster
  223. //
  224. {
  225. DWORD sc;
  226. BOOL fIsVersionCheckingDisabled;
  227. BCATraceMsg( "Impersonating the cluster service account before communicating with the sponsor cluster." );
  228. // Impersonate the cluster service account, so that we can contact the sponsor cluster.
  229. // The impersonation is automatically ended when this object is destroyed.
  230. CImpersonateUser ciuImpersonateClusterServiceAccount( HGetClusterServiceAccountToken() );
  231. // Check if version checking is disabled on the sponsor cluster.
  232. sc = ClRtlIsVersionCheckingDisabled( RStrGetClusterBindingString().PszData(), &fIsVersionCheckingDisabled );
  233. if ( sc != ERROR_SUCCESS )
  234. {
  235. LogMsg(
  236. "[BC] Error %#08x occurred trying to determine if version checking is enabled on the node {%ws} with binding string {%ws}."
  237. , sc
  238. , RStrGetClusterName().PszData()
  239. , RStrGetClusterBindingString().PszData()
  240. );
  241. LogMsg( "[BC] This is not a fatal error. Assuming that version checking is required." );
  242. fIsVersionCheckingDisabled = FALSE;
  243. } // if: an error occurred trying to determine if version checking is disabled or not
  244. // Store the result since it will be used later when we try to create the cluster service on this computer.
  245. SetVersionCheckingDisabled( fIsVersionCheckingDisabled != FALSE );
  246. if ( fIsVersionCheckingDisabled != FALSE )
  247. {
  248. LogMsg( "[BC] Cluster version checking is disabled on the sponsor node." );
  249. } // if: version checking is disabled
  250. else
  251. {
  252. // Make sure the this node can interoperate with the sponsor cluster. Note, this call uses
  253. // the cluster service account token got above.
  254. CheckInteroperability();
  255. } // else: version checking is enabled
  256. // Get a binding handle to the extrocluster join interface and store it.
  257. InitializeJoinBinding();
  258. } //
  259. // Call the base class commit routine. This commits the rest of the action list.
  260. BaseClass::Commit();
  261. } // try:
  262. catch( ... )
  263. {
  264. // If we are here, then something went wrong with one of the actions.
  265. LogMsg( "[BC] An error has occurred. The performed actions will be rolled back." );
  266. //
  267. // Rollback all committed actions in the reverse order.
  268. // Catch any exceptions thrown during rollback to make sure that there
  269. // is no collided unwind.
  270. //
  271. try
  272. {
  273. // If we are here, then it means that something has gone wrong in the try block above.
  274. // Of the two actions committed, only m_spacAccountConfigAction needs to be rolled back.
  275. // This is because, if BaseClass::Commit() was successful, we wouldn't be here!
  276. if ( m_spacAccountConfigAction->FIsCommitComplete() )
  277. {
  278. if ( m_spacAccountConfigAction->FIsRollbackPossible() )
  279. {
  280. m_spacAccountConfigAction->Rollback();
  281. } // if: this action can be rolled back
  282. else
  283. {
  284. LogMsg( "[BC] THIS COMPUTER MAY BE IN AN INVALID STATE. Rollback was aborted." );
  285. } // else: this action cannot be rolled back
  286. } // if: the cluster service account has been configured
  287. else
  288. {
  289. BCATraceMsg( "There is no need to cleanup this action since no part of it committed successfully." );
  290. } // else: the cluster service account has not been configured
  291. }
  292. catch( ... )
  293. {
  294. //
  295. // The rollback of the committed actions has failed.
  296. // There is nothing that we can do, is there?
  297. // We certainly cannot rethrow this exception, since
  298. // the exception that caused the rollback is more important.
  299. //
  300. THR( E_UNEXPECTED );
  301. LogMsg( "[BC] THIS COMPUTER MAY BE IN AN INVALID STATE. An error has occurred during rollback. Rollback will be aborted." );
  302. } // catch: all
  303. // Rethrow the exception thrown by commit.
  304. throw;
  305. } // catch: all
  306. // If we are here, then everything went well.
  307. SetCommitCompleted( true );
  308. // Send the last step of this status report.
  309. srJoiningCluster.SendNextStep( S_OK );
  310. } //*** CBaseClusterJoin::Commit()
  311. //////////////////////////////////////////////////////////////////////////////
  312. //++
  313. //
  314. // void
  315. // CBaseClusterJoin::Rollback
  316. //
  317. // Description:
  318. // Performs the rolls back of the action committed by this object.
  319. //
  320. // Arguments:
  321. // None.
  322. //
  323. // Return Value:
  324. // None.
  325. //
  326. // Exceptions Thrown:
  327. // Any exceptions thrown by functions called.
  328. //
  329. //--
  330. //////////////////////////////////////////////////////////////////////////////
  331. void
  332. CBaseClusterJoin::Rollback()
  333. {
  334. BCATraceScope( "" );
  335. // Rollback the actions.
  336. BaseClass::Rollback();
  337. // Rollback the configuration of the cluster service account.
  338. m_spacAccountConfigAction->Rollback();
  339. SetCommitCompleted( false );
  340. } //*** CBaseClusterJoin::Rollback()
  341. //////////////////////////////////////////////////////////////////////////////
  342. //++
  343. //
  344. // HANDLE
  345. // CBaseClusterJoin::HGetAccountToken
  346. //
  347. // Description:
  348. // Gets a handle to an account token. This token is an impersonation
  349. // token.
  350. //
  351. // Arguments:
  352. // pcszAccountNameIn
  353. // pcszAccountPwdIn
  354. // pcszAccountDomainIn
  355. // Specifies the account whose token is to be retrieved.
  356. //
  357. // Return Value:
  358. // Handle to the desired token. This has to be closed using CloseHandle().
  359. //
  360. // Exceptions Thrown:
  361. // CRuntimeError
  362. // If any of the APIs fail.
  363. //
  364. //--
  365. //////////////////////////////////////////////////////////////////////////////
  366. HANDLE
  367. CBaseClusterJoin::HGetAccountToken(
  368. const WCHAR * pcszAccountNameIn
  369. , const WCHAR * pcszAccountPwdIn
  370. , const WCHAR * pcszAccountDomainIn
  371. )
  372. {
  373. BCATraceScope( "" );
  374. HANDLE hAccountToken = NULL;
  375. if ( LogonUser(
  376. const_cast< LPWSTR >( pcszAccountNameIn )
  377. , const_cast< LPWSTR >( pcszAccountDomainIn )
  378. , const_cast< LPWSTR >( pcszAccountPwdIn )
  379. , LOGON32_LOGON_SERVICE
  380. , LOGON32_PROVIDER_DEFAULT
  381. , &hAccountToken
  382. )
  383. == FALSE
  384. )
  385. {
  386. DWORD sc = TW32( GetLastError() );
  387. if ( ( pcszAccountDomainIn != NULL ) && ( pcszAccountNameIn != NULL ) )
  388. {
  389. BCATraceMsg3( "Error %#08x occurred trying to get a token for the account '%ws\\%ws'. Throwing exception.", sc, pcszAccountDomainIn, pcszAccountNameIn );
  390. LogMsg( "[BC] Error %#08x occurred trying to get a token for the account '%ws\\%ws'.", sc, pcszAccountDomainIn, pcszAccountNameIn );
  391. } // if: the account and domain strings are not NULL
  392. else
  393. {
  394. BCATraceMsg1( "Error %#08x occurred trying to get a token for the account. Throwing exception.", sc );
  395. LogMsg( "[BC] Error %#08x occurred trying to get a token for the account.", sc );
  396. } // else: either the account or the domain name is NULL
  397. THROW_RUNTIME_ERROR(
  398. HRESULT_FROM_WIN32( sc )
  399. , IDS_ERROR_GET_ACCOUNT_TOKEN
  400. );
  401. } // if: LogonUser() fails
  402. return hAccountToken;
  403. } //*** CBaseClusterJoin::HGetAccountToken()
  404. //////////////////////////////////////////////////////////////////////////////
  405. //++
  406. //
  407. // void
  408. // CBaseClusterJoin::CheckInteroperability
  409. //
  410. // Description:
  411. // This functions checks to see if this node can interoperate with the
  412. // sponsor cluster.
  413. //
  414. // Arguments:
  415. // None.
  416. //
  417. // Return Value:
  418. // None.
  419. //
  420. // Exceptions Thrown:
  421. // CRuntimeError
  422. // If any of the APIs fail.
  423. //
  424. // CConfigError
  425. // If this node cannot interoperate with the sponsor.
  426. //
  427. // Remarks:
  428. // The thread calling this function should be running in the context of an
  429. // account that has access to the sponsor cluster.
  430. //--
  431. //////////////////////////////////////////////////////////////////////////////
  432. void
  433. CBaseClusterJoin::CheckInteroperability( void )
  434. {
  435. BCATraceScope( "" );
  436. RPC_STATUS rsError = RPC_S_OK;
  437. RPC_BINDING_HANDLE rbhBindingHandle = NULL;
  438. SmartRpcBinding srbBindingHandle;
  439. do
  440. {
  441. LPWSTR pszBindingString = NULL;
  442. SmartRpcString srsBindingString( &pszBindingString );
  443. // Create a string binding handle.
  444. {
  445. LogMsg(
  446. L"[BC] Creating a binding string handle for cluster {%ws} with binding string {%ws} to check interoperability."
  447. , RStrGetClusterName().PszData()
  448. , RStrGetClusterBindingString().PszData()
  449. );
  450. rsError = TW32( RpcStringBindingComposeW(
  451. L"6e17aaa0-1a47-11d1-98bd-0000f875292e"
  452. , L"ncadg_ip_udp"
  453. , const_cast< LPWSTR >( RStrGetClusterBindingString().PszData() )
  454. , NULL
  455. , NULL
  456. , &pszBindingString
  457. ) );
  458. if ( rsError != RPC_S_OK )
  459. {
  460. LogMsg( L"[BC] An error occurred trying to compose an RPC string binding." );
  461. break;
  462. } // if: RpcStringBindingComposeW() failed
  463. // No need to free pszBindingString - srsBindingString will automatically free it.
  464. }
  465. // Get the actual binding handle
  466. {
  467. rsError = TW32( RpcBindingFromStringBindingW( pszBindingString, &rbhBindingHandle ) );
  468. if ( rsError != RPC_S_OK )
  469. {
  470. LogMsg( L"[BC] An error occurred trying to get an RPC binding handle from a string binding." );
  471. break;
  472. } // if: RpcBindingFromStringBindingW() failed
  473. // No need to free rbhBindingHandle - srbBindingHandle will automatically free it.
  474. srbBindingHandle.Assign( rbhBindingHandle );
  475. }
  476. // Resolve the binding handle
  477. {
  478. rsError = TW32( RpcEpResolveBinding( rbhBindingHandle, JoinVersion_v2_0_c_ifspec ) );
  479. if ( rsError != RPC_S_OK )
  480. {
  481. LogMsg( L"[BC] An error occurred trying to resolve the RPC binding handle." );
  482. break;
  483. } // if: RpcEpResolveBinding() failed
  484. }
  485. // Set RPC security
  486. {
  487. rsError = TW32( RpcBindingSetAuthInfoW(
  488. rbhBindingHandle
  489. , NULL
  490. , RPC_C_AUTHN_LEVEL_CONNECT
  491. , RPC_C_AUTHN_WINNT
  492. , NULL
  493. , RPC_C_AUTHZ_NAME
  494. ) );
  495. if ( rsError != RPC_S_OK )
  496. {
  497. LogMsg( L"[BC] An error occurred trying to set security on the binding handle." );
  498. break;
  499. } // if: RpcBindingSetAuthInfoW() failed
  500. }
  501. }
  502. while( false ); // dummy do-while loop to avoid gotos.
  503. if ( rsError != RPC_S_OK )
  504. {
  505. LogMsg(
  506. "[BC] Error %#08x occurred trying to connect to the sponsor cluster for an interoperability check with binding string {%ws}."
  507. , rsError
  508. , RStrGetClusterBindingString().PszData()
  509. );
  510. THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( rsError ), IDS_ERROR_JOIN_CHECK_INTEROP );
  511. } // if: something has gone wrong
  512. LogMsg( L"[BC] Got RPC binding handle to check interoperability without any problems." );
  513. //
  514. // Get and verify the sponsor version
  515. //
  516. {
  517. DWORD dwSponsorNodeId;
  518. DWORD dwClusterHighestVersion;
  519. DWORD dwClusterLowestVersion;
  520. DWORD dwJoinStatus;
  521. DWORD sc;
  522. DWORD dwNodeHighestVersion = DwGetNodeHighestVersion();
  523. DWORD dwNodeLowestVersion = DwGetNodeLowestVersion();
  524. bool fVersionMismatch = false;
  525. //
  526. // From Whistler onwards, CsRpcGetJoinVersionData() will return a failure code in its last parameter
  527. // if the version of this node is not compatible with the sponsor version. Prior to this, the last
  528. // parameter always contained a success value and the cluster versions had to be compared subsequent to this
  529. // call. This will, however, still have to be done as long as interoperability with Win2K
  530. // is a requirement, since Win2K sponsors do not return an error in the last parameter.
  531. //
  532. sc = TW32( CsRpcGetJoinVersionData(
  533. rbhBindingHandle
  534. , 0
  535. , dwNodeHighestVersion
  536. , dwNodeLowestVersion
  537. , &dwSponsorNodeId
  538. , &dwClusterHighestVersion
  539. , &dwClusterLowestVersion
  540. , &dwJoinStatus
  541. ) );
  542. if ( sc != ERROR_SUCCESS )
  543. {
  544. LogMsg( "[BC] Error %#08x occurred trying to verify if this node can interoperate with the sponsor cluster.", sc );
  545. BCATraceMsg1( "Error %#08x occurred trying to verify if this node can interoperate with the sponsor cluster. Throwing exception.", sc );
  546. THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( sc ), IDS_ERROR_JOIN_CHECK_INTEROP );
  547. } // if: CsRpcGetJoinVersionData() failed
  548. BCATraceMsg4(
  549. "( Node Highest, Node Lowest ) = ( %#08x, %#08x ), ( Cluster Highest, Cluster Lowest ) = ( %#08x, %#08x )."
  550. , dwNodeHighestVersion
  551. , dwNodeLowestVersion
  552. , dwClusterHighestVersion
  553. , dwClusterLowestVersion
  554. );
  555. if ( dwJoinStatus == ERROR_SUCCESS )
  556. {
  557. DWORD dwClusterMajorVersion = CLUSTER_GET_MAJOR_VERSION( dwClusterHighestVersion );
  558. // Assert( dwClusterMajorVersion > ( CLUSTER_INTERNAL_CURRENT_MAJOR_VERSION - 1 ) );
  559. //
  560. // Only want to join clusters that are no more than one version back.
  561. //
  562. if ( dwClusterMajorVersion < ( CLUSTER_INTERNAL_CURRENT_MAJOR_VERSION - 1 ) )
  563. {
  564. fVersionMismatch = true;
  565. } // if:
  566. } // if: the join status was ok
  567. else
  568. {
  569. fVersionMismatch = true;
  570. } // else: join is not possible
  571. if ( fVersionMismatch )
  572. {
  573. LogMsg( "[BC] This node cannot interoperate with the sponsor cluster.", sc );
  574. BCATraceMsg1( "This node cannot interoperate with the sponsor cluster. Throwing exception.", sc );
  575. THROW_CONFIG_ERROR( HRESULT_FROM_WIN32( TW32( ERROR_CLUSTER_MEMBERSHIP_INVALID_STATE ) ), IDS_ERROR_JOIN_INCOMPAT_SPONSOR );
  576. } // if: there was a version mismatch
  577. else
  578. {
  579. LogMsg( "[BC] This node is compatible with the sponsor cluster." );
  580. BCATraceMsg( "This node is compatible with the sponsor cluster." );
  581. } // else: this node can join the cluster
  582. }
  583. } //*** CBaseClusterJoin::CheckInteroperability()
  584. //////////////////////////////////////////////////////////////////////////////
  585. //++
  586. //
  587. // void
  588. // CBaseClusterJoin::InitializeJoinBinding
  589. //
  590. // Description:
  591. // Get a binding handle to the extrocluster join interface and store it.
  592. //
  593. // Arguments:
  594. // None.
  595. //
  596. // Return Value:
  597. // None.
  598. //
  599. // Exceptions Thrown:
  600. // CRuntimeError
  601. // If any of the APIs fail.
  602. //
  603. // Remarks:
  604. // The thread calling this function should be running in the context of an
  605. // account that has access to the sponsor cluster.
  606. //--
  607. //////////////////////////////////////////////////////////////////////////////
  608. void
  609. CBaseClusterJoin::InitializeJoinBinding( void )
  610. {
  611. BCATraceScope( "" );
  612. RPC_STATUS rsError = RPC_S_OK;
  613. RPC_BINDING_HANDLE rbhBindingHandle = NULL;
  614. do
  615. {
  616. LPWSTR pszBindingString = NULL;
  617. SmartRpcString srsBindingString( &pszBindingString );
  618. // Create a string binding handle.
  619. {
  620. LogMsg(
  621. L"[BC] Creating a string binding handle for cluster {%ws} using binding string {%ws} for extro cluster join."
  622. , RStrGetClusterName().PszData()
  623. , RStrGetClusterBindingString().PszData()
  624. );
  625. rsError = TW32( RpcStringBindingComposeW(
  626. L"ffe561b8-bf15-11cf-8c5e-08002bb49649"
  627. , L"ncadg_ip_udp"
  628. , const_cast< LPWSTR >( RStrGetClusterBindingString().PszData() )
  629. , NULL
  630. , NULL
  631. , &pszBindingString
  632. ) );
  633. if ( rsError != RPC_S_OK )
  634. {
  635. LogMsg( L"[BCAn error occurred trying to compose an RPC string binding." );
  636. break;
  637. } // if: RpcStringBindingComposeW() failed
  638. // No need to free pszBindingString - srsBindingString will automatically free it.
  639. }
  640. // Get the actual binding handle
  641. {
  642. rsError = TW32( RpcBindingFromStringBindingW( pszBindingString, &rbhBindingHandle ) );
  643. if ( rsError != RPC_S_OK )
  644. {
  645. LogMsg( L"[BC] An error occurred trying to get an RPC binding handle from a string binding." );
  646. break;
  647. } // if: RpcBindingFromStringBindingW() failed
  648. // No need to free rbhBindingHandle - m_srbJoinBinding will automatically free it.
  649. m_srbJoinBinding.Assign( rbhBindingHandle );
  650. }
  651. // Resolve the binding handle
  652. {
  653. rsError = TW32( RpcEpResolveBinding( rbhBindingHandle, ExtroCluster_v2_0_c_ifspec ) );
  654. if ( rsError != RPC_S_OK )
  655. {
  656. LogMsg( L"[BC] An error occurred trying to resolve the RPC binding handle." );
  657. break;
  658. } // if: RpcEpResolveBinding() failed
  659. }
  660. // Set RPC security
  661. {
  662. rsError = TW32( RpcBindingSetAuthInfoW(
  663. rbhBindingHandle
  664. , NULL
  665. , RPC_C_AUTHN_LEVEL_CONNECT
  666. , RPC_C_AUTHN_WINNT
  667. , NULL
  668. , RPC_C_AUTHZ_NAME
  669. ) );
  670. if ( rsError != RPC_S_OK )
  671. {
  672. LogMsg( L"[BC] An error occurred trying to set security on the binding handle." );
  673. break;
  674. } // if: RpcBindingSetAuthInfoW() failed
  675. }
  676. // Make sure that the server is who it claims to be.
  677. rsError = TW32( TestRPCSecurity( rbhBindingHandle ) );
  678. if ( rsError != RPC_S_OK )
  679. {
  680. LogMsg( L"[BC] An error occurred trying to test RPC security." );
  681. break;
  682. } // if: TestRPCSecurity() failed
  683. }
  684. while( false ); // dummy do-while loop to avoid gotos.
  685. if ( rsError != RPC_S_OK )
  686. {
  687. LogMsg( "[BC] Error %#x occurred trying to get a handle to the extrocluster join interface.", rsError );
  688. THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( rsError ), IDS_ERROR_JOIN_CLUSTER_INIT );
  689. } // if: something has gone wrong
  690. LogMsg( L"[BC] Got RPC binding handle for extro cluster join without any problems." );
  691. } //*** CBaseClusterJoin::InitializeJoinBinding()