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.
6686 lines
173 KiB
6686 lines
173 KiB
//***************************************************************************
|
|
// CFGUTIL.CPP
|
|
//
|
|
//
|
|
// Module: WMI Framework Instance provider
|
|
//
|
|
// Purpose: Low-level utilities to configure NICs -- bind/unbind,
|
|
// get/set IP address lists, and get/set NLB cluster params.
|
|
//
|
|
// Copyright (c)2001 Microsoft Corporation, All Rights Reserved
|
|
//
|
|
// History:
|
|
//
|
|
// 04/05/01 JosephJ Created (original version, called cfgutils.cpp under
|
|
// nlbmgr\provider).
|
|
// 07/23/01 JosephJ Moved functionality to lib.
|
|
//
|
|
//***************************************************************************
|
|
#include "private.h"
|
|
#include <clusapi.h>
|
|
//
|
|
// Following two needed ONLY for RtlEncryptMemory...
|
|
//
|
|
#include <ntsecapi.h>
|
|
#include <crypt.h>
|
|
#include "cfgutil.tmh"
|
|
|
|
|
|
#define NLB_API_DLL_NAME L"wlbsctrl.dll"
|
|
#define NLB_CLIENT_NAME L"NLBManager"
|
|
|
|
//
|
|
// This magic has the side effect defining "smart pointers"
|
|
// IWbemServicesPtr
|
|
// IWbemLocatorPtr
|
|
// IWbemClassObjectPtr
|
|
// IEnumWbemClassObjectPtr
|
|
// IWbemCallResultPtr
|
|
// IWbemStatusCodeTextPtr
|
|
//
|
|
// These types automatically call the COM Release function when the
|
|
// objects go out of scope.
|
|
//
|
|
_COM_SMARTPTR_TYPEDEF(IWbemServices, __uuidof(IWbemServices));
|
|
_COM_SMARTPTR_TYPEDEF(IWbemLocator, __uuidof(IWbemLocator));
|
|
_COM_SMARTPTR_TYPEDEF(IEnumWbemClassObject, __uuidof(IEnumWbemClassObject));
|
|
_COM_SMARTPTR_TYPEDEF(IWbemCallResult, __uuidof(IWbemCallResult));
|
|
_COM_SMARTPTR_TYPEDEF(IWbemStatusCodeText, __uuidof(IWbemStatusCodeText));
|
|
|
|
|
|
WBEMSTATUS
|
|
CfgUtilGetWmiAdapterObjFromAdapterConfigurationObj(
|
|
IN IWbemServicesPtr spWbemServiceIF, // smart pointer
|
|
IN IWbemClassObjectPtr spObj, // smart pointer
|
|
OUT IWbemClassObjectPtr &spAdapterObj // smart pointer, by reference
|
|
);
|
|
|
|
USHORT crc16(LPCWSTR ptr);
|
|
|
|
#if OBSOLETE
|
|
WBEMSTATUS
|
|
get_string_parameter(
|
|
IN IWbemClassObjectPtr spObj,
|
|
IN LPCWSTR szParameterName,
|
|
OUT LPWSTR *ppStringValue
|
|
);
|
|
#endif // OBSOLETE
|
|
|
|
WBEMSTATUS
|
|
get_nic_instance(
|
|
IN IWbemServicesPtr spWbemServiceIF,
|
|
IN LPCWSTR szNicGuid,
|
|
OUT IWbemClassObjectPtr &sprefObj
|
|
);
|
|
|
|
WBEMSTATUS
|
|
get_multi_string_parameter(
|
|
IN IWbemClassObjectPtr spObj,
|
|
IN LPCWSTR szParameterName,
|
|
IN UINT MaxStringLen, // in wchars, INCLUDING space for trailing zeros.
|
|
OUT UINT *pNumItems,
|
|
OUT LPCWSTR *ppStringValue
|
|
);
|
|
|
|
WBEMSTATUS
|
|
set_string_parameter(
|
|
IN IWbemClassObjectPtr spObj,
|
|
IN LPCWSTR szParameterName,
|
|
IN LPCWSTR szValue
|
|
);
|
|
|
|
WBEMSTATUS
|
|
set_multi_string_parameter(
|
|
IN IWbemClassObjectPtr spObj,
|
|
IN LPCWSTR szParameterName,
|
|
IN UINT MaxStringLen, // in wchars, INCLUDING space for trailing zeros.
|
|
IN UINT NumItems,
|
|
IN LPCWSTR pStringValue
|
|
);
|
|
|
|
WBEMSTATUS
|
|
get_friendly_name_from_registry(
|
|
LPCWSTR szGuid,
|
|
LPWSTR *pszFriendlyName
|
|
);
|
|
|
|
|
|
|
|
//
|
|
// This locally-defined class implements interfaces to WMI, NetConfig,
|
|
// and low-level NLB APIs.
|
|
//
|
|
class CfgUtils
|
|
{
|
|
|
|
public:
|
|
|
|
//
|
|
// Initialization function -- call before using any other functions
|
|
//
|
|
WBEMSTATUS
|
|
Initialize(
|
|
BOOL fServer, // TRUE == try to dynamically load wlbsstrl.dll.
|
|
BOOL fNoPing // TRUE == CfgUtilPing becomes a no-op, always
|
|
// returning success.
|
|
);
|
|
|
|
//
|
|
// Deinitialization function -- call after using any other functions
|
|
//
|
|
VOID
|
|
Deinitialize(
|
|
VOID
|
|
);
|
|
|
|
//
|
|
// Constructor and distructor.
|
|
//
|
|
CfgUtils(VOID)
|
|
{
|
|
//
|
|
// WARNING: We do a blanked zero memory initialization of our entire
|
|
// structure. Any other initialization should go into the
|
|
// Initialize() function.
|
|
//
|
|
ZeroMemory(this, sizeof(*this));
|
|
|
|
InitializeCriticalSection(&m_Crit);
|
|
}
|
|
|
|
~CfgUtils()
|
|
{
|
|
DeleteCriticalSection(&m_Crit);
|
|
}
|
|
|
|
//
|
|
// Check if we're initialized
|
|
//
|
|
BOOL
|
|
IsInitalized(VOID)
|
|
{
|
|
return m_ComInitialized && m_WmiInitialized;
|
|
}
|
|
|
|
// OBSOLETE IWbemStatusCodeTextPtr m_spWbemStatusIF; // Smart pointer
|
|
IWbemServicesPtr m_spWbemServiceIF; // Smart pointer
|
|
|
|
//
|
|
// Following are pointers to functions we call from dynamically-
|
|
// loaded wlbsctrl.dll. m_hWlbsCtrlDll is the module handle
|
|
// returned from LoadLibrary("wlbsctrl.dll");
|
|
// It should be freed in the context of this->Deintialize.
|
|
//
|
|
HMODULE m_hWlbsCtrlDll;
|
|
BOOL m_NLBApiHooksPresent; // Was Loadlibrary/GetProcAddress/WlbsOpen successful ?
|
|
|
|
WlbsOpen_FUNC m_pfWlbsOpen; // NLB api to create connection to NLB driver, It returns INVALID_HANDLE_VALUE (NOT NULL) on failure
|
|
WlbsLocalClusterControl_FUNC m_pfWlbsLocalClusterControl; // NLB api to control local NLB operation
|
|
WlbsAddPortRule_FUNC m_pfWlbsAddPortRule; // NLB api to add a port rule
|
|
WlbsDeleteAllPortRules_FUNC m_pfWlbsDeleteAllPortRules; // NLB api to delete all port rules
|
|
WlbsEnumPortRules_FUNC m_pfWlbsEnumPortRules;// NLB api to enumerate port rules
|
|
WlbsSetDefaults_FUNC m_pfWlbsSetDefaults; // NLB api to set default values for NLB configuration
|
|
WlbsValidateParams_FUNC m_pfWlbsValidateParams; // NLB api to validate registry parameters
|
|
WlbsParamReadReg_FUNC m_pfWlbsParamReadReg; // NLB api to read registry parameters
|
|
|
|
//
|
|
// We need to define this prototype here, because it's not exported
|
|
// in wlbsconfig.h
|
|
typedef BOOL (WINAPI *WlbsParamWriteReg_FUNC)
|
|
(
|
|
const GUID & pAdapterGuid,
|
|
PWLBS_REG_PARAMS reg_data
|
|
);
|
|
|
|
WlbsParamWriteReg_FUNC m_pfWlbsParamWriteReg; // NLB api to write registry parameters
|
|
WlbsWriteAndCommitChanges_FUNC m_pfWlbsWriteAndCommitChanges; // NLB api to write parametrs into registry and to commit changes to NLB driver
|
|
WlbsSetRemotePassword_FUNC m_pfWlbsSetRemotePassword; // NLB api to set the remote password.
|
|
WlbsGetClusterMembers_FUNC m_pfWlbsGetClusterMembers; // NLB api to retrieve information on members of the cluster
|
|
|
|
BOOL
|
|
DisablePing(VOID)
|
|
{
|
|
return m_fNoPing!=FALSE;
|
|
}
|
|
|
|
private:
|
|
|
|
|
|
//
|
|
// A single lock serialzes all access.
|
|
// Use mfn_Lock and mfn_Unlock.
|
|
//
|
|
CRITICAL_SECTION m_Crit;
|
|
|
|
BOOL m_ComInitialized;
|
|
BOOL m_WmiInitialized;
|
|
BOOL m_WinsockInitialized;
|
|
BOOL m_fNoPing;
|
|
|
|
VOID
|
|
mfn_Lock(
|
|
VOID
|
|
)
|
|
{
|
|
EnterCriticalSection(&m_Crit);
|
|
}
|
|
|
|
VOID
|
|
mfn_Unlock(
|
|
VOID
|
|
)
|
|
{
|
|
LeaveCriticalSection(&m_Crit);
|
|
}
|
|
|
|
VOID
|
|
mfn_LoadWlbsFuncs(VOID);
|
|
|
|
VOID
|
|
mfn_UnloadWlbsFuncs(VOID); // ok to call multiple times (i.e. idempotent).
|
|
};
|
|
|
|
|
|
//
|
|
// This class manages NetCfg interfaces
|
|
//
|
|
class MyNetCfg
|
|
{
|
|
|
|
public:
|
|
|
|
MyNetCfg(VOID)
|
|
{
|
|
m_pINetCfg = NULL;
|
|
m_pLock = NULL;
|
|
}
|
|
|
|
~MyNetCfg()
|
|
{
|
|
ASSERT(m_pINetCfg==NULL);
|
|
ASSERT(m_pLock==NULL);
|
|
}
|
|
|
|
WBEMSTATUS
|
|
Initialize(
|
|
BOOL fWriteLock
|
|
);
|
|
|
|
VOID
|
|
Deinitialize(
|
|
VOID
|
|
);
|
|
|
|
|
|
WBEMSTATUS
|
|
GetNlbCompatibleNics(
|
|
OUT LPWSTR **ppszNics,
|
|
OUT UINT *pNumNics,
|
|
OUT UINT *pNumBoundToNlb // OPTIONAL
|
|
);
|
|
|
|
WBEMSTATUS
|
|
GetNicIF(
|
|
IN LPCWSTR szNicGuid,
|
|
OUT INetCfgComponent **ppINic
|
|
);
|
|
|
|
WBEMSTATUS
|
|
GetBindingIF(
|
|
IN LPCWSTR szComponent,
|
|
OUT INetCfgComponentBindings **ppIBinding
|
|
);
|
|
|
|
typedef enum
|
|
{
|
|
NOOP,
|
|
BIND,
|
|
UNBIND
|
|
|
|
} UPDATE_OP;
|
|
|
|
WBEMSTATUS
|
|
UpdateBindingState(
|
|
IN LPCWSTR szNic,
|
|
IN LPCWSTR szComponent,
|
|
IN UPDATE_OP Op,
|
|
OUT BOOL *pfBound
|
|
);
|
|
|
|
static
|
|
WBEMSTATUS
|
|
GetWriteLockState(
|
|
OUT BOOL *pfCanLock,
|
|
LPWSTR *pszHeldBy // OPTIONAL, free using delete[].
|
|
);
|
|
|
|
private:
|
|
|
|
INetCfg *m_pINetCfg;
|
|
INetCfgLock *m_pLock;
|
|
|
|
}; // Class MyNetCfg
|
|
|
|
//
|
|
// We keep a single global instance of this class around currently...
|
|
//
|
|
CfgUtils g_CfgUtils;
|
|
|
|
|
|
WBEMSTATUS
|
|
CfgUtilInitialize(BOOL fServer, BOOL fNoPing)
|
|
{
|
|
return g_CfgUtils.Initialize(fServer, fNoPing);
|
|
}
|
|
|
|
VOID
|
|
CfgUtilDeitialize(VOID)
|
|
{
|
|
return g_CfgUtils.Deinitialize();
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
CfgUtils::Initialize(BOOL fServer, BOOL fNoPing)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_INITIALIZATION_FAILURE;
|
|
HRESULT hr;
|
|
TRACE_INFO(L"-> CfgUtils::Initialize(fServer=%lu, fNoPing=%lu)",
|
|
fServer, fNoPing);
|
|
|
|
mfn_Lock();
|
|
|
|
//
|
|
// Initialize COM
|
|
//
|
|
{
|
|
hr = CoInitializeEx(0, COINIT_DISABLE_OLE1DDE| COINIT_MULTITHREADED);
|
|
if ( FAILED(hr) )
|
|
{
|
|
TRACE_CRIT(L"CfgUtils: Failed to initialize COM library (hr=0x%08lx)", hr);
|
|
goto end;
|
|
}
|
|
m_ComInitialized = TRUE;
|
|
}
|
|
|
|
//
|
|
// WMI Initialization
|
|
//
|
|
{
|
|
IWbemLocatorPtr spWbemLocatorIF = NULL; // Smart pointer
|
|
|
|
#if OBSOLETE
|
|
//
|
|
// Get error text generator interface
|
|
//
|
|
SCODE sc = CoCreateInstance(
|
|
CLSID_WbemStatusCodeText,
|
|
0,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IWbemStatusCodeText,
|
|
(LPVOID *) &m_spWbemStatusIF
|
|
);
|
|
if( sc != S_OK )
|
|
{
|
|
ASSERT(m_spWbemStatusIF == NULL); // smart pointer
|
|
TRACE_CRIT(L"CfgUtils: CoCreateInstance IWbemStatusCodeText failure\n");
|
|
goto end;
|
|
}
|
|
TRACE_INFO(L"CfgUtils: m_spIWbemStatusIF=0x%p\n", (PVOID) m_spWbemStatusIF);
|
|
#endif // OBSOLETE
|
|
|
|
//
|
|
// Get "locator" interface
|
|
//
|
|
hr = CoCreateInstance(
|
|
CLSID_WbemLocator, 0,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IWbemLocator,
|
|
(LPVOID *) &spWbemLocatorIF
|
|
);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
ASSERT(spWbemLocatorIF == NULL); // smart pointer
|
|
TRACE_CRIT(L"CoCreateInstance IWebmLocator failed 0x%08lx", (UINT)hr);
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Get interface to provider for NetworkAdapter class objects
|
|
// on the local machine
|
|
//
|
|
_bstr_t serverPath = L"root\\cimv2";
|
|
hr = spWbemLocatorIF->ConnectServer(
|
|
serverPath,
|
|
NULL, // strUser,
|
|
NULL, // strPassword,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&m_spWbemServiceIF
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
ASSERT(m_spWbemServiceIF == NULL); // smart pointer
|
|
TRACE_CRIT(L"ConnectServer to cimv2 failed 0x%08lx", (UINT)hr);
|
|
goto end;
|
|
}
|
|
TRACE_INFO(L"CfgUtils: m_spIWbemServiceIF=0x%p\n", (PVOID) m_spWbemServiceIF);
|
|
|
|
hr = CoSetProxyBlanket(
|
|
m_spWbemServiceIF,
|
|
RPC_C_AUTHN_WINNT,
|
|
RPC_C_AUTHZ_DEFAULT, // RPC_C_AUTHZ_NAME,
|
|
COLE_DEFAULT_PRINCIPAL, // NULL,
|
|
RPC_C_AUTHN_LEVEL_DEFAULT,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
COLE_DEFAULT_AUTHINFO, // NULL,
|
|
EOAC_DEFAULT // EOAC_NONE
|
|
);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE_INFO(L"Error 0x%08lx setting proxy blanket", (UINT) hr);
|
|
goto end;
|
|
}
|
|
|
|
|
|
//
|
|
// Release locator interface.
|
|
//
|
|
// <NO need to do this explicitly, because this is a smart pointer>
|
|
//
|
|
spWbemLocatorIF = NULL;
|
|
m_WmiInitialized = TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// Netconfig Initialization
|
|
//
|
|
{
|
|
// Nothing to do here...
|
|
}
|
|
|
|
//
|
|
// WLBS API Initialization
|
|
//
|
|
|
|
//
|
|
// Dynamically load selected entrypoints from wlbsctrl.dll.
|
|
// We do not fail initialization if this operation fails.
|
|
// (Because this could be running on a machine that doesn't have
|
|
// wlbsctrl.dll). Instead we set/clear a flag (m_NLBApiHooksPresent)
|
|
//
|
|
//
|
|
if (fServer)
|
|
{
|
|
mfn_LoadWlbsFuncs();
|
|
}
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
|
|
//
|
|
// Winsock initialization. We don't consider it an error if we fail.
|
|
// As only certain functions will fail (eg CfgUtilPing).
|
|
//
|
|
{
|
|
WSADATA data;
|
|
int iWsaStatus = WSAStartup (WINSOCK_VERSION, & data);
|
|
if (iWsaStatus == 0)
|
|
{
|
|
TRACE_INFO("%!FUNC! Winsock initialized successfully");
|
|
m_WinsockInitialized = TRUE;
|
|
}
|
|
else
|
|
{
|
|
TRACE_CRIT("%!FUNC! WARNING Winsock initialization failed with error 0x%lx",
|
|
iWsaStatus);
|
|
m_WinsockInitialized = FALSE;
|
|
}
|
|
}
|
|
|
|
end:
|
|
|
|
mfn_Unlock();
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
TRACE_CRIT("%!FUNC! -- FAILING INITIALIZATION! Status=0x%08lx",
|
|
(UINT) Status);
|
|
CfgUtils::Deinitialize();
|
|
}
|
|
|
|
|
|
//
|
|
// Set the NoPing field...
|
|
//
|
|
m_fNoPing = fNoPing;
|
|
|
|
TRACE_INFO(L"<- CfgUtils::Initialize(Status=0x%08lx)", (UINT) Status);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
CfgUtils::Deinitialize(
|
|
VOID
|
|
)
|
|
//
|
|
// NOTE: can be called in the context of a failed initialization.
|
|
//
|
|
{
|
|
TRACE_INFO(L"-> CfgUtils::Deinitialize");
|
|
|
|
mfn_Lock();
|
|
|
|
//
|
|
// Winsock deinitialization.
|
|
//
|
|
if (m_WinsockInitialized)
|
|
{
|
|
WSACleanup();
|
|
m_WinsockInitialized = FALSE;
|
|
}
|
|
|
|
//
|
|
// De-initialize WLBS API
|
|
//
|
|
mfn_UnloadWlbsFuncs();
|
|
|
|
//
|
|
// Deinitialize Netconfig
|
|
//
|
|
|
|
//
|
|
// Deinitialize WMI
|
|
//
|
|
{
|
|
#if OBSOLETE
|
|
//
|
|
// Release interface to NetworkAdapter provider
|
|
//
|
|
if (m_spWbemStatusIF!= NULL)
|
|
{
|
|
// Smart pointer.
|
|
m_spWbemStatusIF= NULL;
|
|
}
|
|
#endif // OBSOLETE
|
|
|
|
if (m_spWbemServiceIF!= NULL)
|
|
{
|
|
// Smart pointer.
|
|
m_spWbemServiceIF= NULL;
|
|
}
|
|
|
|
m_WmiInitialized = FALSE;
|
|
}
|
|
|
|
//
|
|
// Deinitialize COM.
|
|
//
|
|
if (m_ComInitialized)
|
|
{
|
|
TRACE_CRIT(L"CfgUtils: Deinitializing COM");
|
|
CoUninitialize();
|
|
m_ComInitialized = FALSE;
|
|
}
|
|
|
|
mfn_Unlock();
|
|
|
|
TRACE_INFO(L"<- CfgUtils::Deinitialize");
|
|
}
|
|
|
|
VOID
|
|
CfgUtils::mfn_LoadWlbsFuncs(VOID)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HMODULE DllHdl;
|
|
|
|
m_NLBApiHooksPresent = FALSE;
|
|
|
|
if ((DllHdl = LoadLibrary(NLB_API_DLL_NAME)) == NULL)
|
|
{
|
|
TRACE_CRIT("%!FUNC! LoadLibrary of %ls failed with error : 0x%x", NLB_API_DLL_NAME, GetLastError());
|
|
}
|
|
else
|
|
{
|
|
|
|
m_pfWlbsOpen = (WlbsOpen_FUNC) GetProcAddress(DllHdl, "WlbsOpen");
|
|
m_pfWlbsLocalClusterControl = (WlbsLocalClusterControl_FUNC) GetProcAddress(DllHdl, "WlbsLocalClusterControl");
|
|
m_pfWlbsAddPortRule = (WlbsAddPortRule_FUNC) GetProcAddress(DllHdl, "WlbsAddPortRule");
|
|
m_pfWlbsDeleteAllPortRules = (WlbsDeleteAllPortRules_FUNC) GetProcAddress(DllHdl, "WlbsDeleteAllPortRules");
|
|
m_pfWlbsEnumPortRules = (WlbsEnumPortRules_FUNC) GetProcAddress(DllHdl, "WlbsEnumPortRules");
|
|
m_pfWlbsSetDefaults = (WlbsSetDefaults_FUNC) GetProcAddress(DllHdl, "WlbsSetDefaults");
|
|
m_pfWlbsValidateParams = (WlbsValidateParams_FUNC) GetProcAddress(DllHdl, "WlbsValidateParams");
|
|
m_pfWlbsParamReadReg = (WlbsParamReadReg_FUNC) GetProcAddress(DllHdl, "WlbsParamReadReg");
|
|
m_pfWlbsParamWriteReg = (WlbsParamWriteReg_FUNC) GetProcAddress(DllHdl, "ParamWriteReg");
|
|
m_pfWlbsWriteAndCommitChanges = (WlbsWriteAndCommitChanges_FUNC) GetProcAddress(DllHdl, "WlbsWriteAndCommitChanges");
|
|
m_pfWlbsSetRemotePassword = (WlbsSetRemotePassword_FUNC) GetProcAddress(DllHdl, "WlbsSetRemotePassword");
|
|
m_pfWlbsGetClusterMembers = (WlbsGetClusterMembers_FUNC) GetProcAddress(DllHdl, "WlbsGetClusterMembers");
|
|
|
|
if((m_pfWlbsOpen == NULL)
|
|
|| (m_pfWlbsLocalClusterControl == NULL)
|
|
|| (m_pfWlbsAddPortRule == NULL)
|
|
|| (m_pfWlbsDeleteAllPortRules == NULL)
|
|
|| (m_pfWlbsEnumPortRules == NULL)
|
|
|| (m_pfWlbsSetDefaults == NULL)
|
|
|| (m_pfWlbsValidateParams == NULL)
|
|
|| (m_pfWlbsParamReadReg == NULL)
|
|
|| (m_pfWlbsParamWriteReg == NULL)
|
|
|| (m_pfWlbsWriteAndCommitChanges == NULL)
|
|
|| (m_pfWlbsSetRemotePassword == NULL)
|
|
|| (m_pfWlbsGetClusterMembers == NULL))
|
|
{
|
|
TRACE_CRIT("%!FUNC! GetProcAddress failed for NLB API DLL functions");
|
|
FreeLibrary(DllHdl);
|
|
DllHdl = NULL;
|
|
}
|
|
else
|
|
{
|
|
fSuccess = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
if (fSuccess)
|
|
{
|
|
m_hWlbsCtrlDll = DllHdl;
|
|
m_NLBApiHooksPresent = TRUE;
|
|
}
|
|
else
|
|
{
|
|
mfn_UnloadWlbsFuncs(); // this will zero-out the function pointers.
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
CfgUtils::mfn_UnloadWlbsFuncs(VOID)
|
|
//
|
|
// ok to call multiple times (i.e. idempotent).
|
|
// MUST be called with lock held.
|
|
//
|
|
{
|
|
m_NLBApiHooksPresent = FALSE;
|
|
|
|
m_pfWlbsOpen = NULL;
|
|
m_pfWlbsLocalClusterControl = NULL;
|
|
m_pfWlbsAddPortRule = NULL;
|
|
m_pfWlbsDeleteAllPortRules = NULL;
|
|
m_pfWlbsEnumPortRules = NULL;
|
|
m_pfWlbsSetDefaults = NULL;
|
|
m_pfWlbsValidateParams = NULL;
|
|
m_pfWlbsParamReadReg = NULL ;
|
|
m_pfWlbsParamWriteReg = NULL ;
|
|
m_pfWlbsWriteAndCommitChanges = NULL;
|
|
m_pfWlbsSetRemotePassword = NULL;
|
|
m_pfWlbsGetClusterMembers = NULL;
|
|
|
|
if (m_hWlbsCtrlDll != NULL)
|
|
{
|
|
FreeLibrary(m_hWlbsCtrlDll);
|
|
m_hWlbsCtrlDll = NULL;
|
|
}
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SCODE CfgUtilParseAuthorityUserArgs
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// This function is a straight lift from the wmi sdk sample project : utillib,
|
|
// File : wbemsec.cpp, Function : ParseAuthorityUserArgs
|
|
// This function is used internally only.
|
|
//
|
|
// Examines the Authority and User argument and determines the authentication
|
|
// type and possibly extracts the domain name from the user arugment in the
|
|
// NTLM case. For NTLM, the domain can be at the end of the authentication
|
|
// string, or in the front of the user name, ex; "redmond\a-davj"
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// AuthArg Output, contains the domain name
|
|
// UserArg Output, user name
|
|
// Authority Input
|
|
// User Input
|
|
//
|
|
// RETURN VALUE: WBEMSTATUS
|
|
//
|
|
//***************************************************************************
|
|
|
|
WBEMSTATUS CfgUtilParseAuthorityUserArgs(BSTR & AuthArg, BSTR & UserArg, LPCWSTR Authority, LPCWSTR User)
|
|
{
|
|
|
|
TRACE_INFO(L"-> %!FUNC!");
|
|
|
|
//
|
|
// If the Authority string is passed, then, it better begin with "NTLMDOMAIN:"
|
|
//
|
|
if(!(Authority == NULL || wcslen(Authority) == 0 || !_wcsnicmp(Authority, L"NTLMDOMAIN:",11)))
|
|
{
|
|
TRACE_CRIT(L"%!FUNC! Invalid authority string : %ls, Must be NULL or empty or begin with \"NTLMDOMAIN:\"",Authority);
|
|
TRACE_INFO(L"<- %!FUNC! returning WBEM_E_INVALID_PARAMETER");
|
|
return WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
// The ntlm case is more complex. There are four cases
|
|
// 1) Authority = NTLMDOMAIN:name" and User = "User"
|
|
// 2) Authority = NULL and User = "User"
|
|
// 3) Authority = "NTLMDOMAIN:" User = "domain\user"
|
|
// 4) Authority = NULL and User = "domain\user"
|
|
|
|
//
|
|
// first step is to determine if there is a backslash in the user name somewhere between the
|
|
// second and second to last character
|
|
//
|
|
|
|
WCHAR * pSlashInUser = NULL;
|
|
if(User)
|
|
{
|
|
WCHAR * pEnd = (WCHAR *)User + wcslen(User) - 1;
|
|
for(pSlashInUser = (WCHAR *)User; pSlashInUser <= pEnd; pSlashInUser++)
|
|
if(*pSlashInUser == L'\\') // dont think forward slash is allowed!
|
|
break;
|
|
if(pSlashInUser > pEnd)
|
|
pSlashInUser = NULL;
|
|
}
|
|
|
|
//
|
|
// If Authority string is passed and it is of the form "NTLMDOMAIN:XXXX", copy over "XXXX" into
|
|
// AuthArg. The only other form that it could take is "NTLMDOMAIN:", in which case, we leave
|
|
// AuthArg to be NULL.
|
|
//
|
|
if(Authority && wcslen(Authority) > 11)
|
|
{
|
|
if(pSlashInUser)
|
|
{
|
|
TRACE_CRIT(L"%!FUNC! Invalid combination of User : %ls & Authority string : %ls",User,Authority);
|
|
TRACE_INFO(L"<- %!FUNC! returning WBEM_E_INVALID_PARAMETER");
|
|
return WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((AuthArg = SysAllocString(Authority + 11)) == NULL)
|
|
{
|
|
TRACE_CRIT(L"%!FUNC! Out of memory, Memory allocation failed for Authority string : %ls",Authority + 11);
|
|
TRACE_INFO(L"<- %!FUNC! returning WBEM_E_OUT_OF_MEMORY");
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
if(User)
|
|
{
|
|
UserArg = SysAllocString(User);
|
|
TRACE_CRIT(L"%!FUNC! Out of memory, Memory allocation failed for User string : %ls",User);
|
|
SysFreeString(AuthArg);
|
|
TRACE_INFO(L"<- %!FUNC! returning WBEM_E_OUT_OF_MEMORY");
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
TRACE_INFO(L"<- %!FUNC! returning WBEM_NO_ERROR");
|
|
return WBEM_NO_ERROR;
|
|
}
|
|
else if(pSlashInUser)
|
|
{
|
|
// backslash was found in "User", extract the domain name present before the backslash
|
|
int iDomLen = pSlashInUser-User;
|
|
WCHAR cTemp[MAX_PATH];
|
|
wcsncpy(cTemp, User, iDomLen);
|
|
cTemp[iDomLen] = 0;
|
|
|
|
if ((AuthArg = SysAllocString(cTemp)) == NULL)
|
|
{
|
|
TRACE_CRIT(L"%!FUNC! Out of memory, Memory allocation failed for Authority (\"Authority\\User\") string : %ls",cTemp);
|
|
TRACE_INFO(L"<- %!FUNC! returning WBEM_E_OUT_OF_MEMORY");
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
if(wcslen(pSlashInUser+1))
|
|
{
|
|
if ((UserArg = SysAllocString(pSlashInUser+1)) == NULL)
|
|
{
|
|
TRACE_CRIT(L"%!FUNC! Out of memory, Memory allocation failed for Authority (\"Authority\\User\") string : %ls",pSlashInUser+1);
|
|
SysFreeString(AuthArg);
|
|
TRACE_INFO(L"<- %!FUNC! returning WBEM_E_OUT_OF_MEMORY");
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
}
|
|
else // User name did not contain backslash (ie. domain) AND (Authority was NOT passed or was = "NTLMDOMAIN:")
|
|
{
|
|
if(User)
|
|
{
|
|
if ((UserArg = SysAllocString(User)) == NULL)
|
|
{
|
|
TRACE_CRIT(L"%!FUNC! Out of memory, Memory allocation failed for User (No Authority) string : %ls",User);
|
|
TRACE_INFO(L"<- %!FUNC! returning WBEM_E_OUT_OF_MEMORY");
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
}
|
|
|
|
TRACE_INFO(L"<- %!FUNC! returning WBEM_NO_ERROR");
|
|
return WBEM_NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// Gets the list of statically-bound IP addresses for the NIC.
|
|
// Sets *pNumIpAddresses to 0 if DHCP
|
|
//
|
|
WBEMSTATUS
|
|
CfgUtilGetIpAddressesAndFriendlyName(
|
|
IN LPCWSTR szNic,
|
|
OUT UINT *pNumIpAddresses,
|
|
OUT NLB_IP_ADDRESS_INFO **ppIpInfo, // Free using c++ delete operator.
|
|
OUT LPWSTR *pszFriendlyName // Optional, Free using c++ delete
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_NO_ERROR;
|
|
IWbemClassObjectPtr spObj = NULL; // smart pointer
|
|
HRESULT hr;
|
|
LPCWSTR pAddrs = NULL;
|
|
LPCWSTR pSubnets = NULL;
|
|
UINT AddrCount = 0;
|
|
UINT ValidAddrCount = 0;
|
|
NLB_IP_ADDRESS_INFO *pIpInfo = NULL;
|
|
|
|
TRACE_INFO(L"-> %!FUNC!(Nic=%ws)", szNic);
|
|
|
|
*pNumIpAddresses = NULL;
|
|
*ppIpInfo = NULL;
|
|
if (pszFriendlyName!=NULL)
|
|
{
|
|
*pszFriendlyName = NULL;
|
|
}
|
|
|
|
//
|
|
// If not initialized, fail...
|
|
//
|
|
if (!g_CfgUtils.IsInitalized())
|
|
{
|
|
TRACE_CRIT(L"%!FUNC!(Nic=%ws) FAILING because uninitialized", szNic);
|
|
Status = WBEM_E_INITIALIZATION_FAILURE;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Get WMI instance to specific NIC
|
|
//
|
|
Status = get_nic_instance(
|
|
g_CfgUtils.m_spWbemServiceIF,
|
|
szNic,
|
|
spObj // pass by reference
|
|
);
|
|
if (FAILED(Status))
|
|
{
|
|
ASSERT(spObj == NULL);
|
|
goto end;
|
|
}
|
|
|
|
|
|
//
|
|
// Extract IP addresses and subnets.
|
|
//
|
|
{
|
|
//
|
|
// This gets the ip addresses in a 2D WCHAR array -- inner dimension
|
|
// is WLBS_MAX_CLI_IP_ADDR.
|
|
//
|
|
Status = get_multi_string_parameter(
|
|
spObj,
|
|
L"IPAddress", // szParameterName,
|
|
WLBS_MAX_CL_IP_ADDR, // MaxStringLen - in wchars, incl null
|
|
&AddrCount,
|
|
&pAddrs
|
|
);
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
pAddrs = NULL;
|
|
goto end;
|
|
}
|
|
else
|
|
{
|
|
TRACE_INFO("GOT %lu IP ADDRESSES!", AddrCount);
|
|
}
|
|
|
|
UINT SubnetCount;
|
|
Status = get_multi_string_parameter(
|
|
spObj,
|
|
L"IPSubnet", // szParameterName,
|
|
WLBS_MAX_CL_NET_MASK, // MaxStringLen - in wchars, incl null
|
|
&SubnetCount,
|
|
&pSubnets
|
|
);
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
pSubnets = NULL;
|
|
goto end;
|
|
}
|
|
else if (SubnetCount != AddrCount)
|
|
{
|
|
TRACE_CRIT("FAILING SubnetCount!=AddressCount!");
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Convert IP addresses to our internal form.
|
|
//
|
|
if (AddrCount != 0)
|
|
{
|
|
pIpInfo = new NLB_IP_ADDRESS_INFO[AddrCount];
|
|
if (pIpInfo == NULL)
|
|
{
|
|
TRACE_CRIT("get_multi_str_parm: Alloc failure!");
|
|
Status = WBEM_E_OUT_OF_MEMORY;
|
|
goto end;
|
|
}
|
|
ZeroMemory(pIpInfo, AddrCount*sizeof(*pIpInfo));
|
|
|
|
for (UINT u=0;u<AddrCount; u++)
|
|
{
|
|
//
|
|
// We extrace each IP address and it's corresponding subnet mask
|
|
// from the 2 2D arrays and insert it into a NLB_IP_ADDRESS_INFO
|
|
// structure.
|
|
//
|
|
LPCWSTR pIp = pAddrs+u*WLBS_MAX_CL_IP_ADDR;
|
|
LPCWSTR pSub = pSubnets+u*WLBS_MAX_CL_NET_MASK;
|
|
TRACE_INFO("IPaddress: %ws; SubnetMask:%ws", pIp, pSub);
|
|
UINT len = wcslen(pIp);
|
|
UINT len1 = wcslen(pSub);
|
|
if ( (len < WLBS_MAX_CL_IP_ADDR) && (len1 < WLBS_MAX_CL_NET_MASK))
|
|
{
|
|
//
|
|
// We can sometimes get blank IP addresses -- if there's been
|
|
// an IP address conflict. So let's skip those.
|
|
//
|
|
if (*pIp==0 || _wcsspnp(pIp, L".0")==NULL)
|
|
{
|
|
TRACE_CRIT(L"%!FUNC! ignoring blank IP address!");
|
|
}
|
|
else
|
|
{
|
|
CopyMemory(pIpInfo[u].IpAddress, pIp, (len+1)*sizeof(WCHAR));
|
|
CopyMemory(pIpInfo[u].SubnetMask, pSub, (len1+1)*sizeof(WCHAR));
|
|
ValidAddrCount++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This would be an implementation error in get_multi_string_...
|
|
//
|
|
ASSERT(FALSE);
|
|
Status = WBEM_E_CRITICAL_ERROR;
|
|
goto end;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ValidAddrCount == 0)
|
|
{
|
|
delete[] pIpInfo; // could be NULL.
|
|
pIpInfo = NULL;
|
|
}
|
|
|
|
//
|
|
// If requested, get friendly name.
|
|
// We don't fail if there's an error, just return the empty "" string.
|
|
//
|
|
if (pszFriendlyName != NULL)
|
|
{
|
|
IWbemClassObjectPtr spAdapterObj = NULL; // smart pointer
|
|
LPWSTR szFriendlyName = NULL;
|
|
WBEMSTATUS TmpStatus;
|
|
|
|
TRACE_INFO(L"%!FUNC!: Getting friendly name for Nic %ws", szNic);
|
|
|
|
#if USE_WMI_FOR_FRIENDLY_NAME
|
|
|
|
//
|
|
// Enabling this code block causes us to take over 1000 times as long
|
|
// to get the friendly name -- so don't enable it!
|
|
// This code (i.e. the slow version) ships in .Net Server Beta3,
|
|
// but is commented out and repaced by the faster registry-growelling
|
|
// version.
|
|
//
|
|
|
|
do
|
|
{
|
|
TmpStatus = CfgUtilGetWmiAdapterObjFromAdapterConfigurationObj(
|
|
g_CfgUtils.m_spWbemServiceIF,
|
|
spObj,
|
|
spAdapterObj // passed by ref
|
|
);
|
|
|
|
if (FAILED(TmpStatus))
|
|
{
|
|
break;
|
|
}
|
|
|
|
TmpStatus = CfgUtilGetWmiStringParam(
|
|
spAdapterObj,
|
|
L"NetConnectionID",
|
|
&szFriendlyName
|
|
);
|
|
if (FAILED(TmpStatus))
|
|
{
|
|
TRACE_CRIT("%!FUNC! Get NetConnectionID failed error=0x%08lx\n",
|
|
(UINT) TmpStatus);
|
|
|
|
}
|
|
|
|
} while (FALSE);
|
|
#else !USE_WMI_FOR_FRIENDLY_NAME
|
|
Status = get_friendly_name_from_registry(szNic, &szFriendlyName);
|
|
|
|
#endif // !USE_WMI_FOR_FRIENDLY_NAME
|
|
if (FAILED(Status))
|
|
{
|
|
TRACE_INFO(L"%!FUNC!: Got error 0x%lx attempting to get friendly name", Status);
|
|
szFriendlyName = NULL;
|
|
Status = WBEM_NO_ERROR; // we'll ignore this..
|
|
}
|
|
else
|
|
{
|
|
TRACE_INFO(L"%!FUNC!: Got friendly name \"%ws\" for NIC %ws",
|
|
szFriendlyName ? szFriendlyName:L"<null>", szNic);
|
|
}
|
|
|
|
|
|
if (szFriendlyName == NULL)
|
|
{
|
|
//
|
|
// Try to put an empty string.
|
|
//
|
|
szFriendlyName = new WCHAR[1];
|
|
if (szFriendlyName == NULL)
|
|
{
|
|
Status = WBEM_E_OUT_OF_MEMORY;
|
|
TRACE_CRIT("%!FUNC! Alloc failure!");
|
|
goto end;
|
|
}
|
|
*szFriendlyName = 0; // Empty string
|
|
}
|
|
|
|
*pszFriendlyName = szFriendlyName;
|
|
szFriendlyName = NULL;
|
|
}
|
|
|
|
end:
|
|
|
|
if (pAddrs != NULL)
|
|
{
|
|
delete pAddrs;
|
|
}
|
|
if (pSubnets != NULL)
|
|
{
|
|
delete pSubnets;
|
|
}
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
if (pIpInfo != NULL)
|
|
{
|
|
delete[] pIpInfo;
|
|
pIpInfo = NULL;
|
|
}
|
|
ValidAddrCount = 0;
|
|
}
|
|
|
|
*pNumIpAddresses = ValidAddrCount;
|
|
*ppIpInfo = pIpInfo;
|
|
spObj = NULL; // smart pointer
|
|
|
|
TRACE_INFO(L"<- %!FUNC!(Nic=%ws) returns 0x%08lx", szNic, (UINT) Status);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
//
|
|
// Sets the list of statically-bound IP addresses for the NIC.
|
|
// if NumIpAddresses is 0, the NIC is configured for DHCP.
|
|
//
|
|
WBEMSTATUS
|
|
CfgUtilSetStaticIpAddresses(
|
|
IN LPCWSTR szNic,
|
|
IN UINT NumIpAddresses,
|
|
IN NLB_IP_ADDRESS_INFO *pIpInfo
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
IWbemClassObjectPtr spWbemInputInstance = NULL; // smart pointer
|
|
WCHAR *rgIpAddresses = NULL;
|
|
WCHAR *rgIpSubnets = NULL;
|
|
LPWSTR pRelPath = NULL;
|
|
NLB_IP_ADDRESS_INFO AutonetIpInfo;
|
|
|
|
TRACE_INFO(L"-> %!FUNC!(Nic=%ws)", szNic);
|
|
|
|
//
|
|
// If not initialized, fail...
|
|
//
|
|
if (!g_CfgUtils.IsInitalized())
|
|
{
|
|
TRACE_CRIT(L"%!FUNC!(Nic=%ws) FAILING because uninitialized", szNic);
|
|
Status = WBEM_E_INITIALIZATION_FAILURE;
|
|
goto end;
|
|
}
|
|
|
|
if (NumIpAddresses == 0)
|
|
{
|
|
|
|
//
|
|
// If there are no IP addresses specified, we generate a
|
|
// random autonet address. This is because the wmi set operation
|
|
// below simply fails if no addresses are specified. Strictly speaking
|
|
// we should try dhcp.
|
|
//
|
|
// AutoNet address in the address range 169.254,
|
|
// and it will give itself a class B subnet mask that
|
|
// is 255.255.0.0.
|
|
//
|
|
|
|
ZeroMemory(&AutonetIpInfo, sizeof(AutonetIpInfo));
|
|
|
|
UINT u1, u2;
|
|
u1 = crc16(szNic);
|
|
u2 = (u1>>8)&0xff;
|
|
u1 = u1&0xff;
|
|
if (u1>=255) u1=254;
|
|
if (u2==0) u2=1;
|
|
if (u2>=255) u2=254;
|
|
|
|
StringCbPrintf(AutonetIpInfo.IpAddress, sizeof(AutonetIpInfo.IpAddress), L"169.254.%lu.%lu", u1, u2);
|
|
ARRAYSTRCPY(AutonetIpInfo.SubnetMask, L"255.255.0.0");
|
|
|
|
NumIpAddresses = 1;
|
|
pIpInfo = &AutonetIpInfo;
|
|
|
|
// SECURITY BUGBUG -- consider compiling this out...
|
|
}
|
|
|
|
|
|
if (NumIpAddresses != 0)
|
|
{
|
|
//
|
|
// Convert IP addresses from our internal form into 2D arrays.
|
|
//
|
|
rgIpAddresses = new WCHAR[NumIpAddresses * WLBS_MAX_CL_IP_ADDR];
|
|
rgIpSubnets = new WCHAR[NumIpAddresses * WLBS_MAX_CL_NET_MASK];
|
|
if (rgIpAddresses == NULL || rgIpSubnets == NULL)
|
|
{
|
|
TRACE_CRIT("SetStaticIpAddresses: Alloc failure!");
|
|
Status = WBEM_E_OUT_OF_MEMORY;
|
|
goto end;
|
|
}
|
|
|
|
for (UINT u=0;u<NumIpAddresses; u++)
|
|
{
|
|
//
|
|
// We extrace each IP address and it's corresponding subnet mask
|
|
// from the 2 2D arrays and insert it into a NLB_IP_ADDRESS_INFO
|
|
// structure.
|
|
//
|
|
LPWSTR pIpDest = rgIpAddresses+u*WLBS_MAX_CL_IP_ADDR;
|
|
LPWSTR pSubDest = rgIpSubnets+u*WLBS_MAX_CL_NET_MASK;
|
|
LPCWSTR pIpSrc = pIpInfo[u].IpAddress;
|
|
LPCWSTR pSubSrc = pIpInfo[u].SubnetMask;
|
|
UINT len = wcslen(pIpSrc);
|
|
UINT len1 = wcslen(pSubSrc);
|
|
if ( (len < WLBS_MAX_CL_IP_ADDR) && (len1 < WLBS_MAX_CL_NET_MASK))
|
|
{
|
|
CopyMemory(pIpDest, pIpSrc, (len+1)*sizeof(WCHAR));
|
|
CopyMemory(pSubDest, pSubSrc, (len1+1)*sizeof(WCHAR));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This would be an implementation error in get_multi_string_...
|
|
//
|
|
ASSERT(FALSE);
|
|
goto end;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get input instance and relpath...
|
|
//
|
|
Status = CfgUtilGetWmiInputInstanceAndRelPath(
|
|
g_CfgUtils.m_spWbemServiceIF,
|
|
L"Win32_NetworkAdapterConfiguration", // szClassName
|
|
L"SettingID", // szPropertyName
|
|
szNic, // szPropertyValue
|
|
L"EnableStatic", // szMethodName,
|
|
spWbemInputInstance, // smart pointer
|
|
&pRelPath // free using delete
|
|
);
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Set up input parameters to the call to Enable static.
|
|
//
|
|
{
|
|
|
|
//
|
|
// This gets the ip addresses in a 2D WCHAR array -- inner dimension
|
|
// is WLBS_MAX_CLI_IP_ADDR.
|
|
//
|
|
Status = set_multi_string_parameter(
|
|
spWbemInputInstance,
|
|
L"IPAddress", // szParameterName,
|
|
WLBS_MAX_CL_IP_ADDR, // MaxStringLen - in wchars, incl null
|
|
NumIpAddresses,
|
|
rgIpAddresses
|
|
);
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
goto end;
|
|
}
|
|
else
|
|
{
|
|
TRACE_INFO("SET %lu IP ADDRESSES!", NumIpAddresses);
|
|
}
|
|
|
|
Status = set_multi_string_parameter(
|
|
spWbemInputInstance,
|
|
L"SubnetMask", // szParameterName,
|
|
WLBS_MAX_CL_NET_MASK, // MaxStringLen - in wchars, incl null
|
|
NumIpAddresses,
|
|
rgIpSubnets
|
|
);
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// execute method and get the output result
|
|
// WARNING: we try this a few times because the wmi call apperears to
|
|
// suffer from a recoverable error. TODO: Need to get to the bottom of
|
|
// this.
|
|
//
|
|
UINT uiMaxTries = 10;
|
|
for (UINT NumTries=uiMaxTries; NumTries--;)
|
|
{
|
|
HRESULT hr;
|
|
IWbemClassObjectPtr spWbemOutput = NULL; // smart pointer.
|
|
_variant_t v_retVal;
|
|
|
|
TRACE_CRIT("Going to call EnableStatic");
|
|
|
|
hr = g_CfgUtils.m_spWbemServiceIF->ExecMethod(
|
|
_bstr_t(pRelPath),
|
|
L"EnableStatic",
|
|
0,
|
|
NULL,
|
|
spWbemInputInstance,
|
|
&spWbemOutput,
|
|
NULL
|
|
);
|
|
TRACE_CRIT("EnableStatic returns");
|
|
|
|
if( FAILED( hr) )
|
|
{
|
|
TRACE_CRIT("%!FUNC! IWbemServices::ExecMethod failure 0x%08lx while invoking EnableStatic", (UINT) hr);
|
|
goto end;
|
|
}
|
|
|
|
hr = spWbemOutput->Get(
|
|
L"ReturnValue",
|
|
0,
|
|
&v_retVal,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if( FAILED( hr) )
|
|
{
|
|
TRACE_CRIT("%!FUNC! IWbemClassObject::Get failure while checking status of EnableStatic call");
|
|
goto end;
|
|
}
|
|
|
|
LONG lRet = (LONG) v_retVal;
|
|
v_retVal.Clear();
|
|
|
|
if (lRet == 0)
|
|
{
|
|
TRACE_INFO("%!FUNC! EnableStatic returns SUCCESS! after %d attempts", uiMaxTries-NumTries);
|
|
Status = WBEM_NO_ERROR;
|
|
break;
|
|
}
|
|
|
|
// We failed. Sleep and try again.
|
|
Sleep(1000);
|
|
|
|
// Failures seen while testing status:
|
|
// 0x42 = Invalid subnet mask (can happen when removing IPs from adapter, if removing all of them)
|
|
// 0x51 = Unable to configure DHCP service
|
|
// 0x54 = IP not enabled on adapter (happens while the adapter is processing the request to add an IP)
|
|
// For other return codes, see http://index2. Search for EnableStatic in sdnt\admin\wmi\wbem\providers\mofs\win32_network.mof
|
|
if (lRet == 0x42 || lRet == 0x51 || lRet == 0x54) // These appear to be a recoverable errors
|
|
{
|
|
TRACE_INFO(
|
|
"%!FUNC! EnableStatic on NIC %ws returns recoverable FAILURE:0x%08lx! after %d attempts",
|
|
szNic,
|
|
lRet,
|
|
uiMaxTries-NumTries
|
|
);
|
|
Status = WBEM_E_CRITICAL_ERROR;
|
|
}
|
|
else
|
|
{
|
|
TRACE_INFO(
|
|
"%!FUNC! EnableStatic on NIC %ws returns FAILURE:0x%08lx! after %d attempts",
|
|
szNic,
|
|
lRet,
|
|
uiMaxTries-NumTries
|
|
);
|
|
Status = WBEM_E_CRITICAL_ERROR;
|
|
}
|
|
}
|
|
|
|
if (!FAILED(Status))
|
|
{
|
|
BOOL fMatch = FALSE;
|
|
UINT uMatchAttemptsLeft = 5;
|
|
|
|
do
|
|
{
|
|
fMatch = TRUE;
|
|
|
|
//
|
|
// Sometimes this function returns before the ip addresses actually
|
|
// show up in IPCONFIG. So let's check.
|
|
//
|
|
WBEMSTATUS wStat2;
|
|
UINT NumAddrs2=0;
|
|
NLB_IP_ADDRESS_INFO *pIpInfo2 = NULL;
|
|
wStat2 = CfgUtilGetIpAddressesAndFriendlyName(
|
|
szNic,
|
|
&NumAddrs2,
|
|
&pIpInfo2,
|
|
NULL // pszFriendlyName (unused)
|
|
);
|
|
if (FAILED(wStat2))
|
|
{
|
|
//
|
|
// We won't bother trying again.
|
|
//
|
|
break;
|
|
}
|
|
|
|
if (NumAddrs2 == 0)
|
|
{
|
|
pIpInfo2 = NULL;
|
|
}
|
|
|
|
//
|
|
// Check for match
|
|
//
|
|
if (NumAddrs2 != NumIpAddresses)
|
|
{
|
|
fMatch = FALSE;
|
|
}
|
|
else
|
|
{
|
|
|
|
for (UINT u=0; u<NumAddrs2; u++)
|
|
{
|
|
NLB_IP_ADDRESS_INFO *pInfoA=pIpInfo+u;
|
|
NLB_IP_ADDRESS_INFO *pInfoB=pIpInfo2+u;
|
|
if ( _wcsicmp(pInfoA->IpAddress, pInfoB->IpAddress)
|
|
|| _wcsicmp(pInfoA->SubnetMask, pInfoB->SubnetMask))
|
|
{
|
|
fMatch = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
delete[] pIpInfo2;
|
|
|
|
if (fMatch)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (uMatchAttemptsLeft)
|
|
{
|
|
uMatchAttemptsLeft--;
|
|
Sleep(2000);
|
|
}
|
|
|
|
} while (uMatchAttemptsLeft);
|
|
}
|
|
|
|
end:
|
|
|
|
if (rgIpAddresses != NULL)
|
|
{
|
|
delete[] rgIpAddresses;
|
|
}
|
|
if (rgIpSubnets != NULL)
|
|
{
|
|
delete[] rgIpSubnets;
|
|
}
|
|
|
|
if (pRelPath != NULL)
|
|
{
|
|
delete pRelPath;
|
|
}
|
|
|
|
spWbemInputInstance = NULL;
|
|
|
|
TRACE_INFO(L"<- %!FUNC!(Nic=%ws) returns 0x%08lx", szNic, (UINT) Status);
|
|
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Sets the IP addresses for the NIC to be DHCP-assigned.
|
|
//
|
|
WBEMSTATUS
|
|
CfgUtilSetDHCP(
|
|
IN LPCWSTR szNic
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
IWbemClassObjectPtr spWbemInputInstance = NULL; // smart pointer
|
|
LPWSTR pRelPath = NULL;
|
|
|
|
TRACE_INFO(L"-> %!FUNC!(Nic=%ws)", szNic);
|
|
|
|
//
|
|
// If not initialized, fail...
|
|
//
|
|
if (!g_CfgUtils.IsInitalized())
|
|
{
|
|
TRACE_CRIT(L"%!FUNC!(Nic=%ws) FAILING because uninitialized", szNic);
|
|
Status = WBEM_E_INITIALIZATION_FAILURE;
|
|
goto end;
|
|
}
|
|
|
|
|
|
//
|
|
// Get input instance and relpath...
|
|
//
|
|
Status = CfgUtilGetWmiInputInstanceAndRelPath(
|
|
g_CfgUtils.m_spWbemServiceIF,
|
|
L"Win32_NetworkAdapterConfiguration", // szClassName
|
|
L"SettingID", // szPropertyName
|
|
szNic, // szPropertyValue
|
|
L"EnableDHCP", // szMethodName,
|
|
spWbemInputInstance, // smart pointer
|
|
&pRelPath // free using delete
|
|
);
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// No input params to setup.
|
|
//
|
|
|
|
|
|
//
|
|
// execute method and get the output result
|
|
// WARNING: we try this a few times because the wmi call apperears to
|
|
// suffer from a recoverable error. TODO: Need to get to the bottom of
|
|
// this.
|
|
//
|
|
UINT uiMaxTries = 10;
|
|
for (UINT NumTries=uiMaxTries; NumTries--;)
|
|
{
|
|
HRESULT hr;
|
|
IWbemClassObjectPtr spWbemOutput = NULL; // smart pointer.
|
|
_variant_t v_retVal;
|
|
|
|
TRACE_CRIT("Going to call EnableDHCP");
|
|
|
|
hr = g_CfgUtils.m_spWbemServiceIF->ExecMethod(
|
|
_bstr_t(pRelPath),
|
|
L"EnableDHCP",
|
|
0,
|
|
NULL,
|
|
spWbemInputInstance,
|
|
&spWbemOutput,
|
|
NULL
|
|
);
|
|
TRACE_CRIT("EnableDHCP returns");
|
|
|
|
if( FAILED( hr) )
|
|
{
|
|
TRACE_CRIT("%!FUNC! IWbemServices::ExecMethod failure 0x%08lx while invoking EnableDHCP", (UINT) hr);
|
|
goto end;
|
|
}
|
|
|
|
hr = spWbemOutput->Get(
|
|
L"ReturnValue",
|
|
0,
|
|
&v_retVal,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if( FAILED( hr) )
|
|
{
|
|
TRACE_CRIT("%!FUNC! IWbemClassObject::Get failure while checking status of EnableDHCP call");
|
|
goto end;
|
|
}
|
|
|
|
LONG lRet = (LONG) v_retVal;
|
|
v_retVal.Clear();
|
|
|
|
if (lRet == 0)
|
|
{
|
|
TRACE_INFO("%!FUNC! EnableDHCP returns SUCCESS! after %d attempts", uiMaxTries-NumTries);
|
|
Status = WBEM_NO_ERROR;
|
|
break;
|
|
}
|
|
|
|
// We failed. Sleep and try again.
|
|
Sleep(1000);
|
|
|
|
// Failures seen while testing status:
|
|
// 0x42 = Invalid subnet mask (can happen when removing IPs from adapter, if removing all of them)
|
|
// 0x51 = Unable to configure DHCP service
|
|
// 0x54 = IP not enabled on adapter (happens while the adapter is processing the request to add an IP)
|
|
// For other return codes, see http://index2. Search for EnableStatic in sdnt\admin\wmi\wbem\providers\mofs\win32_network.mof
|
|
if (lRet == 0x42 || lRet == 0x51 || lRet == 0x54) // These appear to be a recoverable errors
|
|
{
|
|
TRACE_INFO(
|
|
"%!FUNC! EnableDHCP on NIC %ws returns recoverable FAILURE:0x%08lx! after %d attempts",
|
|
szNic,
|
|
lRet,
|
|
uiMaxTries-NumTries
|
|
);
|
|
Status = WBEM_E_CRITICAL_ERROR;
|
|
}
|
|
else
|
|
{
|
|
TRACE_INFO(
|
|
"%!FUNC! EnableDHCP on NIC %ws returns FAILURE:0x%08lx! after %d attempts",
|
|
szNic,
|
|
lRet,
|
|
uiMaxTries-NumTries
|
|
);
|
|
Status = WBEM_E_CRITICAL_ERROR;
|
|
}
|
|
}
|
|
|
|
end:
|
|
|
|
spWbemInputInstance = NULL;
|
|
|
|
TRACE_INFO(L"<- %!FUNC!(Nic=%ws) returns 0x%08lx", szNic, (UINT) Status);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
//
|
|
// Determines whether the specified nic is configured with DHCP or not.
|
|
//
|
|
WBEMSTATUS
|
|
CfgUtilGetDHCP(
|
|
IN LPCWSTR szNic,
|
|
OUT BOOL *pfDHCP
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_NO_ERROR;
|
|
IWbemClassObjectPtr spObj = NULL; // smart pointer
|
|
HRESULT hr;
|
|
|
|
TRACE_INFO(L"-> %!FUNC!(Nic=%ws)", szNic);
|
|
|
|
*pfDHCP = FALSE;
|
|
|
|
//
|
|
// If not initialized, fail...
|
|
//
|
|
if (!g_CfgUtils.IsInitalized())
|
|
{
|
|
TRACE_CRIT(L"%!FUNC!(Nic=%ws) FAILING because uninitialized", szNic);
|
|
Status = WBEM_E_INITIALIZATION_FAILURE;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Get WMI instance to specific NIC
|
|
//
|
|
Status = get_nic_instance(
|
|
g_CfgUtils.m_spWbemServiceIF,
|
|
szNic,
|
|
spObj // pass by reference
|
|
);
|
|
if (FAILED(Status))
|
|
{
|
|
ASSERT(spObj == NULL);
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Extract IP addresses and subnets.
|
|
//
|
|
Status = CfgUtilGetWmiBoolParam(
|
|
spObj,
|
|
L"DHCPEnabled", // szParameterName,
|
|
pfDHCP
|
|
);
|
|
|
|
if (Status == WBEM_E_NOT_FOUND)
|
|
{
|
|
//
|
|
// We treat not-found as no-dhcp -- this is what we see in practise.
|
|
//
|
|
*pfDHCP = FALSE;
|
|
Status = WBEM_NO_ERROR;
|
|
}
|
|
end:
|
|
|
|
spObj = NULL; // smart pointer
|
|
|
|
TRACE_INFO(L"<- %!FUNC!(Nic=%ws) returns 0x%08lx (fDHCP=%lu)",
|
|
szNic, (UINT) Status, *pfDHCP);
|
|
|
|
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
CfgUtilGetNetcfgWriteLockState(
|
|
OUT BOOL *pfCanLock,
|
|
LPWSTR *pszHeldBy // OPTIONAL, free using delete[].
|
|
)
|
|
{
|
|
WBEMSTATUS Status;
|
|
|
|
Status = MyNetCfg::GetWriteLockState(pfCanLock, pszHeldBy);
|
|
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Determines whether NLB is bound to the specified NIC.
|
|
//
|
|
WBEMSTATUS
|
|
CfgUtilCheckIfNlbBound(
|
|
IN LPCWSTR szNic,
|
|
OUT BOOL *pfBound
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_NO_ERROR;
|
|
BOOL fNetCfgInitialized = FALSE;
|
|
MyNetCfg NetCfg;
|
|
BOOL fBound = FALSE;
|
|
|
|
|
|
//
|
|
// Get and initialize interface to netcfg
|
|
//
|
|
Status = NetCfg.Initialize(FALSE); // FALSE == don't get write lock.
|
|
if (FAILED(Status))
|
|
{
|
|
goto end;
|
|
}
|
|
fNetCfgInitialized = TRUE;
|
|
|
|
//
|
|
//
|
|
//
|
|
Status = NetCfg.UpdateBindingState(
|
|
szNic,
|
|
L"ms_wlbs",
|
|
MyNetCfg::NOOP,
|
|
&fBound
|
|
);
|
|
|
|
end:
|
|
|
|
if (fNetCfgInitialized)
|
|
{
|
|
NetCfg.Deinitialize();
|
|
}
|
|
|
|
*pfBound = fBound;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
//
|
|
// Binds/unbinds NLB to the specified NIC.
|
|
//
|
|
WBEMSTATUS
|
|
CfgUtilChangeNlbBindState(
|
|
IN LPCWSTR szNic,
|
|
IN BOOL fBind
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_NO_ERROR;
|
|
BOOL fNetCfgInitialized = FALSE;
|
|
MyNetCfg NetCfg;
|
|
BOOL fBound = FALSE;
|
|
|
|
|
|
//
|
|
// Get and initialize interface to netcfg
|
|
//
|
|
Status = NetCfg.Initialize(TRUE); // TRUE == get write lock.
|
|
if (FAILED(Status))
|
|
{
|
|
goto end;
|
|
}
|
|
fNetCfgInitialized = TRUE;
|
|
|
|
//
|
|
//
|
|
//
|
|
Status = NetCfg.UpdateBindingState(
|
|
szNic,
|
|
L"ms_wlbs",
|
|
fBind ? MyNetCfg::BIND : MyNetCfg::UNBIND,
|
|
&fBound
|
|
);
|
|
|
|
end:
|
|
|
|
if (fNetCfgInitialized)
|
|
{
|
|
NetCfg.Deinitialize();
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Gets the current NLB configuration for the specified NIC
|
|
//
|
|
WBEMSTATUS
|
|
CfgUtilGetNlbConfig(
|
|
IN LPCWSTR szNic,
|
|
OUT WLBS_REG_PARAMS *pParams
|
|
)
|
|
{
|
|
GUID Guid;
|
|
WBEMSTATUS Status = WBEM_NO_ERROR;
|
|
|
|
|
|
// Verify that the NLB API hooks are present
|
|
if (!g_CfgUtils.m_NLBApiHooksPresent)
|
|
{
|
|
TRACE_CRIT(L"%!FUNC! FAILING because NLB API hooks are not present");
|
|
Status = WBEM_E_INITIALIZATION_FAILURE;
|
|
goto end;
|
|
}
|
|
|
|
HRESULT hr = CLSIDFromString((LPWSTR)szNic, &Guid);
|
|
if (FAILED(hr))
|
|
{
|
|
Status = WBEM_E_INVALID_PARAMETER;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Read the configuration.
|
|
//
|
|
BOOL fRet = g_CfgUtils.m_pfWlbsParamReadReg(&Guid, pParams);
|
|
|
|
if (!fRet)
|
|
{
|
|
TRACE_CRIT("Could not read NLB configuration for %wsz", szNic);
|
|
Status = WBEM_E_CRITICAL_ERROR;
|
|
goto end;
|
|
}
|
|
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
end:
|
|
|
|
// g_CfgUtils.mfn_Unlock();
|
|
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Sets the current NLB configuration for the specified NIC. This
|
|
// includes notifying the driver if required.
|
|
//
|
|
WBEMSTATUS
|
|
CfgUtilSetNlbConfig(
|
|
IN LPCWSTR szNic,
|
|
IN WLBS_REG_PARAMS *pParams,
|
|
IN BOOL fJustBound
|
|
)
|
|
{
|
|
GUID Guid;
|
|
WBEMSTATUS Status = WBEM_NO_ERROR;
|
|
DWORD dwRet = 0;
|
|
WLBS_REG_PARAMS ParamsCopy;
|
|
|
|
if (fJustBound)
|
|
{
|
|
// We need to set the install_date value to the current time.
|
|
// This field is used in the heartbeats to distinguish two
|
|
// hosts.
|
|
// This is bug 480120 nlb:cluster converged when duplicate host ID exist
|
|
// (see also wlbscfg.dll (netcfgconfig.cpp:
|
|
// CNetcfgCluster::InitializeWithDefault)
|
|
time_t cur_time;
|
|
ParamsCopy = *pParams; // Struct copy.
|
|
ParamsCopy.install_date = time(& cur_time);
|
|
pParams = &ParamsCopy;
|
|
}
|
|
|
|
|
|
// Verify that the NLB API hooks are present
|
|
if (!g_CfgUtils.m_NLBApiHooksPresent)
|
|
{
|
|
TRACE_CRIT(L"%!FUNC! FAILING because NLB API hooks are not present");
|
|
Status = WBEM_E_INITIALIZATION_FAILURE;
|
|
goto end;
|
|
}
|
|
|
|
HRESULT hr = CLSIDFromString((LPWSTR)szNic, &Guid);
|
|
if (FAILED(hr))
|
|
{
|
|
Status = WBEM_E_INVALID_PARAMETER;
|
|
goto end;
|
|
}
|
|
|
|
HANDLE Nlb_driver_hdl;
|
|
|
|
// Get handle to NLB driver
|
|
if ((Nlb_driver_hdl = g_CfgUtils.m_pfWlbsOpen()) == INVALID_HANDLE_VALUE)
|
|
{
|
|
TRACE_CRIT("%!FUNC! WlbsOpen returned NULL, Could not create connection to NLB driver");
|
|
Status = WBEM_E_CRITICAL_ERROR;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Write the configuration.
|
|
//
|
|
dwRet = g_CfgUtils.m_pfWlbsWriteAndCommitChanges(Nlb_driver_hdl, &Guid, pParams);
|
|
|
|
if (dwRet != WLBS_OK)
|
|
{
|
|
TRACE_CRIT("Could not write NLB configuration for %wsz. Err=0x%08lx",
|
|
szNic, dwRet);
|
|
Status = WBEM_E_CRITICAL_ERROR;
|
|
}
|
|
else
|
|
{
|
|
|
|
Status = WBEM_NO_ERROR;
|
|
}
|
|
|
|
// Close handle to NLB driver
|
|
CloseHandle(Nlb_driver_hdl);
|
|
|
|
|
|
end:
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
CfgUtilRegWriteParams(
|
|
IN LPCWSTR szNic,
|
|
IN WLBS_REG_PARAMS *pParams
|
|
)
|
|
//
|
|
// Just writes the current NLB configuration for the specified NIC to the
|
|
// registry. MAY BE CALLED WHEN NLB IS UNBOUND.
|
|
//
|
|
{
|
|
GUID Guid;
|
|
WLBS_REG_PARAMS TmpParams = *pParams;
|
|
WBEMSTATUS Status = WBEM_NO_ERROR;
|
|
DWORD dwRet = 0;
|
|
|
|
TRACE_INFO(L"->");
|
|
|
|
// Verify that the NLB API hooks are present
|
|
if (!g_CfgUtils.m_NLBApiHooksPresent)
|
|
{
|
|
TRACE_CRIT(L"FAILING because NLB API hooks are not present");
|
|
Status = WBEM_E_INITIALIZATION_FAILURE;
|
|
goto end;
|
|
}
|
|
|
|
HRESULT hr = CLSIDFromString((LPWSTR)szNic, &Guid);
|
|
if (FAILED(hr))
|
|
{
|
|
Status = WBEM_E_INVALID_PARAMETER;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Write the configuration.
|
|
//
|
|
dwRet = g_CfgUtils.m_pfWlbsParamWriteReg(Guid, &TmpParams);
|
|
|
|
|
|
if (dwRet != WLBS_OK)
|
|
{
|
|
TRACE_CRIT("Could not write NLB configuration for %wsz. Err=0x%08lx",
|
|
szNic, dwRet);
|
|
Status = WBEM_E_CRITICAL_ERROR;
|
|
}
|
|
else
|
|
{
|
|
Status = WBEM_NO_ERROR;
|
|
}
|
|
|
|
|
|
end:
|
|
|
|
TRACE_INFO(L"<- returns %lx", Status);
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
WBEMSTATUS
|
|
CfgUtilsAnalyzeNlbUpdate(
|
|
IN const WLBS_REG_PARAMS *pCurrentParams, OPTIONAL
|
|
IN WLBS_REG_PARAMS *pNewParams,
|
|
OUT BOOL *pfConnectivityChange
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
BOOL fConnectivityChange = FALSE;
|
|
|
|
|
|
//
|
|
// If not initialized, fail...
|
|
//
|
|
if (!g_CfgUtils.IsInitalized())
|
|
{
|
|
TRACE_CRIT(L"%!FUNC! FAILING because uninitialized");
|
|
Status = WBEM_E_INITIALIZATION_FAILURE;
|
|
goto end;
|
|
}
|
|
|
|
if (pCurrentParams != NULL)
|
|
{
|
|
//
|
|
// If the structures have identical content, we return S_FALSE.
|
|
// We do this check before we call ValidateParm below, because
|
|
// ValidateParam has the side effect of filling out / modifying
|
|
// certain fields.
|
|
//
|
|
if (memcmp(pCurrentParams, pNewParams, sizeof(*pCurrentParams))==0)
|
|
{
|
|
Status = WBEM_S_FALSE;
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Validate pNewParams -- this may also modify pNewParams slightly, by
|
|
// re-formatting ip addresses into canonical format.
|
|
//
|
|
// Verify that the NLB API hooks are present
|
|
BOOL fRet = FALSE;
|
|
|
|
if (!g_CfgUtils.m_NLBApiHooksPresent)
|
|
{
|
|
fRet = MyWlbsValidateParams(pNewParams);
|
|
}
|
|
else
|
|
{
|
|
fRet = g_CfgUtils.m_pfWlbsValidateParams(pNewParams);
|
|
}
|
|
|
|
if (!fRet)
|
|
{
|
|
TRACE_CRIT(L"%!FUNC!FAILING because New params are invalid");
|
|
Status = WBEM_E_INVALID_PARAMETER;
|
|
goto end;
|
|
}
|
|
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
if (pCurrentParams == NULL)
|
|
{
|
|
//
|
|
// NLB was not previously bound.
|
|
//
|
|
fConnectivityChange = TRUE;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Change in multicast modes or mac address.
|
|
//
|
|
if ( (pCurrentParams->mcast_support != pNewParams->mcast_support)
|
|
|| _wcsicmp(pCurrentParams->cl_mac_addr, pNewParams->cl_mac_addr)!=0)
|
|
{
|
|
fConnectivityChange = TRUE;
|
|
}
|
|
|
|
//
|
|
// Change in primary cluster ip or subnet mask
|
|
//
|
|
if ( _wcsicmp(pCurrentParams->cl_ip_addr,pNewParams->cl_ip_addr)!=0
|
|
|| _wcsicmp(pCurrentParams->cl_net_mask,pNewParams->cl_net_mask)!=0)
|
|
{
|
|
fConnectivityChange = TRUE;
|
|
}
|
|
|
|
|
|
end:
|
|
*pfConnectivityChange = fConnectivityChange;
|
|
return Status;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
CfgUtilsValidateNicGuid(
|
|
IN LPCWSTR szGuid
|
|
)
|
|
//
|
|
//
|
|
{
|
|
//
|
|
// Sample GUID: {EBE09517-07B4-4E88-AAF1-E06F5540608B}
|
|
//
|
|
WBEMSTATUS Status = WBEM_E_INVALID_PARAMETER;
|
|
UINT Length = wcslen(szGuid);
|
|
|
|
#define MY_NLB_GUID_LEN 38
|
|
if (Length != MY_NLB_GUID_LEN)
|
|
{
|
|
TRACE_CRIT("Length != %d", MY_NLB_GUID_LEN);
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Open tcpip's registry key and look for guid there -- if not found,
|
|
// we'll return WBEM_E_NOT_FOUND
|
|
//
|
|
{
|
|
WCHAR szKey[128]; // This is enough for the tcpip+guid key
|
|
|
|
ARRAYSTRCPY(szKey, L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\" );
|
|
ARRAYSTRCAT(szKey, szGuid);
|
|
HKEY hKey = NULL;
|
|
LONG lRet;
|
|
lRet = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE, // handle to an open key
|
|
szKey, // address of subkey name
|
|
0, // reserved
|
|
KEY_QUERY_VALUE, // desired security access
|
|
&hKey // address of buffer for opened handle
|
|
);
|
|
if (lRet != ERROR_SUCCESS)
|
|
{
|
|
TRACE_CRIT("Guid %ws doesn't exist under tcpip", szGuid);
|
|
Status = WBEM_E_NOT_FOUND;
|
|
goto end;
|
|
}
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
end:
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
#if OBSOLETE
|
|
WBEMSTATUS
|
|
get_string_parameter(
|
|
IN IWbemClassObjectPtr spObj,
|
|
IN LPCWSTR szParameterName,
|
|
OUT LPWSTR *ppStringValue
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_NOT_FOUND;
|
|
WCHAR *pStringValue = NULL;
|
|
_variant_t v_value;
|
|
CIMTYPE v_type;
|
|
HRESULT hr;
|
|
|
|
hr = spObj->Get(
|
|
_bstr_t(szParameterName), // Name
|
|
0, // Reserved, must be 0
|
|
&v_value, // Place to store value
|
|
&v_type, // Type of value
|
|
NULL // Flavor (unused)
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
// Couldn't read the Setting ID field!
|
|
//
|
|
TRACE_CRIT(
|
|
"get_str_parm:Couldn't retrieve %ws from 0x%p",
|
|
szParameterName,
|
|
(PVOID) spObj
|
|
);
|
|
goto end;
|
|
}
|
|
else
|
|
{
|
|
if (v_type != VT_BSTR)
|
|
{
|
|
TRACE_CRIT(
|
|
"get_str_parm: Parm value not of string type %ws from 0x%p",
|
|
szParameterName,
|
|
(PVOID) spObj
|
|
);
|
|
Status = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
|
|
_bstr_t bstrNicGuid(v_value);
|
|
LPCWSTR sz = bstrNicGuid; // Pointer to internal buffer.
|
|
|
|
if (sz==NULL)
|
|
{
|
|
// hmm.. null value
|
|
Status = WBEM_NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
UINT len = wcslen(sz);
|
|
pStringValue = new WCHAR[len+1];
|
|
if (pStringValue == NULL)
|
|
{
|
|
TRACE_CRIT("get_str_parm: Alloc failure!");
|
|
Status = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
CopyMemory(pStringValue, sz, (len+1)*sizeof(WCHAR));
|
|
Status = WBEM_NO_ERROR;
|
|
}
|
|
}
|
|
|
|
TRACE_VERB(
|
|
"get_str_parm: String parm %ws of 0x%p is %ws",
|
|
szParameterName,
|
|
(PVOID) spObj,
|
|
(sz==NULL) ? L"<null>" : sz
|
|
);
|
|
}
|
|
|
|
v_value.Clear(); // Must be cleared after each call to Get.
|
|
}
|
|
|
|
end:
|
|
|
|
*ppStringValue = pStringValue;
|
|
|
|
return Status;
|
|
|
|
}
|
|
#endif // OBSOLETE
|
|
|
|
|
|
WBEMSTATUS
|
|
get_nic_instance(
|
|
IN IWbemServicesPtr spWbemServiceIF,
|
|
IN LPCWSTR szNicGuid,
|
|
OUT IWbemClassObjectPtr &sprefObj
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_NOT_FOUND;
|
|
IWbemClassObjectPtr spObj = NULL; // smart pointer.
|
|
|
|
Status = CfgUtilGetWmiObjectInstance(
|
|
spWbemServiceIF,
|
|
L"Win32_NetworkAdapterConfiguration", // szClassName
|
|
L"SettingID", // szParameterName
|
|
szNicGuid, // ParameterValue
|
|
spObj // smart pointer, passed by ref
|
|
);
|
|
if (FAILED(Status))
|
|
{
|
|
ASSERT(spObj == NULL);
|
|
goto end;
|
|
}
|
|
|
|
end:
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
sprefObj = NULL;
|
|
}
|
|
else
|
|
{
|
|
sprefObj = spObj; // smart pointer.
|
|
}
|
|
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
get_multi_string_parameter(
|
|
IN IWbemClassObjectPtr spObj,
|
|
IN LPCWSTR szParameterName,
|
|
IN UINT MaxStringLen, // in wchars, INCLUDING space for trailing zeros.
|
|
OUT UINT *pNumItems,
|
|
OUT LPCWSTR *ppStringValue
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_NOT_FOUND;
|
|
WCHAR *pStringValue = NULL;
|
|
_variant_t v_value;
|
|
CIMTYPE v_type;
|
|
HRESULT hr;
|
|
LONG count = 0;
|
|
|
|
*ppStringValue = NULL;
|
|
*pNumItems = 0;
|
|
|
|
hr = spObj->Get(
|
|
_bstr_t(szParameterName),
|
|
0, // Reserved, must be 0
|
|
&v_value, // Place to store value
|
|
&v_type, // Type of value
|
|
NULL // Flavor (unused)
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
// Couldn't read the requested parameter.
|
|
//
|
|
TRACE_CRIT(
|
|
"get_multi_str_parm:Couldn't retrieve %ws from 0x%p",
|
|
szParameterName,
|
|
(PVOID) spObj
|
|
);
|
|
goto end;
|
|
}
|
|
|
|
|
|
{
|
|
VARIANT ipsV = v_value.Detach();
|
|
|
|
do // while false
|
|
{
|
|
BSTR* pbstr;
|
|
|
|
if (ipsV.vt == VT_NULL)
|
|
{
|
|
//
|
|
// NULL string -- this is ok
|
|
//
|
|
count = 0;
|
|
}
|
|
else
|
|
{
|
|
count = ipsV.parray->rgsabound[0].cElements;
|
|
}
|
|
|
|
if (count==0)
|
|
{
|
|
Status = WBEM_NO_ERROR;
|
|
break;
|
|
}
|
|
|
|
pStringValue = new WCHAR[count*MaxStringLen];
|
|
|
|
if (pStringValue == NULL)
|
|
{
|
|
TRACE_CRIT("get_multi_str_parm: Alloc failure!");
|
|
Status = WBEM_E_OUT_OF_MEMORY;
|
|
break;
|
|
}
|
|
ZeroMemory(pStringValue, sizeof(WCHAR)*count*MaxStringLen);
|
|
|
|
hr = SafeArrayAccessData(ipsV.parray, ( void **) &pbstr);
|
|
if(FAILED(hr))
|
|
{
|
|
Status = WBEM_E_INVALID_PARAMETER; // TODO: pick better error
|
|
break;
|
|
}
|
|
|
|
Status = WBEM_NO_ERROR;
|
|
for( LONG x = 0; x < count; x++ )
|
|
{
|
|
LPCWSTR sz = pbstr[x]; // Pointer to internal buffer.
|
|
|
|
if (sz==NULL)
|
|
{
|
|
// hmm.. null value
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
UINT len = wcslen(sz);
|
|
if ((len+1) > MaxStringLen)
|
|
{
|
|
TRACE_CRIT("get_str_parm: string size too long!");
|
|
Status = WBEM_E_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
WCHAR *pDest = pStringValue+x*MaxStringLen;
|
|
CopyMemory(pDest, sz, (len+1)*sizeof(WCHAR));
|
|
}
|
|
}
|
|
}
|
|
|
|
(VOID) SafeArrayUnaccessData( ipsV.parray );
|
|
|
|
} while (FALSE);
|
|
|
|
VariantClear( &ipsV );
|
|
}
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
if (pStringValue!=NULL)
|
|
{
|
|
delete[] pStringValue;
|
|
*pStringValue = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*ppStringValue = pStringValue;
|
|
*pNumItems = count;
|
|
}
|
|
|
|
|
|
end:
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
//
|
|
// Static method to return the state of the lock;
|
|
//
|
|
WBEMSTATUS
|
|
MyNetCfg::GetWriteLockState(
|
|
OUT BOOL *pfCanLock,
|
|
LPWSTR *pszHeldBy // OPTIONAL, free using delete[].
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
INetCfg *pnc = NULL;
|
|
INetCfgLock *pncl = NULL;
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
BOOL fCanLock = FALSE;
|
|
WCHAR *szLockedBy = NULL;
|
|
|
|
*pfCanLock = FALSE;
|
|
if (pszHeldBy!=NULL)
|
|
{
|
|
*pszHeldBy = NULL;
|
|
}
|
|
|
|
hr = CoCreateInstance( CLSID_CNetCfg,
|
|
NULL,
|
|
CLSCTX_SERVER,
|
|
IID_INetCfg,
|
|
(void **) &pnc);
|
|
|
|
if( !SUCCEEDED( hr ) )
|
|
{
|
|
// failure to create instance.
|
|
TRACE_CRIT("ERROR: could not get interface to Net Config");
|
|
pnc = NULL;
|
|
goto end;
|
|
}
|
|
|
|
hr = pnc->QueryInterface( IID_INetCfgLock, ( void **) &pncl );
|
|
if( !SUCCEEDED( hr ) )
|
|
{
|
|
TRACE_CRIT("ERROR: could not get interface to NetCfg Lock");
|
|
pncl = NULL;
|
|
goto end;
|
|
}
|
|
|
|
hr = pncl->AcquireWriteLock(100, NLB_CLIENT_NAME, &szLockedBy);
|
|
if(hr == S_FALSE)
|
|
{
|
|
TRACE_INFO("Write lock held by %ws",
|
|
(szLockedBy!=NULL) ? szLockedBy : L"<null>");
|
|
if (pszHeldBy!=NULL && szLockedBy != NULL)
|
|
{
|
|
LPWSTR szTmp = NULL;
|
|
UINT uLen = wcslen(szLockedBy);
|
|
szTmp = new WCHAR[uLen+1];
|
|
if (szTmp != NULL)
|
|
{
|
|
CopyMemory(szTmp, szLockedBy, (uLen+1)*sizeof(*szTmp));
|
|
}
|
|
*pszHeldBy = szTmp;
|
|
}
|
|
fCanLock = FALSE;
|
|
Status = WBEM_NO_ERROR;
|
|
}
|
|
else if (hr == S_OK)
|
|
{
|
|
//
|
|
// We could get the lock, let's release it.
|
|
//
|
|
(void) pncl->ReleaseWriteLock();
|
|
fCanLock = TRUE;
|
|
Status = WBEM_NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
TRACE_INFO("AcquireWriteLock failed with error 0x%08lx", (UINT) hr);
|
|
fCanLock = FALSE;
|
|
Status = WBEM_NO_ERROR;
|
|
}
|
|
CoTaskMemFree(szLockedBy); // szLockedBy can be NULL;
|
|
|
|
*pfCanLock = fCanLock;
|
|
|
|
end:
|
|
|
|
if (pncl!=NULL)
|
|
{
|
|
pncl->Release();
|
|
pncl=NULL;
|
|
}
|
|
|
|
if (pnc != NULL)
|
|
{
|
|
pnc->Release();
|
|
pnc= NULL;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
MyNetCfg::Initialize(
|
|
BOOL fWriteLock
|
|
)
|
|
{
|
|
// 2/13/02 JosephJ SECURITY BUGBUG: verify that IF this call is made from a non-admin that we fail.
|
|
//
|
|
HRESULT hr;
|
|
INetCfg *pnc = NULL;
|
|
INetCfgLock *pncl = NULL;
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
BOOL fLocked = FALSE;
|
|
BOOL fInitialized=FALSE;
|
|
|
|
if (m_pINetCfg != NULL || m_pLock != NULL)
|
|
{
|
|
ASSERT(FALSE);
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// 2/13/02 JosephJ SECURITY BUGBUG: CLSCTX_SERVER -- should we be specifying something more restrictive here?
|
|
// Also: can some other COM object hijack this GUID?
|
|
//
|
|
hr = CoCreateInstance( CLSID_CNetCfg,
|
|
NULL,
|
|
CLSCTX_SERVER,
|
|
IID_INetCfg,
|
|
(void **) &pnc);
|
|
|
|
if( !SUCCEEDED( hr ) )
|
|
{
|
|
// failure to create instance.
|
|
TRACE_CRIT("ERROR: could not get interface to Net Config");
|
|
pnc = NULL;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// If require, get the write lock
|
|
//
|
|
if (fWriteLock)
|
|
{
|
|
WCHAR *szLockedBy = NULL;
|
|
hr = pnc->QueryInterface( IID_INetCfgLock, ( void **) &pncl );
|
|
if( !SUCCEEDED( hr ) )
|
|
{
|
|
TRACE_CRIT("ERROR: could not get interface to NetCfg Lock");
|
|
pncl = NULL;
|
|
goto end;
|
|
}
|
|
|
|
hr = pncl->AcquireWriteLock( 1, // One Second
|
|
NLB_CLIENT_NAME,
|
|
&szLockedBy);
|
|
if( hr != S_OK )
|
|
{
|
|
TRACE_CRIT("Could not get write lock. Lock held by %ws",
|
|
(szLockedBy!=NULL) ? szLockedBy : L"<null>");
|
|
goto end;
|
|
|
|
}
|
|
CoTaskMemFree(szLockedBy); // szLockedBy can be NULL;
|
|
fLocked = TRUE;
|
|
}
|
|
|
|
// Initializes network configuration by loading into
|
|
// memory all basic networking information
|
|
//
|
|
hr = pnc->Initialize( NULL );
|
|
if( !SUCCEEDED( hr ) )
|
|
{
|
|
// failure to Initialize
|
|
TRACE_CRIT("INetCfg::Initialize failure ");
|
|
goto end;
|
|
}
|
|
fInitialized = TRUE;
|
|
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
end:
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
if (pncl!=NULL)
|
|
{
|
|
if (fLocked)
|
|
{
|
|
pncl->ReleaseWriteLock();
|
|
}
|
|
pncl->Release();
|
|
pncl=NULL;
|
|
}
|
|
if( pnc != NULL)
|
|
{
|
|
if (fInitialized)
|
|
{
|
|
pnc->Uninitialize();
|
|
}
|
|
pnc->Release();
|
|
pnc= NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_pINetCfg = pnc;
|
|
m_pLock = pncl;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
MyNetCfg::Deinitialize(
|
|
VOID
|
|
)
|
|
{
|
|
if (m_pLock!=NULL)
|
|
{
|
|
m_pLock->ReleaseWriteLock();
|
|
m_pLock->Release();
|
|
m_pLock=NULL;
|
|
}
|
|
if( m_pINetCfg != NULL)
|
|
{
|
|
m_pINetCfg->Uninitialize();
|
|
m_pINetCfg->Release();
|
|
m_pINetCfg= NULL;
|
|
}
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
MyNetCfg::GetNicIF(
|
|
IN LPCWSTR szNicGuid,
|
|
OUT INetCfgComponent **ppINic
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
INetCfgComponent *pncc = NULL;
|
|
HRESULT hr;
|
|
IEnumNetCfgComponent* pencc = NULL;
|
|
ULONG countToFetch = 1;
|
|
ULONG countFetched;
|
|
DWORD characteristics;
|
|
|
|
|
|
if (m_pINetCfg == NULL)
|
|
{
|
|
//
|
|
// This means we're not initialized
|
|
//
|
|
ASSERT(FALSE);
|
|
goto end;
|
|
}
|
|
|
|
hr = m_pINetCfg->EnumComponents( &GUID_DEVCLASS_NET, &pencc );
|
|
if( !SUCCEEDED( hr ) )
|
|
{
|
|
// failure to Enumerate net components
|
|
TRACE_CRIT("Could not enum netcfg adapters");
|
|
pencc = NULL;
|
|
goto end;
|
|
}
|
|
|
|
while( ( hr = pencc->Next( countToFetch, &pncc, &countFetched ) )== S_OK )
|
|
{
|
|
LPWSTR szName = NULL;
|
|
|
|
hr = pncc->GetBindName( &szName );
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
TRACE_CRIT("WARNING: couldn't get bind name for 0x%p, ignoring",
|
|
(PVOID) pncc);
|
|
continue;
|
|
}
|
|
if(!_wcsicmp(szName, szNicGuid))
|
|
{
|
|
//
|
|
// Got this one!
|
|
//
|
|
CoTaskMemFree( szName );
|
|
break;
|
|
}
|
|
CoTaskMemFree( szName );
|
|
pncc->Release();
|
|
pncc=NULL;
|
|
}
|
|
|
|
if (pncc == NULL)
|
|
{
|
|
TRACE_CRIT("Could not find NIC %ws", szNicGuid);
|
|
Status = WBEM_E_NOT_FOUND;
|
|
}
|
|
else
|
|
{
|
|
Status = WBEM_NO_ERROR;
|
|
}
|
|
|
|
end:
|
|
|
|
if (pencc != NULL)
|
|
{
|
|
pencc->Release();
|
|
}
|
|
|
|
*ppINic = pncc;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
LPWSTR *
|
|
CfgUtilsAllocateStringArray(
|
|
UINT NumStrings,
|
|
UINT MaxStringLen // excluding ending NULL
|
|
)
|
|
/*
|
|
Allocate a single chunk of memory using the new LPWSTR[] operator.
|
|
The first NumStrings LPWSTR values of this operator contain an array
|
|
of pointers to WCHAR strings. Each of these strings
|
|
is of size (MaxStringLen+1) WCHARS.
|
|
The rest of the memory contains the strings themselve.
|
|
|
|
Return NULL if NumStrings==0 or on allocation failure.
|
|
|
|
Each of the strings are initialized to be empty strings (first char is 0).
|
|
*/
|
|
{
|
|
LPWSTR *pStrings = NULL;
|
|
UINT TotalSize = 0;
|
|
|
|
if (NumStrings == 0)
|
|
{
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Note - even if MaxStringLen is 0 we will allocate space for NumStrings
|
|
// pointers and NumStrings empty (first char is 0) strings.
|
|
//
|
|
|
|
//
|
|
// Calculate space for the array of pointers to strings...
|
|
//
|
|
TotalSize = NumStrings*sizeof(LPWSTR);
|
|
|
|
//
|
|
// Calculate space for the strings themselves...
|
|
// Remember to add +1 for each ending 0 character.
|
|
//
|
|
TotalSize += NumStrings*(MaxStringLen+1)*sizeof(WCHAR);
|
|
|
|
//
|
|
// Allocate space for *both* the array of pointers and the strings
|
|
// in one shot -- we're doing a new of type LPWSTR[] for the whole
|
|
// lot, so need to specify the size in units of LPWSTR (with an
|
|
// additional +1 in case there's roundoff.
|
|
//
|
|
pStrings = new LPWSTR[(TotalSize/sizeof(LPWSTR))+1];
|
|
if (pStrings == NULL)
|
|
{
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Make sz point to the start of the place where we'll be placing
|
|
// the string data.
|
|
//
|
|
LPWSTR sz = (LPWSTR) (pStrings+NumStrings);
|
|
for (UINT u=0; u<NumStrings; u++)
|
|
{
|
|
*sz=NULL;
|
|
pStrings[u] = sz;
|
|
sz+=(MaxStringLen+1); // +1 for ending NULL
|
|
}
|
|
|
|
end:
|
|
|
|
return pStrings;
|
|
|
|
}
|
|
|
|
|
|
|
|
WBEMSTATUS
|
|
MyNetCfg::GetNlbCompatibleNics(
|
|
OUT LPWSTR **ppszNics,
|
|
OUT UINT *pNumNics,
|
|
OUT UINT *pNumBoundToNlb // OPTIONAL
|
|
)
|
|
/*
|
|
Returns an array of pointers to string-version of GUIDS
|
|
that represent the set of alive and healthy NICS that are
|
|
suitable for NLB to bind to -- basically alive ethernet NICs.
|
|
|
|
Delete ppNics using the delete WCHAR[] operator. Do not
|
|
delete the individual strings.
|
|
*/
|
|
{
|
|
#define MY_GUID_LENGTH 38
|
|
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
HRESULT hr;
|
|
IEnumNetCfgComponent* pencc = NULL;
|
|
INetCfgComponent *pncc = NULL;
|
|
ULONG countToFetch = 1;
|
|
ULONG countFetched;
|
|
UINT NumNics = 0;
|
|
LPWSTR *pszNics = NULL;
|
|
INetCfgComponentBindings *pINlbBinding=NULL;
|
|
UINT NumNlbBoundNics = 0;
|
|
|
|
typedef struct _MYNICNODE MYNICNODE;
|
|
|
|
typedef struct _MYNICNODE
|
|
{
|
|
LPWSTR szNicGuid;
|
|
MYNICNODE *pNext;
|
|
} MYNICNODE;
|
|
|
|
MYNICNODE *pNicNodeList = NULL;
|
|
MYNICNODE *pNicNode = NULL;
|
|
|
|
|
|
*ppszNics = NULL;
|
|
*pNumNics = 0;
|
|
|
|
if (pNumBoundToNlb != NULL)
|
|
{
|
|
*pNumBoundToNlb = 0;
|
|
}
|
|
|
|
if (m_pINetCfg == NULL)
|
|
{
|
|
//
|
|
// This means we're not initialized
|
|
//
|
|
ASSERT(FALSE);
|
|
goto end;
|
|
}
|
|
|
|
hr = m_pINetCfg->EnumComponents( &GUID_DEVCLASS_NET, &pencc );
|
|
if( !SUCCEEDED( hr ) )
|
|
{
|
|
// failure to Enumerate net components
|
|
TRACE_CRIT("%!FUNC! Could not enum netcfg adapters");
|
|
pencc = NULL;
|
|
goto end;
|
|
}
|
|
|
|
|
|
//
|
|
// Check if nlb is bound to the nlb component.
|
|
//
|
|
|
|
//
|
|
// If we need to count of NLB-bound nics, get instance of the nlb component
|
|
//
|
|
if (pNumBoundToNlb != NULL)
|
|
{
|
|
Status = GetBindingIF(L"ms_wlbs", &pINlbBinding);
|
|
if (FAILED(Status))
|
|
{
|
|
TRACE_CRIT("%!FUNC! WARNING: NLB doesn't appear to be installed on this machine");
|
|
pINlbBinding = NULL;
|
|
}
|
|
}
|
|
|
|
while( ( hr = pencc->Next( countToFetch, &pncc, &countFetched ) )== S_OK )
|
|
{
|
|
LPWSTR szName = NULL;
|
|
|
|
hr = pncc->GetBindName( &szName );
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
TRACE_CRIT("%!FUNC! WARNING: couldn't get bind name for 0x%p, ignoring",
|
|
(PVOID) pncc);
|
|
continue;
|
|
}
|
|
|
|
do // while FALSE -- just to allow breaking out
|
|
{
|
|
|
|
|
|
UINT Len = wcslen(szName);
|
|
if (Len != MY_GUID_LENGTH)
|
|
{
|
|
TRACE_CRIT("%!FUNC! WARNING: GUID %ws has unexpected length %ul",
|
|
szName, Len);
|
|
break;
|
|
}
|
|
|
|
DWORD characteristics = 0;
|
|
|
|
hr = pncc->GetCharacteristics( &characteristics );
|
|
if(!SUCCEEDED(hr))
|
|
{
|
|
TRACE_CRIT("%!FUNC! WARNING: couldn't get characteristics for %ws, ignoring",
|
|
szName);
|
|
break;
|
|
}
|
|
|
|
if (((characteristics & NCF_PHYSICAL) || (characteristics & NCF_VIRTUAL)) && !(characteristics & NCF_HIDDEN))
|
|
{
|
|
ULONG devstat = 0;
|
|
|
|
// This is a physical or virtual miniport that is NOT hidden. These
|
|
// are the same adapters that show up in the "Network Connections"
|
|
// dialog. Hidden devices include WAN miniports, RAS miniports and
|
|
// NLB miniports - all of which should be excluded here.
|
|
|
|
// check if the nic is enabled, we are only
|
|
// interested in enabled nics.
|
|
//
|
|
hr = pncc->GetDeviceStatus( &devstat );
|
|
if(!SUCCEEDED(hr))
|
|
{
|
|
TRACE_CRIT(
|
|
"%!FUNC! WARNING: couldn't get dev status for %ws, ignoring",
|
|
szName
|
|
);
|
|
break;
|
|
}
|
|
|
|
// if any of the nics has any of the problem codes
|
|
// then it cannot be used.
|
|
|
|
if( devstat != CM_PROB_NOT_CONFIGURED
|
|
&&
|
|
devstat != CM_PROB_FAILED_START
|
|
&&
|
|
devstat != CM_PROB_NORMAL_CONFLICT
|
|
&&
|
|
devstat != CM_PROB_NEED_RESTART
|
|
&&
|
|
devstat != CM_PROB_REINSTALL
|
|
&&
|
|
devstat != CM_PROB_WILL_BE_REMOVED
|
|
&&
|
|
devstat != CM_PROB_DISABLED
|
|
&&
|
|
devstat != CM_PROB_FAILED_INSTALL
|
|
&&
|
|
devstat != CM_PROB_FAILED_ADD
|
|
)
|
|
{
|
|
//
|
|
// No problem with this nic and also
|
|
// physical device
|
|
// thus we want it.
|
|
//
|
|
|
|
if (pINlbBinding != NULL)
|
|
{
|
|
BOOL fBound = FALSE;
|
|
|
|
hr = pINlbBinding->IsBoundTo(pncc);
|
|
|
|
if( !SUCCEEDED( hr ) )
|
|
{
|
|
TRACE_CRIT("IsBoundTo method failed for Nic %ws", szName);
|
|
goto end;
|
|
}
|
|
|
|
if( hr == S_OK )
|
|
{
|
|
TRACE_VERB("BOUND: %ws\n", szName);
|
|
NumNlbBoundNics++;
|
|
fBound = TRUE;
|
|
}
|
|
else if (hr == S_FALSE )
|
|
{
|
|
TRACE_VERB("NOT BOUND: %ws\n", szName);
|
|
fBound = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
// We allocate a little node to keep this string
|
|
// temporarily and add it to our list of nodes.
|
|
//
|
|
pNicNode = new MYNICNODE;
|
|
if (pNicNode == NULL)
|
|
{
|
|
Status = WBEM_E_OUT_OF_MEMORY;
|
|
goto end;
|
|
}
|
|
ZeroMemory(pNicNode, sizeof(*pNicNode));
|
|
pNicNode->szNicGuid = szName;
|
|
szName = NULL; // so we don't delete inside the lopp.
|
|
pNicNode->pNext = pNicNodeList;
|
|
pNicNodeList = pNicNode;
|
|
NumNics++;
|
|
}
|
|
else
|
|
{
|
|
// There is a problem...
|
|
TRACE_CRIT(
|
|
"%!FUNC! WARNING: Skipping %ws because DeviceStatus=0x%08lx",
|
|
szName, devstat
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRACE_VERB("%!FUNC! Ignoring non-physical device %ws", szName);
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
if (szName != NULL)
|
|
{
|
|
CoTaskMemFree( szName );
|
|
}
|
|
pncc->Release();
|
|
pncc=NULL;
|
|
}
|
|
|
|
if (pINlbBinding!=NULL)
|
|
{
|
|
pINlbBinding->Release();
|
|
pINlbBinding = NULL;
|
|
}
|
|
|
|
if (NumNics==0)
|
|
{
|
|
Status = WBEM_NO_ERROR;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Now let's allocate space for all the nic strings and:w
|
|
// copy them over..
|
|
//
|
|
#define MY_GUID_LENGTH 38
|
|
pszNics = CfgUtilsAllocateStringArray(NumNics, MY_GUID_LENGTH);
|
|
if (pszNics == NULL)
|
|
{
|
|
Status = WBEM_E_OUT_OF_MEMORY;
|
|
goto end;
|
|
}
|
|
|
|
pNicNode= pNicNodeList;
|
|
for (UINT u=0; u<NumNics; u++, pNicNode=pNicNode->pNext)
|
|
{
|
|
ASSERT(pNicNode != NULL); // because we just counted NumNics of em.
|
|
UINT Len = wcslen(pNicNode->szNicGuid);
|
|
if (Len != MY_GUID_LENGTH)
|
|
{
|
|
//
|
|
// We should never get here beause we checked the length earlier.
|
|
//
|
|
TRACE_CRIT("%!FUNC! ERROR: GUID %ws has unexpected length %ul",
|
|
pNicNode->szNicGuid, Len);
|
|
ASSERT(FALSE);
|
|
Status = WBEM_E_CRITICAL_ERROR;
|
|
goto end;
|
|
}
|
|
CopyMemory(
|
|
pszNics[u],
|
|
pNicNode->szNicGuid,
|
|
(MY_GUID_LENGTH+1)*sizeof(WCHAR));
|
|
ASSERT(pszNics[u][MY_GUID_LENGTH]==0);
|
|
}
|
|
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
|
|
end:
|
|
|
|
//
|
|
// Now release the temporarly allocated memory.
|
|
//
|
|
pNicNode= pNicNodeList;
|
|
while (pNicNode!=NULL)
|
|
{
|
|
MYNICNODE *pTmp = pNicNode->pNext;
|
|
CoTaskMemFree(pNicNode->szNicGuid);
|
|
pNicNode->szNicGuid = NULL;
|
|
delete pNicNode;
|
|
pNicNode = pTmp;
|
|
}
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
TRACE_CRIT("%!FUNC! fails with status 0x%08lx", (UINT) Status);
|
|
NumNics = 0;
|
|
if (pszNics!=NULL)
|
|
{
|
|
delete pszNics;
|
|
pszNics = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pNumBoundToNlb != NULL)
|
|
{
|
|
*pNumBoundToNlb = NumNlbBoundNics;
|
|
}
|
|
*ppszNics = pszNics;
|
|
*pNumNics = NumNics;
|
|
}
|
|
|
|
if (pencc != NULL)
|
|
{
|
|
pencc->Release();
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
MyNetCfg::GetBindingIF(
|
|
IN LPCWSTR szComponent,
|
|
OUT INetCfgComponentBindings **ppIBinding
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
INetCfgComponent *pncc = NULL;
|
|
INetCfgComponentBindings *pnccb = NULL;
|
|
HRESULT hr;
|
|
|
|
|
|
if (m_pINetCfg == NULL)
|
|
{
|
|
//
|
|
// This means we're not initialized
|
|
//
|
|
ASSERT(FALSE);
|
|
goto end;
|
|
}
|
|
|
|
|
|
hr = m_pINetCfg->FindComponent(szComponent, &pncc);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE_CRIT("Error checking if component %ws does not exist\n", szComponent);
|
|
pncc = NULL;
|
|
goto end;
|
|
}
|
|
else if (hr == S_FALSE)
|
|
{
|
|
Status = WBEM_E_NOT_FOUND;
|
|
TRACE_CRIT("Component %ws does not exist\n", szComponent);
|
|
goto end;
|
|
}
|
|
|
|
|
|
hr = pncc->QueryInterface( IID_INetCfgComponentBindings, (void **) &pnccb );
|
|
if( !SUCCEEDED( hr ) )
|
|
{
|
|
TRACE_CRIT("INetCfgComponent::QueryInterface failed ");
|
|
pnccb = NULL;
|
|
goto end;
|
|
}
|
|
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
end:
|
|
|
|
if (pncc)
|
|
{
|
|
pncc->Release();
|
|
pncc=NULL;
|
|
}
|
|
|
|
*ppIBinding = pnccb;
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
set_string_parameter(
|
|
IN IWbemClassObjectPtr spObj,
|
|
IN LPCWSTR szParameterName,
|
|
IN LPCWSTR szValue
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
HRESULT hr;
|
|
|
|
{
|
|
_bstr_t bstrName = szParameterName;
|
|
_variant_t v_value = (LPWSTR) szValue; // Allocates.
|
|
|
|
hr = spObj->Put(
|
|
bstrName, // Parameter Name
|
|
0, // Must be 0
|
|
&v_value,
|
|
0 // Must be 0
|
|
);
|
|
v_value.Clear();
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE_CRIT("Unable to put parameter %ws", szParameterName);
|
|
goto end;
|
|
}
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
//
|
|
// I think bstrName releases the internally allocated string
|
|
// on exiting this block.
|
|
//
|
|
|
|
}
|
|
|
|
end:
|
|
|
|
return Status;
|
|
}
|
|
|
|
WBEMSTATUS
|
|
set_multi_string_parameter(
|
|
IN IWbemClassObjectPtr spObj,
|
|
IN LPCWSTR szParameterName,
|
|
IN UINT MaxStringLen, // in wchars, INCLUDING space for trailing zeros.
|
|
IN UINT NumItems,
|
|
IN LPCWSTR pStringValue
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
SAFEARRAY *pSA = NULL;
|
|
HRESULT hr;
|
|
LONG Index = 0;
|
|
|
|
//
|
|
// Create safe array for the parameter values
|
|
//
|
|
pSA = SafeArrayCreateVector(
|
|
VT_BSTR,
|
|
0, // lower bound
|
|
NumItems // size of the fixed-sized vector.
|
|
);
|
|
if (pSA == NULL)
|
|
{
|
|
TRACE_CRIT("Could not create safe array");
|
|
Status = WBEM_E_OUT_OF_MEMORY;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Place the strings into the safe array
|
|
//
|
|
{
|
|
for (Index = 0; Index<NumItems; Index++)
|
|
{
|
|
LPCWSTR sz = pStringValue + Index*MaxStringLen;
|
|
|
|
//
|
|
// SafeArrayPutElement expects the string passed in to
|
|
// be of type BSTR, which is of type wchar *, except, that
|
|
// the first 2 wchars contains length and other(?)
|
|
// information. This is why you can't simply pass in sz.
|
|
//
|
|
// So to get this we initalize an object of type _bstr_t
|
|
// based on sz. On initializaton, bstrValue allocates memory
|
|
// and copies the string.
|
|
//
|
|
_bstr_t bstrValue = sz;
|
|
wchar_t *pwchar = (wchar_t *) bstrValue; // returns internal pointer.
|
|
|
|
// bpStr[Index] = sz; // may work as well.
|
|
//
|
|
// SafeArrayPutElement internally allocates space for pwchar and
|
|
// copies over the string.
|
|
// So pSA doesn't contain a direct reference to pwchar.
|
|
//
|
|
hr = SafeArrayPutElement(pSA, &Index, pwchar);
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE_CRIT("Unable to put element %wsz", sz);
|
|
(VOID) SafeArrayUnaccessData(pSA);
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// I think that bstrValue's contents are deallocated on exit of
|
|
// this block.
|
|
//
|
|
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
//
|
|
// Just check ...
|
|
//
|
|
{
|
|
BSTR *pbStr=NULL;
|
|
hr = SafeArrayAccessData(pSA, ( void **) &pbStr);
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE_CRIT("Could not access data of safe array");
|
|
goto end;
|
|
}
|
|
for (UINT u = 0; u<NumItems; u++)
|
|
{
|
|
LPCWSTR sz = pbStr[u];
|
|
if (_wcsicmp(sz, (pStringValue + u*MaxStringLen)))
|
|
{
|
|
TRACE_CRIT("!!!MISMATCH!!!!");
|
|
}
|
|
else
|
|
{
|
|
TRACE_CRIT("!!!MATCH!!!!");
|
|
}
|
|
}
|
|
(VOID) SafeArrayUnaccessData(pSA);
|
|
pbStr=NULL;
|
|
}
|
|
#endif // DBG
|
|
|
|
//
|
|
// Put the parameter.
|
|
//
|
|
{
|
|
VARIANT V;
|
|
_bstr_t bstrName = szParameterName;
|
|
|
|
VariantInit(&V);
|
|
V.vt = VT_ARRAY | VT_BSTR;
|
|
V.parray = pSA;
|
|
_variant_t v_value;
|
|
v_value.Attach(V); // Takes owhership of V. V now becomes empty.
|
|
ASSERT(V.vt == VT_EMPTY);
|
|
pSA = NULL; // should be no need to delete this explicitly now.
|
|
// v_value.Clear() should delete it, I think.
|
|
|
|
hr = spObj->Put(
|
|
bstrName, // Parameter Name
|
|
0, // Must be 0
|
|
&v_value,
|
|
0 // Must be 0
|
|
);
|
|
|
|
v_value.Clear();
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE_CRIT("Unable to put parameter %ws", szParameterName);
|
|
goto end;
|
|
}
|
|
Status = WBEM_NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// ?Destroy the data?
|
|
//
|
|
if (FAILED(Status))
|
|
{
|
|
if (pSA!=NULL)
|
|
{
|
|
SafeArrayDestroy(pSA);
|
|
pSA = NULL;
|
|
}
|
|
}
|
|
|
|
end:
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
WBEMSTATUS
|
|
MyNetCfg::UpdateBindingState(
|
|
IN LPCWSTR szNic,
|
|
IN LPCWSTR szComponent,
|
|
IN UPDATE_OP Op,
|
|
OUT BOOL *pfBound
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
INetCfgComponent *pINic = NULL;
|
|
INetCfgComponentBindings *pIBinding=NULL;
|
|
BOOL fBound = FALSE;
|
|
HRESULT hr;
|
|
|
|
//
|
|
// Get instance to the NIC
|
|
//
|
|
Status = GetNicIF(szNic, &pINic);
|
|
if (FAILED(Status))
|
|
{
|
|
pINic = NULL;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Get instance of the nlb component
|
|
//
|
|
Status = GetBindingIF(szComponent, &pIBinding);
|
|
if (FAILED(Status))
|
|
{
|
|
pIBinding = NULL;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Check if nlb is bound to the nlb component.
|
|
//
|
|
hr = pIBinding->IsBoundTo(pINic);
|
|
if( !SUCCEEDED( hr ) )
|
|
{
|
|
TRACE_CRIT("IsBoundTo method failed for Nic %ws", szNic);
|
|
goto end;
|
|
}
|
|
|
|
if( hr == S_OK )
|
|
{
|
|
fBound = TRUE;
|
|
}
|
|
else if (hr == S_FALSE )
|
|
{
|
|
fBound = FALSE;
|
|
}
|
|
|
|
if ( (Op == MyNetCfg::NOOP)
|
|
|| (Op == MyNetCfg::BIND && fBound)
|
|
|| (Op == MyNetCfg::UNBIND && !fBound))
|
|
{
|
|
Status = WBEM_NO_ERROR;
|
|
goto end;
|
|
}
|
|
|
|
if (Op == MyNetCfg::BIND)
|
|
{
|
|
hr = pIBinding->BindTo( pINic );
|
|
}
|
|
else if (Op == MyNetCfg::UNBIND)
|
|
{
|
|
hr = pIBinding->UnbindFrom( pINic );
|
|
}
|
|
else
|
|
{
|
|
ASSERT(FALSE);
|
|
goto end;
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE_CRIT("Error 0x%08lx %ws %ws on %ws",
|
|
(UINT) hr,
|
|
((Op==MyNetCfg::BIND) ? L"binding" : L"unbinding"),
|
|
szComponent,
|
|
szNic
|
|
);
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// apply the binding change made.
|
|
//
|
|
hr = m_pINetCfg->Apply();
|
|
if( !SUCCEEDED( hr ) )
|
|
{
|
|
TRACE_CRIT("INetCfg::Apply failed with 0x%08lx", (UINT) hr);
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// We're done. Our state should now be toggled.
|
|
//
|
|
fBound = !fBound;
|
|
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
end:
|
|
|
|
if (pINic!=NULL)
|
|
{
|
|
pINic->Release();
|
|
pINic = NULL;
|
|
}
|
|
|
|
if (pIBinding!=NULL)
|
|
{
|
|
pIBinding->Release();
|
|
pIBinding = NULL;
|
|
}
|
|
|
|
*pfBound = fBound;
|
|
|
|
return Status;
|
|
}
|
|
|
|
bool MapOpcodeToIoctl(WLBS_OPERATION_CODES Opcode, LONG *plIoctl)
|
|
{
|
|
struct OPCODE_IOCTL_MAP
|
|
{
|
|
WLBS_OPERATION_CODES Opcode;
|
|
LONG ioctl;
|
|
}
|
|
|
|
OpcodeIoctlMap[] =
|
|
{
|
|
{WLBS_START, IOCTL_CVY_CLUSTER_ON},
|
|
{WLBS_STOP, IOCTL_CVY_CLUSTER_OFF},
|
|
{WLBS_DRAIN, IOCTL_CVY_CLUSTER_DRAIN},
|
|
{WLBS_SUSPEND, IOCTL_CVY_CLUSTER_SUSPEND},
|
|
{WLBS_RESUME, IOCTL_CVY_CLUSTER_RESUME},
|
|
{WLBS_PORT_ENABLE, IOCTL_CVY_PORT_ON},
|
|
{WLBS_PORT_DISABLE, IOCTL_CVY_PORT_OFF},
|
|
{WLBS_PORT_DRAIN, IOCTL_CVY_PORT_DRAIN},
|
|
{WLBS_QUERY, IOCTL_CVY_QUERY},
|
|
{WLBS_QUERY_PORT_STATE, IOCTL_CVY_QUERY_PORT_STATE}
|
|
};
|
|
|
|
for (int i=0; i<sizeof(OpcodeIoctlMap) /sizeof(OpcodeIoctlMap[0]); i++)
|
|
{
|
|
if (OpcodeIoctlMap[i].Opcode == Opcode)
|
|
{
|
|
*plIoctl = OpcodeIoctlMap[i].ioctl;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Default
|
|
//
|
|
return false;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
CfgUtilControlCluster(
|
|
IN LPCWSTR szNic,
|
|
IN WLBS_OPERATION_CODES Opcode,
|
|
IN DWORD Vip,
|
|
IN DWORD PortNum,
|
|
OUT DWORD * pdwHostMap,
|
|
OUT DWORD * pdwNlbStatus
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
GUID Guid;
|
|
WBEMSTATUS Status;
|
|
LONG ioctl;
|
|
|
|
TRACE_INFO(L"-> %!FUNC! szNic : %ls, Opcode: %d, Vip : 0x%x, Port : 0x%x", szNic, Opcode, Vip, PortNum);
|
|
|
|
if (pdwNlbStatus)
|
|
{
|
|
*pdwNlbStatus = WLBS_FAILURE;
|
|
}
|
|
|
|
if (!g_CfgUtils.IsInitalized())
|
|
{
|
|
TRACE_CRIT(L"%!FUNC!(Nic=%ws) FAILING because uninitialized", szNic);
|
|
Status = WBEM_E_INITIALIZATION_FAILURE;
|
|
goto end;
|
|
}
|
|
|
|
hr = CLSIDFromString((LPWSTR)szNic, &Guid);
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE_CRIT(
|
|
L"CWlbsControl::Initialize failed at CLSIDFromString %ws",
|
|
szNic
|
|
);
|
|
Status = WBEM_E_INVALID_PARAMETER;
|
|
if (pdwNlbStatus)
|
|
{
|
|
*pdwNlbStatus = WLBS_BAD_PARAMS;
|
|
}
|
|
goto end;
|
|
}
|
|
|
|
// Verify that the NLB API hooks are present
|
|
if (!g_CfgUtils.m_NLBApiHooksPresent)
|
|
{
|
|
TRACE_CRIT(L"%!FUNC! FAILING because NLB API hooks are not present");
|
|
Status = WBEM_E_INITIALIZATION_FAILURE;
|
|
goto end;
|
|
}
|
|
|
|
HANDLE Nlb_driver_hdl;
|
|
|
|
// Get handle to NLB driver
|
|
if ((Nlb_driver_hdl = g_CfgUtils.m_pfWlbsOpen()) == INVALID_HANDLE_VALUE)
|
|
{
|
|
TRACE_CRIT(L"%!FUNC! WlbsOpen returned NULL, Could not create connection to NLB driver");
|
|
Status = WBEM_E_CRITICAL_ERROR;
|
|
goto end;
|
|
}
|
|
|
|
// Convert Opcode to ioctl
|
|
if (!MapOpcodeToIoctl(Opcode, &ioctl))
|
|
{
|
|
TRACE_CRIT(L"%!FUNC!: Invalid value (0x%x) for operation!",Opcode);
|
|
Status = WBEM_E_INVALID_PARAMETER;
|
|
if (pdwNlbStatus)
|
|
{
|
|
*pdwNlbStatus = WLBS_BAD_PARAMS;
|
|
}
|
|
CloseHandle(Nlb_driver_hdl);
|
|
goto end;
|
|
}
|
|
|
|
DWORD dwRet = g_CfgUtils.m_pfWlbsLocalClusterControl(Nlb_driver_hdl, &Guid, ioctl, Vip, PortNum, pdwHostMap);
|
|
|
|
if (pdwNlbStatus)
|
|
{
|
|
*pdwNlbStatus = dwRet;
|
|
}
|
|
|
|
// Close handle to NLB driver
|
|
CloseHandle(Nlb_driver_hdl);
|
|
|
|
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
switch(dwRet)
|
|
{
|
|
case WLBS_ALREADY: break;
|
|
case WLBS_CONVERGED: break;
|
|
case WLBS_CONVERGING: break;
|
|
case WLBS_DEFAULT: break;
|
|
case WLBS_DRAIN_STOP: break;
|
|
case WLBS_DRAINING: break;
|
|
case WLBS_OK: break;
|
|
case WLBS_STOPPED: break;
|
|
case WLBS_SUSPENDED: break;
|
|
case NLB_PORT_RULE_NOT_FOUND: break;
|
|
case NLB_PORT_RULE_ENABLED: break;
|
|
case NLB_PORT_RULE_DISABLED: break;
|
|
case NLB_PORT_RULE_DRAINING: break;
|
|
case WLBS_BAD_PARAMS: Status = WBEM_E_INVALID_PARAMETER; break;
|
|
default: Status = WBEM_E_CRITICAL_ERROR; break;
|
|
}
|
|
|
|
end:
|
|
|
|
TRACE_INFO(L"<- %!FUNC! returns Status : 0x%x",Status);
|
|
return Status;
|
|
}
|
|
|
|
WBEMSTATUS
|
|
CfgUtilGetClusterMembers(
|
|
IN LPCWSTR szNic,
|
|
OUT DWORD *pNumMembers,
|
|
OUT NLB_CLUSTER_MEMBER_INFO **ppMembers // free using delete[]
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
GUID AdapterGuid;
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
DWORD dwNumHosts = CVY_MAX_HOSTS;
|
|
PWLBS_RESPONSE pResponse = NULL;
|
|
NLB_CLUSTER_MEMBER_INFO* pMembers = NULL;
|
|
|
|
TRACE_INFO(L"-> szNic : %ls", szNic);
|
|
|
|
ASSERT (pNumMembers != NULL);
|
|
ASSERT (ppMembers != NULL);
|
|
|
|
*pNumMembers = 0;
|
|
*ppMembers = NULL;
|
|
|
|
if (!g_CfgUtils.IsInitalized())
|
|
{
|
|
TRACE_CRIT(L"(Nic=%ws) FAILING because uninitialized", szNic);
|
|
Status = WBEM_E_INITIALIZATION_FAILURE;
|
|
goto end;
|
|
}
|
|
|
|
hr = CLSIDFromString((LPWSTR)szNic, &AdapterGuid);
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE_CRIT(L"CLSIDFromString failed with error %ws", szNic);
|
|
Status = WBEM_E_INVALID_PARAMETER;
|
|
goto end;
|
|
}
|
|
|
|
// Verify that the NLB API hooks are present
|
|
if (!g_CfgUtils.m_NLBApiHooksPresent)
|
|
{
|
|
TRACE_CRIT(L"FAILING because NLB API hooks are not present");
|
|
Status = WBEM_E_INITIALIZATION_FAILURE;
|
|
goto end;
|
|
}
|
|
|
|
pResponse = new WLBS_RESPONSE[CVY_MAX_HOSTS];
|
|
|
|
if (pResponse == NULL)
|
|
{
|
|
TRACE_CRIT(L"FAILING because memory allocation failed");
|
|
Status = WBEM_E_OUT_OF_MEMORY;
|
|
goto end;
|
|
}
|
|
|
|
ZeroMemory(pResponse, sizeof(WLBS_RESPONSE)*CVY_MAX_HOSTS);
|
|
|
|
{
|
|
DWORD dwStatus;
|
|
|
|
dwStatus = g_CfgUtils.m_pfWlbsGetClusterMembers (
|
|
& AdapterGuid,
|
|
& dwNumHosts,
|
|
pResponse
|
|
);
|
|
|
|
//
|
|
// WLBS_TIMEOUT, i.e., 0 hosts responding is considered a failure. So the only success code is WLBS_OK.
|
|
// TODO: If we want timeout to be success, need to make a change here.
|
|
//
|
|
if (dwStatus != WLBS_OK)
|
|
{
|
|
TRACE_CRIT("error getting list of cluster members: 0x%x", dwStatus);
|
|
Status = WBEM_E_FAILED;
|
|
goto end;
|
|
}
|
|
|
|
if (dwNumHosts == 0)
|
|
{
|
|
//
|
|
// Not an error, but we exit here because there were no cluster members.
|
|
//
|
|
TRACE_INFO("WlbsGetClusterMembers returned no cluster members");
|
|
Status = WBEM_S_NO_ERROR;
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
pMembers = new NLB_CLUSTER_MEMBER_INFO[dwNumHosts];
|
|
|
|
if (pMembers == NULL)
|
|
{
|
|
TRACE_CRIT("error allocating struct to host cluster member info");
|
|
Status = WBEM_E_OUT_OF_MEMORY;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Memory allocation succeeded, so set the size of the output array.
|
|
//
|
|
*pNumMembers = dwNumHosts;
|
|
ZeroMemory(pMembers, sizeof(NLB_CLUSTER_MEMBER_INFO)*dwNumHosts);
|
|
*ppMembers = pMembers;
|
|
|
|
for (int i=0; i < dwNumHosts; i++, pMembers++)
|
|
{
|
|
pMembers->HostId = pResponse[i].id;
|
|
|
|
AbcdWszFromIpAddress(pResponse[i].address, pMembers->DedicatedIpAddress, ASIZECCH(pMembers->DedicatedIpAddress));
|
|
|
|
if ((pResponse[i].options.query.hostname)[0] != L'\0')
|
|
{
|
|
wcsncpy(pMembers->HostName, pResponse[i].options.identity.fqdn, CVY_MAX_FQDN + 1);
|
|
pMembers->HostName[CVY_MAX_FQDN] = L'\0';
|
|
}
|
|
}
|
|
|
|
Status = WBEM_S_NO_ERROR;
|
|
|
|
end:
|
|
|
|
// Clean up the output quantities if we had an error
|
|
if (Status != WBEM_S_NO_ERROR)
|
|
{
|
|
if (pMembers != NULL)
|
|
{
|
|
delete [] pMembers;
|
|
pMembers = NULL;
|
|
}
|
|
}
|
|
|
|
if (pResponse != NULL)
|
|
{
|
|
delete [] pResponse;
|
|
pResponse = NULL;
|
|
}
|
|
|
|
TRACE_INFO(L"<- returns Status : 0x%x",Status);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Initializes pParams using default values.
|
|
//
|
|
VOID
|
|
CfgUtilInitializeParams(
|
|
OUT WLBS_REG_PARAMS *pParams
|
|
)
|
|
{
|
|
//
|
|
// We don't expect WlbsSetDefaults to fail (it should have been
|
|
// defined returning VOID).
|
|
//
|
|
DWORD dwRet;
|
|
|
|
|
|
// Verify that the NLB API hooks are present
|
|
if (!g_CfgUtils.m_NLBApiHooksPresent)
|
|
{
|
|
dwRet = MyWlbsSetDefaults(pParams);
|
|
}
|
|
else
|
|
{
|
|
dwRet = g_CfgUtils.m_pfWlbsSetDefaults(pParams);
|
|
}
|
|
|
|
if (dwRet != WLBS_OK)
|
|
{
|
|
ZeroMemory(pParams, sizeof(*pParams));
|
|
TRACE_CRIT("Internal error: WlbsSetDefaults failed");
|
|
ASSERT(FALSE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Converts the specified plain-text password into the hashed version
|
|
// and saves it in pParams.
|
|
//
|
|
DWORD
|
|
CfgUtilSetRemotePassword(
|
|
IN WLBS_REG_PARAMS *pParams,
|
|
IN LPCWSTR szPassword
|
|
|
|
)
|
|
{
|
|
//
|
|
// We don't expect WlbsSetDefaults to fail (it should have been
|
|
// defined returning VOID).
|
|
//
|
|
DWORD dwRet;
|
|
|
|
|
|
// Verify that the NLB API hooks are present
|
|
if (!g_CfgUtils.m_NLBApiHooksPresent)
|
|
{
|
|
TRACE_CRIT(L"%!FUNC! FAILING because NLB API hooks are not present");
|
|
dwRet = WBEM_E_INITIALIZATION_FAILURE;
|
|
goto end;
|
|
}
|
|
else
|
|
{
|
|
dwRet = g_CfgUtils.m_pfWlbsSetRemotePassword(pParams, szPassword);
|
|
}
|
|
|
|
end:
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
WBEMSTATUS
|
|
CfgUtilSafeArrayFromStrings(
|
|
IN LPCWSTR *pStrings,
|
|
IN UINT NumStrings,
|
|
OUT SAFEARRAY **ppSA
|
|
)
|
|
/*
|
|
Allocates and returns a SAFEARRAY of strings -- strings are copies of
|
|
the passed in values.
|
|
|
|
Call SafeArrayDestroy when done with the array.
|
|
*/
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
SAFEARRAY *pSA = NULL;
|
|
HRESULT hr;
|
|
LONG Index = 0;
|
|
|
|
*ppSA = NULL;
|
|
|
|
//
|
|
// Create safe array for the parameter values
|
|
//
|
|
pSA = SafeArrayCreateVector(
|
|
VT_BSTR,
|
|
0, // lower bound
|
|
NumStrings // size of the fixed-sized vector.
|
|
);
|
|
if (pSA == NULL)
|
|
{
|
|
TRACE_CRIT("Could not create safe array");
|
|
Status = WBEM_E_OUT_OF_MEMORY;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Place the strings into the safe array
|
|
//
|
|
{
|
|
for (Index = 0; Index<NumStrings; Index++)
|
|
{
|
|
LPCWSTR sz = pStrings[Index];
|
|
|
|
//
|
|
// SafeArrayPutElement expects the string passed in to
|
|
// be of type BSTR, which is of type wchar *, except, that
|
|
// the first 2 wchars contains length and other(?)
|
|
// information. This is why you can't simply pass in sz.
|
|
//
|
|
// So to get this we initalize an object of type _bstr_t
|
|
// based on sz. On initializaton, bstrValue allocates memory
|
|
// and copies the string.
|
|
//
|
|
_bstr_t bstrValue = sz;
|
|
wchar_t *pwchar = (wchar_t *) bstrValue; // returns internal pointer.
|
|
|
|
// bpStr[Index] = sz; // may work as well.
|
|
//
|
|
// SafeArrayPutElement internally allocates space for pwchar and
|
|
// copies over the string.
|
|
// So pSA doesn't contain a direct reference to pwchar.
|
|
//
|
|
hr = SafeArrayPutElement(pSA, &Index, pwchar);
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE_CRIT("Unable to put element %wsz", sz);
|
|
(VOID) SafeArrayUnaccessData(pSA);
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// I think that bstrValue's contents are deallocated on exit of
|
|
// this block.
|
|
//
|
|
|
|
}
|
|
}
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
end:
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
if (pSA!=NULL)
|
|
{
|
|
SafeArrayDestroy(pSA);
|
|
pSA = NULL;
|
|
}
|
|
}
|
|
|
|
*ppSA = pSA;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
CfgUtilStringsFromSafeArray(
|
|
IN SAFEARRAY *pSA,
|
|
OUT LPWSTR **ppStrings,
|
|
OUT UINT *pNumStrings
|
|
)
|
|
/*
|
|
Extracts copies of the strings in the passed-in safe array.
|
|
Free *pStrings using the delete operator when done.
|
|
NOTE: Do NOT delete the individual strings -- they are
|
|
stored in the memory allocated for pStrings.
|
|
*/
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_OUT_OF_MEMORY;
|
|
LPWSTR *pStrings = NULL;
|
|
LPCWSTR csz;
|
|
LPWSTR sz;
|
|
UINT NumStrings = 0;
|
|
UINT u;
|
|
HRESULT hr;
|
|
BSTR *pbStr =NULL;
|
|
UINT TotalSize =0;
|
|
LONG UBound = 0;
|
|
|
|
*ppStrings = NULL;
|
|
*pNumStrings = 0;
|
|
|
|
hr = SafeArrayGetUBound(pSA, 1, &UBound);
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE_CRIT("Could not get upper bound of safe array");
|
|
goto end;
|
|
}
|
|
NumStrings = (UINT) (UBound+1); // Convert from UpperBound to NumStrings.
|
|
|
|
if (NumStrings == 0)
|
|
{
|
|
// nothing in array -- we're done.
|
|
Status = WBEM_NO_ERROR;
|
|
goto end;
|
|
|
|
}
|
|
|
|
hr = SafeArrayAccessData(pSA, ( void **) &pbStr);
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE_CRIT("Could not access data of safe array");
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Calculate space for the array of pointers to strings...
|
|
//
|
|
TotalSize = NumStrings*sizeof(LPWSTR);
|
|
|
|
//
|
|
// Calculate space for the strings themselves...
|
|
//
|
|
for (u=0; u<NumStrings; u++)
|
|
{
|
|
csz = pbStr[u];
|
|
TotalSize += (wcslen(csz)+1)*sizeof(WCHAR);
|
|
}
|
|
|
|
//
|
|
// Allocate space for *both* the array of pointers and the strings
|
|
// in one shot -- we're doing a new of type LPWSTR[] for the whole
|
|
// lot, so need to specify the size in units of LPWSTR (with an
|
|
// additional +1 in case there's roundoff).
|
|
//
|
|
pStrings = new LPWSTR[(TotalSize/sizeof(LPWSTR))+1];
|
|
if (pStrings == NULL)
|
|
{
|
|
Status = WBEM_E_OUT_OF_MEMORY;
|
|
(VOID) SafeArrayUnaccessData(pSA);
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Make sz point to the start of the place where we'll be placing
|
|
// the string data.
|
|
//
|
|
sz = (LPWSTR) (pStrings+NumStrings);
|
|
for (u=0; u<NumStrings; u++)
|
|
{
|
|
csz = pbStr[u];
|
|
UINT len = wcslen(csz)+1;
|
|
CopyMemory(sz, csz, len*sizeof(WCHAR));
|
|
pStrings[u] = sz;
|
|
sz+=len;
|
|
}
|
|
|
|
(VOID) SafeArrayUnaccessData(pSA);
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
end:
|
|
|
|
pbStr=NULL;
|
|
if (FAILED(Status))
|
|
{
|
|
if (pStrings!=NULL)
|
|
{
|
|
delete[] pStrings;
|
|
pStrings = NULL;
|
|
}
|
|
NumStrings = 0;
|
|
}
|
|
|
|
*ppStrings = pStrings;
|
|
*pNumStrings = NumStrings;
|
|
|
|
return Status;
|
|
}
|
|
|
|
WBEMSTATUS
|
|
CfgUtilGetWmiObjectInstance(
|
|
IN IWbemServicesPtr spWbemServiceIF,
|
|
IN LPCWSTR szClassName,
|
|
IN LPCWSTR szPropertyName,
|
|
IN LPCWSTR szPropertyValue,
|
|
OUT IWbemClassObjectPtr &sprefObj // smart pointer
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_NOT_FOUND;
|
|
HRESULT hr;
|
|
|
|
//
|
|
// TODO: consider using IWbemServices::ExecQuery
|
|
//
|
|
IEnumWbemClassObjectPtr spEnum=NULL; // smart pointer
|
|
IWbemClassObjectPtr spObj = NULL; // smart pointer.
|
|
_bstr_t bstrClassName = szClassName;
|
|
|
|
//
|
|
// get all instances of object
|
|
//
|
|
hr = spWbemServiceIF->CreateInstanceEnum(
|
|
bstrClassName,
|
|
WBEM_FLAG_RETURN_IMMEDIATELY,
|
|
NULL,
|
|
&spEnum
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE_CRIT("IWbemServices::CreateInstanceEnum failure\n" );
|
|
spEnum = NULL;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Look for the object with the matching property.
|
|
//
|
|
do
|
|
{
|
|
ULONG count = 1;
|
|
|
|
hr = spEnum->Next(
|
|
INFINITE,
|
|
1,
|
|
&spObj,
|
|
&count
|
|
);
|
|
//
|
|
// Note -- Next() returns S_OK if number asked == number returned.
|
|
// and S_FALSE if number asked < than number requested.
|
|
// Since we're asking for only ...
|
|
//
|
|
if (hr == S_OK)
|
|
{
|
|
LPWSTR szEnumValue = NULL;
|
|
|
|
Status = CfgUtilGetWmiStringParam(
|
|
spObj,
|
|
szPropertyName,
|
|
&szEnumValue // Delete when done.
|
|
);
|
|
if (FAILED(Status))
|
|
{
|
|
//
|
|
// Ignore this failure here.
|
|
//
|
|
|
|
}
|
|
else if (szEnumValue!=NULL)
|
|
{
|
|
BOOL fFound = FALSE;
|
|
if (!_wcsicmp(szEnumValue, szPropertyValue))
|
|
{
|
|
fFound = TRUE;
|
|
}
|
|
delete szEnumValue;
|
|
|
|
if (fFound)
|
|
{
|
|
break; // BREAK BREAK BREAK BREAK
|
|
}
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRACE_INFO(
|
|
"====0x%p->Next() returns Error 0x%lx; count=0x%lu", (PVOID) spObj,
|
|
(UINT) hr, count);
|
|
}
|
|
|
|
|
|
//
|
|
// Since I don't fully trust smart pointers, I'm specifically
|
|
// setting spObj to NULL here...
|
|
//
|
|
spObj = NULL; // smart pointer
|
|
|
|
} while (hr == S_OK);
|
|
|
|
if (spObj == NULL)
|
|
{
|
|
//
|
|
// We couldn't find a NIC which matches the one asked for...
|
|
//
|
|
Status = WBEM_E_NOT_FOUND;
|
|
goto end;
|
|
}
|
|
|
|
end:
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
sprefObj = NULL;
|
|
}
|
|
else
|
|
{
|
|
sprefObj = spObj; // smart pointer.
|
|
}
|
|
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
CfgUtilGetWmiRelPath(
|
|
IN IWbemClassObjectPtr spObj,
|
|
OUT LPWSTR * pszRelPath // free using delete
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
LPWSTR pRelPath = NULL;
|
|
|
|
|
|
//
|
|
// Extract the relative path, needed for ExecMethod.
|
|
//
|
|
Status = CfgUtilGetWmiStringParam(
|
|
spObj,
|
|
L"__RELPATH", // szParameterName
|
|
&pRelPath // Delete when done.
|
|
);
|
|
if (FAILED(Status))
|
|
{
|
|
TRACE_CRIT("Couldn't get rel path");
|
|
pRelPath = NULL;
|
|
goto end;
|
|
}
|
|
else
|
|
{
|
|
if (pRelPath==NULL)
|
|
{
|
|
ASSERT(FALSE); // we don't expect this!
|
|
goto end;
|
|
}
|
|
TRACE_VERB("GOT RELATIVE PATH %ws", pRelPath);
|
|
}
|
|
|
|
end:
|
|
*pszRelPath = pRelPath;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
CfgUtilGetWmiInputInstanceAndRelPath(
|
|
IN IWbemServicesPtr spWbemServiceIF,
|
|
IN LPCWSTR szClassName,
|
|
IN LPCWSTR szPropertyName, // NULL: return Class rel path
|
|
IN LPCWSTR szPropertyValue,
|
|
IN LPCWSTR szMethodName,
|
|
OUT IWbemClassObjectPtr &spWbemInputInstance, // smart pointer
|
|
OUT LPWSTR * pszRelPath // free using delete
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
IWbemClassObjectPtr spClassObj = NULL; // smart pointer
|
|
HRESULT hr;
|
|
LPWSTR pRelPath = NULL;
|
|
|
|
TRACE_INFO(L"-> %!FUNC!(PropertyValue=%ws)",
|
|
szPropertyValue==NULL ? L"<class>" : szPropertyValue);
|
|
|
|
//
|
|
// Get CLASS object
|
|
//
|
|
{
|
|
hr = spWbemServiceIF->GetObject(
|
|
_bstr_t(szClassName),
|
|
0,
|
|
NULL,
|
|
&spClassObj,
|
|
NULL
|
|
);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE_CRIT("Couldn't get nic class object pointer");
|
|
Status = (WBEMSTATUS)hr;
|
|
goto end;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Get WMI path to specific object
|
|
//
|
|
if (szPropertyName == NULL)
|
|
{
|
|
// Get WMI path to the class
|
|
Status = CfgUtilGetWmiRelPath(
|
|
spClassObj,
|
|
&pRelPath
|
|
);
|
|
if (FAILED(Status))
|
|
{
|
|
goto end;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IWbemClassObjectPtr spObj = NULL; // smart pointer
|
|
pRelPath = NULL;
|
|
|
|
Status = CfgUtilGetWmiObjectInstance(
|
|
spWbemServiceIF,
|
|
szClassName,
|
|
szPropertyName,
|
|
szPropertyValue,
|
|
spObj // smart pointer, passed by ref
|
|
);
|
|
if (FAILED(Status))
|
|
{
|
|
ASSERT(spObj == NULL);
|
|
goto end;
|
|
}
|
|
|
|
Status = CfgUtilGetWmiRelPath(
|
|
spObj,
|
|
&pRelPath
|
|
);
|
|
spObj = NULL; // smart pointer
|
|
if (FAILED(Status))
|
|
{
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get the input parameters to the call to the method
|
|
//
|
|
{
|
|
IWbemClassObjectPtr spWbemInput = NULL; // smart pointer
|
|
|
|
// check if any input parameters specified.
|
|
|
|
hr = spClassObj->GetMethod(
|
|
szMethodName,
|
|
0,
|
|
&spWbemInput,
|
|
NULL
|
|
);
|
|
if(FAILED(hr))
|
|
{
|
|
TRACE_CRIT("IWbemClassObject::GetMethod failure");
|
|
Status = (WBEMSTATUS) hr;
|
|
goto end;
|
|
}
|
|
|
|
if (spWbemInput != NULL)
|
|
{
|
|
hr = spWbemInput->SpawnInstance( 0, &spWbemInputInstance );
|
|
if( FAILED( hr) )
|
|
{
|
|
TRACE_CRIT("IWbemClassObject::SpawnInstance failure. Unable to spawn instance." );
|
|
Status = (WBEMSTATUS) hr;
|
|
goto end;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This method has no input arguments!
|
|
//
|
|
spWbemInputInstance = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
end:
|
|
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
if (pRelPath != NULL)
|
|
{
|
|
delete pRelPath;
|
|
pRelPath = NULL;
|
|
}
|
|
}
|
|
|
|
*pszRelPath = pRelPath;
|
|
|
|
TRACE_INFO(L"<- %!FUNC! returns 0x%08lx", (UINT) Status);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
CfgUtilGetWmiStringParam(
|
|
IN IWbemClassObjectPtr spObj,
|
|
IN LPCWSTR szParameterName,
|
|
OUT LPWSTR *ppStringValue
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_NOT_FOUND;
|
|
WCHAR *pStringValue = NULL;
|
|
|
|
try
|
|
{
|
|
|
|
_variant_t v_value;
|
|
CIMTYPE v_type;
|
|
HRESULT hr;
|
|
|
|
hr = spObj->Get(
|
|
_bstr_t(szParameterName), // Name
|
|
0, // Reserved, must be 0
|
|
&v_value, // Place to store value
|
|
&v_type, // Type of value
|
|
NULL // Flavor (unused)
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
// Couldn't read the Setting ID field!
|
|
//
|
|
TRACE_CRIT(
|
|
"get_str_parm:Couldn't retrieve %ws from 0x%p. Hr=0x%08lx",
|
|
szParameterName,
|
|
(PVOID) spObj,
|
|
hr
|
|
);
|
|
goto end;
|
|
}
|
|
else if (v_type == VT_NULL || v_value.vt == VT_NULL)
|
|
{
|
|
pStringValue = NULL;
|
|
Status = WBEM_NO_ERROR;
|
|
goto end;
|
|
}
|
|
else
|
|
{
|
|
if (v_type != VT_BSTR)
|
|
{
|
|
TRACE_CRIT(
|
|
"get_str_parm: Parm value not of string type %ws from 0x%p",
|
|
szParameterName,
|
|
(PVOID) spObj
|
|
);
|
|
Status = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
|
|
_bstr_t bstrNicGuid(v_value);
|
|
LPCWSTR sz = bstrNicGuid; // Pointer to internal buffer.
|
|
|
|
if (sz==NULL)
|
|
{
|
|
// hmm.. null value
|
|
pStringValue = NULL;
|
|
Status = WBEM_NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
UINT len = wcslen(sz);
|
|
pStringValue = new WCHAR[len+1];
|
|
if (pStringValue == NULL)
|
|
{
|
|
TRACE_CRIT("get_str_parm: Alloc failure!");
|
|
Status = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
CopyMemory(pStringValue, sz, (len+1)*sizeof(WCHAR));
|
|
Status = WBEM_NO_ERROR;
|
|
}
|
|
}
|
|
|
|
TRACE_VERB(
|
|
"get_str_parm: String parm %ws of 0x%p is %ws",
|
|
szParameterName,
|
|
(PVOID) spObj,
|
|
(sz==NULL) ? L"<null>" : sz
|
|
);
|
|
}
|
|
|
|
v_value.Clear(); // Must be cleared after each call to Get.
|
|
}
|
|
|
|
}
|
|
catch( _com_error e )
|
|
{
|
|
TRACE_INFO(L"%!FUNC! -- com exception");
|
|
Status = WBEM_E_NOT_FOUND;
|
|
}
|
|
|
|
end:
|
|
|
|
if (!FAILED(Status) && pStringValue == NULL)
|
|
{
|
|
//
|
|
// We convert a NULL value to an empty, not NULL string.
|
|
//
|
|
pStringValue = new WCHAR[1];
|
|
if (pStringValue == NULL)
|
|
{
|
|
Status = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
*pStringValue = 0;
|
|
Status = WBEM_NO_ERROR;
|
|
}
|
|
}
|
|
|
|
|
|
*ppStringValue = pStringValue;
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
CfgUtilSetWmiStringParam(
|
|
IN IWbemClassObjectPtr spObj,
|
|
IN LPCWSTR szParameterName,
|
|
IN LPCWSTR szValue
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
|
|
try
|
|
{
|
|
|
|
HRESULT hr;
|
|
_bstr_t bstrName = szParameterName;
|
|
_variant_t v_value = (LPWSTR) szValue; // Allocates.
|
|
|
|
hr = spObj->Put(
|
|
bstrName, // Parameter Name
|
|
0, // Must be 0
|
|
&v_value,
|
|
0 // Must be 0
|
|
);
|
|
v_value.Clear();
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE_CRIT("Unable to put parameter %ws", szParameterName);
|
|
goto end;
|
|
}
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
//
|
|
// I think bstrName releases the internally allocated string
|
|
// on exiting this block.
|
|
//
|
|
}
|
|
catch( _com_error e )
|
|
{
|
|
TRACE_INFO(L"%!FUNC! -- com exception");
|
|
Status = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
end:
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
CfgUtilGetWmiStringArrayParam(
|
|
IN IWbemClassObjectPtr spObj,
|
|
IN LPCWSTR szParameterName,
|
|
OUT LPWSTR **ppStrings,
|
|
OUT UINT *pNumStrings
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_NOT_FOUND;
|
|
|
|
try
|
|
{
|
|
_variant_t v_value;
|
|
CIMTYPE v_type;
|
|
HRESULT hr;
|
|
LONG count = 0;
|
|
|
|
*ppStrings = NULL;
|
|
*pNumStrings = 0;
|
|
|
|
hr = spObj->Get(
|
|
_bstr_t(szParameterName),
|
|
0, // Reserved, must be 0
|
|
&v_value, // Place to store value
|
|
&v_type, // Type of value
|
|
NULL // Flavor (unused)
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
// Couldn't read the requested parameter.
|
|
//
|
|
TRACE_CRIT(
|
|
"get_multi_str_parm:Couldn't retrieve %ws from 0x%p",
|
|
szParameterName,
|
|
(PVOID) spObj
|
|
);
|
|
Status = WBEM_E_INVALID_PARAMETER;
|
|
goto end;
|
|
}
|
|
|
|
|
|
if (v_type != (VT_ARRAY | VT_BSTR))
|
|
{
|
|
|
|
if (v_type == VT_NULL)
|
|
{
|
|
//
|
|
// We convert a NULL value to zero strings
|
|
//
|
|
Status = WBEM_NO_ERROR;
|
|
goto end;
|
|
}
|
|
TRACE_CRIT("vt is not of type string!");
|
|
goto end;
|
|
}
|
|
else if (v_value.vt == VT_NULL)
|
|
{
|
|
//
|
|
// I've seen this too...
|
|
//
|
|
// We convert a NULL value to zero strings
|
|
//
|
|
TRACE_CRIT("WARNING: vt is NULL!");
|
|
Status = WBEM_NO_ERROR;
|
|
goto end;
|
|
|
|
}
|
|
else
|
|
{
|
|
VARIANT ipsV = v_value.Detach();
|
|
SAFEARRAY *pSA = ipsV.parray;
|
|
|
|
Status = CfgUtilStringsFromSafeArray(
|
|
pSA,
|
|
ppStrings,
|
|
pNumStrings
|
|
);
|
|
|
|
VariantClear( &ipsV );
|
|
}
|
|
}
|
|
catch( _com_error e )
|
|
{
|
|
TRACE_INFO(L"%!FUNC! -- com exception");
|
|
Status = WBEM_E_NOT_FOUND;
|
|
}
|
|
|
|
end:
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
CfgUtilSetWmiStringArrayParam(
|
|
IN IWbemClassObjectPtr spObj,
|
|
IN LPCWSTR szParameterName,
|
|
IN LPCWSTR *ppStrings,
|
|
IN UINT NumStrings
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
SAFEARRAY *pSA = NULL;
|
|
|
|
|
|
try
|
|
{
|
|
|
|
HRESULT hr;
|
|
LONG Index = 0;
|
|
|
|
|
|
Status = CfgUtilSafeArrayFromStrings(
|
|
ppStrings,
|
|
NumStrings,
|
|
&pSA
|
|
);
|
|
if (FAILED(Status))
|
|
{
|
|
pSA = NULL;
|
|
goto end;
|
|
}
|
|
|
|
|
|
//
|
|
// Put the parameter.
|
|
//
|
|
{
|
|
VARIANT V;
|
|
_bstr_t bstrName = szParameterName;
|
|
|
|
VariantInit(&V);
|
|
V.vt = VT_ARRAY | VT_BSTR;
|
|
V.parray = pSA;
|
|
_variant_t v_value;
|
|
v_value.Attach(V); // Takes owhership of V. V now becomes empty.
|
|
ASSERT(V.vt == VT_EMPTY);
|
|
pSA = NULL; // should be no need to delete this explicitly now.
|
|
// v_value.Clear() should delete it, I think.
|
|
|
|
hr = spObj->Put(
|
|
bstrName, // Parameter Name
|
|
0, // Must be 0
|
|
&v_value,
|
|
0 // Must be 0
|
|
);
|
|
|
|
v_value.Clear();
|
|
if (FAILED(hr))
|
|
{
|
|
Status = (WBEMSTATUS) hr;
|
|
TRACE_CRIT("Unable to put parameter %ws", szParameterName);
|
|
goto end;
|
|
}
|
|
Status = WBEM_NO_ERROR;
|
|
}
|
|
|
|
}
|
|
catch( _com_error e )
|
|
{
|
|
TRACE_INFO(L"%!FUNC! -- com exception");
|
|
Status = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
end:
|
|
|
|
if (pSA!=NULL)
|
|
{
|
|
SafeArrayDestroy(pSA);
|
|
pSA = NULL;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
CfgUtilGetWmiDWORDParam(
|
|
IN IWbemClassObjectPtr spObj,
|
|
IN LPCWSTR szParameterName,
|
|
OUT DWORD *pValue
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_NOT_FOUND;
|
|
DWORD Value=0;
|
|
|
|
|
|
try
|
|
{
|
|
_variant_t v_value;
|
|
CIMTYPE v_type;
|
|
HRESULT hr;
|
|
|
|
hr = spObj->Get(
|
|
_bstr_t(szParameterName), // Name
|
|
0, // Reserved, must be 0
|
|
&v_value, // Place to store value
|
|
&v_type, // Type of value
|
|
NULL // Flavor (unused)
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
// Couldn't read the parameter
|
|
//
|
|
TRACE_CRIT(
|
|
"GetDWORDParm:Couldn't retrieve %ws from 0x%p",
|
|
szParameterName,
|
|
(PVOID) spObj
|
|
);
|
|
goto end;
|
|
}
|
|
else
|
|
{
|
|
Value = (DWORD) (long) v_value;
|
|
v_value.Clear(); // Must be cleared after each call to Get.
|
|
Status = WBEM_NO_ERROR;
|
|
}
|
|
|
|
}
|
|
catch( _com_error e )
|
|
{
|
|
TRACE_INFO(L"%!FUNC! -- com exception");
|
|
Status = WBEM_E_NOT_FOUND;
|
|
}
|
|
|
|
end:
|
|
|
|
*pValue = Value;
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
CfgUtilSetWmiDWORDParam(
|
|
IN IWbemClassObjectPtr spObj,
|
|
IN LPCWSTR szParameterName,
|
|
IN DWORD Value
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
|
|
|
|
try
|
|
{
|
|
|
|
HRESULT hr;
|
|
_bstr_t bstrName = szParameterName;
|
|
_variant_t v_value = (long) Value;
|
|
|
|
hr = spObj->Put(
|
|
bstrName, // Parameter Name
|
|
0, // Must be 0
|
|
&v_value,
|
|
0 // Must be 0
|
|
);
|
|
v_value.Clear();
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE_CRIT("Unable to put parameter %ws", szParameterName);
|
|
goto end;
|
|
}
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
}
|
|
catch( _com_error e )
|
|
{
|
|
TRACE_INFO(L"%!FUNC! -- com exception");
|
|
Status = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
end:
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
CfgUtilGetWmiBoolParam(
|
|
IN IWbemClassObjectPtr spObj,
|
|
IN LPCWSTR szParameterName,
|
|
OUT BOOL *pValue
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_NOT_FOUND;
|
|
BOOL Value=0;
|
|
|
|
try
|
|
{
|
|
_variant_t v_value;
|
|
CIMTYPE v_type;
|
|
HRESULT hr;
|
|
|
|
hr = spObj->Get(
|
|
_bstr_t(szParameterName), // Name
|
|
0, // Reserved, must be 0
|
|
&v_value, // Place to store value
|
|
&v_type, // Type of value
|
|
NULL // Flavor (unused)
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
// Couldn't read the parameter
|
|
//
|
|
TRACE_CRIT(
|
|
"GetDWORDParm:Couldn't retrieve %ws from 0x%p",
|
|
szParameterName,
|
|
(PVOID) spObj
|
|
);
|
|
goto end;
|
|
}
|
|
else
|
|
{
|
|
Value = ((bool) v_value)!=0;
|
|
v_value.Clear(); // Must be cleared after each call to Get.
|
|
Status = WBEM_NO_ERROR;
|
|
}
|
|
|
|
}
|
|
catch( _com_error e )
|
|
{
|
|
TRACE_INFO(L"%!FUNC! -- com exception");
|
|
Status = WBEM_E_NOT_FOUND;
|
|
}
|
|
|
|
end:
|
|
|
|
*pValue = Value;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
CfgUtilSetWmiBoolParam(
|
|
IN IWbemClassObjectPtr spObj,
|
|
IN LPCWSTR szParameterName,
|
|
IN BOOL Value
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
|
|
try
|
|
{
|
|
HRESULT hr;
|
|
_bstr_t bstrName = szParameterName;
|
|
_variant_t v_value = (long) Value;
|
|
|
|
hr = spObj->Put(
|
|
bstrName, // Parameter Name
|
|
0, // Must be 0
|
|
&v_value,
|
|
0 // Must be 0
|
|
);
|
|
v_value.Clear();
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE_CRIT("Unable to put parameter %ws", szParameterName);
|
|
goto end;
|
|
}
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
}
|
|
catch( _com_error e )
|
|
{
|
|
TRACE_INFO(L"%!FUNC! -- com exception");
|
|
Status = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
end:
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
CfgUtilConnectToServer(
|
|
IN LPCWSTR szNetworkResource, // \\machinename\root\microsoftnlb \root\...
|
|
IN LPCWSTR szUser,
|
|
IN LPCWSTR szPassword,
|
|
IN LPCWSTR szAuthority,
|
|
OUT IWbemServices **ppWbemService // deref when done.
|
|
)
|
|
{
|
|
HRESULT hr = WBEM_E_CRITICAL_ERROR;
|
|
IWbemLocatorPtr spLocator=NULL; // Smart pointer
|
|
IWbemServices *pService=NULL;
|
|
|
|
try
|
|
{
|
|
|
|
_bstr_t serverPath(szNetworkResource);
|
|
|
|
*ppWbemService = NULL;
|
|
|
|
hr = CoCreateInstance(CLSID_WbemLocator, 0,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IWbemLocator,
|
|
(LPVOID *) &spLocator);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE_CRIT(L"CoCreateInstance IWebmLocator failed 0x%08lx ", (UINT)hr);
|
|
goto end;
|
|
}
|
|
|
|
for (int timesToRetry=0; timesToRetry<10; timesToRetry++)
|
|
{
|
|
//
|
|
// SECURITY BUGBUG -- need to make sure that
|
|
// password is zeroed out!
|
|
//
|
|
hr = spLocator->ConnectServer(
|
|
serverPath,
|
|
// (szUser!=NULL) ? (_bstr_t(szUser)) : NULL,
|
|
_bstr_t(szUser),
|
|
// (szPassword==NULL) ? NULL : _bstr_t(szPassword),
|
|
_bstr_t(szPassword),
|
|
NULL, // Locale
|
|
0, // Security flags
|
|
//(szAuthority==NULL) ? NULL : _bstr_t(szAuthority),
|
|
_bstr_t(szAuthority),
|
|
NULL,
|
|
&pService
|
|
);
|
|
|
|
if( !FAILED( hr) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// these have been found to be special cases where retrying may
|
|
// help. The errors below are not in any header file, and I searched
|
|
// the index2a sources for these constants -- no hits.
|
|
// TODO: file bug against WMI.
|
|
//
|
|
if( ( hr == 0x800706bf ) || ( hr == 0x80070767 ) || ( hr == 0x80070005 ) )
|
|
{
|
|
TRACE_CRIT(L"connectserver recoverable failure, retrying.");
|
|
Sleep(500);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Unrecoverable error...
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE_CRIT(L"Error 0x%08lx connecting to server", (UINT) hr);
|
|
goto end;
|
|
}
|
|
else
|
|
{
|
|
TRACE_INFO(L"Successfully connected to server %s", serverPath);
|
|
}
|
|
|
|
// 2/13/02 JosephJ SECURITY BUGBUG: verify that Both calls to CoSetProxyBlanket are the right
|
|
// ones to be made, from a security perspective.
|
|
//
|
|
// If NONE of User, Password, Authority is passed, call
|
|
// CoSetProxyBlanket with AuthInfo of COLE_DEFAULT_AUTHINFO
|
|
//
|
|
if(((szUser == NULL) || (wcslen(szUser) < 1))
|
|
&&((szPassword == NULL) || (wcslen(szPassword) < 1))
|
|
&&((szAuthority == NULL) || (wcslen(szAuthority) < 1)))
|
|
{
|
|
hr = CoSetProxyBlanket(
|
|
pService,
|
|
RPC_C_AUTHN_WINNT,
|
|
RPC_C_AUTHZ_DEFAULT, // RPC_C_AUTHZ_NAME,
|
|
COLE_DEFAULT_PRINCIPAL, // NULL,
|
|
RPC_C_AUTHN_LEVEL_DEFAULT,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
COLE_DEFAULT_AUTHINFO, // NULL,
|
|
EOAC_DEFAULT // EOAC_NONE
|
|
);
|
|
}
|
|
else // User or Authority was passed in, we need to create an authority argument for the login
|
|
{
|
|
|
|
COAUTHIDENTITY authident;
|
|
BSTR AuthArg, UserArg;
|
|
|
|
AuthArg = NULL;
|
|
UserArg = NULL;
|
|
|
|
hr = CfgUtilParseAuthorityUserArgs(AuthArg, UserArg, szAuthority, szUser);
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE_CRIT(L"Error CfgUtilParseAuthorityUserArgs returns 0x%08lx", (UINT)hr);
|
|
goto end;
|
|
}
|
|
|
|
if(UserArg)
|
|
{
|
|
authident.UserLength = wcslen(UserArg);
|
|
authident.User = (LPWSTR)UserArg;
|
|
}
|
|
|
|
if(AuthArg)
|
|
{
|
|
authident.DomainLength = wcslen(AuthArg);
|
|
authident.Domain = (LPWSTR)AuthArg;
|
|
}
|
|
|
|
if(szPassword)
|
|
{
|
|
authident.PasswordLength = wcslen(szPassword);
|
|
authident.Password = (LPWSTR)szPassword;
|
|
}
|
|
|
|
authident.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
|
|
|
|
hr = CoSetProxyBlanket(
|
|
pService,
|
|
RPC_C_AUTHN_WINNT,
|
|
RPC_C_AUTHZ_DEFAULT, // RPC_C_AUTHZ_NAME,
|
|
COLE_DEFAULT_PRINCIPAL, // NULL,
|
|
RPC_C_AUTHN_LEVEL_DEFAULT,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
&authident, // THIS IS THE DISTINGUISHING ARGUMENT
|
|
EOAC_DEFAULT // EOAC_NONE
|
|
);
|
|
|
|
if(UserArg)
|
|
SysFreeString(UserArg);
|
|
if(AuthArg)
|
|
SysFreeString(AuthArg);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE_CRIT(L"Error 0x%08lx setting proxy blanket", (UINT) hr);
|
|
goto end;
|
|
}
|
|
|
|
hr = WBEM_NO_ERROR;
|
|
|
|
}
|
|
catch( _com_error e )
|
|
{
|
|
TRACE_INFO(L"%!FUNC! -- com exception");
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
end:
|
|
|
|
spLocator = NULL; // smart pointer.
|
|
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
if (pService != NULL)
|
|
{
|
|
pService->Release();
|
|
pService=NULL;
|
|
}
|
|
}
|
|
|
|
*ppWbemService = pService;
|
|
|
|
return (WBEMSTATUS) hr;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
CfgUtilGetWmiMachineName(
|
|
IN IWbemServicesPtr spWbemServiceIF,
|
|
OUT LPWSTR * pszMachineName // free using delete
|
|
)
|
|
/*
|
|
Return the machine name and (optionally) machine guid.
|
|
*/
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
IWbemClassObjectPtr spClassObj = NULL; // smart pointer
|
|
HRESULT hr;
|
|
|
|
hr = spWbemServiceIF->GetObject(
|
|
_bstr_t(L"NlbsNic"),
|
|
0,
|
|
NULL,
|
|
&spClassObj,
|
|
NULL
|
|
);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE_CRIT("Couldn't get nic class object pointer");
|
|
Status = (WBEMSTATUS)hr;
|
|
goto end;
|
|
}
|
|
|
|
|
|
Status = CfgUtilGetWmiStringParam(
|
|
spClassObj,
|
|
L"__Server", // <-------------------------
|
|
pszMachineName
|
|
);
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
TRACE_CRIT(L"%!FUNC! Attempt to read server name. Error=0x%08lx",
|
|
(UINT) Status);
|
|
*pszMachineName = NULL;
|
|
}
|
|
else
|
|
{
|
|
TRACE_CRIT(L"%!FUNC! Got __Server value:%ws", *pszMachineName);
|
|
}
|
|
|
|
end:
|
|
|
|
spClassObj = NULL; // smart pointer
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
CfgUtilsGetNlbCompatibleNics(
|
|
OUT LPWSTR **ppszNics,
|
|
OUT UINT *pNumNics,
|
|
OUT UINT *pNumBoundToNlb // OPTIONAL
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_NO_ERROR;
|
|
BOOL fNetCfgInitialized = FALSE;
|
|
MyNetCfg NetCfg;
|
|
BOOL fBound = FALSE;
|
|
|
|
|
|
//
|
|
// Get and initialize interface to netcfg
|
|
//
|
|
Status = NetCfg.Initialize(FALSE); // TRUE == get write lock.
|
|
if (FAILED(Status))
|
|
{
|
|
goto end;
|
|
}
|
|
fNetCfgInitialized = TRUE;
|
|
|
|
//
|
|
//
|
|
//
|
|
Status = NetCfg.GetNlbCompatibleNics(
|
|
ppszNics,
|
|
pNumNics,
|
|
pNumBoundToNlb // OPTIONAL
|
|
);
|
|
|
|
end:
|
|
|
|
if (fNetCfgInitialized)
|
|
{
|
|
NetCfg.Deinitialize();
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
WBEMSTATUS
|
|
CfgUtilGetWmiAdapterObjFromAdapterConfigurationObj(
|
|
IN IWbemServicesPtr spWbemServiceIF, // smart pointer
|
|
IN IWbemClassObjectPtr spObj, // smart pointer
|
|
OUT IWbemClassObjectPtr &spAdapterObj // smart pointer, by reference
|
|
)
|
|
/*
|
|
We need to return the "Win32_NetworkAdapter" object associated with
|
|
the "Win32_NetworkAdapterConfiguration" object.
|
|
|
|
The key of Win32_NetworkAdapter is DeviceId.
|
|
The key of Win32_NetworkAdapterConfiguration is Index.
|
|
|
|
We use the "Win32_NetworkAdapterSetting" association class for this.
|
|
|
|
*/
|
|
{
|
|
#define ARRAYSIZE(_arr) (sizeof(_arr)/sizeof(_arr[0]))
|
|
WCHAR sz[ 256 ];
|
|
IEnumWbemClassObject * pConfigurations = NULL;
|
|
ULONG ulReturned = 0;
|
|
DWORD dwIndex = 0;
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
|
|
spAdapterObj = NULL; // smart pointer
|
|
|
|
Status = CfgUtilGetWmiDWORDParam(
|
|
spObj,
|
|
L"Index",
|
|
&dwIndex
|
|
);
|
|
if (FAILED(Status))
|
|
{
|
|
goto end;
|
|
}
|
|
|
|
StringCbPrintf(
|
|
sz,
|
|
sizeof( sz ),
|
|
L"Associators of {Win32_NetworkAdapterConfiguration.Index='%d'}"
|
|
L" where AssocClass=Win32_NetworkAdapterSetting",
|
|
dwIndex
|
|
);
|
|
|
|
Status = (WBEMSTATUS) spWbemServiceIF->ExecQuery(
|
|
_bstr_t(L"WQL"),
|
|
_bstr_t(sz) ,
|
|
WBEM_FLAG_FORWARD_ONLY,
|
|
NULL,
|
|
&pConfigurations
|
|
);
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
TRACE_CRIT("%!FUNC!: ExecQuery \"%ws\" failed with error 0x%08lx",
|
|
sz,
|
|
(UINT) Status
|
|
);
|
|
pConfigurations = NULL;
|
|
goto end;
|
|
}
|
|
|
|
Status = (WBEMSTATUS) pConfigurations->Next(
|
|
WBEM_INFINITE,
|
|
1,
|
|
&spAdapterObj,
|
|
&ulReturned
|
|
);
|
|
if ((Status != S_OK) || (ulReturned!=1))
|
|
{
|
|
TRACE_CRIT("%!FUNC!: No NetworkAdapter associated with NetworkAdapterCOnfiguration!");
|
|
ASSERT(spAdapterObj == NULL); // smart pointer.
|
|
goto end;
|
|
}
|
|
|
|
end:
|
|
|
|
if (pConfigurations!=NULL)
|
|
{
|
|
pConfigurations->Release();
|
|
pConfigurations = NULL;
|
|
}
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
//
|
|
// Gets the port rules, if any, from the specfied nlb params structure
|
|
//
|
|
WBEMSTATUS
|
|
CfgUtilGetPortRules(
|
|
IN const WLBS_REG_PARAMS *pConstParams,
|
|
OUT WLBS_PORT_RULE **ppRules, // Free using delete
|
|
OUT UINT *pNumRules
|
|
)
|
|
{
|
|
WBEMSTATUS Status;
|
|
|
|
WLBS_REG_PARAMS *pParams = (WLBS_REG_PARAMS *) pConstParams;
|
|
*ppRules = NULL;
|
|
*pNumRules = 0;
|
|
|
|
WLBS_PORT_RULE AllPortRules[WLBS_MAX_RULES];
|
|
DWORD NumRules = WLBS_MAX_RULES;
|
|
DWORD dwRes;
|
|
|
|
// Verify that the NLB API hooks are present
|
|
if (!g_CfgUtils.m_NLBApiHooksPresent)
|
|
{
|
|
dwRes = MyWlbsEnumPortRules (pParams, AllPortRules, &NumRules);
|
|
}
|
|
else
|
|
{
|
|
dwRes = g_CfgUtils.m_pfWlbsEnumPortRules (pParams, AllPortRules, &NumRules);
|
|
}
|
|
|
|
if (dwRes != WLBS_OK)
|
|
{
|
|
Status = WBEM_E_INVALID_PARAMETER;
|
|
goto end;
|
|
}
|
|
|
|
if (NumRules!=0)
|
|
{
|
|
*ppRules = new WLBS_PORT_RULE[NumRules];
|
|
if (*ppRules == NULL)
|
|
{
|
|
Status = WBEM_E_OUT_OF_MEMORY;
|
|
goto end;
|
|
}
|
|
CopyMemory(*ppRules, AllPortRules, sizeof(WLBS_PORT_RULE)*NumRules);
|
|
*pNumRules = NumRules;
|
|
}
|
|
Status = WBEM_NO_ERROR;
|
|
end:
|
|
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Sets the specified port rules in the specfied nlb params structure
|
|
//
|
|
WBEMSTATUS
|
|
CfgUtilSetPortRules(
|
|
IN WLBS_PORT_RULE *pRules,
|
|
IN UINT NumRules,
|
|
IN OUT WLBS_REG_PARAMS *pParams
|
|
)
|
|
{
|
|
WBEMSTATUS Status;
|
|
|
|
if (NumRules > WLBS_MAX_RULES)
|
|
{
|
|
Status = WBEM_E_INVALID_PARAMETER;
|
|
goto end;
|
|
}
|
|
|
|
// Verify that the NLB API hooks are present
|
|
if (!g_CfgUtils.m_NLBApiHooksPresent)
|
|
{
|
|
MyWlbsDeleteAllPortRules(pParams);
|
|
}
|
|
else
|
|
{
|
|
g_CfgUtils.m_pfWlbsDeleteAllPortRules(pParams);
|
|
}
|
|
|
|
for (UINT u = 0; u < NumRules; u++)
|
|
{
|
|
DWORD dwRes;
|
|
// Verify that the NLB API hooks are present
|
|
if (!g_CfgUtils.m_NLBApiHooksPresent)
|
|
{
|
|
dwRes = MyWlbsAddPortRule( pParams, pRules+u);
|
|
}
|
|
else
|
|
{
|
|
dwRes = g_CfgUtils.m_pfWlbsAddPortRule( pParams, pRules+u);
|
|
}
|
|
}
|
|
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
end:
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
CfgUtilsGetPortRuleString(
|
|
IN PWLBS_PORT_RULE pPr,
|
|
OUT LPWSTR pString // At least NLB_MAX_PORT_STRING_SIZE wchars
|
|
)
|
|
{
|
|
const UINT cchString = NLB_MAX_PORT_STRING_SIZE;
|
|
BOOL fRet = FALSE;
|
|
HRESULT hr;
|
|
|
|
LPCWSTR szProtocol = L"";
|
|
LPCWSTR szMode = L"";
|
|
LPCWSTR szAffinity = L"";
|
|
|
|
if (cchString == 0) goto end;
|
|
|
|
ZeroMemory(pString, cchString*sizeof(WCHAR));
|
|
|
|
switch(pPr->protocol)
|
|
{
|
|
case CVY_TCP:
|
|
szProtocol = L"TCP";
|
|
break;
|
|
case CVY_UDP:
|
|
szProtocol = L"UDP";
|
|
break;
|
|
case CVY_TCP_UDP:
|
|
szProtocol = L"BOTH";
|
|
break;
|
|
default:
|
|
goto end; // bad parse
|
|
}
|
|
|
|
switch(pPr->mode)
|
|
{
|
|
case CVY_SINGLE:
|
|
szMode = L"SINGLE";
|
|
break;
|
|
case CVY_MULTI:
|
|
szMode = L"MULTIPLE";
|
|
switch(pPr->mode_data.multi.affinity)
|
|
{
|
|
case CVY_AFFINITY_NONE:
|
|
szAffinity = L"NONE";
|
|
break;
|
|
case CVY_AFFINITY_SINGLE:
|
|
szAffinity = L"SINGLE";
|
|
break;
|
|
case CVY_AFFINITY_CLASSC:
|
|
szAffinity = L"CLASSC";
|
|
break;
|
|
default:
|
|
goto end; // bad parse
|
|
}
|
|
break;
|
|
case CVY_NEVER:
|
|
szMode = L"DISABLED";
|
|
break;
|
|
default:
|
|
goto end; // bad parse
|
|
}
|
|
|
|
*pString = 0;
|
|
hr = StringCchPrintf(
|
|
pString,
|
|
cchString,
|
|
L"ip=%ws protocol=%ws start=%u end=%u mode=%ws ",
|
|
pPr->virtual_ip_addr,
|
|
szProtocol,
|
|
pPr->start_port,
|
|
pPr->end_port,
|
|
szMode
|
|
);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
goto end; // not enough space.
|
|
}
|
|
|
|
UINT Len = wcslen(pString);
|
|
if (Len >= (cchString-1))
|
|
{
|
|
goto end; // not enough space to add anything else
|
|
}
|
|
|
|
if (pPr->mode == CVY_MULTI)
|
|
{
|
|
if (pPr->mode_data.multi.equal_load)
|
|
{
|
|
hr = StringCchPrintf(
|
|
pString+Len,
|
|
(cchString-Len),
|
|
L"affinity=%ws",
|
|
szAffinity
|
|
);
|
|
}
|
|
else
|
|
{
|
|
hr = StringCchPrintf(
|
|
pString+Len,
|
|
(cchString-Len),
|
|
L"affinity=%ws load=%u",
|
|
szAffinity,
|
|
pPr->mode_data.multi.load
|
|
);
|
|
}
|
|
}
|
|
else if (pPr->mode == CVY_SINGLE)
|
|
{
|
|
hr = StringCchPrintf(
|
|
pString+Len,
|
|
(cchString-Len),
|
|
L"priority=%u",
|
|
pPr->mode_data.single.priority
|
|
);
|
|
}
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
|
|
|
|
end:
|
|
|
|
return fRet;
|
|
}
|
|
|
|
BOOL
|
|
CfgUtilsSetPortRuleString(
|
|
IN LPCWSTR pString,
|
|
OUT PWLBS_PORT_RULE pPr
|
|
)
|
|
{
|
|
//
|
|
// Look for following name=value pairs
|
|
//
|
|
// ip=1.1.1.1
|
|
// protocol=[TCP|UDP|BOTH]
|
|
// start=122
|
|
// end=122
|
|
// mode=[SINGLE|MULTIPLE|DISABLED]
|
|
// affinity=[NONE|SINGLE|CLASSC]
|
|
// load=80
|
|
// priority=1"
|
|
//
|
|
|
|
#define INVALID_VALUE ((DWORD)-1)
|
|
LPWSTR psz = NULL;
|
|
WCHAR szCleanedString[2*NLB_MAX_PORT_STRING_SIZE];
|
|
WCHAR c;
|
|
BOOL fRet = FALSE;
|
|
DWORD protocol= INVALID_VALUE;
|
|
DWORD start_port= INVALID_VALUE;
|
|
DWORD end_port= INVALID_VALUE;
|
|
DWORD mode= INVALID_VALUE;
|
|
DWORD affinity= INVALID_VALUE;
|
|
DWORD load= INVALID_VALUE;
|
|
DWORD priority= INVALID_VALUE;
|
|
|
|
ZeroMemory(pPr, sizeof(*pPr));
|
|
|
|
//
|
|
// Set szCleanedString to be a version of pString in "canonical" form:
|
|
// extraneous whitespace stripped out and whitspace represented by a
|
|
// single '\b' character.
|
|
{
|
|
UINT Len = wcslen(pString);
|
|
if (Len > (sizeof(szCleanedString)/sizeof(WCHAR)))
|
|
{
|
|
goto end;
|
|
}
|
|
ARRAYSTRCPY(szCleanedString, pString);
|
|
|
|
//
|
|
// convert different forms of whitespace into blanks
|
|
//
|
|
for (psz=szCleanedString; (c=*psz)!=0; psz++)
|
|
{
|
|
if (c == ' ' || c == '\t' || c == '\n')
|
|
{
|
|
*psz = ' ';
|
|
}
|
|
}
|
|
|
|
//
|
|
// convert runs of whitespace into a single blank
|
|
// also get rid of initial whitespace
|
|
//
|
|
LPWSTR psz1 = szCleanedString;
|
|
BOOL fRun = TRUE; // initial value of TRUE gets rid of initial space
|
|
for (psz=szCleanedString; (c=*psz)!=0; psz++)
|
|
{
|
|
if (c == ' ')
|
|
{
|
|
if (fRun)
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
fRun = TRUE;
|
|
}
|
|
}
|
|
else if (c == '=')
|
|
{
|
|
if (fRun)
|
|
{
|
|
//
|
|
// The '=' was preceed by whitespace -- delete that
|
|
// whitespace. We keep fRun TRUE so subsequent whitespace
|
|
// is eliminated.
|
|
//
|
|
if (psz1 == szCleanedString)
|
|
{
|
|
// we're just starting, and we get an '=' -- bad
|
|
goto end;
|
|
}
|
|
psz1--;
|
|
if (*psz1 != ' ')
|
|
{
|
|
ASSERT(*psz1 == '=');
|
|
goto end; // two equals in a row, not accepted!
|
|
}
|
|
}
|
|
}
|
|
else // non blank and non '=' chracter
|
|
{
|
|
fRun = FALSE;
|
|
}
|
|
*psz1++ = c;
|
|
}
|
|
*psz1=0;
|
|
}
|
|
|
|
// wprintf(L"CLEANED: \"%ws\"\n", szCleanedString);
|
|
|
|
//
|
|
// Now actually do the parse.
|
|
//
|
|
psz = szCleanedString;
|
|
while(*psz!=0)
|
|
{
|
|
WCHAR Name[32];
|
|
WCHAR Value[32];
|
|
|
|
//
|
|
// Look for the Name in Name=Value pair.
|
|
//
|
|
if (swscanf(psz, L"%16[a-zA-Z]=%16[0-9.a-zA-Z]", Name, Value) != 2)
|
|
{
|
|
// bad parse;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Skip past the name=value pair -- it contains no blanks
|
|
//
|
|
for (; (c=*psz)!=NULL; psz++)
|
|
{
|
|
if (c==' ')
|
|
{
|
|
psz++; // to skip past the blank
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Now look for the specific name/values
|
|
//
|
|
// ip=1.1.1.1
|
|
// protocol=[TCP|UDP|BOTH]
|
|
// start=122
|
|
// end=122
|
|
// mode=[SINGLE|MULTIPLE|DISABLED]
|
|
// affinity=[NONE|SINGLE|CLASSC]
|
|
// load=80
|
|
// priority=1"
|
|
//
|
|
if (!_wcsicmp(Name, L"ip"))
|
|
{
|
|
if (swscanf(Value, L"%15[0-9.]", pPr->virtual_ip_addr) != 1)
|
|
{
|
|
goto end;
|
|
}
|
|
}
|
|
else if (!_wcsicmp(Name, L"protocol"))
|
|
{
|
|
if (!_wcsicmp(Value, L"TCP"))
|
|
{
|
|
protocol = CVY_TCP;
|
|
}
|
|
else if (!_wcsicmp(Value, L"UDP"))
|
|
{
|
|
protocol = CVY_UDP;
|
|
}
|
|
else if (!_wcsicmp(Value, L"BOTH"))
|
|
{
|
|
protocol = CVY_TCP_UDP;
|
|
}
|
|
else
|
|
{
|
|
// bad parse;
|
|
goto end;
|
|
}
|
|
}
|
|
else if (!_wcsicmp(Name, L"protocol"))
|
|
{
|
|
}
|
|
else if (!_wcsicmp(Name, L"start"))
|
|
{
|
|
if (swscanf(Value, L"%u", &start_port)!=1)
|
|
{
|
|
// bad parse;
|
|
goto end;
|
|
}
|
|
if (start_port > 65535)
|
|
{
|
|
// bad parse;
|
|
goto end;
|
|
}
|
|
}
|
|
else if (!_wcsicmp(Name, L"end"))
|
|
{
|
|
if (swscanf(Value, L"%u", &end_port)!=1)
|
|
{
|
|
// bad parse;
|
|
goto end;
|
|
}
|
|
if (end_port > 65535)
|
|
{
|
|
// bad parse;
|
|
goto end;
|
|
}
|
|
}
|
|
else if (!_wcsicmp(Name, L"mode"))
|
|
{
|
|
if (!_wcsicmp(Value, L"SINGLE"))
|
|
{
|
|
mode = CVY_SINGLE;
|
|
}
|
|
else if (!_wcsicmp(Value, L"MULTIPLE"))
|
|
{
|
|
mode = CVY_MULTI;
|
|
}
|
|
else if (!_wcsicmp(Value, L"DISABLED"))
|
|
{
|
|
mode = CVY_NEVER;
|
|
}
|
|
else
|
|
{
|
|
// bad parse;
|
|
goto end;
|
|
}
|
|
}
|
|
else if (!_wcsicmp(Name, L"affinity"))
|
|
{
|
|
if (!_wcsicmp(Value, L"NONE"))
|
|
{
|
|
affinity = CVY_AFFINITY_NONE;
|
|
}
|
|
else if (!_wcsicmp(Value, L"SINGLE"))
|
|
{
|
|
affinity = CVY_AFFINITY_SINGLE;
|
|
}
|
|
else if (!_wcsicmp(Value, L"CLASSC"))
|
|
{
|
|
affinity = CVY_AFFINITY_CLASSC;
|
|
}
|
|
else
|
|
{
|
|
// bad parse;
|
|
goto end;
|
|
}
|
|
}
|
|
else if (!_wcsicmp(Name, L"load"))
|
|
{
|
|
if (swscanf(Value, L"%u", &load)!=1)
|
|
{
|
|
if (load > 100)
|
|
{
|
|
// bad parse;
|
|
goto end;
|
|
}
|
|
}
|
|
}
|
|
else if (!_wcsicmp(Name, L"priority"))
|
|
{
|
|
if (swscanf(Value, L"%u", &priority)!=1)
|
|
{
|
|
if (priority > 31)
|
|
{
|
|
// bad parse;
|
|
goto end;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// bad parse
|
|
goto end;
|
|
}
|
|
// printf("SUCCESSFUL PARSE: %ws = %ws\n", Name, Value);
|
|
}
|
|
|
|
|
|
//
|
|
// Set up the PARAMS structure, doing extra parameter validation along the
|
|
// way.
|
|
//
|
|
switch(mode)
|
|
{
|
|
case CVY_SINGLE:
|
|
|
|
if (load != INVALID_VALUE || affinity != INVALID_VALUE)
|
|
{
|
|
goto end; // bad parse;
|
|
}
|
|
if ((priority < CVY_MIN_PRIORITY) || (priority > CVY_MAX_PRIORITY))
|
|
{
|
|
goto end; // bad parse
|
|
}
|
|
pPr->mode_data.single.priority = priority;
|
|
break;
|
|
|
|
case CVY_MULTI:
|
|
|
|
if (priority != INVALID_VALUE)
|
|
{
|
|
goto end; // bad parse;
|
|
}
|
|
|
|
switch(affinity)
|
|
{
|
|
case CVY_AFFINITY_NONE:
|
|
break;
|
|
case CVY_AFFINITY_SINGLE:
|
|
break;
|
|
case CVY_AFFINITY_CLASSC:
|
|
break;
|
|
case INVALID_VALUE:
|
|
default:
|
|
goto end; // bad parse;
|
|
}
|
|
|
|
pPr->mode_data.multi.affinity = affinity;
|
|
|
|
if (load == INVALID_VALUE)
|
|
{
|
|
// this means it's unassigned, which means equal.
|
|
pPr->mode_data.multi.equal_load = 1;
|
|
}
|
|
else if (load > CVY_MAX_LOAD)
|
|
{
|
|
goto end; // bad parse
|
|
}
|
|
else
|
|
{
|
|
pPr->mode_data.multi.load = load;
|
|
}
|
|
break;
|
|
|
|
case CVY_NEVER:
|
|
|
|
if (load != INVALID_VALUE || affinity != INVALID_VALUE
|
|
|| priority != INVALID_VALUE)
|
|
{
|
|
goto end; // bad parse;
|
|
}
|
|
break;
|
|
|
|
case INVALID_VALUE:
|
|
default:
|
|
goto end; // bad parse;
|
|
|
|
}
|
|
|
|
pPr->mode = mode;
|
|
pPr->end_port = end_port;
|
|
pPr->start_port = start_port;
|
|
pPr->protocol = protocol;
|
|
|
|
|
|
fRet = TRUE;
|
|
|
|
end:
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
//
|
|
// Attempts to resolve the ip address and ping the host.
|
|
//
|
|
WBEMSTATUS
|
|
CfgUtilPing(
|
|
LPCWSTR szBindString,
|
|
UINT Timeout, // In milliseconds.
|
|
OUT ULONG *pResolvedIpAddress // in network byte order.
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_INVALID_PARAMETER;
|
|
UINT w32Status = ERROR_SUCCESS;
|
|
LONG inaddr;
|
|
char rgchBindString[1024];
|
|
TRACE_INFO("->%!FUNC!(BindString=%ws)", szBindString);
|
|
|
|
*pResolvedIpAddress = 0;
|
|
|
|
//
|
|
// Convert to ANSI.
|
|
//
|
|
{
|
|
UINT u = wcslen(szBindString);
|
|
if (u >= (sizeof(rgchBindString)/sizeof(rgchBindString[0])))
|
|
{
|
|
Status = WBEM_E_INVALID_PARAMETER;
|
|
goto end;
|
|
}
|
|
do
|
|
{
|
|
rgchBindString[u] = (char) szBindString[u];
|
|
|
|
} while (u--);
|
|
}
|
|
|
|
//
|
|
// Resolve to an IP address...
|
|
//
|
|
inaddr = inet_addr(rgchBindString);
|
|
if (inaddr == -1L)
|
|
{
|
|
struct hostent *hostp = NULL;
|
|
hostp = gethostbyname(rgchBindString);
|
|
if (hostp) {
|
|
unsigned char *pc = (unsigned char *) & inaddr;
|
|
// If we find a host entry, set up the internet address
|
|
inaddr = *(long *)hostp->h_addr;
|
|
TRACE_VERB(
|
|
L"%!FUNC! Resolved %ws to IP address %d.%d.%d.%d.\n",
|
|
szBindString,
|
|
pc[0],
|
|
pc[1],
|
|
pc[2],
|
|
pc[3]
|
|
);
|
|
} else {
|
|
// Neither dotted, not name.
|
|
w32Status = WSAGetLastError();
|
|
TRACE_CRIT(L"%!FUNC! WSA error 0x%08lx resolving address %ws.",
|
|
w32Status, szBindString);
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
*pResolvedIpAddress = (ULONG) inaddr;
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
if (g_CfgUtils.DisablePing())
|
|
{
|
|
TRACE_INFO(L"%!FUNC!: ICMP ping disabled, so not actually pinging.");
|
|
Status = WBEM_NO_ERROR;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Send Icmp echo.
|
|
//
|
|
HANDLE IcmpHandle;
|
|
|
|
IcmpHandle = IcmpCreateFile();
|
|
if (IcmpHandle == INVALID_HANDLE_VALUE) {
|
|
w32Status = GetLastError();
|
|
TRACE_CRIT(L"%!FUNC! Unable to contact IP driver, error code %d.",w32Status);
|
|
goto end;
|
|
}
|
|
|
|
const int MinInterval = 500;
|
|
|
|
while (Timeout)
|
|
{
|
|
static BYTE SendBuffer[32];
|
|
BYTE RcvBuffer[1024];
|
|
int numberOfReplies;
|
|
numberOfReplies = IcmpSendEcho2(IcmpHandle,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
inaddr,
|
|
SendBuffer,
|
|
sizeof(SendBuffer),
|
|
NULL,
|
|
RcvBuffer,
|
|
sizeof(RcvBuffer),
|
|
MinInterval
|
|
);
|
|
|
|
if (numberOfReplies == 0) {
|
|
|
|
int errorCode = GetLastError();
|
|
TRACE_INFO(L"%!FUNC! Got no replies yet; ICMP Error %d", errorCode);
|
|
|
|
|
|
if (Timeout > MinInterval)
|
|
{
|
|
Timeout -= MinInterval;
|
|
// TODO: look at ping sources for proper error reporting
|
|
// (host unreachable, etc...)
|
|
|
|
Sleep(MinInterval);
|
|
}
|
|
else
|
|
{
|
|
Timeout = 0;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
Status = WBEM_NO_ERROR;
|
|
break;
|
|
}
|
|
}
|
|
|
|
end:
|
|
|
|
TRACE_INFO("<-%!FUNC! returns 0x%08lx", Status);
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Validates a network address
|
|
//
|
|
WBEMSTATUS
|
|
CfgUtilsValidateNetworkAddress(
|
|
IN LPCWSTR szAddress, // format: "10.0.0.1[/255.0.0.0]"
|
|
OUT PUINT puIpAddress, // in network byte order
|
|
OUT PUINT puSubnetMask, // in network byte order (0 if unspecified)
|
|
OUT PUINT puDefaultSubnetMask // depends on class: 'a', 'b', 'c', 'd', 'e'
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_INVALID_PARAMETER;
|
|
UINT w32Status = ERROR_SUCCESS;
|
|
UINT uIpAddress=0;
|
|
UINT uSubnetMask=0;
|
|
UINT uDefaultSubnetMask=0;
|
|
char rgchBindString[32];
|
|
char *szIpAddress = rgchBindString;
|
|
char *szSubnetMask = NULL;
|
|
|
|
//
|
|
// Take care of the fact that the following two args could be NULL
|
|
//
|
|
if (puSubnetMask == NULL)
|
|
{
|
|
puSubnetMask = &uSubnetMask;
|
|
}
|
|
if (puDefaultSubnetMask == NULL)
|
|
{
|
|
puDefaultSubnetMask = &uDefaultSubnetMask;
|
|
}
|
|
|
|
*puIpAddress = 0;
|
|
*puSubnetMask = 0;
|
|
*puDefaultSubnetMask = 0;
|
|
|
|
//
|
|
// Convert to ANSI.
|
|
//
|
|
{
|
|
UINT u = wcslen(szAddress);
|
|
if (u >= (sizeof(rgchBindString)/sizeof(rgchBindString[0])))
|
|
{
|
|
goto end;
|
|
}
|
|
|
|
do
|
|
{
|
|
char c = (char) szAddress[u];
|
|
|
|
//
|
|
// NOTE: We're counting down. Last time through, c is 0.
|
|
//
|
|
|
|
//
|
|
// We split up the network address into the ip address portion
|
|
// and the subnet portion.
|
|
//
|
|
if (c == '/')
|
|
{
|
|
if (szSubnetMask != NULL)
|
|
{
|
|
// multiple '/'s -- not good!
|
|
goto end;
|
|
}
|
|
|
|
szSubnetMask = &rgchBindString[u+1];
|
|
c = 0;
|
|
}
|
|
|
|
rgchBindString[u] = c;
|
|
|
|
} while (u--);
|
|
}
|
|
|
|
//
|
|
// Get the UINT version of ip address and subnet.
|
|
//
|
|
uIpAddress = inet_addr(szIpAddress);
|
|
if (szSubnetMask == NULL)
|
|
{
|
|
szSubnetMask = "";
|
|
}
|
|
uSubnetMask = inet_addr(szSubnetMask);
|
|
|
|
|
|
//
|
|
// Parameter validation...
|
|
//
|
|
{
|
|
if (uIpAddress==0 || uIpAddress == INADDR_NONE)
|
|
{
|
|
// ip address null, or invalid
|
|
goto end;
|
|
}
|
|
|
|
if (*szSubnetMask != 0 && uSubnetMask == INADDR_NONE)
|
|
{
|
|
// ip subnet specified, but invalid
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Classify IP address 'a', 'b', 'c', 'd'
|
|
//
|
|
{
|
|
//
|
|
// Get msb byte in network byte order
|
|
//
|
|
unsigned char uc = (unsigned char) (uIpAddress & 0xff);
|
|
if ((uc & 0x80) == 0)
|
|
{
|
|
// class A
|
|
uDefaultSubnetMask = 0x000000ff; // network order
|
|
}
|
|
else if (( uc & 0x40) == 0)
|
|
{
|
|
// class B
|
|
uDefaultSubnetMask = 0x0000ffff; // network order
|
|
}
|
|
else if (( uc & 0x20) == 0)
|
|
{
|
|
// class C
|
|
uDefaultSubnetMask = 0x00ffffff; // network order
|
|
}
|
|
else
|
|
{
|
|
// class D or E
|
|
uDefaultSubnetMask = 0;
|
|
}
|
|
}
|
|
}
|
|
*puIpAddress = uIpAddress;
|
|
*puSubnetMask = uSubnetMask;
|
|
*puDefaultSubnetMask = uDefaultSubnetMask;
|
|
|
|
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
end:
|
|
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
This function enables the "SeLoadDriverPrivilege" privilege (required to load/unload device driver)
|
|
in the access token.
|
|
|
|
What is the need for this function?
|
|
The setup/pnp apis called by the nlb manager's wmi provider to bind/unbind NLB to the nic, require that the
|
|
"SeLoadDriverPrivilege" privilege be present AND enabled in the access token of the thread.
|
|
|
|
Why is this funcion placed here (in the client) instead of the provider?
|
|
RPC not merely disables, but removes all privileges that are NOT enabled in the client and only passes along
|
|
to the server (ie. provider), those privileges that are enabled. Since "SeLoadDriverPrivilege" is not enabled
|
|
by default, RPC would not pass this privilege along to the provider. So, if this function was placed in the
|
|
provider, it would fail because the privilege is NOT present to be enabled.
|
|
|
|
This privilege needs to be enabled only when the server is located in the same machine as the client. When, the
|
|
server is remote, it was observed that the "SeLoadDriverPrivilege" privilege is enabled by default.
|
|
|
|
NOTE: When called by a non-admin, this function will fail because this privilege is not assigned to non-admins
|
|
and hence, can not be enabled.
|
|
--KarthicN, 5/7/02
|
|
*/
|
|
|
|
BOOL CfgUtils_Enable_Load_Unload_Driver_Privilege(VOID)
|
|
{
|
|
HANDLE TokenHandle;
|
|
TOKEN_PRIVILEGES TP;
|
|
LUID Luid;
|
|
DWORD dwError;
|
|
|
|
TRACE_INFO("->%!FUNC!");
|
|
|
|
// Look up the LUID for "SeLoadDriverPrivilege"
|
|
if (!LookupPrivilegeValue(NULL, // lookup privilege on local system
|
|
SE_LOAD_DRIVER_NAME, // "SeLoadDriverPrivilege" : Load and unload device drivers
|
|
&Luid)) // receives LUID of privilege
|
|
{
|
|
TRACE_CRIT("%!FUNC! LookupPrivilegeValue() failed with error = %u", GetLastError() );
|
|
TRACE_INFO("<-%!FUNC! Returning FALSE");
|
|
return FALSE;
|
|
}
|
|
|
|
// Get a handle to the process access token.
|
|
if (!OpenProcessToken(GetCurrentProcess(),
|
|
TOKEN_ADJUST_PRIVILEGES,
|
|
&TokenHandle))
|
|
{
|
|
TRACE_CRIT("%!FUNC! OpenProcessToken() for TOKEN_ADJUST_PRIVILEGES failed with error = %u", GetLastError());
|
|
TRACE_INFO("<-%!FUNC! Returning FALSE");
|
|
return FALSE;
|
|
}
|
|
|
|
TP.PrivilegeCount = 1;
|
|
TP.Privileges[0].Luid = Luid;
|
|
TP.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
|
|
// Enable the "SeLoadDriverPrivilege" privilege.
|
|
AdjustTokenPrivileges(TokenHandle,
|
|
FALSE,
|
|
&TP,
|
|
sizeof(TOKEN_PRIVILEGES),
|
|
NULL,
|
|
NULL);
|
|
|
|
// Call GetLastError to determine whether the function succeeded.
|
|
dwError = GetLastError();
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
TRACE_CRIT("%!FUNC! AdjustTokenPrivileges() failed with error = %u", dwError );
|
|
CloseHandle(TokenHandle);
|
|
TRACE_INFO("<-%!FUNC! Returning FALSE");
|
|
return FALSE;
|
|
}
|
|
|
|
CloseHandle(TokenHandle);
|
|
|
|
TRACE_INFO("<-%!FUNC! Returning TRUE");
|
|
return TRUE;
|
|
}
|
|
|
|
USHORT crc16(LPCWSTR ptr)
|
|
{
|
|
int crc = 0; // Holds CRC
|
|
int i; //
|
|
int count; // holds len
|
|
|
|
count = wcslen(ptr);
|
|
while(--count >= 0) {
|
|
i = *ptr;
|
|
// make all uppercase // ((case insens))
|
|
i = ((i >= 'a') && (i <= 'z')) ? (i-32) : i;
|
|
crc = crc ^ (i << 8);
|
|
ptr++;
|
|
for (i=0; i<8; ++i)
|
|
if (crc & 0x8000)
|
|
crc = (crc << 1) ^ 0x1021;
|
|
else
|
|
crc = crc << 1;
|
|
}
|
|
return (crc & 0xffff);
|
|
}
|
|
|
|
WBEMSTATUS
|
|
get_friendly_name_from_registry(
|
|
LPCWSTR szGuid,
|
|
LPWSTR *pszFriendlyName
|
|
)
|
|
{
|
|
WBEMSTATUS wStat = WBEM_E_NOT_FOUND;
|
|
HKEY hkNetwork = NULL;
|
|
WCHAR adapter[200];
|
|
int ret;
|
|
wchar_t data[200];
|
|
|
|
*pszFriendlyName = NULL;
|
|
|
|
ret = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
L"SYSTEM\\CurrentControlSet\\Control\\Network",
|
|
0,
|
|
KEY_READ,
|
|
&hkNetwork
|
|
);
|
|
|
|
if (ret != ERROR_SUCCESS)
|
|
{
|
|
TRACE_CRIT("%!FUNC! RegOpenKeyEx(Network) fails with err %lu", ret);
|
|
hkNetwork = NULL;
|
|
goto end;
|
|
}
|
|
|
|
*adapter=0;
|
|
|
|
#if OBSOLETE
|
|
for (int num=0; 1; num++)
|
|
{
|
|
HKEY hk=NULL;
|
|
FILETIME time;
|
|
|
|
*adapter=0;
|
|
|
|
DWORD dwDataBuffer=200;
|
|
ret=RegEnumKeyEx(
|
|
hkNetwork,
|
|
num,
|
|
adapter,
|
|
&dwDataBuffer,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&time);
|
|
if ((ret!=ERROR_SUCCESS) && (ret!=ERROR_MORE_DATA))
|
|
{
|
|
if (ret != ERROR_NO_MORE_ITEMS)
|
|
{
|
|
TRACE_CRIT("%!FUNC! RegEnumKey(Network) returns error %lu", ret);
|
|
wStat = WBEM_E_CRITICAL_ERROR;
|
|
}
|
|
else
|
|
{
|
|
wStat = WBEM_E_NOT_FOUND;
|
|
}
|
|
break;
|
|
}
|
|
|
|
//
|
|
// open the items one by one
|
|
//
|
|
ret=RegOpenKeyEx(hkNetwork, adapter, 0, KEY_READ, &hk);
|
|
if (ret == ERROR_SUCCESS)
|
|
{
|
|
DWORD dwValueType=REG_SZ;
|
|
dwDataBuffer=200;
|
|
|
|
*data = 0;
|
|
|
|
ret = RegQueryValueEx(
|
|
hk,
|
|
L"",
|
|
0,
|
|
&dwValueType,
|
|
(LPBYTE)data,
|
|
&dwDataBuffer
|
|
);
|
|
|
|
RegCloseKey(hk);
|
|
|
|
if (ret == ERROR_SUCCESS)
|
|
{
|
|
if (_wcsicmp(L"Network Adapters", data)==0)
|
|
{
|
|
//
|
|
// Found it!
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif // OBSOLETE
|
|
ARRAYSTRCPY(adapter, L"{4D36E972-E325-11CE-BFC1-08002BE10318}");
|
|
|
|
|
|
if (*adapter!=0)
|
|
{
|
|
HKEY hk = NULL;
|
|
wchar_t path[200];
|
|
//
|
|
// found the guid now
|
|
// look for friendly nic name
|
|
//
|
|
|
|
StringCbPrintf(path, sizeof(path), L"%ws\\%ws\\Connection", adapter, szGuid);
|
|
ret=RegOpenKeyEx(hkNetwork, path, 0, KEY_READ, &hk);
|
|
if (ret != ERROR_SUCCESS)
|
|
{
|
|
TRACE_CRIT("%!FUNC! Error %lu trying to open path %ws", ret, path);
|
|
}
|
|
else
|
|
{
|
|
DWORD dwDataBuffer=200;
|
|
DWORD dwValueType=REG_SZ;
|
|
|
|
*data = 0;
|
|
|
|
ret = RegQueryValueEx(
|
|
hk,
|
|
L"Name",
|
|
0,
|
|
&dwValueType,
|
|
(LPBYTE)data,
|
|
&dwDataBuffer
|
|
);
|
|
|
|
RegCloseKey(hk);
|
|
|
|
if(ret != ERROR_SUCCESS)
|
|
{
|
|
TRACE_CRIT("%!FUNC! Error %lu trying to query Name value on path %ws", ret, path);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We're done!
|
|
//
|
|
TRACE_CRIT("%!FUNC! Found friendly name: \"%ws\"", data);
|
|
LPWSTR szName = new WCHAR[(dwDataBuffer+1)/sizeof(WCHAR)];
|
|
if (szName == NULL)
|
|
{
|
|
TRACE_CRIT("%!FUNC! Allocation failure!");
|
|
wStat = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
// note -- dwDataBuffer includes space for ending null.
|
|
CopyMemory(szName, data, dwDataBuffer);
|
|
*pszFriendlyName = szName;
|
|
wStat = WBEM_NO_ERROR;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
end:
|
|
|
|
if (hkNetwork!=NULL)
|
|
{
|
|
RegCloseKey(hkNetwork);
|
|
}
|
|
|
|
return wStat;
|
|
}
|
|
|
|
#define STATUS_SUCCESS 0
|
|
|
|
BOOL
|
|
CfgUtilEncryptPassword(
|
|
IN LPCWSTR szPassword,
|
|
OUT UINT cchEncPwd, // size in chars of szEncPwd, inc space for ending 0
|
|
OUT LPWSTR szEncPwd
|
|
)
|
|
{
|
|
//
|
|
// Note -- buffer passed to RtlEncrypt/DecryptMemory must be
|
|
// multiples of RTL_ENCRYPT_MEMORY_SIZE -- so we must round them up
|
|
// appropriately.
|
|
//
|
|
|
|
BOOL fRet = FALSE;
|
|
UINT uLen = wcslen(szPassword);
|
|
UINT uEncryptCb = (uLen+1)*sizeof(WCHAR);
|
|
WCHAR rgPasswordCopy[64];
|
|
|
|
// Round up if required...
|
|
{
|
|
UINT mod = uEncryptCb % RTL_ENCRYPT_MEMORY_SIZE;
|
|
if (mod != 0)
|
|
{
|
|
uEncryptCb += (RTL_ENCRYPT_MEMORY_SIZE - mod);
|
|
};
|
|
}
|
|
|
|
ASSERT((uEncryptCb % RTL_ENCRYPT_MEMORY_SIZE)==0);
|
|
|
|
if (uEncryptCb > sizeof(rgPasswordCopy))
|
|
{
|
|
//
|
|
// szPassword is too large for our internal buffer ... bail
|
|
//
|
|
fRet = FALSE;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// We're going to expand the encrypted password to make it
|
|
// printable -- so we require 2 chars for every byte
|
|
// of encrypted data. Also need the space for ending NULL char.
|
|
// Check if we have enough space...
|
|
//
|
|
if (2*uEncryptCb >= cchEncPwd)
|
|
{
|
|
// Nah, bail...
|
|
fRet = FALSE;
|
|
goto end;
|
|
}
|
|
|
|
RtlSecureZeroMemory(rgPasswordCopy, sizeof(rgPasswordCopy));
|
|
ARRAYSTRCPY(rgPasswordCopy, szPassword);
|
|
|
|
NTSTATUS ntStat;
|
|
ntStat = RtlEncryptMemory (rgPasswordCopy, uEncryptCb, 0);
|
|
if (ntStat != STATUS_SUCCESS)
|
|
{
|
|
TRACE_CRIT(L"%!FUNC! RtlEncryptMemory fails with ntStat 0x%lx", ntStat);
|
|
fRet = FALSE;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Now we expand the encrypted password
|
|
//
|
|
{
|
|
UINT u;
|
|
for (u=0;u<uEncryptCb;u++)
|
|
{
|
|
//
|
|
// In this loop, we treat rgPasswordCopy of a BYTE array of
|
|
// length uEncryptCb...
|
|
//
|
|
BYTE b = ((BYTE*)rgPasswordCopy)[u];
|
|
szEncPwd[2*u] = 'a' + ((b & 0xf0) >> 4);
|
|
szEncPwd[2*u+1] = 'a' + (b & 0xf);
|
|
}
|
|
ASSERT(2*u < cchEncPwd); // We already check this earlier...
|
|
szEncPwd[2*u]=0;
|
|
}
|
|
|
|
fRet = TRUE;
|
|
|
|
end:
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CfgUtilDecryptPassword(
|
|
IN LPCWSTR szEncPwd,
|
|
OUT UINT cchPwd, // size in chars of szPwd, inc space for ending 0
|
|
OUT LPWSTR szPwd
|
|
)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
UINT uEncLen = wcslen(szEncPwd);
|
|
UINT cbEncPwd = uEncLen/2; // Length, in bytes, of binary form of enc pwd.
|
|
|
|
if (uEncLen == 0 || cchPwd == 0)
|
|
{
|
|
//
|
|
// Encrypted pwd and cchPwd must be non-zero,
|
|
//
|
|
fRet = FALSE;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// uEncLen is twice the number of BYTES in the binary form of the
|
|
// encrypted password, and the latter number sould be a multiple
|
|
// of RTL_ENCRYPT_MEMORY_SIZE. Let's check this.
|
|
//
|
|
if (uEncLen % (RTL_ENCRYPT_MEMORY_SIZE*2)!=0)
|
|
{
|
|
// It's not, so we bail.
|
|
fRet = FALSE;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Make sure there is enough space in szPwd to store the
|
|
// binary form of the encrypted password (and the final form of
|
|
// the decrypted password, which will include the ending NULL).
|
|
//
|
|
if (cbEncPwd > cchPwd*sizeof(WCHAR))
|
|
{
|
|
// bail
|
|
fRet = FALSE;
|
|
goto end;
|
|
}
|
|
|
|
RtlSecureZeroMemory(szPwd, cchPwd*sizeof(WCHAR));
|
|
//
|
|
// Now let's translate the printable version of the encrypted password
|
|
// to the binary version...
|
|
//
|
|
{
|
|
UINT u;
|
|
for (u=0; u<cbEncPwd; u++)
|
|
{
|
|
BYTE b;
|
|
b = (BYTE) (szEncPwd[2*u] - 'a');
|
|
b <<= 4;
|
|
b |= (BYTE) (szEncPwd[2*u+1] - 'a');
|
|
|
|
((BYTE*)szPwd)[u] = b;
|
|
}
|
|
ASSERT(u<2*cchPwd);
|
|
}
|
|
|
|
|
|
NTSTATUS ntStat;
|
|
ntStat = RtlDecryptMemory (szPwd, cbEncPwd, 0);
|
|
if (ntStat != STATUS_SUCCESS)
|
|
{
|
|
TRACE_CRIT(L"%!FUNC! RtlEncryptMemory fails with ntStat 0x%lx", ntStat);
|
|
fRet = FALSE;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// At this point, the decrypted pwd MUST be null terminated, or we
|
|
// have some error. Note also that we have pre-zeroed out szPwd on entry,
|
|
// and checked that cchPwd is non zero.
|
|
//
|
|
if (szPwd[cchPwd-1] != 0)
|
|
{
|
|
// bad decryption...
|
|
fRet = FALSE;
|
|
}
|
|
|
|
fRet = TRUE;
|
|
|
|
|
|
end:
|
|
return fRet;
|
|
}
|
|
|
|
//
|
|
// Sets pfMSCSInstalled to TRUE if MSCS is installed, FALSE otherwise.
|
|
// Returns TRUE on success, FALSE otherwise.
|
|
//
|
|
BOOL
|
|
CfgUtilIsMSCSInstalled(VOID)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
typedef DWORD (CALLBACK* LPFNGNCS)(LPCWSTR,DWORD*);
|
|
LPFNGNCS pfnGetNodeClusterState = NULL;
|
|
HINSTANCE hDll = NULL;
|
|
DWORD dwClusterState = 0;
|
|
|
|
hDll = LoadLibrary(L"clusapi.dll");
|
|
if (NULL == hDll)
|
|
{
|
|
TRACE_CRIT("%!FUNC! Load clusapi.dll failed with %d", GetLastError());
|
|
goto end;
|
|
}
|
|
|
|
pfnGetNodeClusterState = (LPFNGNCS) GetProcAddress(
|
|
hDll,
|
|
"GetNodeClusterState"
|
|
);
|
|
|
|
if (NULL == pfnGetNodeClusterState)
|
|
{
|
|
TRACE_CRIT("%!FUNC! GetProcAddress(GetNodeClusterState) failed with error %d", GetLastError());
|
|
goto end;
|
|
}
|
|
|
|
if (ERROR_SUCCESS == pfnGetNodeClusterState(NULL, &dwClusterState))
|
|
{
|
|
if ( ClusterStateNotRunning == dwClusterState
|
|
|| ClusterStateRunning == dwClusterState)
|
|
{
|
|
fRet = TRUE;
|
|
TRACE_INFO("%!FUNC! MSCS IS installed.");
|
|
}
|
|
else
|
|
{
|
|
// MSCS is not installed. That's good!
|
|
TRACE_INFO("%!FUNC! MSCS Cluster state = %lu (assumed not installed)",
|
|
dwClusterState);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRACE_CRIT("%!FUNC! error getting MSCS cluster state.");
|
|
}
|
|
|
|
(void) FreeLibrary(hDll);
|
|
|
|
end:
|
|
|
|
return fRet;
|
|
}
|