|
|
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1999-2002 Microsoft Corporation
//
// Module Name:
// CBaseClusterAddNode.cpp
//
// Description:
// Contains the definition of the CBaseClusterAddNode class.
//
// Maintained By:
// David Potter (DavidP) 14-JUN-2001
// Vij Vasu (Vvasu) 08-MAR-2000
//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// Include Files
//////////////////////////////////////////////////////////////////////////////
// The precompiled header.
#include "Pch.h"
// The header file of this class.
#include "CBaseClusterAddNode.h"
//////////////////////////////////////////////////////////////////////////////
//++
//
// CBaseClusterAddNode::CBaseClusterAddNode
//
// Description:
// Constructor of the CBaseClusterAddNode class.
//
// This function also stores the parameters that are required for
// creating a cluster and adding nodes to the cluster. At this time,
// only minimal validation is done on the these parameters.
//
// This function also checks if the computer is in the correct state
// for cluster configuration.
//
// Arguments:
// pbcaiInterfaceIn
// Pointer to the interface class for this library.
//
// pszClusterNameIn
// Name of the cluster to be formed or joined.
//
// pcccServiceAccountIn
// Specifies the account to be used as the cluster service account.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CRuntimeError
// If any of the APIs fail.
//
//--
//////////////////////////////////////////////////////////////////////////////
CBaseClusterAddNode::CBaseClusterAddNode( CBCAInterface * pbcaiInterfaceIn , const WCHAR * pcszClusterNameIn , const WCHAR * pcszClusterBindingStringIn , IClusCfgCredentials * pcccServiceAccountIn , DWORD dwClusterIPAddressIn ) : BaseClass( pbcaiInterfaceIn ) , m_pcccServiceAccount( pcccServiceAccountIn ) , m_strClusterBindingString( pcszClusterBindingStringIn ) , m_fIsVersionCheckingDisabled( false ) , m_dwClusterIPAddress( dwClusterIPAddressIn ) { TraceFunc( "" );
DWORD sc = ERROR_SUCCESS; NTSTATUS nsStatus; CBString bstrAccountName; CBString bstrAccountDomain; HRESULT hr = S_OK; CStr strAccountUserPrincipalName;
// Hang onto credentials so that derived classes can use them.
m_pcccServiceAccount->AddRef(); hr = THR( m_pcccServiceAccount->GetIdentity( &bstrAccountName, &bstrAccountDomain ) ); TraceMemoryAddBSTR( static_cast< BSTR >( bstrAccountName ) ); TraceMemoryAddBSTR( static_cast< BSTR >( bstrAccountDomain ) ); if ( FAILED( hr ) ) { LogMsg( "[BC] Failed to retrieve cluster account credentials. Throwing an exception." ); THROW_CONFIG_ERROR( hr, IDS_ERROR_INVALID_CLUSTER_ACCOUNT ); } //
// Perform a sanity check on the parameters used by this class
//
if ( ( pcszClusterNameIn == NULL ) || ( *pcszClusterNameIn == L'\0' ) ) { LogMsg( "[BC] The cluster name is invalid. Throwing an exception." ); THROW_CONFIG_ERROR( E_INVALIDARG, IDS_ERROR_INVALID_CLUSTER_NAME ); } // if: the cluster name is empty
if ( bstrAccountName.Length() == 0 ) { LogMsg( "[BC] The cluster account name is empty. Throwing an exception." ); THROW_CONFIG_ERROR( E_INVALIDARG, IDS_ERROR_INVALID_CLUSTER_ACCOUNT ); } // if: the cluster account is empty
//
// Set the cluster name. This method also converts the
// cluster name to its NetBIOS name.
//
SetClusterName( pcszClusterNameIn );
strAccountUserPrincipalName = StrGetServiceAccountUPN();
//
// Write parameters to log file.
//
LogMsg( "[BC] Cluster Name => '%s'", m_strClusterName.PszData() ); LogMsg( "[BC] Cluster Service Account => '%s'", strAccountUserPrincipalName.PszData() );
//
// Open a handle to the LSA policy. This is used by several action classes.
//
{ LSA_OBJECT_ATTRIBUTES loaObjectAttributes; LSA_HANDLE hPolicyHandle;
ZeroMemory( &loaObjectAttributes, sizeof( loaObjectAttributes ) );
nsStatus = LsaOpenPolicy( NULL // System name
, &loaObjectAttributes // Object attributes.
, POLICY_ALL_ACCESS // Desired Access
, &hPolicyHandle // Policy handle
);
if ( nsStatus != STATUS_SUCCESS ) { LogMsg( "[BC] Error %#08x occurred trying to open the LSA Policy.", nsStatus ); THROW_RUNTIME_ERROR( nsStatus, IDS_ERROR_LSA_POLICY_OPEN ); } // if LsaOpenPolicy failed.
// Store the opened handle in the member variable.
m_slsahPolicyHandle.Assign( hPolicyHandle ); }
//
// Make sure that this computer is part of a domain.
//
{ PPOLICY_PRIMARY_DOMAIN_INFO ppolDomainInfo = NULL; bool fIsPartOfDomain;
// Get information about the primary domain of this computer.
nsStatus = THR( LsaQueryInformationPolicy( HGetLSAPolicyHandle() , PolicyPrimaryDomainInformation , reinterpret_cast< PVOID * >( &ppolDomainInfo ) ) );
// Check if this computer is part of a domain and free the allocated memory.
fIsPartOfDomain = ( ppolDomainInfo->Sid != NULL ); LsaFreeMemory( ppolDomainInfo );
if ( NT_SUCCESS( nsStatus ) == FALSE ) { LogMsg( "[BC] Error %#08x occurred trying to obtain the primary domain of this computer. Cannot proceed (throwing an exception).", sc );
THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( sc ), IDS_ERROR_GETTING_PRIMARY_DOMAIN ); } // LsaQueryInformationPolicy() failed.
if ( ! fIsPartOfDomain ) { THROW_CONFIG_ERROR( HRESULT_FROM_WIN32( ERROR_INVALID_DOMAINNAME ), IDS_ERROR_NO_DOMAIN ); } // if: this computer is not a part of a domain
}
//
// Lookup the cluster service account SID and store it.
//
do { DWORD dwSidSize = 0; DWORD dwDomainSize = 0; SID_NAME_USE snuSidNameUse;
// Find out how much space is required by the SID.
if ( LookupAccountNameW( NULL , strAccountUserPrincipalName.PszData() , NULL , &dwSidSize , NULL , &dwDomainSize , &snuSidNameUse ) == FALSE ) { sc = GetLastError();
if ( sc != ERROR_INSUFFICIENT_BUFFER ) { TW32( sc ); LogMsg( "[BC] LookupAccountNameW() failed with error %#08x while querying for required buffer size.", sc ); break; } // if: something else has gone wrong.
else { // This is expected.
sc = ERROR_SUCCESS; } // if: ERROR_INSUFFICIENT_BUFFER was returned.
} // if: LookupAccountNameW failed
// Allocate memory for the new SID and the domain name.
m_sspClusterAccountSid.Assign( reinterpret_cast< SID * >( new BYTE[ dwSidSize ] ) ); SmartSz sszDomainName( new WCHAR[ dwDomainSize ] );
if ( m_sspClusterAccountSid.FIsEmpty() || sszDomainName.FIsEmpty() ) { sc = TW32( ERROR_OUTOFMEMORY ); break; } // if: there wasn't enough memory for this SID.
// Fill in the SID
if ( LookupAccountNameW( NULL , strAccountUserPrincipalName.PszData() , m_sspClusterAccountSid.PMem() , &dwSidSize , sszDomainName.PMem() , &dwDomainSize , &snuSidNameUse ) == FALSE ) { sc = TW32( GetLastError() ); LogMsg( "[BC] LookupAccountNameW() failed with error %#08x while attempting to get the cluster account SID.", sc ); break; } // if: LookupAccountNameW failed
} while( false ); // dummy do-while loop to avoid gotos.
if ( sc != ERROR_SUCCESS ) { LogMsg( "[BC] Error %#08x occurred trying to validate the cluster service account. Cannot proceed (throwing an exception).", sc );
THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( sc ), IDS_ERROR_VALIDATING_ACCOUNT ); } // if: we could not get the cluster account SID
// Check if the installation state of the cluster binaries is correct.
{ eClusterInstallState ecisInstallState;
sc = TW32( ClRtlGetClusterInstallState( NULL, &ecisInstallState ) );
if ( sc != ERROR_SUCCESS ) { LogMsg( "[BC] Error %#08x occurred trying to get cluster installation state. Throwing an exception.", sc );
THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( sc ), IDS_ERROR_GETTING_INSTALL_STATE ); } // if: there was a problem getting the cluster installation state
LogMsg( "[BC] Current install state = %d. Required %d.", ecisInstallState, eClusterInstallStateFilesCopied );
//
// The installation state should be that the binaries have been copied
// but the cluster service has not been configured.
//
if ( ecisInstallState != eClusterInstallStateFilesCopied ) { LogMsg( "[BC] The cluster installation state is set to %d. Expected %d. Cannot proceed (throwing an exception).", ecisInstallState, eClusterInstallStateFilesCopied );
THROW_CONFIG_ERROR( HRESULT_FROM_WIN32( TW32( ERROR_INVALID_STATE ) ), IDS_ERROR_INCORRECT_INSTALL_STATE ); } // if: the installation state is not correct
LogMsg( "[BC] The cluster installation state is correct. Configuration can proceed." ); }
// Get the name and version information for this node.
{ m_dwComputerNameLen = sizeof( m_szComputerName );
// Get the computer name.
if ( GetComputerNameW( m_szComputerName, &m_dwComputerNameLen ) == FALSE ) { sc = TW32( GetLastError() ); LogMsg( "[BC] Error %#08x occurred trying to get the name of this computer. Configuration cannot proceed (throwing an exception).", sc ); THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( sc ), IDS_ERROR_GETTING_COMPUTER_NAME ); } // if: GetComputerNameW() failed.
m_dwNodeHighestVersion = CLUSTER_MAKE_VERSION( CLUSTER_INTERNAL_CURRENT_MAJOR_VERSION, VER_PRODUCTBUILD ); m_dwNodeLowestVersion = CLUSTER_INTERNAL_PREVIOUS_HIGHEST_VERSION;
LogMsg( "[BC] Computer Name = '%ws' (Length %d), NodeHighestVersion = %#08x, NodeLowestVersion = %#08x." , m_szComputerName , m_dwComputerNameLen , m_dwNodeHighestVersion , m_dwNodeLowestVersion ); }
TraceFuncExit();
} //*** CBaseClusterAddNode::CBaseClusterAddNode
//////////////////////////////////////////////////////////////////////////////
//++
//
// CBaseClusterAddNode::~CBaseClusterAddNode
//
// Description:
// Destructor of the CBaseClusterAddNode class
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
CBaseClusterAddNode::~CBaseClusterAddNode( void ) throw() { TraceFunc( "" ); if ( m_pcccServiceAccount != NULL ) { m_pcccServiceAccount->Release(); } TraceFuncExit();
} //*** CBaseClusterAddNode::~CBaseClusterAddNode
//////////////////////////////////////////////////////////////////////////////
//++
//
// CBaseClusterAddNode::SetClusterName
//
// Description:
// Set the name of the cluster being formed.
//
// Arguments:
// pszClusterNameIn -- Name of the cluster.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
void CBaseClusterAddNode::SetClusterName( LPCWSTR pszClusterNameIn ) { TraceFunc( "" );
BOOL fSuccess; DWORD sc; WCHAR szClusterNetBIOSName[ MAX_COMPUTERNAME_LENGTH + 1 ]; DWORD nSize = ARRAYSIZE( szClusterNetBIOSName );
m_strClusterName = pszClusterNameIn;
fSuccess = DnsHostnameToComputerNameW( pszClusterNameIn , szClusterNetBIOSName , &nSize ); if ( ! fSuccess ) { sc = TW32( GetLastError() ); LogMsg( "[BC] Error %#08x occurred trying to convert the cluster name '%ls' to a NetBIOS name. Throwing an exception.", sc, pszClusterNameIn ); THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( sc ), IDS_ERROR_CVT_CLUSTER_NAME ); }
m_strClusterNetBIOSName = szClusterNetBIOSName;
TraceFuncExit();
} //*** CBaseClusterAddNode::SetClusterName
//////////////////////////////////////////////////////////////////////////////
//++
//
// CBaseClusterAddNode::StrGetServiceAccountUPN
//
// Description:
// Get the User Principal Name (in domain\name format) of the cluster
// service account.
//
// Arguments:
// None.
//
// Return Value:
// The service account UPN.
//
// Exceptions Thrown:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
CStr CBaseClusterAddNode::StrGetServiceAccountUPN( void ) { TraceFunc( "" );
CBString bstrName; CBString bstrDomain; HRESULT hr = m_pcccServiceAccount->GetIdentity( &bstrName, &bstrDomain );
if ( bstrName.IsEmpty() == FALSE ) { TraceMemoryAddBSTR( static_cast< BSTR >( bstrName ) ); }
if ( bstrDomain.IsEmpty() == FALSE ) { TraceMemoryAddBSTR( static_cast< BSTR >( bstrDomain ) ); }
if ( FAILED( hr ) ) { LogMsg( "[BC] Failed to retrieve cluster account credentials. Throwing an exception." ); THROW_CONFIG_ERROR( hr, IDS_ERROR_INVALID_CLUSTER_ACCOUNT ); }
RETURN( CStr( CStr( bstrDomain ) + CStr( L"\\" ) + CStr( bstrName ) ) );
} //*** CBaseClusterAddNode::StrGetServiceAccountUPN
|