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.
 
 
 
 
 
 

1557 lines
38 KiB

//***************************************************************************
//
// UTILS.CPP
//
// Module: NLB Manager (client-side exe)
//
// Purpose: Misc utilities
//
// Copyright (c)2001 Microsoft Corporation, All Rights Reserved
//
// History:
//
// 07/25/01 JosephJ Created
//
//***************************************************************************
#include "precomp.h"
#pragma hdrstop
#include "wlbsutil.h"
#include "private.h"
#include "utils.tmh"
#define szNLBMGRREG_BASE_KEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NLB"
LPCWSTR
clustermode_description(
const WLBS_REG_PARAMS *pParams
);
LPCWSTR
rct_description(
const WLBS_REG_PARAMS *pParams
);
// default constructor
//
ClusterProperties::ClusterProperties()
{
cIP = L"0.0.0.0";
cSubnetMask = L"0.0.0.0";
#define szDEFAULT_CLUSTER_NAME L"www.nlb-cluster.com"
cFullInternetName = szDEFAULT_CLUSTER_NAME;
cNetworkAddress = L"00-00-00-00-00-00";
multicastSupportEnabled = false;
remoteControlEnabled = false;
password = L"";
igmpSupportEnabled = false;
clusterIPToMulticastIP = true;
}
// equality operator
//
bool
ClusterProperties::operator==( const ClusterProperties& objToCompare )
{
bool btemp1, btemp2; // Variables to pass to below function. Returned values not used
return !HaveClusterPropertiesChanged(objToCompare, &btemp1, &btemp2);
}
// equality operator
//
bool
ClusterProperties::HaveClusterPropertiesChanged( const ClusterProperties& objToCompare,
bool *pbOnlyClusterNameChanged,
bool *pbClusterIpChanged)
{
*pbClusterIpChanged = false;
*pbOnlyClusterNameChanged = false;
if( cIP != objToCompare.cIP )
{
*pbClusterIpChanged = true;
return true;
}
else if (
( cSubnetMask != objToCompare.cSubnetMask )
||
( cNetworkAddress != objToCompare.cNetworkAddress )
||
( multicastSupportEnabled != objToCompare.multicastSupportEnabled )
||
( igmpSupportEnabled != objToCompare.igmpSupportEnabled )
||
( clusterIPToMulticastIP != objToCompare.clusterIPToMulticastIP )
)
{
return true;
}
else if (
( cFullInternetName != objToCompare.cFullInternetName )
||
( remoteControlEnabled != objToCompare.remoteControlEnabled )
)
{
*pbOnlyClusterNameChanged = true;
return true;
}
else if (
( remoteControlEnabled == true )
&&
( password != objToCompare.password )
)
{
*pbOnlyClusterNameChanged = true;
return true;
}
return false;
}
// inequality operator
//
bool
ClusterProperties::operator!=( const ClusterProperties& objToCompare )
{
bool btemp1, btemp2; // Variables to pass to below function. Returned values not used
return HaveClusterPropertiesChanged(objToCompare, &btemp1, &btemp2);
}
// default constructor
//
HostProperties::HostProperties()
{
// TODO set all properties with default values.
}
// equality operator
//
bool
HostProperties::operator==( const HostProperties& objToCompare )
{
if( ( hIP == objToCompare.hIP )
&&
( hSubnetMask == objToCompare.hSubnetMask )
&&
( hID == objToCompare.hID )
&&
( initialClusterStateActive == objToCompare.initialClusterStateActive )
&&
( machineName == objToCompare.machineName )
)
{
return true;
}
else
{
return false;
}
}
// inequality operator
//
bool
HostProperties::operator!=( const HostProperties& objToCompare )
{
return !operator==(objToCompare );
}
_bstr_t
CommonUtils::getCIPAddressCtrlString( CIPAddressCtrl& ip )
{
unsigned long addr;
ip.GetAddress( addr );
PUCHAR bp = (PUCHAR) &addr;
wchar_t buf[BUF_SIZE];
StringCbPrintf(buf, sizeof(buf), L"%d.%d.%d.%d", bp[3], bp[2], bp[1], bp[0] );
return _bstr_t( buf );
}
void
CommonUtils::fillCIPAddressCtrlString( CIPAddressCtrl& ip,
const _bstr_t& ipAddress )
{
// set the IPAddress control to blank if ipAddress is zero.
unsigned long addr = inet_addr( ipAddress );
if( addr != 0 )
{
PUCHAR bp = (PUCHAR) &addr;
ip.SetAddress( bp[0], bp[1], bp[2], bp[3] );
}
else
{
ip.ClearAddress();
}
}
void
CommonUtils::getVectorFromSafeArray( SAFEARRAY*& stringArray,
vector<_bstr_t>& strings )
{
LONG count = stringArray->rgsabound[0].cElements;
BSTR* pbstr;
HRESULT hr;
if( SUCCEEDED( SafeArrayAccessData( stringArray, ( void **) &pbstr)))
{
for( LONG x = 0; x < count; x++ )
{
strings.push_back( pbstr[x] );
}
hr = SafeArrayUnaccessData( stringArray );
}
}
// checkIfValid
//
bool
MIPAddress::checkIfValid( const _bstr_t& ipAddrToCheck )
{
// The validity rules are as follows
//
// The first byte (FB) has to be : 0 < FB < 224 && FB != 127
// Note that 127 is loopback address.
// hostid portion of an address cannot be zero.
//
// class A range is 1 - 126. hostid portion is last 3 bytes.
// class B range is 128 - 191 hostid portion is last 2 bytes
// class C range is 192 - 223 hostid portion is last byte.
// split up the ipAddrToCheck into its 4 bytes.
//
WTokens tokens;
tokens.init( wstring( ipAddrToCheck ) , L".");
vector<wstring> byteTokens = tokens.tokenize();
if( byteTokens.size() != 4 )
{
return false;
}
int firstByte = _wtoi( byteTokens[0].c_str() );
int secondByte = _wtoi( byteTokens[1].c_str() );
int thirdByte = _wtoi( byteTokens[2].c_str() );
int fourthByte = _wtoi( byteTokens[3].c_str() );
// check firstByte
if ( ( firstByte > 0 )
&&
( firstByte < 224 )
&&
( firstByte != 127 )
)
{
// check that host id portion is not zero.
IPClass ipClass;
getIPClass( ipAddrToCheck, ipClass );
switch( ipClass )
{
case classA :
// last three bytes should not be zero.
if( ( _wtoi( byteTokens[1].c_str() ) == 0 )
&&
( _wtoi( byteTokens[2].c_str() )== 0 )
&&
( _wtoi( byteTokens[3].c_str() )== 0 )
)
{
return false;
}
break;
case classB :
// last two bytes should not be zero.
if( ( _wtoi( byteTokens[2].c_str() )== 0 )
&&
( _wtoi( byteTokens[3].c_str() )== 0 )
)
{
return false;
}
break;
case classC :
// last byte should not be zero.
if( _wtoi( byteTokens[3].c_str() )
== 0 )
{
return false;
}
break;
default :
// this should not have happened.
return false;
break;
}
return true;
}
else
{
return false;
}
}
// getDefaultSubnetMask
//
bool
MIPAddress::getDefaultSubnetMask( const _bstr_t& ipAddr,
_bstr_t& subnetMask )
{
// first ensure that the ip is valid.
//
bool isValid = checkIfValid( ipAddr );
if( isValid == false )
{
return false;
}
// get the class to which this ip belongs.
// as this determines the subnet.
IPClass ipClass;
getIPClass( ipAddr,
ipClass );
switch( ipClass )
{
case classA :
subnetMask = L"255.0.0.0";
break;
case classB :
subnetMask = L"255.255.0.0";
break;
case classC :
subnetMask = L"255.255.255.0";
break;
default :
// this should not have happened.
return false;
break;
}
return true;
}
// getIPClass
//
bool
MIPAddress::getIPClass( const _bstr_t& ipAddr,
IPClass& ipClass )
{
// get the first byte of the ipAddr
WTokens tokens;
tokens.init( wstring( ipAddr ) , L".");
vector<wstring> byteTokens = tokens.tokenize();
if( byteTokens.size() == 0 )
{
return false;
}
int firstByte = _wtoi( byteTokens[0].c_str() );
if( ( firstByte >= 1 )
&&
( firstByte <= 126 )
)
{
// classA
ipClass = classA;
return true;
}
else if( (firstByte >= 128 )
&&
(firstByte <= 191 )
)
{
// classB
ipClass = classB;
return true;
}
else if( (firstByte >= 192 )
&&
(firstByte <= 223 )
)
{
// classC
ipClass = classC;
return true;
}
else if( (firstByte >= 224 )
&&
(firstByte <= 239 )
)
{
// classD
ipClass = classD;
return true;
}
else if( (firstByte >= 240 )
&&
(firstByte <= 247 )
)
{
// classE
ipClass = classE;
return true;
}
else
{
// invalid net portiion.
return false;
}
}
bool
MIPAddress::isValidIPAddressSubnetMaskPair( const _bstr_t& ipAddress,
const _bstr_t& subnetMask )
{
if( IsValidIPAddressSubnetMaskPair( ipAddress, subnetMask ) == TRUE )
{
return true;
}
else
{
return false;
}
}
bool
MIPAddress::isContiguousSubnetMask( const _bstr_t& subnetMask )
{
if( IsContiguousSubnetMask( subnetMask ) == TRUE )
{
return true;
}
else
{
return false;
}
}
MUsingCom::MUsingCom( DWORD type )
: status( MUsingCom_SUCCESS )
{
HRESULT hr;
// Initialize com.
hr = CoInitializeEx(0, type );
if ( FAILED(hr) )
{
// cout << "Failed to initialize COM library" << hr << endl;
status = COM_FAILURE;
}
}
// destructor
MUsingCom::~MUsingCom()
{
CoUninitialize();
}
// getStatus
MUsingCom::MUsingCom_Error
MUsingCom::getStatus()
{
return status;
}
// static member definition.
map< UINT, _bstr_t>
ResourceString::resourceStrings;
ResourceString* ResourceString::_instance = 0;
// Instance
//
ResourceString*
ResourceString::Instance()
{
if( _instance == 0 )
{
_instance = new ResourceString;
}
return _instance;
}
// GetIDString
//
const _bstr_t&
ResourceString::GetIDString( UINT id )
{
// check if string has been loaded previously.
if( resourceStrings.find( id ) == resourceStrings.end() )
{
// first time load.
CString str;
if( str.LoadString( id ) == 0 )
{
// no string mapping to this id.
throw _com_error( WBEM_E_NOT_FOUND );
}
resourceStrings[id] = str;
}
return resourceStrings[ id ];
}
// GETRESOURCEIDSTRING
// helper function.
//
const _bstr_t&
GETRESOURCEIDSTRING( UINT id )
{
return ResourceString::GetIDString( id );
}
//
// constructor
WTokens::WTokens( wstring strToken, wstring strDelimit )
: _strToken( strToken ), _strDelimit( strDelimit )
{}
//
// default constructor
WTokens::WTokens()
{}
//
// destructor
WTokens::~WTokens()
{}
//
// tokenize
vector<wstring>
WTokens::tokenize()
{
vector<wstring> vecTokens;
wchar_t* token;
token = wcstok( (wchar_t *) _strToken.c_str() , _strDelimit.c_str() );
while( token != NULL )
{
vecTokens.push_back( token );
token = wcstok( NULL, _strDelimit.c_str() );
}
return vecTokens;
}
//
void
WTokens::init(
wstring strToken,
wstring strDelimit )
{
_strToken = strToken;
_strDelimit = strDelimit;
}
void
GetErrorCodeText(WBEMSTATUS wStat , _bstr_t& errText )
{
WCHAR rgch[128];
UINT uErr = (UINT) wStat;
LPCWSTR szErr = NULL;
CLocalLogger log;
switch(uErr)
{
case WBEM_E_ACCESS_DENIED:
szErr = GETRESOURCEIDSTRING(IDS_ERROR_ACCESS_DENIED);
break;
case E_ACCESSDENIED:
szErr = GETRESOURCEIDSTRING(IDS_ERROR_ACCESS_DENIED);
break;
case 0x800706ba: // RPC service unavailable
// TODO: find the constant definition for this.
szErr = GETRESOURCEIDSTRING(IDS_ERROR_NLB_NOT_FOUND);
break;
case WBEM_E_LOCAL_CREDENTIALS:
szErr = GETRESOURCEIDSTRING(IDS_ERROR_INVALID_LOCAL_CREDENTIALS);
break;
default:
log.Log(IDS_ERROR_CODE, (UINT) uErr);
szErr = log.GetStringSafe();
break;
}
errText = szErr;
}
UINT
NlbMgrRegReadUINT(
HKEY hKey,
LPCWSTR szName,
UINT Default
)
{
LONG lRet;
DWORD dwType;
DWORD dwData;
DWORD dwRet;
dwData = sizeof(dwRet);
lRet = RegQueryValueEx(
hKey, // handle to key to query
szName,
NULL, // reserved
&dwType, // address of buffer for value type
(LPBYTE) &dwRet, // address of data buffer
&dwData // address of data buffer size
);
if ( lRet != ERROR_SUCCESS
|| dwType != REG_DWORD
|| dwData != sizeof(dwData))
{
dwRet = (DWORD) Default;
}
return (UINT) dwRet;
}
VOID
NlbMgrRegWriteUINT(
HKEY hKey,
LPCWSTR szName,
UINT Value
)
{
LONG lRet;
lRet = RegSetValueEx(
hKey, // handle to key to set value for
szName,
0, // reserved
REG_DWORD, // flag for value type
(BYTE*) &Value,// address of value data
sizeof(Value) // size of value data
);
if (lRet !=ERROR_SUCCESS)
{
// trace error
}
}
HKEY
NlbMgrRegCreateKey(
LPCWSTR szSubKey
)
{
WCHAR szKey[256];
DWORD dwOptions = 0;
HKEY hKey = NULL;
ARRAYSTRCPY(szKey, szNLBMGRREG_BASE_KEY);
if (szSubKey != NULL)
{
if (wcslen(szSubKey)>128)
{
// too long.
goto end;
}
ARRAYSTRCAT(szKey, L"\\");
ARRAYSTRCAT(szKey, szSubKey);
}
DWORD dwDisposition;
LONG lRet;
lRet = RegCreateKeyEx(
HKEY_CURRENT_USER, // handle to an open key
szKey, // address of subkey name
0, // reserved
L"class", // address of class string
0, // special options flag
KEY_ALL_ACCESS, // desired security access
NULL, // address of key security structure
&hKey, // address of buffer for opened handle
&dwDisposition // address of disposition value buffer
);
if (lRet != ERROR_SUCCESS)
{
hKey = NULL;
}
end:
return hKey;
}
void
GetTimeAndDate(_bstr_t &bstrTime, _bstr_t &bstrDate)
{
WCHAR wszTime[128];
WCHAR wszDate[128];
ConvertTimeToTimeAndDateStrings(time(NULL), wszTime, ASIZECCH(wszTime), wszDate, ASIZECCH(wszDate));
bstrTime = _bstr_t(wszTime);
bstrDate = _bstr_t(wszDate);
}
VOID
CLocalLogger::Log(
IN UINT ResourceID,
// IN LPCWSTR FormatString,
...
)
{
DWORD dwRet;
WCHAR wszFormat[2048];
WCHAR wszBuffer[2048];
HINSTANCE hInst = AfxGetInstanceHandle();
if (!LoadString(hInst, ResourceID, wszFormat, ASIZE(wszFormat)-1))
{
TRACE_CRIT("LoadString returned 0, GetLastError() : 0x%x, Could not log message !!!", GetLastError());
goto end;
}
va_list arglist;
va_start (arglist, ResourceID);
dwRet = FormatMessage(FORMAT_MESSAGE_FROM_STRING,
wszFormat,
0, // Message Identifier - Ignored for FORMAT_MESSAGE_FROM_STRING
0, // Language Identifier
wszBuffer,
ASIZE(wszBuffer)-1,
&arglist);
va_end (arglist);
if (dwRet==0)
{
TRACE_CRIT("FormatMessage returned error : %u, Could not log message !!!", dwRet);
goto end;
}
UINT uLen = wcslen(wszBuffer)+1; // 1 for extra NULL
if ((m_LogSize < (m_CurrentOffset+uLen)))
{
//
// Not enough space -- we double the buffer + some extra
// and copy over the old log.
//
UINT uNewSize = 2*m_LogSize+uLen+1024;
WCHAR *pTmp = new WCHAR[uNewSize];
if (pTmp == NULL)
{
goto end;
}
if (m_CurrentOffset!=0)
{
CopyMemory(pTmp, m_pszLog, m_CurrentOffset*sizeof(WCHAR));
pTmp[m_CurrentOffset] = 0;
}
delete[] m_pszLog;
m_pszLog = pTmp;
m_LogSize = uNewSize;
}
//
// Having made sure there is enough space, copy over the new stuff
//
CopyMemory(m_pszLog+m_CurrentOffset, wszBuffer, uLen*sizeof(WCHAR));
m_CurrentOffset += (uLen-1); // -1 for ending NULL.
end:
return;
}
VOID
CLocalLogger::LogString(
LPCWSTR wszBuffer
)
{
UINT uLen = wcslen(wszBuffer)+1; // 1 for extra NULL
if ((m_LogSize < (m_CurrentOffset+uLen)))
{
//
// Not enough space -- we double the buffer + some extra
// and copy over the old log.
//
UINT uNewSize = 2*m_LogSize+uLen+1024;
WCHAR *pTmp = new WCHAR[uNewSize];
if (pTmp == NULL)
{
goto end;
}
if (m_CurrentOffset!=0)
{
CopyMemory(pTmp, m_pszLog, m_CurrentOffset*sizeof(WCHAR));
pTmp[m_CurrentOffset] = 0;
}
delete[] m_pszLog;
m_pszLog = pTmp;
m_LogSize = uNewSize;
}
//
// Having made sure there is enough space, copy over the new stuff
//
CopyMemory(m_pszLog+m_CurrentOffset, wszBuffer, uLen*sizeof(WCHAR));
m_CurrentOffset += (uLen-1); // -1 for ending NULL.
end:
return;
}
NLBERROR
AnalyzeNlbConfiguration(
IN const NLB_EXTENDED_CLUSTER_CONFIGURATION &Cfg,
IN OUT CLocalLogger &logErrors
)
//
// logErrors - a log of config errors
//
{
NLBERROR nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION;
WBEMSTATUS wStatus;
const WLBS_REG_PARAMS *pParams = &Cfg.NlbParams;
BOOL fRet = FALSE;
NlbIpAddressList addrList;
BOOL fError = FALSE;
//
// We expect NLB to be bound and have a valid configuration (i.e.,
// one wholse NlbParams contains initialized data).
//
if (!Cfg.IsValidNlbConfig())
{
logErrors.Log(IDS_LOG_INVALID_CLUSTER_SPECIFICATION);
nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION;
goto end;
}
//
// Make a copy of the the tcpip address list in addrList
//
fRet = addrList.Set(Cfg.NumIpAddresses, Cfg.pIpAddressInfo, 0);
if (!fRet)
{
TRACE_CRIT(L"Unable to copy old IP address list");
nerr = NLBERR_RESOURCE_ALLOCATION_FAILURE;
logErrors.Log(IDS_LOG_RESOURCE_ALLOCATION_FAILURE);
fError = TRUE;
goto end;
}
//
// Check stuff related to the cluster ip and subnet.
//
do
{
UINT uClusterIp = 0;
const NLB_IP_ADDRESS_INFO *pClusterIpInfo = NULL;
//
// Check that IP is valid
//
{
wStatus = CfgUtilsValidateNetworkAddress(
pParams->cl_ip_addr,
&uClusterIp,
NULL,
NULL
);
if (FAILED(wStatus))
{
logErrors.Log(IDS_LOG_INVALID_CIP, pParams->cl_ip_addr);
nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION;
fError = TRUE;
goto end;
}
}
//
// Check that cluster IP is present in tcpip address list
//
{
pClusterIpInfo = addrList.Find(pParams->cl_ip_addr);
if (pClusterIpInfo == NULL)
{
logErrors.Log(IDS_LOG_CIP_MISSING_FROM_TCPIP, pParams->cl_ip_addr);
fError = TRUE; // we keep going...
}
}
//
// Check that the cluster subnet matches what is in the tcpip address
// list.
//
if (pClusterIpInfo != NULL)
{
if (_wcsicmp(pParams->cl_net_mask, pClusterIpInfo->SubnetMask))
{
logErrors.Log(
IDS_LOG_CIP_SUBNET_MASK_MISMATCH,
pParams->cl_net_mask,
pClusterIpInfo->SubnetMask
);
fError = TRUE; // we keep going...
}
}
} while (FALSE);
//
// Check stuff related to the dedicated IP (if present)
//
do
{
const NLB_IP_ADDRESS_INFO *pDedicatedIpInfo = NULL;
//
// If empty dip, bail...
//
if (Cfg.IsBlankDedicatedIp())
{
break;
}
//
// Check that DIP doesn't match CIP
//
if (!_wcsicmp(pParams->cl_ip_addr, pParams->ded_ip_addr))
{
logErrors.Log(IDS_LOG_CIP_EQUAL_DIP, pParams->cl_ip_addr);
fError = TRUE;
}
//
// Check that the DIP is the 1st address in tcpip's address list.
//
{
const NLB_IP_ADDRESS_INFO *pTmpIpInfo = NULL;
pDedicatedIpInfo = addrList.Find(pParams->ded_ip_addr);
if (pDedicatedIpInfo == NULL)
{
logErrors.Log(IDS_LOG_DIP_MISSING_FROM_TCPIP, pParams->ded_ip_addr);
fError = TRUE; // we keep going...
}
else
{
pTmpIpInfo = addrList.Find(NULL); // returns the 1st
if (pTmpIpInfo != pDedicatedIpInfo)
{
logErrors.Log(IDS_LOG_DIP_NOT_FIRST_IN_TCPIP, pParams->ded_ip_addr);
}
}
}
//
// Check that the DIP subnet matches that in tcpip's address list.
//
if (pDedicatedIpInfo != NULL)
{
if (_wcsicmp(pParams->ded_net_mask, pDedicatedIpInfo->SubnetMask))
{
logErrors.Log(
IDS_LOG_DIP_SUBNET_MASK_MISMATCH,
pParams->ded_net_mask,
pDedicatedIpInfo->SubnetMask
);
fError = TRUE; // we keep going...
}
}
} while (FALSE);
//
// Check host priority
//
// NOTHING to do.
//
//
// Check port rules
//
{
WLBS_PORT_RULE *pRules = NULL;
UINT NumRules=0;
LPCWSTR szAllVip = GETRESOURCEIDSTRING(IDS_REPORT_VIP_ALL);
LPCWSTR szPrevVip = NULL;
wStatus = CfgUtilGetPortRules(pParams, &pRules, &NumRules);
if (FAILED(wStatus))
{
logErrors.Log(IDS_LOG_CANT_EXTRACT_PORTRULES);
fError = TRUE;
nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION;
goto end;
}
for (UINT u = 0; u< NumRules; u++)
{
LPCWSTR szVip = pRules[u].virtual_ip_addr;
const NLB_IP_ADDRESS_INFO *pIpInfo = NULL;
//
// Skip the "all-vips" (255.255.255.255) case...
//
if (!lstrcmpi(szVip, szAllVip))
{
continue;
}
if (!lstrcmpi(szVip, L"255.255.255.255"))
{
continue;
}
//
// SKip if we've already checked this VIP (assumes the vips
// are in sorted order)
//
if (szPrevVip != NULL && !lstrcmpi(szVip, szPrevVip))
{
continue;
}
szPrevVip = szVip;
//
// Check that the VIP is present in tcpip's address list.
//
pIpInfo = addrList.Find(szVip); // returns the 1st
if (pIpInfo == NULL)
{
logErrors.Log(IDS_LOG_VIP_NOT_IN_TCPIP, szVip);
fError = TRUE; // We continue...
}
//
// Check that VIPs don't match DIPS.
//
{
if (!lstrcmpi(szVip, pParams->ded_ip_addr))
{
logErrors.Log(IDS_LOG_PORTVIP_MATCHES_DIP, szVip);
}
}
}
}
if (fError)
{
nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION;
}
else
{
nerr = NLBERR_OK;
}
end:
return nerr;
}
NLBERROR
AnalyzeNlbConfigurationPair(
IN const NLB_EXTENDED_CLUSTER_CONFIGURATION &Cfg,
IN const NLB_EXTENDED_CLUSTER_CONFIGURATION &OtherCfg,
IN BOOL fOtherIsCluster,
IN BOOL fCheckOtherForConsistancy,
OUT BOOL &fConnectivityChange,
IN OUT CLocalLogger &logErrors,
IN OUT CLocalLogger &logDifferences
)
{
NLBERROR nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION;
WBEMSTATUS wStatus;
const WLBS_REG_PARAMS *pParams = &Cfg.NlbParams;
const WLBS_REG_PARAMS *pOtherParams = &OtherCfg.NlbParams;
BOOL fRet = FALSE;
NlbIpAddressList addrList;
NlbIpAddressList otherAddrList;
BOOL fError = FALSE;
BOOL fOtherChange = FALSE;
fConnectivityChange = FALSE;
//
// We expect NLB to be bound and have a valid configuration (i.e.,
// one wholse NlbParams contains initialized data).
//
if (!Cfg.IsValidNlbConfig())
{
logErrors.Log(IDS_LOG_INVALID_CLUSTER_SPECIFICATION);
nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION;
fError = TRUE;
goto end;
}
if (!OtherCfg.IsValidNlbConfig())
{
if (OtherCfg.IsNlbBound())
{
// TODO:
}
else
{
// TODO:
}
nerr = NLBERR_OK;
fConnectivityChange = TRUE;
goto end;
}
//
// Make a copy of the the tcpip address list in addrList
//
fRet = addrList.Set(Cfg.NumIpAddresses, Cfg.pIpAddressInfo, 0);
if (!fRet)
{
TRACE_CRIT(L"Unable to copy IP address list");
nerr = NLBERR_RESOURCE_ALLOCATION_FAILURE;
logErrors.Log(IDS_LOG_RESOURCE_ALLOCATION_FAILURE);
fError = TRUE;
goto end;
}
//
// Make a copy of the other tcpip address list in otherAddrList
//
fRet = otherAddrList.Set(OtherCfg.NumIpAddresses, OtherCfg.pIpAddressInfo, 0);
if (!fRet)
{
TRACE_CRIT(L"Unable to copy other IP address list");
nerr = NLBERR_RESOURCE_ALLOCATION_FAILURE;
logErrors.Log(IDS_LOG_RESOURCE_ALLOCATION_FAILURE);
fError = TRUE;
goto end;
}
//
// Check for changes in IP address lists
//
{
UINT u;
BOOL fWriteHeader=TRUE;
//
// Look for added
//
fWriteHeader=TRUE;
for (u=0;u<Cfg.NumIpAddresses; u++)
{
NLB_IP_ADDRESS_INFO *pIpInfo = Cfg.pIpAddressInfo+u;
const NLB_IP_ADDRESS_INFO *pOtherIpInfo = NULL;
pOtherIpInfo = otherAddrList.Find(pIpInfo->IpAddress);
if (pOtherIpInfo == NULL)
{
// found a new one!
fConnectivityChange = TRUE;
if (fWriteHeader)
{
logDifferences.Log(IDS_LOG_ADDED_IPADDR_HEADER);
fWriteHeader=FALSE;
}
logDifferences.Log(
IDS_LOG_ADDED_IPADDR,
pIpInfo->IpAddress,
pIpInfo->SubnetMask
);
}
}
//
// Look for removed
//
fWriteHeader=TRUE;
for (u=0;u<OtherCfg.NumIpAddresses; u++)
{
NLB_IP_ADDRESS_INFO *pOtherIpInfo = OtherCfg.pIpAddressInfo+u;
const NLB_IP_ADDRESS_INFO *pIpInfo = NULL;
pIpInfo = addrList.Find(pOtherIpInfo->IpAddress);
if (pIpInfo == NULL)
{
// found a removed one!
fConnectivityChange = TRUE;
if (fWriteHeader)
{
logDifferences.Log(IDS_LOG_REMOVED_IPADDR_HEADER);
fWriteHeader = FALSE;
}
logDifferences.Log(
IDS_LOG_REMOVE_IPADDR,
pOtherIpInfo->IpAddress,
pOtherIpInfo->SubnetMask
);
}
}
//
// Look for modified
//
fWriteHeader=TRUE;
for (u=0;u<Cfg.NumIpAddresses; u++)
{
NLB_IP_ADDRESS_INFO *pIpInfo = Cfg.pIpAddressInfo+u;
const NLB_IP_ADDRESS_INFO *pOtherIpInfo = NULL;
pOtherIpInfo = otherAddrList.Find(pIpInfo->IpAddress);
if ( pOtherIpInfo != NULL
&& lstrcmpi(pIpInfo->SubnetMask, pOtherIpInfo->SubnetMask))
{
// found a modified one!
fConnectivityChange = TRUE;
if (fWriteHeader)
{
logDifferences.Log(IDS_LOG_MODIFIED_IPADDR_HEADER);
fWriteHeader = FALSE;
}
logDifferences.Log(
IDS_LOG_MODIFIED_IPADDR,
pOtherIpInfo->IpAddress,
pOtherIpInfo->SubnetMask,
pIpInfo->SubnetMask
);
}
}
}
//
// Cluster name
//
{
if (lstrcmpi(pOtherParams->domain_name, pParams->domain_name))
{
logDifferences.Log(
IDS_LOG_MODIFIED_CLUSTER_NAME,
pOtherParams->domain_name,
pParams->domain_name
);
fConnectivityChange = TRUE;
}
}
//
// Check for cluster traffic mode change
//
{
BOOL fModeChange = FALSE;
if (pParams->mcast_support != pOtherParams->mcast_support)
{
fModeChange = TRUE;
}
else if (pParams->mcast_support &&
pParams->fIGMPSupport != pOtherParams->fIGMPSupport)
{
fModeChange = TRUE;
}
if (fModeChange)
{
LPCWSTR szClusterMode = clustermode_description(pParams);
LPCWSTR szOtherClusterMode = clustermode_description(pOtherParams);
logDifferences.Log(
IDS_LOG_MODIFIED_TRAFFIC_MODE,
szOtherClusterMode,
szClusterMode
);
fConnectivityChange = TRUE;
}
}
//
// Check if there is change in rct or a new rct password specified...
//
{
if (Cfg.GetRemoteControlEnabled() !=
OtherCfg.GetRemoteControlEnabled())
{
LPCWSTR szRctDescription = rct_description(pParams);
LPCWSTR szOtherRctDescription = rct_description(pOtherParams);
logDifferences.Log(
IDS_LOG_MODIFIED_RCT,
szOtherRctDescription,
szRctDescription
);
fOtherChange = TRUE;
}
else
{
LPCWSTR szNewPwd = Cfg.GetNewRemoteControlPasswordRaw();
if (szNewPwd != NULL)
{
logDifferences.Log(IDS_LOG_NEW_RCT_PWD);
fOtherChange = TRUE;
}
}
}
//
// Port rules
//
{
}
nerr = NLBERR_OK;
end:
return nerr;
}
LPCWSTR
clustermode_description(
const WLBS_REG_PARAMS *pParams
)
{
LPCWSTR szClusterMode = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_CM_UNICAST);
if (pParams->mcast_support)
{
if (pParams->fIGMPSupport)
{
szClusterMode = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_CM_IGMP);
}
else
{
szClusterMode = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_CM_MULTI);
}
}
return szClusterMode;
}
LPCWSTR
rct_description(
const WLBS_REG_PARAMS *pParams
)
{
LPCWSTR szClusterRctEnabled;
if (pParams->rct_enabled)
{
szClusterRctEnabled = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_RCT_ENABLED);
}
else
{
szClusterRctEnabled = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_RCT_DISABLED);
}
return szClusterRctEnabled;
}
void
ProcessMsgQueue()
{
theApplication.ProcessMsgQueue();
}
BOOL
PromptForEncryptedCreds(
IN HWND hWnd,
IN LPCWSTR szCaptionText,
IN LPCWSTR szMessageText,
IN OUT LPWSTR szUserName,
IN UINT cchUserName,
IN OUT LPWSTR szPassword, // encrypted password
IN UINT cchPassword // size of szPassword
)
/*
Decrypts szPassword, then brings UI prompting the user to change
the password, then encrypts the resultant password.
*/
{
TRACE_INFO("-> %!FUNC!");
BOOL fRet = FALSE;
DWORD dwRet = 0;
CREDUI_INFO UiInfo;
PCTSTR pszTargetName= L"%computername%";
WCHAR rgUserName[CREDUI_MAX_USERNAME_LENGTH+1];
WCHAR rgClearPassword[CREDUI_MAX_PASSWORD_LENGTH+1];
WCHAR rgEncPassword[MAX_ENCRYPTED_PASSWORD_LENGTH];
BOOL fSave = FALSE;
DWORD dwFlags = 0;
HRESULT hr;
rgUserName[0] = 0;
rgClearPassword[0] = 0;
rgEncPassword[0] = 0;
hr = ARRAYSTRCPY(rgUserName, szUserName);
if (hr != S_OK)
{
TRACE_CRIT(L"rgUserName buffer too small for szUserName");
goto end;
}
//
// Decrypt the password...
// WARNING: after decryption we need to be sure to zero-out
// the clear-text pwd before returning from this function.
//
// Special case: If enc pwd is "", we "decrypt" it to "".
//
if (*szPassword == 0)
{
*rgClearPassword = 0;
fRet = TRUE;
}
else
{
fRet = CfgUtilDecryptPassword(
szPassword,
ASIZE(rgClearPassword),
rgClearPassword
);
}
if (!fRet)
{
TRACE_CRIT(L"CfgUtilDecryptPassword fails! -- bailing!");
goto end;
}
ZeroMemory(&UiInfo, sizeof(UiInfo));
UiInfo.cbSize = sizeof(CREDUI_INFO);
UiInfo.hwndParent = hWnd;
UiInfo.pszMessageText = szMessageText;
UiInfo.pszCaptionText = szCaptionText;
UiInfo.hbmBanner = NULL; // use default.
//
// Specifying DO_NOT_PERSIST and GENERIC_CREDENTIALS disables all syntax
// checking, so a null username can be specified.
//
dwFlags = CREDUI_FLAGS_DO_NOT_PERSIST
| CREDUI_FLAGS_GENERIC_CREDENTIALS
// | CREDUI_FLAGS_VALIDATE_USERNAME
// | CREDUI_FLAGS_COMPLETE_USERNAME
// | CREDUI_FLAGS_USERNAME_TARGET_CREDENTIALS
;
dwRet = CredUIPromptForCredentials (
&UiInfo,
pszTargetName,
NULL, // Reserved
0, // dwAuthError
rgUserName,
ASIZE(rgUserName),
rgClearPassword,
ASIZE(rgClearPassword),
&fSave,
dwFlags
);
if (dwRet != 0)
{
TRACE_CRIT(L"CredUIPromptForCredentials fails. dwRet = 0x%x", dwRet);
fRet = FALSE;
}
else
{
if (*rgUserName == 0)
{
*rgEncPassword=0; // we ignore the password field in this case.
fRet = TRUE;
}
else
{
//
// TODO: prepend %computername% if required.
//
fRet = CfgUtilEncryptPassword(
rgClearPassword,
ASIZE(rgEncPassword),
rgEncPassword
);
}
if (!fRet)
{
TRACE_CRIT("CfgUtilEncryptPassword fails");
}
else
{
//
// We want to make sure we will succeed before we overwrite
// the user's passed-in buffers for username and password...
//
UINT uLen = wcslen(rgEncPassword);
if (uLen >= cchPassword)
{
TRACE_CRIT(L"cchPassword is too small");
fRet = FALSE;
}
uLen = wcslen(rgUserName);
if(uLen >= cchUserName)
{
TRACE_CRIT(L"cchUserName is too small");
fRet = FALSE;
}
}
if (fRet)
{
(void)StringCchCopy(szPassword, cchPassword, rgEncPassword);
(void)StringCchCopy(szUserName, cchUserName, rgUserName);
}
}
end:
SecureZeroMemory(rgClearPassword, sizeof(rgClearPassword));
TRACE_INFO("<- %!FUNC! returns %d", (int) fRet);
return fRet;
}