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