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.

405 lines
14 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1999-2000 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // CBaseClusterAddNode.cpp
  7. //
  8. // Description:
  9. // Contains the definition of the CBaseClusterAddNode 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. // The header file of this class.
  21. #include "CBaseClusterAddNode.h"
  22. // For OS version checking, installation state, etc.
  23. #include "clusrtl.h"
  24. // For CLUSTER_INTERNAL_CURRENT_MAJOR_VERSION and other version defines.
  25. #include "clusverp.h"
  26. //////////////////////////////////////////////////////////////////////////////
  27. //++
  28. //
  29. // CBaseClusterAddNode::CBaseClusterAddNode
  30. //
  31. // Description:
  32. // Constructor of the CBaseClusterAddNode class.
  33. //
  34. // This function also stores the parameters that are required for
  35. // cluster form and join. At this time, only minimal validation is done
  36. // on the these parameters.
  37. //
  38. // This function also checks if the computer is in the correct state
  39. // for cluster configuration.
  40. //
  41. // Arguments:
  42. // pbcaiInterfaceIn
  43. // Pointer to the interface class for this library.
  44. //
  45. // pszClusterNameIn
  46. // Name of the cluster to be formed or joined.
  47. //
  48. // pszClusterAccountNameIn
  49. // pszClusterAccountPwdIn
  50. // pszClusterAccountDomainIn
  51. // Specifies the account to be used as the cluster service account.
  52. //
  53. // Return Value:
  54. // None.
  55. //
  56. // Exceptions Thrown:
  57. // CRuntimeError
  58. // If any of the APIs fail.
  59. //
  60. //--
  61. //////////////////////////////////////////////////////////////////////////////
  62. CBaseClusterAddNode::CBaseClusterAddNode(
  63. CBCAInterface * pbcaiInterfaceIn
  64. , const WCHAR * pcszClusterNameIn
  65. , const WCHAR * pcszClusterBindingStringIn
  66. , const WCHAR * pcszClusterAccountNameIn
  67. , const WCHAR * pcszClusterAccountPwdIn
  68. , const WCHAR * pcszClusterAccountDomainIn
  69. )
  70. : BaseClass( pbcaiInterfaceIn )
  71. , m_strClusterAccountName( pcszClusterAccountNameIn )
  72. , m_strClusterAccountPwd( pcszClusterAccountPwdIn )
  73. , m_strClusterAccountDomain( pcszClusterAccountDomainIn )
  74. , m_strClusterBindingString( pcszClusterBindingStringIn )
  75. , m_fIsVersionCheckingDisabled( false )
  76. {
  77. BCATraceScope( "" );
  78. DWORD dwError = ERROR_SUCCESS;
  79. NTSTATUS nsStatus;
  80. //
  81. // Perform a sanity check on the parameters used by this class
  82. //
  83. if ( ( pcszClusterNameIn == NULL ) || ( *pcszClusterNameIn == L'\0' ) )
  84. {
  85. BCATraceMsg( "The cluster name is invalid. Throwing exception." );
  86. LogMsg( "The cluster name is invalid." );
  87. THROW_CONFIG_ERROR( E_INVALIDARG, IDS_ERROR_INVALID_CLUSTER_NAME );
  88. } // if: the cluster name is empty
  89. if ( ( pcszClusterAccountNameIn == NULL ) || ( *pcszClusterAccountNameIn == L'\0' ) )
  90. {
  91. BCATraceMsg( "The cluster account name is empty. Throwing exception." );
  92. LogMsg( "The cluster account name is invalid." );
  93. THROW_CONFIG_ERROR( E_INVALIDARG, IDS_ERROR_INVALID_CLUSTER_ACCOUNT );
  94. } // if: the cluster account is empty
  95. //
  96. // Set the cluster name. This method also converts the
  97. // cluster name to its NetBIOS name.
  98. //
  99. SetClusterName( pcszClusterNameIn );
  100. m_strClusterDomainAccount = m_strClusterAccountDomain + L"\\";
  101. m_strClusterDomainAccount += m_strClusterAccountName;
  102. //
  103. // Write parameters to log file.
  104. //
  105. LogMsg( "Cluster Name => '%s'", m_strClusterName.PszData() );
  106. LogMsg( "Cluster Service Account => '%s'", m_strClusterDomainAccount.PszData() );
  107. //
  108. // Open a handle to the LSA policy. This is used by several action classes.
  109. //
  110. {
  111. LSA_OBJECT_ATTRIBUTES loaObjectAttributes;
  112. LSA_HANDLE hPolicyHandle;
  113. ZeroMemory( &loaObjectAttributes, sizeof( loaObjectAttributes ) );
  114. nsStatus = LsaOpenPolicy(
  115. NULL // System name
  116. , &loaObjectAttributes // Object attributes.
  117. , POLICY_ALL_ACCESS // Desired Access
  118. , &hPolicyHandle // Policy handle
  119. );
  120. if ( nsStatus != STATUS_SUCCESS )
  121. {
  122. LogMsg( "Error %#08x occurred trying to open the LSA Policy.", nsStatus );
  123. BCATraceMsg1( "Error %#08x occurred trying to open the LSA Policy.", nsStatus );
  124. THROW_RUNTIME_ERROR( nsStatus, IDS_ERROR_LSA_POLICY_OPEN );
  125. } // if LsaOpenPolicy failed.
  126. // Store the opened handle in the member variable.
  127. m_slsahPolicyHandle.Assign( hPolicyHandle );
  128. }
  129. //
  130. // Make sure that this computer is part of a domain.
  131. //
  132. {
  133. PPOLICY_PRIMARY_DOMAIN_INFO ppolDomainInfo = NULL;
  134. bool fIsPartOfDomain;
  135. // Get information about the primary domain of this computer.
  136. nsStatus = THR( LsaQueryInformationPolicy(
  137. HGetLSAPolicyHandle()
  138. , PolicyPrimaryDomainInformation
  139. , reinterpret_cast< PVOID * >( &ppolDomainInfo )
  140. ) );
  141. // Check if this computer is part of a domain and free the allocated memory.
  142. fIsPartOfDomain = ( ppolDomainInfo->Sid != NULL );
  143. LsaFreeMemory( ppolDomainInfo );
  144. if ( NT_SUCCESS( nsStatus ) == FALSE )
  145. {
  146. LogMsg( "Error %#08x occurred trying to obtain the primary domain of this computer. Cannot proceed.", dwError );
  147. BCATraceMsg1( "Error %#08x occurred trying to obtain the primary domain of this computer. Cannot proceed.", dwError );
  148. THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( dwError ), IDS_ERROR_GETTING_PRIMARY_DOMAIN );
  149. } // LsaQueryInformationPolicy() failed.
  150. if ( ! fIsPartOfDomain )
  151. {
  152. THROW_CONFIG_ERROR( HRESULT_FROM_WIN32( ERROR_INVALID_DOMAINNAME ), IDS_ERROR_NO_DOMAIN );
  153. } // if: this computer is not a part of a domain
  154. }
  155. //
  156. // Lookup the cluster service account SID and store it.
  157. //
  158. do
  159. {
  160. DWORD dwSidSize = 0;
  161. DWORD dwDomainSize = 0;
  162. SID_NAME_USE snuSidNameUse;
  163. // Find out how much space is required by the SID.
  164. if ( LookupAccountName(
  165. NULL
  166. , m_strClusterDomainAccount.PszData()
  167. , NULL
  168. , &dwSidSize
  169. , NULL
  170. , &dwDomainSize
  171. , &snuSidNameUse
  172. )
  173. == FALSE
  174. )
  175. {
  176. dwError = GetLastError();
  177. if ( dwError != ERROR_INSUFFICIENT_BUFFER )
  178. {
  179. TW32( dwError );
  180. BCATraceMsg( "LookupAccountName() failed while querying for required buffer size." );
  181. break;
  182. } // if: something else has gone wrong.
  183. else
  184. {
  185. // This is expected.
  186. dwError = ERROR_SUCCESS;
  187. } // if: ERROR_INSUFFICIENT_BUFFER was returned.
  188. } // if: LookupAccountName failed
  189. // Allocate memory for the new SID and the domain name.
  190. m_sspClusterAccountSid.Assign( reinterpret_cast< SID * >( new BYTE[ dwSidSize ] ) );
  191. SmartSz sszDomainName( new WCHAR[ dwDomainSize ] );
  192. if ( m_sspClusterAccountSid.FIsEmpty() || sszDomainName.FIsEmpty() )
  193. {
  194. dwError = TW32( ERROR_OUTOFMEMORY );
  195. break;
  196. } // if: there wasn't enough memory for this SID.
  197. // Fill in the SID
  198. if ( LookupAccountName(
  199. NULL
  200. , m_strClusterDomainAccount.PszData()
  201. , m_sspClusterAccountSid.PMem()
  202. , &dwSidSize
  203. , sszDomainName.PMem()
  204. , &dwDomainSize
  205. , &snuSidNameUse
  206. )
  207. == FALSE
  208. )
  209. {
  210. dwError = TW32( GetLastError() );
  211. BCATraceMsg( "LookupAccountName() failed while attempting to get the cluster account SID." );
  212. break;
  213. } // if: LookupAccountName failed
  214. }
  215. while( false ); // dummy do-while loop to avoid gotos.
  216. if ( dwError != ERROR_SUCCESS )
  217. {
  218. LogMsg( "Error %#08x occurred trying to validate the cluster service account. Cannot proceed.", dwError );
  219. BCATraceMsg1( "Error %#08x occurred trying to lookup the cluster service account. Throwing exception.", dwError );
  220. THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( dwError ), IDS_ERROR_VALIDATING_ACCOUNT );
  221. } // if: we could not get the cluster account SID
  222. // Check if the installation state of the cluster binaries is correct.
  223. {
  224. eClusterInstallState ecisInstallState;
  225. dwError = TW32( ClRtlGetClusterInstallState( NULL, &ecisInstallState ) );
  226. if ( dwError != ERROR_SUCCESS )
  227. {
  228. LogMsg( "Error %#08x occurred trying to get cluster installation state.", dwError );
  229. BCATraceMsg1( "Error %#08x occurred trying to get cluster installation state. Throwing exception.", dwError );
  230. THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( dwError ), IDS_ERROR_GETTING_INSTALL_STATE );
  231. } // if: there was a problem getting the cluster installation state
  232. BCATraceMsg2(
  233. "Current install state = %d. Required %d."
  234. , ecisInstallState
  235. , eClusterInstallStateFilesCopied
  236. );
  237. //
  238. // The installation state should be that the binaries have been copied
  239. // but the cluster service has not been configured.
  240. //
  241. if ( ecisInstallState != eClusterInstallStateFilesCopied )
  242. {
  243. LogMsg( "The cluster installation state is set to %d. Expected %d. Cannot proceed.", ecisInstallState, eClusterInstallStateFilesCopied );
  244. BCATraceMsg1( "Cluster installation state is set to %d, which is incorrect. Throwing exception.", ecisInstallState );
  245. THROW_CONFIG_ERROR( HRESULT_FROM_WIN32( TW32( ERROR_INVALID_STATE ) ), IDS_ERROR_INCORRECT_INSTALL_STATE );
  246. } // if: the installation state is not correct
  247. LogMsg( "The cluster installation state is correct. Configuration can proceed." );
  248. }
  249. // Get the name and version information for this node.
  250. {
  251. m_dwComputerNameLen = sizeof( m_szComputerName );
  252. // Get the computer name.
  253. if ( GetComputerName( m_szComputerName, &m_dwComputerNameLen ) == FALSE )
  254. {
  255. dwError = TW32( GetLastError() );
  256. BCATraceMsg1( "GetComputerName() failed. Error code is %#08x. Throwing exception.", dwError );
  257. LogMsg( "Could not get the name of this computer. Error code is %#08x. Configuration cannot proceed.", dwError );
  258. THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( dwError ), IDS_ERROR_GETTING_COMPUTER_NAME );
  259. } // if: GetComputerName() failed.
  260. m_dwNodeHighestVersion = CLUSTER_MAKE_VERSION( CLUSTER_INTERNAL_CURRENT_MAJOR_VERSION, VER_PRODUCTBUILD );
  261. m_dwNodeLowestVersion = CLUSTER_INTERNAL_PREVIOUS_HIGHEST_VERSION;
  262. BCATraceMsg4(
  263. "Computer Name = '%ws' (Length %d), NodeHighestVersion = %#08x, NodeLowestVersion = %#08x."
  264. , m_szComputerName
  265. , m_dwComputerNameLen
  266. , m_dwNodeHighestVersion
  267. , m_dwNodeLowestVersion
  268. );
  269. LogMsg(
  270. "Computer Name = '%ws' (Length %d), NodeHighestVersion = %#08x, NodeLowestVersion = %#08x."
  271. , m_szComputerName
  272. , m_dwComputerNameLen
  273. , m_dwNodeHighestVersion
  274. , m_dwNodeLowestVersion
  275. );
  276. }
  277. } //*** CBaseClusterAddNode::CBaseClusterAddNode()
  278. //////////////////////////////////////////////////////////////////////////////
  279. //++
  280. //
  281. // CBaseClusterAddNode::~CBaseClusterAddNode
  282. //
  283. // Description:
  284. // Destructor of the CBaseClusterAddNode class
  285. //
  286. // Arguments:
  287. // None.
  288. //
  289. // Return Value:
  290. // None.
  291. //
  292. // Exceptions Thrown:
  293. // None.
  294. //
  295. //--
  296. //////////////////////////////////////////////////////////////////////////////
  297. CBaseClusterAddNode::~CBaseClusterAddNode( void ) throw()
  298. {
  299. BCATraceScope( "" );
  300. } //*** CBaseClusterAddNode::~CBaseClusterAddNode()
  301. //////////////////////////////////////////////////////////////////////////////
  302. //++
  303. //
  304. // CBaseClusterAddNode::SetClusterName
  305. //
  306. // Description:
  307. // Set the name of the cluster being formed.
  308. //
  309. // Arguments:
  310. // pszClusterNameIn -- Name of the cluster.
  311. //
  312. // Return Value:
  313. // None.
  314. //
  315. // Exceptions Thrown:
  316. // None.
  317. //
  318. //--
  319. //////////////////////////////////////////////////////////////////////////////
  320. void
  321. CBaseClusterAddNode::SetClusterName(
  322. LPCWSTR pszClusterNameIn
  323. )
  324. {
  325. BCATraceScope( "" );
  326. BOOL fSuccess;
  327. DWORD dwError;
  328. WCHAR szClusterNetBIOSName[ MAX_COMPUTERNAME_LENGTH + 1 ];
  329. DWORD nSize = sizeof( szClusterNetBIOSName ) / sizeof( szClusterNetBIOSName[ 0 ] );
  330. m_strClusterName = pszClusterNameIn;
  331. fSuccess = DnsHostnameToComputerNameW(
  332. pszClusterNameIn
  333. , szClusterNetBIOSName
  334. , &nSize
  335. );
  336. if ( ! fSuccess )
  337. {
  338. dwError = TW32( GetLastError() );
  339. LogMsg( "Error %#08x occurred trying to convert the cluster name '%ls' to a NetBIOS name.", dwError, pszClusterNameIn );
  340. BCATraceMsg2( "Error %#08x occurred trying to convert the cluster name '%ls' to a NetBIOS name. Throwing exception.", dwError, pszClusterNameIn );
  341. THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( dwError ), IDS_ERROR_CVT_CLUSTER_NAME );
  342. }
  343. m_strClusterNetBIOSName = szClusterNetBIOSName;
  344. } //*** CBaseClusterAddNode::SetClusterName()