/****************************************************************** 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 // This must be the first include. #include "private.h" #include #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; }