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.

809 lines
28 KiB

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