Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2267 lines
71 KiB

/******************************************************************
Copyright (c) 1999 Microsoft Corporation
NlbsNic.CPP -- WMI provider class implementation
Generated by Microsoft WMI Code Generation Engine
TO DO: - See individual function headers
- When linking, make sure you link to framedyd.lib &
msvcrtd.lib (debug) or framedyn.lib & msvcrt.lib (retail).
Description:
******************************************************************/
// History:
// --------
//
// Revised by : mhakim
// Date : 02-12-01
// Reason : Added password support.
//
// Revised by : mhakim
// Date : 02-16-01
// Reason : Added friendly name support.
//
// Reason : filling out version info. This was being not
// done previously in GetObject.
#include <fwcommon.h> // This must be the first include.
#include "private.h"
#include <winsock2.h>
#include "wlbsutil.h"
#include "nlbsnic.h"
#include "nlbsnic.tmh"
// using namespace std;
// MUsingCom com;
BOOL g_UpdateConfigurationEnabled = TRUE;
WBEMSTATUS
ProvExecStaticMethod(
const BSTR bstrMethodName,
CInstance *pInParams,
CInstance *pOutParams
);
WBEMSTATUS
ProvGetCompatibleAdapterGuids(
CInstance *pInParams,
CInstance *pOutParams
);
WBEMSTATUS
ProvGetClusterConfiguration(
CInstance *pInParams,
CInstance *pOutParams
);
WBEMSTATUS
ProvUpdateClusterConfiguration(
CInstance *pInParams,
CInstance *pOutParams
);
WBEMSTATUS
ProvQueryConfigurationUpdateStatus(
CInstance *pInParams,
CInstance *pOutParams
);
WBEMSTATUS
ProvControlCluster(
CInstance *pInParams,
CInstance *pOutParams
);
WBEMSTATUS
ProvGetClusterMembers(
CInstance *pInParams,
CInstance *pOutParams
);
WBEMSTATUS
ProvRegisterManagementApplication(
CInstance *pInParams,
CInstance *pOutParams
);
WBEMSTATUS
ProvUnregisterManagementApplication(
CInstance *pInParams,
CInstance *pOutParams
);
// TO DO: Replace "NameSpace" with the appropriate namespace for your
// provider instance. For instance: "root\\default or "root\\cimv2".
// DONE : mhakim
//===================================================================
CNlbsNic MyNlbsNicSet (PROVIDER_NAME_NLBSNIC, L"root\\microsoftnlb") ;
// Property names
//===============
const static WCHAR* cszAdapterGuid = L"AdapterGuid" ;
const static WCHAR* pDependent = L"Dependent" ;
const static WCHAR* pFriendlyName = L"FriendlyName" ;
const static WCHAR* pFullName = L"FullName" ;
const static WCHAR* pVersion = L"Version" ;
/*****************************************************************************
*
* FUNCTION : CNlbsNic::CNlbsNic
*
* DESCRIPTION : Constructor
*
* INPUTS : none
*
* RETURNS : nothing
*
* COMMENTS : Calls the Provider constructor.
*
*****************************************************************************/
CNlbsNic::CNlbsNic (LPCWSTR lpwszName, LPCWSTR lpwszNameSpace ) :
Provider(lpwszName, lpwszNameSpace),
m_fDelayedInitializationComplete(FALSE)
{
HRESULT hr;
InitializeCriticalSection(&m_Lock);
//
// Static Initialization of the NlbConfigurationUpdate class.
//
NlbConfigurationUpdate::StaticInitialize();
}
/*****************************************************************************
*
* FUNCTION : CNlbsNic::~CNlbsNic
*
* DESCRIPTION : Destructor
*
* INPUTS : none
*
* RETURNS : nothing
*
* COMMENTS :
*
*****************************************************************************/
CNlbsNic::~CNlbsNic ()
{
// this->DelayedDeinitialize();
//
// Static Deinitialization the NlbConfigurationUpdate class.
//
NlbConfigurationUpdate::StaticDeinitialize();
DeleteCriticalSection(&m_Lock);
}
BOOL
CNlbsNic::DelayedInitialize(VOID)
{
BOOL fRet = FALSE;
mfn_Lock();
if (m_fDelayedInitializationComplete == FALSE)
{
WBEMSTATUS Status;
Status = CfgUtilInitialize(
TRUE, // TRUE == server
TRUE // TRUE == don't use ping
);
if (!FAILED(Status))
{
m_fDelayedInitializationComplete = TRUE;
}
}
fRet = m_fDelayedInitializationComplete;
mfn_Unlock();
return fRet;
}
VOID
CNlbsNic::DelayedDeinitialize(VOID)
{
mfn_Lock();
if (m_fDelayedInitializationComplete)
{
//
// Prepare NlbConfigurationUpdate for deinitialization.
//
NlbConfigurationUpdate::PrepareForDeinitialization();
//
// Deinitialize the configuration utilities
//
CfgUtilDeitialize();
m_fDelayedInitializationComplete = FALSE;
}
mfn_Unlock();
return;
}
/*****************************************************************************
*
* FUNCTION : CNlbsNic::EnumerateInstances
*
* DESCRIPTION : Returns all the instances of this class.
*
* INPUTS : A pointer to the MethodContext for communication with WinMgmt.
* A long that contains the flags described in
* IWbemServices::CreateInstanceEnumAsync. Note that the following
* flags are handled by (and filtered out by) WinMgmt:
* WBEM_FLAG_DEEP
* WBEM_FLAG_SHALLOW
* WBEM_FLAG_RETURN_IMMEDIATELY
* WBEM_FLAG_FORWARD_ONLY
* WBEM_FLAG_BIDIRECTIONAL
*
* RETURNS : WBEM_S_NO_ERROR if successful
*
* COMMENTS : TO DO: All instances on the machine should be returned here and
* all properties that this class knows how to populate must
* be filled in. If there are no instances, return
* WBEM_S_NO_ERROR. It is not an error to have no instances.
* If you are implementing a 'method only' provider, you
* should remove this method.
* DONE: mhakim
*
*****************************************************************************/
HRESULT CNlbsNic::EnumerateInstances ( MethodContext* pMethodContext, long lFlags )
{
return WBEM_S_NO_ERROR;
}
/*****************************************************************************
*
* FUNCTION : CNlbsNic::GetObject
*
* DESCRIPTION : Find a single instance based on the key properties for the
* class.
*
* INPUTS : A pointer to a CInstance object containing the key properties.
* A long that contains the flags described in
* IWbemServices::GetObjectAsync.
*
* RETURNS : WBEM_S_NO_ERROR if the instance can be found
* WBEM_E_NOT_FOUND if the instance described by the key properties
* could not be found
* WBEM_E_FAILED if the instance could be found but another error
* occurred.
*
* COMMENTS : If you are implementing a 'method only' provider, you should
* remove this method.
*
*****************************************************************************/
HRESULT CNlbsNic::GetObject ( CInstance* pInstance, long lFlags )
{
return WBEM_E_NOT_FOUND;
}
/*****************************************************************************
*
* FUNCTION : CNlbsNic::ExecQuery
*
* DESCRIPTION : You are passed a method context to use in the creation of
* instances that satisfy the query, and a CFrameworkQuery
* which describes the query. Create and populate all
* instances which satisfy the query. You may return more
* instances or more properties than are requested and WinMgmt
* will post filter out any that do not apply.
*
* INPUTS : A pointer to the MethodContext for communication with WinMgmt.
* A query object describing the query to satisfy.
* A long that contains the flags described in
* IWbemServices::CreateInstanceEnumAsync. Note that the following
* flags are handled by (and filtered out by) WinMgmt:
* WBEM_FLAG_FORWARD_ONLY
* WBEM_FLAG_BIDIRECTIONAL
* WBEM_FLAG_ENSURE_LOCATABLE
*
* RETURNS : WBEM_E_PROVIDER_NOT_CAPABLE if queries not supported for
* this class or if the query is too complex for this class
* to interpret. The framework will call the EnumerateInstances
* function instead and let Winmgmt post filter.
* WBEM_E_FAILED if the query failed
* WBEM_S_NO_ERROR if query was successful
*
* COMMENTS : TO DO: Most providers will not need to implement this method. If you don't, WinMgmt
* will call your enumerate function to get all the instances and perform the
* filtering for you. Unless you expect SIGNIFICANT savings from implementing
* queries, you should remove this method. You should also remove this method
* if you are implementing a 'method only' provider.
*
*****************************************************************************/
HRESULT CNlbsNic::ExecQuery (MethodContext *pMethodContext, CFrameworkQuery& Query, long lFlags)
{
return (WBEM_E_PROVIDER_NOT_CAPABLE);
}
/*****************************************************************************
*
* FUNCTION : CNlbsNic::PutInstance
*
* DESCRIPTION : PutInstance should be used in provider classes that can
* write instance information back to the hardware or
* software. For example: Win32_Environment will allow a
* PutInstance to create or update an environment variable.
* However, a class like MotherboardDevice will not allow
* editing of the number of slots, since it is difficult for
* a provider to affect that number.
*
* INPUTS : A pointer to a CInstance object containing the key properties.
* A long that contains the flags described in
* IWbemServices::PutInstanceAsync.
*
* RETURNS : WBEM_E_PROVIDER_NOT_CAPABLE if PutInstance is not available
* WBEM_E_FAILED if there is an error delivering the instance
* WBEM_E_INVALID_PARAMETER if any of the instance properties
* are incorrect.
* WBEM_S_NO_ERROR if instance is properly delivered
*
* COMMENTS : TO DO: If you don't intend to support writing to your provider,
* or are creating a 'method only' provider, remove this
* method.
*
*****************************************************************************/
HRESULT CNlbsNic::PutInstance ( const CInstance &Instance, long lFlags)
{
// Use the CInstance Get functions (for example, call
// GetCHString(L"Name", sTemp)) against Instance to see the key values
// the client requested.
return (WBEM_E_PROVIDER_NOT_CAPABLE);
}
/*****************************************************************************
*
* FUNCTION : CNlbsNic::DeleteInstance
*
* DESCRIPTION : DeleteInstance, like PutInstance, actually writes information
* to the software or hardware. For most hardware devices,
* DeleteInstance should not be implemented, but for software
* configuration, DeleteInstance implementation is plausible.
*
* INPUTS : A pointer to a CInstance object containing the key properties.
* A long that contains the flags described in
* IWbemServices::DeleteInstanceAsync.
*
* RETURNS : WBEM_E_PROVIDER_NOT_CAPABLE if DeleteInstance is not available.
* WBEM_E_FAILED if there is an error deleting the instance.
* WBEM_E_INVALID_PARAMETER if any of the instance properties
* are incorrect.
* WBEM_S_NO_ERROR if instance is properly deleted.
*
* COMMENTS : TO DO: If you don't intend to support deleting instances or are
* creating a 'method only' provider, remove this method.
*
*****************************************************************************/
HRESULT CNlbsNic::DeleteInstance ( const CInstance &Instance, long lFlags )
{
// Use the CInstance Get functions (for example, call
// GetCHString(L"Name", sTemp)) against Instance to see the key values
// the client requested.
return (WBEM_E_PROVIDER_NOT_CAPABLE);
}
BOOL g_Impersonate = TRUE;
/*****************************************************************************
*
* FUNCTION : CNlbsNic::ExecMethod
*
* DESCRIPTION : Override this function to provide support for methods.
* A method is an entry point for the user of your provider
* to request your class perform some function above and
* beyond a change of state. (A change of state should be
* handled by PutInstance() )
*
* INPUTS : A pointer to a CInstance containing the instance the method was executed against.
* A string containing the method name
* A pointer to the CInstance which contains the IN parameters.
* A pointer to the CInstance to contain the OUT parameters.
* A set of specialized method flags
*
* RETURNS : WBEM_E_PROVIDER_NOT_CAPABLE if not implemented for this class
* WBEM_S_NO_ERROR if method executes successfully
* WBEM_E_FAILED if error occurs executing method
*
* COMMENTS : TO DO: If you don't intend to support Methods, remove this method.
*
*****************************************************************************/
HRESULT CNlbsNic::ExecMethod ( const CInstance& Instance,
const BSTR bstrMethodName,
CInstance *pInParams,
CInstance *pOutParams,
long lFlags)
{
// For non-static methods, use the CInstance Get functions (for example,
// call GetCHString(L"Name", sTemp)) against Instance to see the key
// values the client requested.
HRESULT hresult = WBEM_E_PROVIDER_NOT_CAPABLE;
BOOL fImpersonating = FALSE;
TRACE_INFO("-> %!FUNC! Method Name : %ls", bstrMethodName);
if (!DelayedInitialize())
{
TRACE_CRIT("%!FUNC! -- delayed initialization failed!");
goto end;
}
//
// The NLB Manager provider runs under the context of "NetworkServiceHost" and hence
// may NOT have sufficient privileges to perform sensitive operations (like binding/
// unbinding NLB). So, we impersonate the client in order to use the client's (potentially
// higher) credentials to perform such operations.
//
hresult = CoImpersonateClient();
// 2/13/02 JosephJ SECURITY BUGBUG: is this check for RPC_E_CALL_COMPLETE
// ok?
if (hresult != S_OK && hresult != RPC_E_CALL_COMPLETE)
{
TRACE_CRIT("%!FUNC! ERROR: CoImpersonateClient returns 0x%08lx", (UINT) hresult);
goto end;
}
fImpersonating = TRUE;
// Adding this assert since we are not sure if RPC_E_CALL_COMPLETE
// could be a legitimate error. - KarthicN, 4/12/02.
ASSERT(hresult != RPC_E_CALL_COMPLETE);
// Check if caller is an administrator?
if (mfn_IsCallerAdmin() == FALSE)
{
TRACE_CRIT("%!FUNC! IsCallerAdmin() returned FALSE, returning WBEM_E_ACCESS_DENIED");
hresult= WBEM_E_ACCESS_DENIED;
goto end;
}
if (!g_Impersonate)
{
// Revert to using server credentials
CoRevertToSelf();
fImpersonating = FALSE;
}
hresult = ProvExecStaticMethod(bstrMethodName, pInParams, pOutParams);
end:
if (fImpersonating)
{
CoRevertToSelf();
}
TRACE_INFO("<- %!FUNC! return : 0x%08lx", (UINT)hresult);
return hresult;
}
////////////////////////////////////////////////////////////////////////////////
//
// Name : IsCallerAdmin
// Description : This function checks if the caller is a member of the
// Administrators local group. Since the provider is acting on
// behalf of the client, it is important to IMPERSONATE the client
// BEFORE calling this function. Impersonating the client will ensure
// that this function checks if the client (& NOT this process that
// runs under the identity of NetworkServiceHost) is a member of
// the Administrators local group.
// Arguments : None.
// Return Value:
// TRUE - Caller is a member of Administrators local group.
// FALSE - Caller is NOT a member of Administrators local group.
////////////////////////////////////////////////////////////////////////////////
BOOL CNlbsNic::mfn_IsCallerAdmin(VOID)
{
BOOL bRet;
PSID AdministratorsGroup;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
TRACE_VERB(L"->%!FUNC!");
//
// Allocate and Initialize SID for Administrators in the built-in system domain
//
bRet = AllocateAndInitializeSid(&NtAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID, // The built-in system domain (S-1-5-32)
DOMAIN_ALIAS_RID_ADMINS, // Local group used for administration of the domain
0, 0, 0, 0, 0, 0,
&AdministratorsGroup);
if(bRet)
{
//
// Is SID enabled in the impersonation token of the calling thread ?
//
if (!CheckTokenMembership(NULL, // Use the Impersonation token of the calling thread
AdministratorsGroup,
&bRet))
{
bRet = FALSE;
TRACE_CRIT(L"%!FUNC! CheckTokenMembership() failed. Error : 0x%x", GetLastError());
}
FreeSid(AdministratorsGroup);
}
else
{
TRACE_CRIT("%!FUNC! AllocateAndInitializeSid() failed. Error : 0x%x", GetLastError());
}
TRACE_VERB(L"<-%!FUNC! Returning %ls", bRet ? L"TRUE" : L"FALSE");
return bRet;
}
////////////////////////////////////////////////////////////////////////////////
//
// Check_Load_Unload_Driver_Privilege
//
// Purpose: This function checks if the SE_LOAD_DRIVER_NAME (= "SeLoadDriverPrivilege")
// is enabled in the impersonation access token. If there is no impersonation
// access token and if the global impersonation flag is set to false (used for
// debug purposes), then we check the primary access token.
//
////////////////////////////////////////////////////////////////////////////////
BOOL Check_Load_Unload_Driver_Privilege()
{
PRIVILEGE_SET PrivilegeSet;
DWORD dwError;
LUID Luid;
BOOL bResult = FALSE;
HANDLE TokenHandle = NULL;
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 error: %u", GetLastError());
TRACE_INFO("<-%!FUNC! Returning FALSE");
return FALSE;
}
//
// Get a handle to the impersonation access token with TOKEN_QUERY right.
//
// Note: If this thread is NOT impersonating, then, the following call
// will fail with ERROR_NO_TOKEN.
//
if (!OpenThreadToken(GetCurrentThread(),
TOKEN_QUERY,
FALSE, // Use the credentials of the client that is being impersonated
&TokenHandle))
{
dwError = GetLastError();
//
// We were unable to open the impersonation access token. If it is because it doesn't
// exist and if the "g_Impersonate" flag is set to FALSE , then try to open the primary
// access token.
// This blob is mainly to handle the case where we are intentionally NOT
// impersonating by setting the "g_Impersonate" to FALSE. This flag was introduced
// mainly to easily switch between impersonating and not impersonating for debugging
// purposes. This was needed due to the problems that we encountered when impersonating
// + using "NetworkServiceHost".
// --KarthicN, May 6, 2002.
//
if ((dwError == ERROR_NO_TOKEN) && (g_Impersonate == FALSE))
{
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_QUERY,
&TokenHandle))
{
TRACE_CRIT("%!FUNC! OpenProcessToken error: %u", GetLastError());
TRACE_INFO("<-%!FUNC! Returning FALSE");
return FALSE;
}
}
else
{
TRACE_CRIT("%!FUNC! OpenThreadToken error: %u, Global Impersonation flag = %ls", dwError, g_Impersonate ? L"TRUE" : L"FALSE");
TRACE_INFO("<-%!FUNC! Returning FALSE");
return FALSE;
}
}
PrivilegeSet.PrivilegeCount = 1;
PrivilegeSet.Control = PRIVILEGE_SET_ALL_NECESSARY;
PrivilegeSet.Privilege[0].Luid = Luid;
PrivilegeSet.Privilege[0].Attributes = 0;
if (!PrivilegeCheck(TokenHandle, &PrivilegeSet, &bResult))
{
bResult = FALSE;
TRACE_CRIT("%!FUNC! PrivilegeCheck error: %u", GetLastError());
}
CloseHandle(TokenHandle);
TRACE_INFO(L"<-%!FUNC! Returning %ls", bResult ? L"TRUE" : L"FALSE");
return bResult;
}
WBEMSTATUS
ProvExecStaticMethod(
const BSTR bstrMethodName,
CInstance *pInParams,
CInstance *pOutParams
)
/*
If bstrMethodName is one of the recognized static methods, we execute
the method. Otherwise we return WBEM_E_PROVIDER_NOT_CAPABLE
*/
{
WBEMSTATUS Status = WBEM_E_PROVIDER_NOT_CAPABLE;
if (!g_UpdateConfigurationEnabled)
{
goto end;
}
if (_wcsicmp(bstrMethodName, L"GetCompatibleAdapterGuids") == 0)
{
Status = ProvGetCompatibleAdapterGuids(
pInParams,
pOutParams
);
}
else if (_wcsicmp(bstrMethodName, L"GetClusterConfiguration") == 0)
{
Status = ProvGetClusterConfiguration(
pInParams,
pOutParams
);
}
else if (_wcsicmp(bstrMethodName, L"UpdateClusterConfiguration") == 0)
{
//
// NOTE:
// One of the functions of this method is to bind/unbind NLB to the network adapter. Since this operation involves unloading
// and loading of the device driver, PnP apis (that are called), attempt to enable the "SeLoadDriverPrivilege"
// privilege in the impersonation access token. Enabling a privilege is successful only when the privilege is present,
// in the first place to be enabled. When the wmi client and wmi provider are in the same machine, it was observed that
// the "SeLoadDriverPrivilege" privilege was NOT event present in the impersonation access token of the server. This is
// because, only the enabled privileges of the client are passed along to the server.
// So, we now require that the client enable the "SeLoadDriverPrivilege" privilege in its access token before calling
// this method. The following call to Check_Load_Unload_Driver_Privilege() checks if "SeLoadDriverPrivilege" privilege
// is enabled in the impersonation access token (except if "g_Impersonate" is false). Although the PnP apis only
// require that this privilege be present, we have decided to elevate the requirement to this privilege being present
// AND enabled. This is because, if the privilege is NOT enabled, the operation to enable it may or may not succeed
// depending on the client's credentials.
// --KarthicN, May 6, 2002.
//
if(!Check_Load_Unload_Driver_Privilege())
{
TRACE_CRIT("%!FUNC! Check_Load_Unload_Driver_Privilege() failed, Returning WBEM_E_ACCESS_DENIED !!!");
Status = WBEM_E_ACCESS_DENIED;
goto end;
}
Status = ProvUpdateClusterConfiguration(
pInParams,
pOutParams
);
}
else if (_wcsicmp(bstrMethodName, L"QueryConfigurationUpdateStatus") == 0)
{
Status = ProvQueryConfigurationUpdateStatus(
pInParams,
pOutParams
);
}
else if (_wcsicmp(bstrMethodName, L"ControlCluster") == 0)
{
Status = ProvControlCluster(
pInParams,
pOutParams
);
}
else if (_wcsicmp(bstrMethodName, L"GetClusterMembers") == 0)
{
Status = ProvGetClusterMembers(
pInParams,
pOutParams
);
}
else if (_wcsicmp(bstrMethodName, L"RegisterManagementApplication") == 0)
{
Status = ProvRegisterManagementApplication(
pInParams,
pOutParams
);
}
else if (_wcsicmp(bstrMethodName, L"UnregisterManagementApplication") == 0)
{
Status = ProvUnregisterManagementApplication(
pInParams,
pOutParams
);
}
end:
return Status;
}
WBEMSTATUS
ProvGetCompatibleAdapterGuids(
CInstance *pInParams,
CInstance *pOutParams
)
/*++
Implementation of the "GetCompatibleAdapterGuids" method.
--*/
{
LPWSTR *pszNics = NULL;
UINT NumNics = 0;
UINT NumNlbBound = 0;
WBEMSTATUS Status = WBEM_E_PROVIDER_NOT_CAPABLE;
/*
[OUT] String AdapterGuids[], // "{......}"
[OUT] uint32 NumBoundToNlb
*/
TRACE_VERB(L"->%!FUNC!");
Status = CfgUtilsGetNlbCompatibleNics(&pszNics, &NumNics, &NumNlbBound);
if (FAILED(Status))
{
TRACE_CRIT("CfgUtilsGetNlbCompatibleNics returns error 0x%08lx",
(UINT) Status);
pszNics = NULL;
goto end;
}
//
// Fill in AdapterGuids[]
//
{
SAFEARRAY *pSA = NULL;
Status = CfgUtilSafeArrayFromStrings(
(LPCWSTR*) pszNics,
NumNics,
&pSA
);
if (FAILED(Status))
{
pSA = NULL;
goto end;
}
pOutParams->SetStringArray(
L"AdapterGuids",
*pSA // pass by reference
);
SafeArrayDestroy(pSA);
pSA = NULL;
}
pOutParams->SetDWORD(L"NumBoundToNlb", NumNlbBound);
Status = WBEM_NO_ERROR;
end:
pOutParams->SetDWORD(L"ReturnValue", (DWORD) Status);
if (pszNics != NULL)
{
delete pszNics;
pszNics = NULL;
}
TRACE_VERB(L"<-%!FUNC! returns 0x%08lx", (UINT) Status);
return WBEM_NO_ERROR; // real status is in the "ReturnResult" outparm.
}
WBEMSTATUS
ProvGetClusterConfiguration(
CInstance *pInParams,
CInstance *pOutParams
)
/*++
WMI provider wrapper around NlbConfigurationUpdate::GetConfiguration
--*/
{
LPCWSTR pAdapterGuid = NULL;
WBEMSTATUS Status = WBEM_E_PROVIDER_NOT_CAPABLE;
CHString sTemp;
bool fRet;
NLB_EXTENDED_CLUSTER_CONFIGURATION Cfg;
SAFEARRAY *pSA = NULL;
bool fNicNotFound = FALSE;
/*
[IN] String AdapterGuid,
[OUT] uint32 Generation,
[OUT] String NetworkAddresses[], // "10.1.1.1/255.0.0.0"
[OUT] Boolean NLBBound,
[OUT] Boolean DHCPEnabled,
[OUT] String ClusterNetworkAddress, // "10.1.1.1/255.0.0.0"
[OUT] String ClusterName,
[OUT] String TrafficMode, // UNICAST MULTICAST IGMPMULTICAST
[OUT] String PortRules[],
[OUT] uint32 HostPriority,
[OUT] String DedicatedNetworkAddress, // "10.1.1.1/255.0.0.0"
[OUT] uint32 ClusterModeOnStart, // 0 : STOPPED, 1 : STARTED, 2 : SUSPENDED
[OUT] Boolean PersistSuspendOnReboot,
[OUT] Boolean RemoteControlEnabled,
[OUT] uint32 HashedRemoteControlPassword
*/
fRet = pInParams->GetCHString( L"AdapterGuid", sTemp );
if (!fRet)
{
TRACE_CRIT("->%!FUNC!: Missing adapter guid!");
Status = WBEM_E_INVALID_PARAMETER;
goto end;
}
// Note: (LPCWSTR) sTemp returns an internal pointer to sTemp's char
// buffer -- see operator LPCWSTR() of WString docs.
//
pAdapterGuid = (LPCWSTR) sTemp;
if (pAdapterGuid == NULL || *pAdapterGuid == 0)
{
TRACE_CRIT("->%!FUNC!: Null of empty adapter guid!");
Status = WBEM_E_INVALID_PARAMETER;
goto end;
}
else
{
TRACE_VERB(L"->%!FUNC!(Nic=%ws)", pAdapterGuid);
}
Status = NlbConfigurationUpdate::GetConfiguration(
pAdapterGuid,
&Cfg
);
if (FAILED(Status))
{
if (Status == WBEM_E_NOT_FOUND)
{
fNicNotFound = TRUE;
}
goto end;
}
pOutParams->SetDWORD(L"Generation", Cfg.GetGeneration());
//
// Fill in NetworkAddresses[]
//
{
Status = Cfg.GetNetworkAddressesSafeArray(
&pSA
);
if (FAILED(Status))
{
TRACE_CRIT(
"%!FUNC!: couldn't extract network addresses from Cfg"
" for NIC %ws",
pAdapterGuid
);
pSA = NULL;
goto end;
}
if (pSA!=NULL)
{
pOutParams->SetStringArray(
L"NetworkAddresses",
*pSA // pass by reference
);
SafeArrayDestroy(pSA);
pSA = NULL;
}
}
//
// Adapter Friendly Name
//
{
LPWSTR szFriendlyName = NULL;
Status = Cfg.GetFriendlyName(&szFriendlyName);
if (FAILED(Status))
{
TRACE_CRIT(
"%!FUNC!: Could not extract adapter friendly name for NIC %ws",
pAdapterGuid
);
goto end;
}
pOutParams->SetCHString(L"FriendlyName", szFriendlyName);
delete (szFriendlyName);
szFriendlyName = NULL;
}
//
// Set dhcp state
//
pOutParams->Setbool(L"DHCPEnabled", Cfg.fDHCP);
if (!Cfg.IsNlbBound())
{
//
// NLB is not bound
//
pOutParams->Setbool(L"NLBBound", FALSE);
Status = WBEM_NO_ERROR;
goto end;
}
//
// NLB is bound
//
pOutParams->Setbool(L"NLBBound", TRUE);
if (!Cfg.IsValidNlbConfig())
{
TRACE_CRIT(
"%!FUNC!: NLB-specific configuration on NIC %ws is invalid",
pAdapterGuid
);
goto end;
}
//
// Cluster name
//
{
LPWSTR szName = NULL;
Status = Cfg.GetClusterName(&szName);
if (FAILED(Status))
{
TRACE_CRIT(
"%!FUNC!: Could not extract cluster name for NIC %ws",
pAdapterGuid
);
goto end;
}
pOutParams->SetCHString(L"ClusterName", szName);
delete (szName);
szName = NULL;
}
//
// Cluster and dedicated network addresses
//
{
LPWSTR szAddress = NULL;
Status = Cfg.GetClusterNetworkAddress(&szAddress);
if (FAILED(Status))
{
TRACE_CRIT(
"%!FUNC!: Could not extract cluster address for NIC %ws",
pAdapterGuid
);
goto end;
}
pOutParams->SetCHString(L"ClusterNetworkAddress", szAddress);
delete (szAddress);
szAddress = NULL;
Status = Cfg.GetDedicatedNetworkAddress(&szAddress);
if (FAILED(Status))
{
TRACE_CRIT(
"%!FUNC!: Could not extract dedicated address for NIC %ws",
pAdapterGuid
);
goto end;
}
pOutParams->SetCHString(L"DedicatedNetworkAddress", szAddress);
delete (szAddress);
szAddress = NULL;
}
//
// TrafficMode
//
{
LPCWSTR szMode = NULL;
switch(Cfg.GetTrafficMode())
{
case NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE_UNICAST:
szMode = L"UNICAST";
break;
case NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE_MULTICAST:
szMode = L"MULTICAST";
break;
case NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE_IGMPMULTICAST:
szMode = L"IGMPMULTICAST";
break;
default:
assert(FALSE);
Status = WBEM_E_CRITICAL_ERROR;
goto end;
}
pOutParams->SetCHString(L"TrafficMode", szMode);
}
pOutParams->SetDWORD(L"HostPriority", Cfg.GetHostPriority());
/*
if (Cfg.GetClusterModeOnStart() ==
NLB_EXTENDED_CLUSTER_CONFIGURATION::START_MODE_STARTED)
{
pOutParams->Setbool(L"ClusterModeOnStart", TRUE);
}
else
{
pOutParams->Setbool(L"ClusterModeOnStart", FALSE);
}
*/
pOutParams->SetDWORD(L"ClusterModeOnStart", Cfg.GetClusterModeOnStart());
pOutParams->Setbool(L"PersistSuspendOnReboot", Cfg.GetPersistSuspendOnReboot());
pOutParams->Setbool(L"RemoteControlEnabled", Cfg.GetRemoteControlEnabled());
pOutParams->SetDWORD(
L"HashedRemoteControlPassword",
CfgUtilGetHashedRemoteControlPassword(&Cfg.NlbParams)
);
//
// [OUT] String PortRules[],
//
{
LPWSTR *pszPortRules = NULL;
UINT NumPortRules = 0;
pSA=NULL;
Status = Cfg.GetPortRules(
&pszPortRules,
&NumPortRules
);
if (FAILED(Status))
{
pszPortRules = NULL;
goto end;
}
Status = CfgUtilSafeArrayFromStrings(
(LPCWSTR*) pszPortRules,
NumPortRules, // can be zero
&pSA
);
if (FAILED(Status))
{
TRACE_CRIT(
"%!FUNC!: couldn't extract port rules from Cfg"
" for NIC %ws",
pAdapterGuid
);
pSA = NULL;
goto end;
}
if (pSA!=NULL)
{
pOutParams->SetStringArray(
L"PortRules",
*pSA // pass by reference
);
SafeArrayDestroy(pSA);
pSA = NULL;
}
}
Status = WBEM_NO_ERROR;
end:
if (FAILED(Status))
{
//
// We want to reserve WBEM_NOT_FOUND for the SPECIFIC case
// of the NIC not being found
//
if (Status == WBEM_E_NOT_FOUND && !fNicNotFound)
{
Status = WBEM_E_FAILED;
}
pOutParams->SetDWORD(L"ReturnValue", (DWORD) Status);
}
else
{
pOutParams->SetDWORD(L"ReturnValue", (DWORD) WBEM_NO_ERROR);
}
if (pSA!=NULL)
{
SafeArrayDestroy(pSA);
pSA = NULL;
}
TRACE_VERB(L"<-%!FUNC! returns 0x%08lx", (UINT) Status);
return WBEM_NO_ERROR;
}
WBEMSTATUS
ProvUpdateClusterConfiguration(
CInstance *pInParams,
CInstance *pOutParams
)
/*++
WMI provider wrapper NlbConfigurationUpdate::UpdateConfiguration
with some additional wrinkles:
we selectively update the current version.
--*/
{
LPCWSTR pAdapterGuid = NULL;
LPCWSTR pClientDescription = L"Unspecified WMI Client"; // TODO: localize
WBEMSTATUS Status = WBEM_E_PROVIDER_NOT_CAPABLE;
CHString sClientDescription;
CHString sAdapterGuid;
CHString sTemp;
bool fRet;
NLB_EXTENDED_CLUSTER_CONFIGURATION Cfg;
SAFEARRAY *pSA = NULL;
/*
[IN] String ClientDescription,
[IN] String AdapterGuid,
[IN] uint32 Generation,
[IN] Boolean PartialUpdate,
[IN] String NetworkAddresses[], // "10.1.1.1/255.255.255.255"
[IN] Boolean NLBBound,
[IN] String ClusterNetworkAddress, // "10.1.1.1/255.0.0.0"
[IN] String ClusterName,
[IN] String TrafficMode, // UNICAST MULTICAST IGMPMULTICAST
[IN] String PortRules[],
[IN] uint32 HostPriority,
[IN] String DedicatedNetworkAddress, // "10.1.1.1/255.0.0.0"
[IN] uint32 ClusterModeOnStart, // 0 : STOPPED, 1 : STARTED, 2 : SUSPENDED
[IN] Boolean PersistSuspendOnReboot,
[IN] Boolean RemoteControlEnabled,
[IN] String Password,
[OUT] uint32 NewGeneration,
[OUT] String Log
*/
fRet = pInParams->GetCHString( L"ClientDescription", sClientDescription);
if (fRet)
{
// Note: (LPCWSTR) sTemp returns an internal pointer to sTemp's char
pClientDescription = (LPCWSTR) sClientDescription;
}
fRet = pInParams->GetCHString( L"AdapterGuid", sAdapterGuid);
if (!fRet)
{
TRACE_CRIT("->%!FUNC!: Missing adapter guid!");
Status = WBEM_E_INVALID_PARAMETER;
goto end;
}
//
// Note: (LPCWSTR) sTemp returns an internal pointer to sTemp's char
// buffer -- see operator LPCWSTR() of WString docs.
//
pAdapterGuid = (LPCWSTR) sAdapterGuid;
if (pAdapterGuid == NULL || *pAdapterGuid == 0)
{
TRACE_CRIT("->%!FUNC!: Null of empty adapter guid!");
Status = WBEM_E_INVALID_PARAMETER;
goto end;
}
else
{
TRACE_VERB(L"->%!FUNC!(Nic=%ws)", pAdapterGuid);
}
//
// Get the current configuration
//
Status = NlbConfigurationUpdate::GetConfiguration(
pAdapterGuid,
&Cfg
);
if (FAILED(Status))
{
goto end;
}
//
// Modify the snapshot of the current configuration with whatever
// cluster configuration information is specified in the input
// parameters
//
{
DWORD InGeneration = 0;
bool NlbBound = FALSE;
bool bResult = FALSE;
bool bPartialUpdate = FALSE;
bool bCheckForAddressConflicts = FALSE;
//
// Determine if this is a partial or full update.
// If partial update, we allow a subset of cluster configuration
// parameters to be specified, but allow only a restricted set
// of update operations.
//
// Disallowed partial update operations:
// - Transitions between bound and !bound
// - Currently bound but nlb parameters are invalid
//
// Some allowed partial updates:
// - Modifying IP address lists
// - Modifying cluster / dedicated addresses/subnets
// - Modifying existing portrules
// - Adding/deleting port rules
//
bResult = pInParams->GetDWORD(
L"Generation", // <--------------------------------
InGeneration
);
if (!bResult)
{
//
// We allow generation to be unspecified.
//
InGeneration = 0;
}
else
{
//
// If generation is specified,
// we verify that the current generation matches the
// specified generation.
// TODO: this really must be done in the context of
// mfn_Start update -- after we've acquired the global lock!
//
if (InGeneration != Cfg.GetGeneration())
{
TRACE_CRIT("Partial update: input generation(%lu) != current generation(%lu)", InGeneration, Cfg.GetGeneration());
Status = WBEM_E_HANDLE_OUT_OF_DATE;
goto end;
}
}
bResult = pInParams->Getbool(
L"CheckForAddressConflicts", // <--------------------------------
bCheckForAddressConflicts
);
if (!bResult)
{
TRACE_CRIT(L"Could not read CheckForAddressConflicts -- assuming FALSE\n");
bCheckForAddressConflicts = FALSE;
}
bResult = pInParams->Getbool(
L"NLBBound", // <--------------------------------
NlbBound
);
if (!bResult)
{
NlbBound = Cfg.IsNlbBound();
TRACE_CRIT(L"Could not read NLBBound -- assuming current state %d.",
NlbBound);
}
bResult = pInParams->GetStringArray(
L"NetworkAddresses", // <--------------------------------
pSA
);
if (!bResult)
{
//
// We set pCfg to zero addresses, which causes update to
// use it's own defaults...
//
TRACE_CRIT(L"Could not read Network addresses -- using defaults");
Status = Cfg.SetNetworkAddresses(NULL, 0);
pSA = NULL;
}
else
{
if (pSA != NULL)
{
Status = Cfg.SetNetworkAddressesSafeArray(pSA);
SafeArrayDestroy(pSA);
pSA = NULL;
}
}
if (!NlbBound)
{
// NLB is not to be bound -- no need to read the input params.
Cfg.fBound = FALSE;
Cfg.fValidNlbCfg = FALSE;
}
else
{
BOOL fNewConfig = FALSE;
bool bAddDedicatedIp = FALSE;
bool bAddClusterIps = FALSE;
if (!Cfg.fBound || Cfg.fValidNlbCfg == FALSE)
{
//
// If we were previously unbound or we were bound but with
// a bad configuration, we need to setup our
// new cfg with good defaults
//
CfgUtilInitializeParams(&Cfg.NlbParams);
Cfg.fBound = TRUE;
Cfg.fValidNlbCfg = TRUE;
fNewConfig = TRUE;
}
bResult = pInParams->Getbool(
L"AddDedicatedIp", // <------------------------
bAddDedicatedIp
);
if (!bResult)
{
TRACE_CRIT(L"Could not read AddDedicatedIp -- assuming TRUE\n");
bAddDedicatedIp = TRUE;
}
Cfg.fAddDedicatedIp = (bAddDedicatedIp!=FALSE);
bResult = pInParams->Getbool(
L"AddClusterIps", // <-------------------------
bAddClusterIps
);
if (!bResult)
{
TRACE_CRIT(L"Could not read AddClusterIps -- assuming TRUE\n");
bAddClusterIps = TRUE;
}
Cfg.fAddClusterIps = (bAddClusterIps!=FALSE);
bResult = pInParams->GetCHString(
L"ClusterNetworkAddress", // <--------------------
sTemp
);
if (!bResult)
{
if (fNewConfig)
{
//
// Cluster address MUST be specified for new config.
//
TRACE_CRIT(L"ERROR: Could not read Cluster IP for new config.");
Status = WBEM_E_INVALID_PARAMETER;
goto end;
}
TRACE_CRIT(L"Could not read Cluster IP. Keeping existing.");
}
else
{
LPCWSTR szClusterNetworkAddress = NULL;
szClusterNetworkAddress = (LPCWSTR) sTemp; // no copies here.
Cfg.SetClusterNetworkAddress(szClusterNetworkAddress);
szClusterNetworkAddress = NULL;
}
bResult = pInParams->GetCHString(
L"ClusterName", // <-------------------------
sTemp
);
if (!bResult)
{
TRACE_CRIT(L"Could not read Cluster Name. Keeping existing");
}
else
{
LPCWSTR szClusterName = NULL;
szClusterName = (LPCWSTR) sTemp; // no copies here.
Cfg.SetClusterName(szClusterName);
szClusterName = NULL;
}
//
// Traffic mode
//
{
bResult = pInParams->GetCHString(
L"TrafficMode", // <-------------------------
sTemp
);
if (!bResult)
{
TRACE_CRIT(L"Could not read TrafficMode. Keeping existing");
}
else
{
LPCWSTR szTrafficMode = NULL;
NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE TrafficMode
= NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE_UNICAST;
szTrafficMode = (LPCWSTR) sTemp; // no copies here.
if (!_wcsicmp(szTrafficMode, L"UNICAST"))
{
TrafficMode =
NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE_UNICAST;
}
else if (!_wcsicmp(szTrafficMode, L"MULTICAST"))
{
TrafficMode =
NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE_MULTICAST;
}
else if (!_wcsicmp(szTrafficMode, L"IGMPMULTICAST"))
{
TrafficMode =
NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE_IGMPMULTICAST;
}
else
{
TRACE_CRIT("Invalid TrafficMode: %ws", szTrafficMode);
Status = WBEM_E_INVALID_PARAMETER;
goto end;
}
Cfg.SetTrafficMode(TrafficMode);
szTrafficMode = NULL;
}
}
//
// String PortRules[]
//
bResult = pInParams->GetStringArray(
L"PortRules", // <--------------------------------
pSA
);
if (!bResult)
{
//
// We set pCfg to zero port rules
//
TRACE_CRIT(L"Could not read port rules-- assuming ZERO");
Status = Cfg.SetPortRules(NULL, 0);
pSA = NULL;
}
else
{
if (pSA != NULL)
{
LPWSTR *pStrings=NULL;
UINT NumStrings = 0;
Status = CfgUtilStringsFromSafeArray(
pSA,
&pStrings, // delete when done
&NumStrings
);
if (FAILED(Status))
{
pStrings=NULL;
TRACE_CRIT(L"Could not extract port rules");
goto end;
}
Status = Cfg.SetPortRules(
(LPCWSTR*)pStrings,
NumStrings
);
delete pStrings;
SafeArrayDestroy(pSA);
pSA = NULL;
}
}
DWORD HostPriority = 0;
bResult = pInParams->GetDWORD(
L"HostPriority", // <---------------------------
HostPriority
);
if (!bResult)
{
TRACE_CRIT(L"Could not read HostPriority. Keeping existing");
}
else
{
Cfg.SetHostPriority(HostPriority);
}
bResult = pInParams->GetCHString(
L"DedicatedNetworkAddress", // <-----------------
sTemp
);
if (!bResult)
{
TRACE_CRIT(L"Could not dedicated IP. Keeping existing");
}
else
{
LPCWSTR szAddress = NULL;
szAddress = (LPCWSTR) sTemp; // no copies here.
Cfg.SetDedicatedNetworkAddress(szAddress);
szAddress = NULL;
}
//
// StartMode
//
{
DWORD ClusterModeOnStart = FALSE;
bResult = pInParams->GetDWORD(
L"ClusterModeOnStart", // <-----------------
ClusterModeOnStart
);
if (!bResult)
{
TRACE_CRIT(L"Could not read StartMode. Keeping existing");
}
else
{
/*
NLB_EXTENDED_CLUSTER_CONFIGURATION::START_MODE
ClusterModeOnStart;
if (StartMode)
{
ClusterModeOnStart =
NLB_EXTENDED_CLUSTER_CONFIGURATION::START_MODE_STARTED;
}
else
{
ClusterModeOnStart =
NLB_EXTENDED_CLUSTER_CONFIGURATION::START_MODE_STOPPED;
}
*/
Cfg.SetClusterModeOnStart(ClusterModeOnStart);
}
}
//
// Persist Suspend on Reboot
//
{
bool bPersistSuspendOnReboot;
bResult = pInParams->Getbool(
L"PersistSuspendOnReboot", // <---------------
bPersistSuspendOnReboot
);
if (!bResult)
{
TRACE_CRIT(L"Could not read PersistSuspendOnReboot. Keeping existing");
}
else
{
Cfg.SetPersistSuspendOnReboot(bPersistSuspendOnReboot);
}
}
//
// Remote control enabled
//
{
bool bRemoteControlEnabled;
bResult = pInParams->Getbool(
L"RemoteControlEnabled", // <---------------
bRemoteControlEnabled
);
if (!bResult)
{
TRACE_CRIT(L"Could not read RemoteControlEnabled. Keeping existing");
}
else
{
Cfg.SetRemoteControlEnabled(bRemoteControlEnabled!=FALSE);
if (bRemoteControlEnabled)
{
DWORD dwPwd;
LPCWSTR szPwd = NULL;
//
// Now read and set string or hashed version of password
// if either are specified.
//
bResult = pInParams->GetCHString(
L"RemoteControlPassword", // <-----------------
sTemp
);
if (bResult)
{
szPwd = (LPCWSTR) sTemp; // no copies here.
(VOID) CfgUtilSetRemotePassword(&Cfg.NlbParams, szPwd);
}
if (szPwd == NULL)
{
//
// Only look for hashed pwd if the real pwd is
// not specified.
//
bResult = pInParams->GetDWORD(
L"HashedRemoteControlPassword", // <-----------------
dwPwd
);
if (bResult)
{
CfgUtilSetHashedRemoteControlPassword(
&Cfg.NlbParams,
dwPwd
);
}
}
}
}
}
//
// TODO: if PartialUpdate is specified, we need to
// make sure that fValidNlbCfg is already set.
//
Cfg.fValidNlbCfg = TRUE;
} while (FALSE) ;
}
//
// Call NlbConfigurationUpdate::DuUpdate to do the actual work.
//
UINT NewGeneration = 0;
LPWSTR pLog = NULL;
try
{
Status = NlbConfigurationUpdate::DoUpdate(
pAdapterGuid,
pClientDescription,
&Cfg,
&NewGeneration,
&pLog
);
}
catch (...)
{
TRACE_CRIT(L"%!FUNC! Caught exception!\n");
ASSERT(!"Caught exception!");
throw;
}
//
// Fill out the out parameters: status new generation and log
//
pOutParams->SetDWORD(L"ReturnValue", (DWORD) Status);
pOutParams->SetDWORD(L"NewGeneration", (DWORD) NewGeneration);
if (pLog != NULL)
{
pOutParams->SetCHString(L"Log", pLog);
delete pLog;
pLog = NULL;
}
//
// If we've actually called DoUpdate,
// we always return WBEM_NO_ERROR. The return value has the
// real result.
//
Status = WBEM_NO_ERROR;
end:
if (pSA!=NULL)
{
SafeArrayDestroy(pSA);
pSA = NULL;
}
TRACE_VERB(L"<-%!FUNC! returns 0x%08lx", (UINT) Status);
return Status;
}
WBEMSTATUS
ProvQueryConfigurationUpdateStatus(
CInstance *pInParams,
CInstance *pOutParams
)
/*++
WMI provider wrapper around NlbConfigurationUpdate::GetUpdateStatus
--*/
{
LPCWSTR pAdapterGuid = NULL;
WBEMSTATUS Status = WBEM_E_PROVIDER_NOT_CAPABLE;
CHString sTemp;
bool fRet;
DWORD Generation = 0;
/*
[IN] String AdapterGuid,
[IN] uint32 Generation,
[OUT] String Log
*/
fRet = pInParams->GetCHString( L"AdapterGuid", sTemp);
if (!fRet)
{
TRACE_CRIT("->%!FUNC!: Missing adapter guid!");
Status = WBEM_E_INVALID_PARAMETER;
goto end;
}
//
// Note: (LPCWSTR) sTemp returns an internal pointer to sTemp's char
// buffer -- see operator LPCWSTR() of WString docs.
//
pAdapterGuid = (LPCWSTR) sTemp;
if (pAdapterGuid == NULL || *pAdapterGuid == 0)
{
TRACE_CRIT("->%!FUNC!: Null of empty adapter guid!");
Status = WBEM_E_INVALID_PARAMETER;
goto end;
}
else
{
TRACE_VERB(L"->%!FUNC!(Nic=%ws)", pAdapterGuid);
}
fRet = pInParams->GetDWORD(
L"Generation", // <--------------------------------
Generation
);
if (!fRet)
{
TRACE_CRIT("%!FUNC!: Missing generation!");
Status = WBEM_E_INVALID_PARAMETER;
goto end;
}
//
// Call NlbConfigurationUpdate::GetUpdateResult to do the actual work.
//
LPWSTR pLog = NULL;
WBEMSTATUS CompletionStatus = WBEM_NO_ERROR;
Status = NlbConfigurationUpdate::GetUpdateStatus(
pAdapterGuid,
Generation,
FALSE, // FALSE == Don't delete completion record
&CompletionStatus,
&pLog
);
if (!FAILED(Status))
{
//
// Fill out the out parameters: status new generation and log
//
pOutParams->SetDWORD(L"ReturnValue", (DWORD) CompletionStatus);
if (pLog != NULL)
{
pOutParams->SetCHString(L"Log", pLog);
delete pLog;
pLog = NULL;
}
}
end:
TRACE_VERB(L"<-%!FUNC! returns 0x%08lx", (UINT) Status);
return Status;
}
WBEMSTATUS
ProvControlCluster(
CInstance *pInParams,
CInstance *pOutParams
)
/*++
WMI provider wrapper around NlbConfigurationUpdate::ProvControlCluster
TODO:
Implement NlbConfigurationUpdate::ProvControlCluster,
which should be a wrapper around around WlbsControlCluster where
the work is actually done (WlbsControlCluster will take the
handle to the device).
--*/
{
LPCWSTR szAdapterGuid, szVip;
CHString sAdapterGuid, sVip;
bool fRet;
DWORD dwPort, dwRetVal, dwVip, dwHostMap, dwStatus;
WBEMSTATUS Status;
WLBS_OPERATION_CODES Opcode;
TRACE_VERB(L"->%!FUNC!");
dwRetVal = dwStatus = WLBS_FAILURE;
dwHostMap = 0;
Status = WBEM_NO_ERROR;
szVip = NULL;
dwVip = dwPort = 0;
// Get the Adapter GUID
fRet = pInParams->GetCHString(L"AdapterGuid", sAdapterGuid);
if (!fRet)
{
TRACE_CRIT(L"%!FUNC!: Missing adapter guid!");
Status = WBEM_E_INVALID_PARAMETER;
goto end;
}
else
{
szAdapterGuid = (LPCWSTR) sAdapterGuid;
if (szAdapterGuid == NULL || *szAdapterGuid == UNICODE_NULL)
{
TRACE_CRIT(L"%!FUNC!: Null or empty adapter guid!");
Status = WBEM_E_INVALID_PARAMETER;
goto end;
}
}
// Get the operation to be performed
DWORD dwOperation;
fRet = pInParams->GetDWORD(L"Operation", dwOperation);
if (!fRet)
{
TRACE_CRIT("%!FUNC!: Missing operation!");
Status = WBEM_E_INVALID_PARAMETER;
goto end;
}
Opcode = (WLBS_OPERATION_CODES)dwOperation;
// If present, get the Virtual IP Address
fRet = pInParams->GetCHString( L"VirtualIpAddress", sVip);
if (fRet)
{
szVip = (LPCWSTR) sVip;
// Check for an empty string
if (szVip != NULL && *szVip == UNICODE_NULL)
{
szVip = NULL;
}
// Check for null
if (szVip != NULL)
{
// If the VIP is "All Vip", then, fill in the numeric value
// directly from the macro, else use the conversion function.
// This is 'cos INADDR_NONE, the return value of inet_addr
// function (called by IpAddressFromAbcdWsz) in the failure
// case, is equivalent to the numeric value of CVY_DEF_ALL_VIP
if (_wcsicmp(szVip, CVY_DEF_ALL_VIP) == 0)
{
dwVip = CVY_ALL_VIP_NUMERIC_VALUE;
}
else
{
dwVip = IpAddressFromAbcdWsz(szVip);
if (dwVip == INADDR_NONE)
{
TRACE_CRIT("%!FUNC! Invalid value (%ls) passed for Vip",szVip);
Status = WBEM_E_INVALID_PARAMETER;
goto end;
}
}
}
}
// If present, Get the port number
// The return value fRet is used in the switch statement further down, so
// do NOT re-assign/change it
fRet = pInParams->GetDWORD(L"Port", dwPort);
switch(Opcode)
{
case WLBS_START:
case WLBS_STOP:
case WLBS_DRAIN:
case WLBS_SUSPEND:
case WLBS_RESUME:
CfgUtilControlCluster( szAdapterGuid, Opcode, 0, 0, NULL, &dwRetVal );
CfgUtilControlCluster( szAdapterGuid, WLBS_QUERY, 0, 0, &dwHostMap, &dwStatus );
// Fill the out parameter: Host Map
pOutParams->SetDWORD(L"HostMap", (DWORD) dwHostMap);
break;
case WLBS_PORT_ENABLE:
case WLBS_PORT_DISABLE:
case WLBS_PORT_DRAIN:
if ((szVip == NULL) || !fRet)
{
TRACE_CRIT("%!FUNC! Virtual IP Address or Port NOT passed for port operation : 0x%x", Opcode);
Status = WBEM_E_INVALID_PARAMETER;
goto end;
}
CfgUtilControlCluster( szAdapterGuid, Opcode, dwVip, dwPort, NULL, &dwRetVal );
CfgUtilControlCluster( szAdapterGuid, WLBS_QUERY_PORT_STATE, dwVip, dwPort, NULL, &dwStatus );
break;
case WLBS_QUERY:
CfgUtilControlCluster( szAdapterGuid, WLBS_QUERY, 0, 0, &dwHostMap, &dwStatus );
// Fill the out parameter: Host Map
pOutParams->SetDWORD(L"HostMap", (DWORD) dwHostMap);
dwRetVal = WLBS_OK;
break;
case WLBS_QUERY_PORT_STATE:
CfgUtilControlCluster( szAdapterGuid, WLBS_QUERY_PORT_STATE, dwVip, dwPort, NULL, &dwStatus );
dwRetVal = WLBS_OK;
break;
default:
TRACE_CRIT("%!FUNC! Invalid value (0x%x) passed for Operation",Opcode);
Status = WBEM_E_INVALID_PARAMETER;
goto end;
}
//
// Fill out the out parameters: return value, cluster/port status
//
pOutParams->SetDWORD(L"ReturnValue", dwRetVal);
pOutParams->SetDWORD(L"CurrentState", dwStatus);
end:
TRACE_VERB(L"<-%!FUNC! returns 0x%08lx", (UINT) Status);
return Status;
}
WBEMSTATUS
ProvGetClusterMembers(
CInstance *pInParams,
CInstance *pOutParams
)
/*++
WMI provider wrapper around NlbConfigurationUpdate::ProvGetClusterMembers
--*/
{
WBEMSTATUS Status;
LPCWSTR szAdapterGuid;
CHString sAdapterGuid;
bool fRet;
NLB_CLUSTER_MEMBER_INFO *pMembers = NULL;
DWORD dwRetVal, dwStatus, dwNumHosts;
LPWSTR *ppwszHostId = NULL;
LPWSTR *ppwszDedicatedIpAddress= NULL;
LPWSTR *ppwszHostName = NULL;
SAFEARRAY *pSAHostId = NULL;
SAFEARRAY *pSADedicatedIpAddress = NULL;
SAFEARRAY *pSAHostName = NULL;
TRACE_VERB(L"->");
dwRetVal = dwStatus = WLBS_FAILURE;
Status = WBEM_NO_ERROR;
// Get the Adapter GUID
fRet = pInParams->GetCHString(L"AdapterGuid", sAdapterGuid);
if (!fRet)
{
TRACE_CRIT(L"Missing adapter guid!");
Status = WBEM_E_INVALID_PARAMETER;
goto end;
}
else
{
szAdapterGuid = (LPCWSTR) sAdapterGuid;
if (szAdapterGuid == NULL || *szAdapterGuid == UNICODE_NULL)
{
TRACE_CRIT(L"Null or empty adapter guid!");
Status = WBEM_E_INVALID_PARAMETER;
goto end;
}
}
dwStatus = CfgUtilGetClusterMembers(szAdapterGuid, &dwNumHosts, &pMembers);
pOutParams->SetDWORD(L"ReturnValue", dwStatus);
if (dwStatus != WBEM_S_NO_ERROR)
{
dwNumHosts = 0;
pMembers = NULL;
TRACE_CRIT(L"CfgUtilGetClusterMembers failed with 0x%x", dwStatus);
goto end;
}
ASSERT (pMembers != NULL);
#define MY_MAX_HOSTID_DIGITS 3
ppwszHostId = CfgUtilsAllocateStringArray(dwNumHosts, MY_MAX_HOSTID_DIGITS);
ppwszDedicatedIpAddress = CfgUtilsAllocateStringArray(dwNumHosts, WLBS_MAX_CL_IP_ADDR);
ppwszHostName = CfgUtilsAllocateStringArray(dwNumHosts, CVY_MAX_FQDN + 1);
if (ppwszHostId == NULL || ppwszDedicatedIpAddress == NULL || ppwszHostName == NULL)
{
TRACE_CRIT(L"Memory allocation failed for strings of host information");
Status = WBEM_E_OUT_OF_MEMORY;
goto end;
}
//
// Copy the cluster member information into the string arrays for the caller
//
for (int i=0; i < dwNumHosts; i++)
{
ASSERT (pMembers[i].HostId <= WLBS_MAX_HOSTS);
if (pMembers[i].HostId > WLBS_MAX_HOSTS)
{
TRACE_CRIT(L"Illegal host id %d obatined from query to cluster", pMembers[i].HostId);
Status = WBEM_E_FAILED;
goto end;
}
_itow(pMembers[i].HostId, ppwszHostId[i], 10);
wcsncpy(ppwszDedicatedIpAddress[i], pMembers[i].DedicatedIpAddress, WLBS_MAX_CL_IP_ADDR);
(ppwszDedicatedIpAddress[i])[WLBS_MAX_CL_IP_ADDR - 1] = L'\0';
wcsncpy(ppwszHostName[i], pMembers[i].HostName, CVY_MAX_FQDN + 1);
(ppwszHostName[i])[CVY_MAX_FQDN] = L'\0';
}
Status = CfgUtilSafeArrayFromStrings(
(LPCWSTR *) ppwszHostId,
dwNumHosts,
&pSAHostId
);
if (FAILED(Status))
{
TRACE_CRIT(L"CfgUtilSafeArrayFromStrings for ppwszHostId failed with 0x%x", Status);
pSAHostId = NULL;
goto end;
}
Status = CfgUtilSafeArrayFromStrings(
(LPCWSTR *) ppwszDedicatedIpAddress,
dwNumHosts,
&pSADedicatedIpAddress
);
if (FAILED(Status))
{
TRACE_CRIT(L"CfgUtilSafeArrayFromStrings for ppwszDedicatedIpAddress failed with 0x%x", Status);
pSADedicatedIpAddress = NULL;
goto end;
}
Status = CfgUtilSafeArrayFromStrings(
(LPCWSTR *) ppwszHostName,
dwNumHosts,
&pSAHostName
);
if (FAILED(Status))
{
TRACE_CRIT(L"CfgUtilSafeArrayFromStrings for ppwszHostName failed with 0x%x", Status);
pSAHostName = NULL;
goto end;
}
if (pSAHostId != NULL)
{
pOutParams->SetStringArray(L"HostIds", *pSAHostId);
}
if (pSADedicatedIpAddress != NULL)
{
pOutParams->SetStringArray(L"DedicatedIpAddresses", *pSADedicatedIpAddress);
}
if (pSAHostName != NULL)
{
pOutParams->SetStringArray(L"HostNames", *pSAHostName);
}
//
// Everything is cool. Reset the status in case the last call gave it some funky, non-failure value.
//
Status = WBEM_NO_ERROR;
end:
if (pSAHostId != NULL)
{
SafeArrayDestroy(pSAHostId);
pSAHostId = NULL;
}
if (pSADedicatedIpAddress != NULL)
{
SafeArrayDestroy(pSADedicatedIpAddress);
pSADedicatedIpAddress = NULL;
}
if (pSAHostName != NULL)
{
SafeArrayDestroy(pSAHostName);
pSAHostName = NULL;
}
if (ppwszHostId != NULL)
{
delete [] ppwszHostId;
ppwszHostId = NULL;
}
if (ppwszDedicatedIpAddress != NULL)
{
delete [] ppwszDedicatedIpAddress;
ppwszDedicatedIpAddress = NULL;
}
if (ppwszHostName != NULL)
{
delete [] ppwszHostName;
ppwszHostName = NULL;
}
if (pMembers != NULL)
{
delete [] pMembers;
}
TRACE_VERB(L"<-returns 0x%08lx", (UINT) Status);
return Status;
}
WBEMSTATUS
ProvRegisterManagementApplication(
CInstance *pInParams,
CInstance *pOutParams
)
/*++
WMI provider wrapper around NlbConfigurationUpdate::ProvControlCluster
TODO:
Read from NLB registry location to see if a differnt GUID is already
register -- if so fail, else set this information, else
return failure and set the out params to the existing application
name and company name.
--*/
{
return WBEM_E_PROVIDER_NOT_CAPABLE;
}
WBEMSTATUS
ProvUnregisterManagementApplication(
CInstance *pInParams,
CInstance *pOutParams
)
/*++
WMI provider wrapper around NlbConfigurationUpdate::ProvControlCluster
TODO:
Read from NLB registry location to see if a the specified GUID is
is registered if so remove the stuff from the registry.
--*/
{
return WBEM_E_PROVIDER_NOT_CAPABLE;
}