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.

931 lines
31 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1999-2001 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // CClusDBForm.cpp
  7. //
  8. // Description:
  9. // Contains the definition of the CClusDBForm 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. // The header for this file
  22. #include "CClusDBForm.h"
  23. // For the CBaseClusterForm class.
  24. #include "CBaseClusterForm.h"
  25. // For UUID related utilities.
  26. #include "CUuid.h"
  27. // For CEnableThreadPrivilege
  28. #include "CEnableThreadPrivilege.h"
  29. // For the CStr class.
  30. #include "CStr.h"
  31. // For sending status reports.
  32. #include "CStatusReport.h"
  33. // For DwRemoveDirectory()
  34. #include "Common.h"
  35. // For inet_ntoa
  36. #include <winsock2.h>
  37. //////////////////////////////////////////////////////////////////////////
  38. // Macros definitions
  39. //////////////////////////////////////////////////////////////////////////
  40. // Section in the INF file that deals with populating the cluster hive.
  41. #define CLUSDB_POPULATE_INF_SECTION_NAME L"ClusDB_Form"
  42. // A placeholder for the cluster group key name in the cluster registry.
  43. #define CLUSREG_KEYNAME_CLUSTERGROUP_PLACEHOLDER L"ClusterGroupGUIDPlaceholder"
  44. // A placeholder for the cluster name resource key name in the cluster registry.
  45. #define CLUSREG_KEYNAME_CLUSTERNAME_RES_PLACEHOLDER L"ClusterNameResGUIDPlaceHolder"
  46. // A placeholder for the cluster IP address resource key name in the cluster registry.
  47. #define CLUSREG_KEYNAME_CLUSTERIP_RES_PLACEHOLDER L"ClusterIPAddrResGUIDPlaceHolder"
  48. // A placeholder for the local quorum resource key name in the cluster registry.
  49. #define CLUSREG_KEYNAME_LOCALQUORUM_RES_PLACEHOLDER L"LocalQuorumResGUIDPlaceHolder"
  50. //////////////////////////////////////////////////////////////////////////////
  51. //++
  52. //
  53. // CClusDBForm::CClusDBForm
  54. //
  55. // Description:
  56. // Constructor of the CClusDBForm class
  57. //
  58. // Arguments:
  59. // pfaParentActionIn
  60. // Pointer to the base cluster action of which this action is a part.
  61. //
  62. // Return Value:
  63. // None.
  64. //
  65. // Exceptions Thrown:
  66. // Any exceptions thrown by underlying functions
  67. //
  68. //--
  69. //////////////////////////////////////////////////////////////////////////////
  70. CClusDBForm::CClusDBForm( CBaseClusterForm * pfaParentActionIn )
  71. : BaseClass( pfaParentActionIn )
  72. {
  73. TraceFunc( "" );
  74. SetRollbackPossible( true );
  75. TraceFuncExit();
  76. } //*** CClusDBForm::CClusDBForm
  77. //////////////////////////////////////////////////////////////////////////////
  78. //++
  79. //
  80. // CClusDBForm::~CClusDBForm
  81. //
  82. // Description:
  83. // Destructor of the CClusDBForm class.
  84. //
  85. // Arguments:
  86. // None.
  87. //
  88. // Return Value:
  89. // None.
  90. //
  91. // Exceptions Thrown:
  92. // Any exceptions thrown by underlying functions
  93. //
  94. //--
  95. //////////////////////////////////////////////////////////////////////////////
  96. CClusDBForm::~CClusDBForm( void )
  97. {
  98. TraceFunc( "" );
  99. TraceFuncExit();
  100. } //*** CClusDBForm::~CClusDBForm
  101. //////////////////////////////////////////////////////////////////////////////
  102. //++
  103. //
  104. // CClusDBForm::Commit
  105. //
  106. // Description:
  107. // Create the cluster database. If anything goes wrong with the creation,
  108. // cleanup the tasks already done.
  109. //
  110. // Arguments:
  111. // None.
  112. //
  113. // Return Value:
  114. // None.
  115. //
  116. // Exceptions Thrown:
  117. // Any that are thrown by the contained actions.
  118. //
  119. //--
  120. //////////////////////////////////////////////////////////////////////////////
  121. void
  122. CClusDBForm::Commit( void )
  123. {
  124. TraceFunc( "" );
  125. // Call the base class commit method.
  126. BaseClass::Commit();
  127. //
  128. // Perform a ClusDB cleanup just to make sure that we do not use some files left over
  129. // from a previous install, aborted uninstall, etc.
  130. //
  131. LogMsg( "[BC-ClusDB-Commit] Cleaning up old cluster database files that may already exist before starting creation." );
  132. {
  133. CStatusReport srCleanDB(
  134. PbcaGetParent()->PBcaiGetInterfacePointer()
  135. , TASKID_Major_Configure_Cluster_Services
  136. , TASKID_Minor_Cleaning_Up_Cluster_Database
  137. , 0, 1
  138. , IDS_TASK_CLEANINGUP_CLUSDB
  139. );
  140. // Send the next step of this status report.
  141. srCleanDB.SendNextStep( S_OK );
  142. CleanupHive();
  143. // Send the last step of this status report.
  144. srCleanDB.SendNextStep( S_OK );
  145. }
  146. try
  147. {
  148. // Create the cluster database
  149. Create();
  150. } // try:
  151. catch( ... )
  152. {
  153. // If we are here, then something went wrong with the create.
  154. LogMsg( "[BC-ClusDB-Commit] Caught exception during commit." );
  155. //
  156. // Cleanup anything that the failed create operation might have done.
  157. // Catch any exceptions thrown during Cleanup to make sure that there
  158. // is no collided unwind.
  159. //
  160. try
  161. {
  162. CleanupHive();
  163. }
  164. catch( ... )
  165. {
  166. //
  167. // The rollback of the committed action has failed.
  168. // There is nothing that we can do.
  169. // We certainly cannot rethrow this exception, since
  170. // the exception that caused the rollback is more important.
  171. //
  172. HRESULT_FROM_WIN32( TW32( ERROR_CLUSCFG_ROLLBACK_FAILED ) );
  173. LogMsg( "[BC-ClusDB-Commit] THIS COMPUTER MAY BE IN AN INVALID STATE. Caught an exception during cleanup." );
  174. } // catch: all
  175. // Rethrow the exception thrown by commit.
  176. throw;
  177. } // catch: all
  178. // If we are here, then everything went well.
  179. SetCommitCompleted( true );
  180. TraceFuncExit();
  181. } //*** CClusDBForm::Commit
  182. //////////////////////////////////////////////////////////////////////////////
  183. //++
  184. //
  185. // CClusDBForm::Rollback
  186. //
  187. // Description:
  188. // Unload the cluster hive and cleanup any associated files.
  189. //
  190. // Arguments:
  191. // None.
  192. //
  193. // Return Value:
  194. // None.
  195. //
  196. // Exceptions Thrown:
  197. // Any that are thrown by the underlying functions.
  198. //
  199. //--
  200. //////////////////////////////////////////////////////////////////////////////
  201. void
  202. CClusDBForm::Rollback( void )
  203. {
  204. TraceFunc( "" );
  205. // Call the base class rollback method.
  206. BaseClass::Rollback();
  207. // Cleanup the cluster database.
  208. CleanupHive();
  209. SetCommitCompleted( false );
  210. TraceFuncExit();
  211. } //*** CClusDBForm::Rollback
  212. //////////////////////////////////////////////////////////////////////////////
  213. //++
  214. //
  215. // CClusDBForm::Create
  216. //
  217. // Description:
  218. // Create the cluster database.
  219. //
  220. // Arguments:
  221. // None.
  222. //
  223. // Return Value:
  224. // None.
  225. //
  226. // Exceptions Thrown:
  227. // CAssert
  228. // The parent action of this action is not CBaseClusterForm
  229. //
  230. // CRuntimeError
  231. // If any of the APIs fail.
  232. //
  233. // Any that are thrown by the called functions.
  234. //
  235. //--
  236. //////////////////////////////////////////////////////////////////////////////
  237. void
  238. CClusDBForm::Create( void )
  239. {
  240. TraceFunc( "" );
  241. LogMsg( "[BC-ClusDB-Create] Attempting to create the cluster database required to create a cluster." );
  242. DWORD sc = ERROR_SUCCESS;
  243. // Get the parent action pointer.
  244. CBaseClusterForm * pcfClusterForm = dynamic_cast< CBaseClusterForm *>( PbcaGetParent() );
  245. CStatusReport srCustomizingDB(
  246. PbcaGetParent()->PBcaiGetInterfacePointer()
  247. , TASKID_Major_Configure_Cluster_Services
  248. , TASKID_Minor_Form_Customizing_Cluster_Database
  249. , 0, 1
  250. , IDS_TASK_FORM_CUSTOMIZING_CLUSDB
  251. );
  252. // If the parent action of this action is not CBaseClusterForm
  253. if ( pcfClusterForm == NULL )
  254. {
  255. THROW_ASSERT( E_POINTER, "The parent action of this action is not CBaseClusterForm." );
  256. } // an invalid pointer was passed in.
  257. // Create the cluster hive.
  258. {
  259. CStatusReport srCreatingDB(
  260. PbcaGetParent()->PBcaiGetInterfacePointer()
  261. , TASKID_Major_Configure_Cluster_Services
  262. , TASKID_Minor_Form_Creating_Cluster_Database
  263. , 0, 1
  264. , IDS_TASK_FORM_CREATING_CLUSDB
  265. );
  266. // Send the next step of this status report.
  267. srCreatingDB.SendNextStep( S_OK );
  268. // Create an empty cluster hive in the registry.
  269. CreateHive( pcfClusterForm );
  270. // Send the last step of this status report.
  271. srCreatingDB.SendNextStep( S_OK );
  272. }
  273. // Send the next step of this status report.
  274. srCustomizingDB.SendNextStep( S_OK );
  275. // Fill up the newly created hive.
  276. PopulateHive( pcfClusterForm );
  277. //
  278. // Create the quorum directory and set its security attributes.
  279. //
  280. do
  281. {
  282. HANDLE hQuorumDirHandle;
  283. const WCHAR * pcszQuorumDir = pcfClusterForm->RStrGetLocalQuorumDirectory().PszData();
  284. // First, remove the local quorum directory, if it exists.
  285. sc = TW32( DwRemoveDirectory( pcszQuorumDir ) );
  286. if ( sc != ERROR_SUCCESS )
  287. {
  288. LogMsg( "[BC-ClusDB-Create] The local quorum directory '%s' already exists, but error %#08x occurred trying to remove it.\n", pcszQuorumDir, sc );
  289. break;
  290. } // if: we could not remove the local quorum directory
  291. if ( CreateDirectory( pcszQuorumDir, NULL ) == FALSE )
  292. {
  293. sc = TW32( GetLastError() );
  294. LogMsg( "[BC-ClusDB-Create] Error %#08x trying to create directory '%ws'", sc, pcszQuorumDir );
  295. break;
  296. } // if: the localquorum directory could not be created
  297. //
  298. // Enable the SE_BACKUP_PRIVILEGE and SE_RESTORE_PRIVILEGE.
  299. //
  300. // What we are doing here is that we are creating an object of
  301. // type CEnableThreadPrivilege. This object enables the privilege
  302. // in the constructor and restores it to its original state in the destructor.
  303. //
  304. CEnableThreadPrivilege etpAcquireBackupPrivilege( SE_BACKUP_NAME );
  305. CEnableThreadPrivilege etpAcquireRestorePrivilege( SE_RESTORE_NAME );
  306. //
  307. // Open a handle to the quorum directory. The calling thread should have SE_BACKUP_PRIVILEGE and
  308. // SE_RESTORE_PRIVILEGE enabled.
  309. //
  310. hQuorumDirHandle = CreateFile(
  311. pcszQuorumDir
  312. , GENERIC_ALL
  313. , FILE_SHARE_WRITE
  314. , NULL
  315. , OPEN_EXISTING
  316. , FILE_FLAG_BACKUP_SEMANTICS
  317. , NULL
  318. );
  319. if ( hQuorumDirHandle == INVALID_HANDLE_VALUE )
  320. {
  321. // The directory does not exist. This is an error.
  322. sc = TW32( GetLastError() );
  323. LogMsg( "[BC-ClusDB-Create] The directory '%ws' does not exist.", pcszQuorumDir );
  324. break;
  325. } // if: the quorum directory does not exist.
  326. // Set the security for this directory.
  327. sc = TW32( ClRtlSetObjSecurityInfo(
  328. hQuorumDirHandle
  329. , SE_FILE_OBJECT
  330. , GENERIC_ALL
  331. , GENERIC_ALL
  332. , 0
  333. ) );
  334. // First close the handle we opened.
  335. CloseHandle( hQuorumDirHandle );
  336. if ( sc != ERROR_SUCCESS )
  337. {
  338. // ClRtlSetObjSecurityInfo() failed.
  339. LogMsg( "[BC-ClusDB-Create] Error %#08x from ClRtlSetObjSecurityInfo().", sc );
  340. break;
  341. } // if: ClRtlSetObjSecurityInfo() failed
  342. }
  343. while( false ); // dummy do-while loop to avoid gotos.
  344. if ( sc != ERROR_SUCCESS )
  345. {
  346. LogMsg( "[BC-ClusDB-Create] Error %#08x occurred while trying to create the local quorum directory. Throwing an exception.", sc );
  347. THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( sc ), IDS_ERROR_QUORUM_DIR_CREATE );
  348. } // if: something went wrong.
  349. // Send the last step of this status report.
  350. srCustomizingDB.SendNextStep( S_OK );
  351. TraceFuncExit();
  352. } //*** CClusDBForm::Create
  353. //////////////////////////////////////////////////////////////////////////////
  354. //++
  355. //
  356. // CClusDBForm::PopulateHive
  357. //
  358. // Description:
  359. // Make the entries required by the cluster service in the hive.
  360. //
  361. // Arguments:
  362. // pcfClusterFormIn
  363. // Pointer to the CBaseClusterForm object which contains this object.
  364. //
  365. // Return Value:
  366. // None.
  367. //
  368. // Exceptions Thrown:
  369. // CRuntimeError
  370. // If any of the APIs fail.
  371. //
  372. // Any that are thrown by the called functions.
  373. //
  374. //--
  375. //////////////////////////////////////////////////////////////////////////////
  376. void
  377. CClusDBForm::PopulateHive( CBaseClusterForm * pcfClusterFormIn )
  378. {
  379. TraceFunc( "" );
  380. LogMsg( "[BC] Populating the cluster hive." );
  381. DWORD sc = ERROR_SUCCESS;
  382. do
  383. {
  384. DWORD dwSDSize = 0;
  385. CRegistryKey rkClusterHiveRoot(
  386. HKEY_LOCAL_MACHINE
  387. , CLUSREG_KEYNAME_CLUSTER
  388. , KEY_ALL_ACCESS
  389. );
  390. if ( SetupInstallFromInfSection(
  391. NULL // optional, handle of a parent window
  392. , pcfClusterFormIn->HGetMainInfFileHandle() // handle to the INF file
  393. , CLUSDB_POPULATE_INF_SECTION_NAME // name of the Install section
  394. , SPINST_REGISTRY // which lines to install from section
  395. , rkClusterHiveRoot.HGetKey() // optional, key for registry installs
  396. , NULL // optional, path for source files
  397. , 0 // optional, specifies copy behavior
  398. , NULL // optional, specifies callback routine
  399. , NULL // optional, callback routine context
  400. , NULL // optional, device information set
  401. , NULL // optional, device info structure
  402. ) == FALSE
  403. )
  404. {
  405. sc = TW32( GetLastError() );
  406. LogMsg( "[BC] Error %#08x returned from SetupInstallFromInfSection while trying to populate the cluster hive.", sc );
  407. break;
  408. } // if: SetupInstallServicesFromInfSection failed
  409. LogMsg( "[BC] Basic hive structure created." );
  410. // Set the cluster name.
  411. rkClusterHiveRoot.SetValue(
  412. CLUSREG_NAME_CLUS_NAME
  413. , REG_SZ
  414. , reinterpret_cast< const BYTE * >( pcfClusterFormIn->RStrGetClusterNetBIOSName().PszData() )
  415. , ( pcfClusterFormIn->RStrGetClusterNetBIOSName().NGetLen() + 1 ) * sizeof( WCHAR )
  416. );
  417. //
  418. // Set the default cluster security descriptor.
  419. //
  420. {
  421. SECURITY_DESCRIPTOR * psdSecurityDescriptor = NULL;
  422. // Build the security descriptor.
  423. sc = TW32( ClRtlBuildDefaultClusterSD(
  424. pcfClusterFormIn->PSidGetServiceAccountSID()
  425. , reinterpret_cast< void ** >( &psdSecurityDescriptor )
  426. , &dwSDSize
  427. ) );
  428. // Assign it to a smart pointer for safe release.
  429. CSmartResource<
  430. CHandleTrait<
  431. HLOCAL
  432. , HLOCAL
  433. , LocalFree
  434. >
  435. >
  436. smartSD( reinterpret_cast< HLOCAL >( psdSecurityDescriptor ) );
  437. if ( sc != ERROR_SUCCESS )
  438. {
  439. LogMsg( "[BC] Error %#08x returned from ClRtlBuildDefaultClusterSD().", sc );
  440. break;
  441. } // if: ClRtlBuildDefaultClusterSD() failed.
  442. // Set the security descriptor in the registry.
  443. rkClusterHiveRoot.SetValue(
  444. CLUSREG_NAME_CLUS_SD
  445. , REG_BINARY
  446. , reinterpret_cast< const BYTE * >( psdSecurityDescriptor )
  447. , dwSDSize
  448. );
  449. // Set the NT4 version of the security descriptor in the registry.
  450. rkClusterHiveRoot.SetValue(
  451. CLUSREG_NAME_CLUS_SECURITY
  452. , REG_BINARY
  453. , reinterpret_cast< const BYTE * >( psdSecurityDescriptor )
  454. , dwSDSize
  455. );
  456. }
  457. LogMsg( "[BC] Cluster common properties set." );
  458. //
  459. // Set the values under the HKLM\Cluster\Nodes key.
  460. //
  461. {
  462. DWORD dwTemp;
  463. CRegistryKey rkNodesKey(
  464. rkClusterHiveRoot.HGetKey()
  465. , CLUSREG_KEYNAME_NODES
  466. , KEY_WRITE
  467. );
  468. CRegistryKey rkThisNodeKey;
  469. // Create a subkey for this node.
  470. rkThisNodeKey.CreateKey(
  471. rkNodesKey.HGetKey()
  472. , pcfClusterFormIn->PszGetNodeIdString()
  473. );
  474. // Set the node name.
  475. rkThisNodeKey.SetValue(
  476. CLUSREG_NAME_NODE_NAME
  477. , REG_SZ
  478. , reinterpret_cast< const BYTE *>( pcfClusterFormIn->PszGetNodeName() )
  479. , ( pcfClusterFormIn->DwGetNodeNameLength() + 1 ) * sizeof( WCHAR )
  480. );
  481. // Set the node highest version.
  482. dwTemp = pcfClusterFormIn->DwGetNodeHighestVersion();
  483. rkThisNodeKey.SetValue(
  484. CLUSREG_NAME_NODE_HIGHEST_VERSION
  485. , REG_DWORD
  486. , reinterpret_cast< const BYTE *>( &dwTemp )
  487. , sizeof( dwTemp )
  488. );
  489. // Set the node lowest version.
  490. dwTemp = pcfClusterFormIn->DwGetNodeLowestVersion();
  491. rkThisNodeKey.SetValue(
  492. CLUSREG_NAME_NODE_LOWEST_VERSION
  493. , REG_DWORD
  494. , reinterpret_cast< const BYTE *>( &dwTemp )
  495. , sizeof( dwTemp )
  496. );
  497. }
  498. LogMsg( "[BC] Cluster node subtree customized." );
  499. // Customize the cluster group and the core resources.
  500. CustomizeClusterGroup( pcfClusterFormIn, rkClusterHiveRoot );
  501. // Flush the changes to the registry.
  502. RegFlushKey( rkClusterHiveRoot.HGetKey() );
  503. LogMsg( "[BC] Cluster hive successfully populated." );
  504. }
  505. while( false ); // dummy do-while loop to avoid gotos.
  506. if ( sc != ERROR_SUCCESS )
  507. {
  508. LogMsg( "[BC] Error %#08x occurred while trying to populate the cluster hive. Throwing an exception.", sc );
  509. THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( sc ), IDS_ERROR_CLUSDB_POPULATE_HIVE );
  510. } // if: something went wrong.
  511. TraceFuncExit();
  512. } //*** CClusDBForm::PopulateHive
  513. //////////////////////////////////////////////////////////////////////////////
  514. //++
  515. //
  516. // CClusDBForm::CustomizeClusterGroup
  517. //
  518. // Description:
  519. // Customize the cluster group and the core resources.
  520. //
  521. // Arguments:
  522. // pcfClusterFormIn
  523. // Pointer to the CBaseClusterForm object which contains this object.
  524. //
  525. // rkClusterHiveRootIn
  526. // A CRegistryKey object representing the root of the cluster hive.
  527. //
  528. // Return Value:
  529. // None.
  530. //
  531. // Exceptions Thrown:
  532. // CRuntimeError
  533. // If any of the APIs fail.
  534. //
  535. // Any that are thrown by the called functions.
  536. //
  537. //--
  538. //////////////////////////////////////////////////////////////////////////////
  539. void
  540. CClusDBForm::CustomizeClusterGroup(
  541. CBaseClusterForm * pcfClusterFormIn
  542. , CRegistryKey & rkClusterHiveRootIn
  543. )
  544. {
  545. TraceFunc( "" );
  546. // UUIDs of the cluster group and core resources.
  547. CUuid uuidClusterGroupUuid;
  548. CUuid uuidClusterIPAddressResourceUuid;
  549. CUuid uuidClusterNameResourceUuid;
  550. CUuid uuidLocalQuorumResourceUuid;
  551. // The lengths of the string versions of the above UUIDs.
  552. UINT uiIPUuidLen = (UINT) wcslen( uuidClusterIPAddressResourceUuid.PszGetUuidString() );
  553. UINT uiNameUuidLen = (UINT) wcslen( uuidClusterNameResourceUuid.PszGetUuidString() );
  554. UINT uiLocalQuorumUuidLen = (UINT) wcslen( uuidLocalQuorumResourceUuid.PszGetUuidString() );
  555. UINT uiUuidLen;
  556. // Length of the multisz string that can hold the above resource UUIDs.
  557. uiUuidLen =
  558. ( ( uiIPUuidLen + 1 )
  559. + ( uiNameUuidLen + 1 )
  560. + ( uiLocalQuorumUuidLen + 1 )
  561. + 1
  562. );
  563. // Allocate a buffer for this multisz string.
  564. SmartSz sszResourceUuids( new WCHAR[ uiUuidLen ] );
  565. // Was the memory successfully allocated?
  566. if ( sszResourceUuids.FIsEmpty() )
  567. {
  568. LogMsg( "[BC] Could not allocate %d character in memory. Throwing an exception.", uiUuidLen );
  569. THROW_RUNTIME_ERROR(
  570. E_OUTOFMEMORY
  571. , IDS_ERROR_CUSTOMIZE_CLUSTER_GROUP
  572. );
  573. } // if: memory allocation failed.
  574. //
  575. // Fill this buffer with the uuids of the core resources.
  576. //
  577. // Make sure that the IP address uuid is the first string in this multisz string.
  578. // This is buffer is reused during setting of the network name dependency on the
  579. // IP address resource.
  580. CopyMemory(
  581. sszResourceUuids.PMem()
  582. , uuidClusterIPAddressResourceUuid.PszGetUuidString()
  583. , ( uiIPUuidLen + 1 ) * sizeof( WCHAR )
  584. );
  585. CopyMemory(
  586. sszResourceUuids.PMem() + uiIPUuidLen + 1
  587. , uuidClusterNameResourceUuid.PszGetUuidString()
  588. , ( uiNameUuidLen + 1 ) * sizeof( WCHAR )
  589. );
  590. CopyMemory(
  591. sszResourceUuids.PMem() + uiIPUuidLen + uiNameUuidLen + 2
  592. , uuidLocalQuorumResourceUuid.PszGetUuidString()
  593. , ( uiLocalQuorumUuidLen + 1 ) * sizeof( WCHAR )
  594. );
  595. ( sszResourceUuids.PMem() )[ uiUuidLen - 1 ] = L'\0';
  596. //
  597. // Customize the cluster group.
  598. //
  599. {
  600. CRegistryKey rkClusterGroupKey(
  601. rkClusterHiveRootIn.HGetKey()
  602. , CLUSREG_KEYNAME_GROUPS L"\\" CLUSREG_KEYNAME_CLUSTERGROUP_PLACEHOLDER
  603. , KEY_WRITE
  604. );
  605. // Replace the placeholder for the cluster group key with an actual UUID.
  606. rkClusterGroupKey.RenameKey( uuidClusterGroupUuid.PszGetUuidString() );
  607. // Set the list of contained resources uuids.
  608. rkClusterGroupKey.SetValue(
  609. CLUSREG_NAME_GRP_CONTAINS
  610. , REG_MULTI_SZ
  611. , reinterpret_cast< const BYTE * >( sszResourceUuids.PMem() )
  612. , uiUuidLen * sizeof( WCHAR )
  613. );
  614. LogMsg( "[BC] Cluster group customized." );
  615. }
  616. //
  617. // Customize the localquorum resource and update the HKLM\Quorum key.
  618. //
  619. {
  620. CRegistryKey rkLocalQuorumResourceKey(
  621. rkClusterHiveRootIn.HGetKey()
  622. , CLUSREG_KEYNAME_RESOURCES L"\\" CLUSREG_KEYNAME_LOCALQUORUM_RES_PLACEHOLDER
  623. , KEY_WRITE
  624. );
  625. CRegistryKey rkQuorumKey(
  626. rkClusterHiveRootIn.HGetKey()
  627. , CLUSREG_KEYNAME_QUORUM
  628. , KEY_WRITE
  629. );
  630. // Replace the placeholder for the localquorum resource key with an actual UUID.
  631. rkLocalQuorumResourceKey.RenameKey( uuidLocalQuorumResourceUuid.PszGetUuidString() );
  632. // Set the uuid of the localquorum resource under the HKLM\Quorum key
  633. rkQuorumKey.SetValue(
  634. CLUSREG_NAME_QUORUM_RESOURCE
  635. , REG_SZ
  636. , reinterpret_cast< const BYTE * >( uuidLocalQuorumResourceUuid.PszGetUuidString() )
  637. , ( uiLocalQuorumUuidLen + 1 ) * sizeof( WCHAR )
  638. );
  639. LogMsg( "[BC] Localquorum resource customized." );
  640. }
  641. //
  642. // Set the cluster IP address resource private properties.
  643. //
  644. {
  645. CRegistryKey rkClusterIPResourceKey(
  646. rkClusterHiveRootIn.HGetKey()
  647. , CLUSREG_KEYNAME_RESOURCES L"\\" CLUSREG_KEYNAME_CLUSTERIP_RES_PLACEHOLDER
  648. , KEY_WRITE
  649. );
  650. LPSTR pszAddr; // don't free!
  651. WCHAR szIPBuffer[ 3 + 1 + 3 + 1 + 3 + 1 + 3 + 1 ]; // "xxx.xxx.xxx.xxx\0"
  652. DWORD dwTemp;
  653. int cchWideFormat = 0;
  654. // Replace the placeholder for the cluster IP address resource key with an actual UUID.
  655. rkClusterIPResourceKey.RenameKey( uuidClusterIPAddressResourceUuid.PszGetUuidString() );
  656. // Create the cluster IP address parameters registry key.
  657. CRegistryKey rkIPResParams;
  658. rkIPResParams.CreateKey(
  659. rkClusterIPResourceKey.HGetKey()
  660. , CLUSREG_KEYNAME_PARAMETERS
  661. );
  662. // Format the cluster IP address into a dotted quad.
  663. dwTemp = pcfClusterFormIn->DwGetIPAddress();
  664. pszAddr = inet_ntoa( * (struct in_addr *) &dwTemp );
  665. if ( pszAddr == NULL )
  666. {
  667. LogMsg( "[BC] inet_ntoa() returned NULL. Mapping it to E_OUTOFMEMORY." );
  668. THROW_RUNTIME_ERROR( E_OUTOFMEMORY, IDS_ERROR_CLUSDB_POPULATE_HIVE );
  669. }
  670. cchWideFormat = MultiByteToWideChar(
  671. CP_ACP
  672. , 0
  673. , pszAddr
  674. , -1
  675. , szIPBuffer
  676. , ARRAYSIZE( szIPBuffer )
  677. );
  678. if ( cchWideFormat == 0 )
  679. {
  680. DWORD sc = TW32( GetLastError() );
  681. LogMsg( "[BC] MultiByteToWideChar failed with error %#08x .", sc );
  682. THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( sc ), IDS_ERROR_CUSTOMIZE_CLUSTER_GROUP );
  683. }
  684. // Write the IP address to the registry.
  685. rkIPResParams.SetValue(
  686. CLUSREG_NAME_IPADDR_ADDRESS
  687. , REG_SZ
  688. , reinterpret_cast< const BYTE * >( szIPBuffer )
  689. , ( (UINT) wcslen( szIPBuffer ) + 1 ) * sizeof(WCHAR)
  690. );
  691. // Format the cluster IP subnet mask into a dotted quad.
  692. dwTemp = pcfClusterFormIn->DwGetIPSubnetMask();
  693. pszAddr = inet_ntoa( * (struct in_addr *) &dwTemp );
  694. if ( pszAddr == NULL )
  695. {
  696. LogMsg( "[BC] inet_ntoa() returned NULL. Mapping it to E_OUTOFMEMORY." );
  697. THROW_RUNTIME_ERROR( E_OUTOFMEMORY, IDS_ERROR_CLUSDB_POPULATE_HIVE );
  698. }
  699. cchWideFormat = MultiByteToWideChar(
  700. CP_ACP
  701. , 0
  702. , pszAddr
  703. , -1
  704. , szIPBuffer
  705. , ARRAYSIZE( szIPBuffer )
  706. );
  707. if ( cchWideFormat == 0 )
  708. {
  709. DWORD sc = TW32( GetLastError() );
  710. LogMsg( "[BC] MultiByteToWideChar failed with error %#08x .", sc );
  711. THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( sc ), IDS_ERROR_CUSTOMIZE_CLUSTER_GROUP );
  712. }
  713. // Write the IP subnet mask to the registry.
  714. rkIPResParams.SetValue(
  715. CLUSREG_NAME_IPADDR_SUBNET_MASK
  716. , REG_SZ
  717. , reinterpret_cast< const BYTE * >( szIPBuffer )
  718. , ( (UINT) wcslen( szIPBuffer ) + 1 ) * sizeof(WCHAR)
  719. );
  720. // Write the IP address network to the registry.
  721. rkIPResParams.SetValue(
  722. CLUSREG_NAME_IPADDR_NETWORK
  723. , REG_SZ
  724. , reinterpret_cast< const BYTE * >( pcfClusterFormIn->RStrGetClusterIPNetwork().PszData() )
  725. , ( pcfClusterFormIn->RStrGetClusterIPNetwork().NGetLen() + 1 ) * sizeof( WCHAR )
  726. );
  727. LogMsg( "[BC] IP address resource customized." );
  728. }
  729. //
  730. // Set the cluster network name resource private properties and dependencies.
  731. //
  732. {
  733. CRegistryKey rkClusterNameResourceKey(
  734. rkClusterHiveRootIn.HGetKey()
  735. , CLUSREG_KEYNAME_RESOURCES L"\\" CLUSREG_KEYNAME_CLUSTERNAME_RES_PLACEHOLDER
  736. , KEY_WRITE
  737. );
  738. // Replace the placeholder for the network name resource key with an actual UUID.
  739. rkClusterNameResourceKey.RenameKey( uuidClusterNameResourceUuid.PszGetUuidString() );
  740. //
  741. // Indicate that the network name resource depends on the IP address resource.
  742. //
  743. ( sszResourceUuids.PMem() )[ uiIPUuidLen + 1 ] = L'\0';
  744. rkClusterNameResourceKey.SetValue(
  745. CLUSREG_NAME_RES_DEPENDS_ON
  746. , REG_MULTI_SZ
  747. , reinterpret_cast< const BYTE * >( sszResourceUuids.PMem() )
  748. , ( uiIPUuidLen + 2 ) * sizeof( WCHAR )
  749. );
  750. //
  751. // Create the cluster name parameters registry key.
  752. //
  753. CRegistryKey rkNetNameResParams;
  754. rkNetNameResParams.CreateKey(
  755. rkClusterNameResourceKey.HGetKey()
  756. , CLUSREG_KEYNAME_PARAMETERS
  757. );
  758. // Write the cluster name to the registry.
  759. rkNetNameResParams.SetValue(
  760. CLUSREG_NAME_NETNAME_NAME
  761. , REG_SZ
  762. , reinterpret_cast< const BYTE * >( pcfClusterFormIn->RStrGetClusterNetBIOSName().PszData() )
  763. , ( pcfClusterFormIn->RStrGetClusterNetBIOSName().NGetLen() + 1 ) * sizeof( WCHAR )
  764. );
  765. // Store the UUID of the network name resource under HKLM\Cluster\ClusterNameResource.
  766. rkClusterHiveRootIn.SetValue(
  767. CLUSREG_NAME_CLUS_CLUSTER_NAME_RES
  768. , REG_SZ
  769. , reinterpret_cast< const BYTE * >( uuidClusterNameResourceUuid.PszGetUuidString() )
  770. , ( uiNameUuidLen + 1 ) * sizeof( WCHAR )
  771. );
  772. LogMsg( "[BC] Network name resource customized." );
  773. }
  774. LogMsg( "[BC] Cluster group and core resources customized." );
  775. TraceFuncExit();
  776. } //*** CClusDBForm::CustomizeClusterGroup