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
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;
|
|
}
|