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.

449 lines
15 KiB

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