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

6686 lines
173 KiB

  1. //***************************************************************************
  2. // CFGUTIL.CPP
  3. //
  4. //
  5. // Module: WMI Framework Instance provider
  6. //
  7. // Purpose: Low-level utilities to configure NICs -- bind/unbind,
  8. // get/set IP address lists, and get/set NLB cluster params.
  9. //
  10. // Copyright (c)2001 Microsoft Corporation, All Rights Reserved
  11. //
  12. // History:
  13. //
  14. // 04/05/01 JosephJ Created (original version, called cfgutils.cpp under
  15. // nlbmgr\provider).
  16. // 07/23/01 JosephJ Moved functionality to lib.
  17. //
  18. //***************************************************************************
  19. #include "private.h"
  20. #include <clusapi.h>
  21. //
  22. // Following two needed ONLY for RtlEncryptMemory...
  23. //
  24. #include <ntsecapi.h>
  25. #include <crypt.h>
  26. #include "cfgutil.tmh"
  27. #define NLB_API_DLL_NAME L"wlbsctrl.dll"
  28. #define NLB_CLIENT_NAME L"NLBManager"
  29. //
  30. // This magic has the side effect defining "smart pointers"
  31. // IWbemServicesPtr
  32. // IWbemLocatorPtr
  33. // IWbemClassObjectPtr
  34. // IEnumWbemClassObjectPtr
  35. // IWbemCallResultPtr
  36. // IWbemStatusCodeTextPtr
  37. //
  38. // These types automatically call the COM Release function when the
  39. // objects go out of scope.
  40. //
  41. _COM_SMARTPTR_TYPEDEF(IWbemServices, __uuidof(IWbemServices));
  42. _COM_SMARTPTR_TYPEDEF(IWbemLocator, __uuidof(IWbemLocator));
  43. _COM_SMARTPTR_TYPEDEF(IEnumWbemClassObject, __uuidof(IEnumWbemClassObject));
  44. _COM_SMARTPTR_TYPEDEF(IWbemCallResult, __uuidof(IWbemCallResult));
  45. _COM_SMARTPTR_TYPEDEF(IWbemStatusCodeText, __uuidof(IWbemStatusCodeText));
  46. WBEMSTATUS
  47. CfgUtilGetWmiAdapterObjFromAdapterConfigurationObj(
  48. IN IWbemServicesPtr spWbemServiceIF, // smart pointer
  49. IN IWbemClassObjectPtr spObj, // smart pointer
  50. OUT IWbemClassObjectPtr &spAdapterObj // smart pointer, by reference
  51. );
  52. USHORT crc16(LPCWSTR ptr);
  53. #if OBSOLETE
  54. WBEMSTATUS
  55. get_string_parameter(
  56. IN IWbemClassObjectPtr spObj,
  57. IN LPCWSTR szParameterName,
  58. OUT LPWSTR *ppStringValue
  59. );
  60. #endif // OBSOLETE
  61. WBEMSTATUS
  62. get_nic_instance(
  63. IN IWbemServicesPtr spWbemServiceIF,
  64. IN LPCWSTR szNicGuid,
  65. OUT IWbemClassObjectPtr &sprefObj
  66. );
  67. WBEMSTATUS
  68. get_multi_string_parameter(
  69. IN IWbemClassObjectPtr spObj,
  70. IN LPCWSTR szParameterName,
  71. IN UINT MaxStringLen, // in wchars, INCLUDING space for trailing zeros.
  72. OUT UINT *pNumItems,
  73. OUT LPCWSTR *ppStringValue
  74. );
  75. WBEMSTATUS
  76. set_string_parameter(
  77. IN IWbemClassObjectPtr spObj,
  78. IN LPCWSTR szParameterName,
  79. IN LPCWSTR szValue
  80. );
  81. WBEMSTATUS
  82. set_multi_string_parameter(
  83. IN IWbemClassObjectPtr spObj,
  84. IN LPCWSTR szParameterName,
  85. IN UINT MaxStringLen, // in wchars, INCLUDING space for trailing zeros.
  86. IN UINT NumItems,
  87. IN LPCWSTR pStringValue
  88. );
  89. WBEMSTATUS
  90. get_friendly_name_from_registry(
  91. LPCWSTR szGuid,
  92. LPWSTR *pszFriendlyName
  93. );
  94. //
  95. // This locally-defined class implements interfaces to WMI, NetConfig,
  96. // and low-level NLB APIs.
  97. //
  98. class CfgUtils
  99. {
  100. public:
  101. //
  102. // Initialization function -- call before using any other functions
  103. //
  104. WBEMSTATUS
  105. Initialize(
  106. BOOL fServer, // TRUE == try to dynamically load wlbsstrl.dll.
  107. BOOL fNoPing // TRUE == CfgUtilPing becomes a no-op, always
  108. // returning success.
  109. );
  110. //
  111. // Deinitialization function -- call after using any other functions
  112. //
  113. VOID
  114. Deinitialize(
  115. VOID
  116. );
  117. //
  118. // Constructor and distructor.
  119. //
  120. CfgUtils(VOID)
  121. {
  122. //
  123. // WARNING: We do a blanked zero memory initialization of our entire
  124. // structure. Any other initialization should go into the
  125. // Initialize() function.
  126. //
  127. ZeroMemory(this, sizeof(*this));
  128. InitializeCriticalSection(&m_Crit);
  129. }
  130. ~CfgUtils()
  131. {
  132. DeleteCriticalSection(&m_Crit);
  133. }
  134. //
  135. // Check if we're initialized
  136. //
  137. BOOL
  138. IsInitalized(VOID)
  139. {
  140. return m_ComInitialized && m_WmiInitialized;
  141. }
  142. // OBSOLETE IWbemStatusCodeTextPtr m_spWbemStatusIF; // Smart pointer
  143. IWbemServicesPtr m_spWbemServiceIF; // Smart pointer
  144. //
  145. // Following are pointers to functions we call from dynamically-
  146. // loaded wlbsctrl.dll. m_hWlbsCtrlDll is the module handle
  147. // returned from LoadLibrary("wlbsctrl.dll");
  148. // It should be freed in the context of this->Deintialize.
  149. //
  150. HMODULE m_hWlbsCtrlDll;
  151. BOOL m_NLBApiHooksPresent; // Was Loadlibrary/GetProcAddress/WlbsOpen successful ?
  152. WlbsOpen_FUNC m_pfWlbsOpen; // NLB api to create connection to NLB driver, It returns INVALID_HANDLE_VALUE (NOT NULL) on failure
  153. WlbsLocalClusterControl_FUNC m_pfWlbsLocalClusterControl; // NLB api to control local NLB operation
  154. WlbsAddPortRule_FUNC m_pfWlbsAddPortRule; // NLB api to add a port rule
  155. WlbsDeleteAllPortRules_FUNC m_pfWlbsDeleteAllPortRules; // NLB api to delete all port rules
  156. WlbsEnumPortRules_FUNC m_pfWlbsEnumPortRules;// NLB api to enumerate port rules
  157. WlbsSetDefaults_FUNC m_pfWlbsSetDefaults; // NLB api to set default values for NLB configuration
  158. WlbsValidateParams_FUNC m_pfWlbsValidateParams; // NLB api to validate registry parameters
  159. WlbsParamReadReg_FUNC m_pfWlbsParamReadReg; // NLB api to read registry parameters
  160. //
  161. // We need to define this prototype here, because it's not exported
  162. // in wlbsconfig.h
  163. typedef BOOL (WINAPI *WlbsParamWriteReg_FUNC)
  164. (
  165. const GUID & pAdapterGuid,
  166. PWLBS_REG_PARAMS reg_data
  167. );
  168. WlbsParamWriteReg_FUNC m_pfWlbsParamWriteReg; // NLB api to write registry parameters
  169. WlbsWriteAndCommitChanges_FUNC m_pfWlbsWriteAndCommitChanges; // NLB api to write parametrs into registry and to commit changes to NLB driver
  170. WlbsSetRemotePassword_FUNC m_pfWlbsSetRemotePassword; // NLB api to set the remote password.
  171. WlbsGetClusterMembers_FUNC m_pfWlbsGetClusterMembers; // NLB api to retrieve information on members of the cluster
  172. BOOL
  173. DisablePing(VOID)
  174. {
  175. return m_fNoPing!=FALSE;
  176. }
  177. private:
  178. //
  179. // A single lock serialzes all access.
  180. // Use mfn_Lock and mfn_Unlock.
  181. //
  182. CRITICAL_SECTION m_Crit;
  183. BOOL m_ComInitialized;
  184. BOOL m_WmiInitialized;
  185. BOOL m_WinsockInitialized;
  186. BOOL m_fNoPing;
  187. VOID
  188. mfn_Lock(
  189. VOID
  190. )
  191. {
  192. EnterCriticalSection(&m_Crit);
  193. }
  194. VOID
  195. mfn_Unlock(
  196. VOID
  197. )
  198. {
  199. LeaveCriticalSection(&m_Crit);
  200. }
  201. VOID
  202. mfn_LoadWlbsFuncs(VOID);
  203. VOID
  204. mfn_UnloadWlbsFuncs(VOID); // ok to call multiple times (i.e. idempotent).
  205. };
  206. //
  207. // This class manages NetCfg interfaces
  208. //
  209. class MyNetCfg
  210. {
  211. public:
  212. MyNetCfg(VOID)
  213. {
  214. m_pINetCfg = NULL;
  215. m_pLock = NULL;
  216. }
  217. ~MyNetCfg()
  218. {
  219. ASSERT(m_pINetCfg==NULL);
  220. ASSERT(m_pLock==NULL);
  221. }
  222. WBEMSTATUS
  223. Initialize(
  224. BOOL fWriteLock
  225. );
  226. VOID
  227. Deinitialize(
  228. VOID
  229. );
  230. WBEMSTATUS
  231. GetNlbCompatibleNics(
  232. OUT LPWSTR **ppszNics,
  233. OUT UINT *pNumNics,
  234. OUT UINT *pNumBoundToNlb // OPTIONAL
  235. );
  236. WBEMSTATUS
  237. GetNicIF(
  238. IN LPCWSTR szNicGuid,
  239. OUT INetCfgComponent **ppINic
  240. );
  241. WBEMSTATUS
  242. GetBindingIF(
  243. IN LPCWSTR szComponent,
  244. OUT INetCfgComponentBindings **ppIBinding
  245. );
  246. typedef enum
  247. {
  248. NOOP,
  249. BIND,
  250. UNBIND
  251. } UPDATE_OP;
  252. WBEMSTATUS
  253. UpdateBindingState(
  254. IN LPCWSTR szNic,
  255. IN LPCWSTR szComponent,
  256. IN UPDATE_OP Op,
  257. OUT BOOL *pfBound
  258. );
  259. static
  260. WBEMSTATUS
  261. GetWriteLockState(
  262. OUT BOOL *pfCanLock,
  263. LPWSTR *pszHeldBy // OPTIONAL, free using delete[].
  264. );
  265. private:
  266. INetCfg *m_pINetCfg;
  267. INetCfgLock *m_pLock;
  268. }; // Class MyNetCfg
  269. //
  270. // We keep a single global instance of this class around currently...
  271. //
  272. CfgUtils g_CfgUtils;
  273. WBEMSTATUS
  274. CfgUtilInitialize(BOOL fServer, BOOL fNoPing)
  275. {
  276. return g_CfgUtils.Initialize(fServer, fNoPing);
  277. }
  278. VOID
  279. CfgUtilDeitialize(VOID)
  280. {
  281. return g_CfgUtils.Deinitialize();
  282. }
  283. WBEMSTATUS
  284. CfgUtils::Initialize(BOOL fServer, BOOL fNoPing)
  285. {
  286. WBEMSTATUS Status = WBEM_E_INITIALIZATION_FAILURE;
  287. HRESULT hr;
  288. TRACE_INFO(L"-> CfgUtils::Initialize(fServer=%lu, fNoPing=%lu)",
  289. fServer, fNoPing);
  290. mfn_Lock();
  291. //
  292. // Initialize COM
  293. //
  294. {
  295. hr = CoInitializeEx(0, COINIT_DISABLE_OLE1DDE| COINIT_MULTITHREADED);
  296. if ( FAILED(hr) )
  297. {
  298. TRACE_CRIT(L"CfgUtils: Failed to initialize COM library (hr=0x%08lx)", hr);
  299. goto end;
  300. }
  301. m_ComInitialized = TRUE;
  302. }
  303. //
  304. // WMI Initialization
  305. //
  306. {
  307. IWbemLocatorPtr spWbemLocatorIF = NULL; // Smart pointer
  308. #if OBSOLETE
  309. //
  310. // Get error text generator interface
  311. //
  312. SCODE sc = CoCreateInstance(
  313. CLSID_WbemStatusCodeText,
  314. 0,
  315. CLSCTX_INPROC_SERVER,
  316. IID_IWbemStatusCodeText,
  317. (LPVOID *) &m_spWbemStatusIF
  318. );
  319. if( sc != S_OK )
  320. {
  321. ASSERT(m_spWbemStatusIF == NULL); // smart pointer
  322. TRACE_CRIT(L"CfgUtils: CoCreateInstance IWbemStatusCodeText failure\n");
  323. goto end;
  324. }
  325. TRACE_INFO(L"CfgUtils: m_spIWbemStatusIF=0x%p\n", (PVOID) m_spWbemStatusIF);
  326. #endif // OBSOLETE
  327. //
  328. // Get "locator" interface
  329. //
  330. hr = CoCreateInstance(
  331. CLSID_WbemLocator, 0,
  332. CLSCTX_INPROC_SERVER,
  333. IID_IWbemLocator,
  334. (LPVOID *) &spWbemLocatorIF
  335. );
  336. if (FAILED(hr))
  337. {
  338. ASSERT(spWbemLocatorIF == NULL); // smart pointer
  339. TRACE_CRIT(L"CoCreateInstance IWebmLocator failed 0x%08lx", (UINT)hr);
  340. goto end;
  341. }
  342. //
  343. // Get interface to provider for NetworkAdapter class objects
  344. // on the local machine
  345. //
  346. _bstr_t serverPath = L"root\\cimv2";
  347. hr = spWbemLocatorIF->ConnectServer(
  348. serverPath,
  349. NULL, // strUser,
  350. NULL, // strPassword,
  351. NULL,
  352. 0,
  353. NULL,
  354. NULL,
  355. &m_spWbemServiceIF
  356. );
  357. if (FAILED(hr))
  358. {
  359. ASSERT(m_spWbemServiceIF == NULL); // smart pointer
  360. TRACE_CRIT(L"ConnectServer to cimv2 failed 0x%08lx", (UINT)hr);
  361. goto end;
  362. }
  363. TRACE_INFO(L"CfgUtils: m_spIWbemServiceIF=0x%p\n", (PVOID) m_spWbemServiceIF);
  364. hr = CoSetProxyBlanket(
  365. m_spWbemServiceIF,
  366. RPC_C_AUTHN_WINNT,
  367. RPC_C_AUTHZ_DEFAULT, // RPC_C_AUTHZ_NAME,
  368. COLE_DEFAULT_PRINCIPAL, // NULL,
  369. RPC_C_AUTHN_LEVEL_DEFAULT,
  370. RPC_C_IMP_LEVEL_IMPERSONATE,
  371. COLE_DEFAULT_AUTHINFO, // NULL,
  372. EOAC_DEFAULT // EOAC_NONE
  373. );
  374. if (FAILED(hr))
  375. {
  376. TRACE_INFO(L"Error 0x%08lx setting proxy blanket", (UINT) hr);
  377. goto end;
  378. }
  379. //
  380. // Release locator interface.
  381. //
  382. // <NO need to do this explicitly, because this is a smart pointer>
  383. //
  384. spWbemLocatorIF = NULL;
  385. m_WmiInitialized = TRUE;
  386. }
  387. //
  388. // Netconfig Initialization
  389. //
  390. {
  391. // Nothing to do here...
  392. }
  393. //
  394. // WLBS API Initialization
  395. //
  396. //
  397. // Dynamically load selected entrypoints from wlbsctrl.dll.
  398. // We do not fail initialization if this operation fails.
  399. // (Because this could be running on a machine that doesn't have
  400. // wlbsctrl.dll). Instead we set/clear a flag (m_NLBApiHooksPresent)
  401. //
  402. //
  403. if (fServer)
  404. {
  405. mfn_LoadWlbsFuncs();
  406. }
  407. Status = WBEM_NO_ERROR;
  408. //
  409. // Winsock initialization. We don't consider it an error if we fail.
  410. // As only certain functions will fail (eg CfgUtilPing).
  411. //
  412. {
  413. WSADATA data;
  414. int iWsaStatus = WSAStartup (WINSOCK_VERSION, & data);
  415. if (iWsaStatus == 0)
  416. {
  417. TRACE_INFO("%!FUNC! Winsock initialized successfully");
  418. m_WinsockInitialized = TRUE;
  419. }
  420. else
  421. {
  422. TRACE_CRIT("%!FUNC! WARNING Winsock initialization failed with error 0x%lx",
  423. iWsaStatus);
  424. m_WinsockInitialized = FALSE;
  425. }
  426. }
  427. end:
  428. mfn_Unlock();
  429. if (FAILED(Status))
  430. {
  431. TRACE_CRIT("%!FUNC! -- FAILING INITIALIZATION! Status=0x%08lx",
  432. (UINT) Status);
  433. CfgUtils::Deinitialize();
  434. }
  435. //
  436. // Set the NoPing field...
  437. //
  438. m_fNoPing = fNoPing;
  439. TRACE_INFO(L"<- CfgUtils::Initialize(Status=0x%08lx)", (UINT) Status);
  440. return Status;
  441. }
  442. VOID
  443. CfgUtils::Deinitialize(
  444. VOID
  445. )
  446. //
  447. // NOTE: can be called in the context of a failed initialization.
  448. //
  449. {
  450. TRACE_INFO(L"-> CfgUtils::Deinitialize");
  451. mfn_Lock();
  452. //
  453. // Winsock deinitialization.
  454. //
  455. if (m_WinsockInitialized)
  456. {
  457. WSACleanup();
  458. m_WinsockInitialized = FALSE;
  459. }
  460. //
  461. // De-initialize WLBS API
  462. //
  463. mfn_UnloadWlbsFuncs();
  464. //
  465. // Deinitialize Netconfig
  466. //
  467. //
  468. // Deinitialize WMI
  469. //
  470. {
  471. #if OBSOLETE
  472. //
  473. // Release interface to NetworkAdapter provider
  474. //
  475. if (m_spWbemStatusIF!= NULL)
  476. {
  477. // Smart pointer.
  478. m_spWbemStatusIF= NULL;
  479. }
  480. #endif // OBSOLETE
  481. if (m_spWbemServiceIF!= NULL)
  482. {
  483. // Smart pointer.
  484. m_spWbemServiceIF= NULL;
  485. }
  486. m_WmiInitialized = FALSE;
  487. }
  488. //
  489. // Deinitialize COM.
  490. //
  491. if (m_ComInitialized)
  492. {
  493. TRACE_CRIT(L"CfgUtils: Deinitializing COM");
  494. CoUninitialize();
  495. m_ComInitialized = FALSE;
  496. }
  497. mfn_Unlock();
  498. TRACE_INFO(L"<- CfgUtils::Deinitialize");
  499. }
  500. VOID
  501. CfgUtils::mfn_LoadWlbsFuncs(VOID)
  502. {
  503. BOOL fSuccess = FALSE;
  504. HMODULE DllHdl;
  505. m_NLBApiHooksPresent = FALSE;
  506. if ((DllHdl = LoadLibrary(NLB_API_DLL_NAME)) == NULL)
  507. {
  508. TRACE_CRIT("%!FUNC! LoadLibrary of %ls failed with error : 0x%x", NLB_API_DLL_NAME, GetLastError());
  509. }
  510. else
  511. {
  512. m_pfWlbsOpen = (WlbsOpen_FUNC) GetProcAddress(DllHdl, "WlbsOpen");
  513. m_pfWlbsLocalClusterControl = (WlbsLocalClusterControl_FUNC) GetProcAddress(DllHdl, "WlbsLocalClusterControl");
  514. m_pfWlbsAddPortRule = (WlbsAddPortRule_FUNC) GetProcAddress(DllHdl, "WlbsAddPortRule");
  515. m_pfWlbsDeleteAllPortRules = (WlbsDeleteAllPortRules_FUNC) GetProcAddress(DllHdl, "WlbsDeleteAllPortRules");
  516. m_pfWlbsEnumPortRules = (WlbsEnumPortRules_FUNC) GetProcAddress(DllHdl, "WlbsEnumPortRules");
  517. m_pfWlbsSetDefaults = (WlbsSetDefaults_FUNC) GetProcAddress(DllHdl, "WlbsSetDefaults");
  518. m_pfWlbsValidateParams = (WlbsValidateParams_FUNC) GetProcAddress(DllHdl, "WlbsValidateParams");
  519. m_pfWlbsParamReadReg = (WlbsParamReadReg_FUNC) GetProcAddress(DllHdl, "WlbsParamReadReg");
  520. m_pfWlbsParamWriteReg = (WlbsParamWriteReg_FUNC) GetProcAddress(DllHdl, "ParamWriteReg");
  521. m_pfWlbsWriteAndCommitChanges = (WlbsWriteAndCommitChanges_FUNC) GetProcAddress(DllHdl, "WlbsWriteAndCommitChanges");
  522. m_pfWlbsSetRemotePassword = (WlbsSetRemotePassword_FUNC) GetProcAddress(DllHdl, "WlbsSetRemotePassword");
  523. m_pfWlbsGetClusterMembers = (WlbsGetClusterMembers_FUNC) GetProcAddress(DllHdl, "WlbsGetClusterMembers");
  524. if((m_pfWlbsOpen == NULL)
  525. || (m_pfWlbsLocalClusterControl == NULL)
  526. || (m_pfWlbsAddPortRule == NULL)
  527. || (m_pfWlbsDeleteAllPortRules == NULL)
  528. || (m_pfWlbsEnumPortRules == NULL)
  529. || (m_pfWlbsSetDefaults == NULL)
  530. || (m_pfWlbsValidateParams == NULL)
  531. || (m_pfWlbsParamReadReg == NULL)
  532. || (m_pfWlbsParamWriteReg == NULL)
  533. || (m_pfWlbsWriteAndCommitChanges == NULL)
  534. || (m_pfWlbsSetRemotePassword == NULL)
  535. || (m_pfWlbsGetClusterMembers == NULL))
  536. {
  537. TRACE_CRIT("%!FUNC! GetProcAddress failed for NLB API DLL functions");
  538. FreeLibrary(DllHdl);
  539. DllHdl = NULL;
  540. }
  541. else
  542. {
  543. fSuccess = TRUE;
  544. }
  545. }
  546. if (fSuccess)
  547. {
  548. m_hWlbsCtrlDll = DllHdl;
  549. m_NLBApiHooksPresent = TRUE;
  550. }
  551. else
  552. {
  553. mfn_UnloadWlbsFuncs(); // this will zero-out the function pointers.
  554. }
  555. return;
  556. }
  557. VOID
  558. CfgUtils::mfn_UnloadWlbsFuncs(VOID)
  559. //
  560. // ok to call multiple times (i.e. idempotent).
  561. // MUST be called with lock held.
  562. //
  563. {
  564. m_NLBApiHooksPresent = FALSE;
  565. m_pfWlbsOpen = NULL;
  566. m_pfWlbsLocalClusterControl = NULL;
  567. m_pfWlbsAddPortRule = NULL;
  568. m_pfWlbsDeleteAllPortRules = NULL;
  569. m_pfWlbsEnumPortRules = NULL;
  570. m_pfWlbsSetDefaults = NULL;
  571. m_pfWlbsValidateParams = NULL;
  572. m_pfWlbsParamReadReg = NULL ;
  573. m_pfWlbsParamWriteReg = NULL ;
  574. m_pfWlbsWriteAndCommitChanges = NULL;
  575. m_pfWlbsSetRemotePassword = NULL;
  576. m_pfWlbsGetClusterMembers = NULL;
  577. if (m_hWlbsCtrlDll != NULL)
  578. {
  579. FreeLibrary(m_hWlbsCtrlDll);
  580. m_hWlbsCtrlDll = NULL;
  581. }
  582. }
  583. //***************************************************************************
  584. //
  585. // SCODE CfgUtilParseAuthorityUserArgs
  586. //
  587. // DESCRIPTION:
  588. //
  589. // This function is a straight lift from the wmi sdk sample project : utillib,
  590. // File : wbemsec.cpp, Function : ParseAuthorityUserArgs
  591. // This function is used internally only.
  592. //
  593. // Examines the Authority and User argument and determines the authentication
  594. // type and possibly extracts the domain name from the user arugment in the
  595. // NTLM case. For NTLM, the domain can be at the end of the authentication
  596. // string, or in the front of the user name, ex; "redmond\a-davj"
  597. //
  598. // PARAMETERS:
  599. //
  600. // AuthArg Output, contains the domain name
  601. // UserArg Output, user name
  602. // Authority Input
  603. // User Input
  604. //
  605. // RETURN VALUE: WBEMSTATUS
  606. //
  607. //***************************************************************************
  608. WBEMSTATUS CfgUtilParseAuthorityUserArgs(BSTR & AuthArg, BSTR & UserArg, LPCWSTR Authority, LPCWSTR User)
  609. {
  610. TRACE_INFO(L"-> %!FUNC!");
  611. //
  612. // If the Authority string is passed, then, it better begin with "NTLMDOMAIN:"
  613. //
  614. if(!(Authority == NULL || wcslen(Authority) == 0 || !_wcsnicmp(Authority, L"NTLMDOMAIN:",11)))
  615. {
  616. TRACE_CRIT(L"%!FUNC! Invalid authority string : %ls, Must be NULL or empty or begin with \"NTLMDOMAIN:\"",Authority);
  617. TRACE_INFO(L"<- %!FUNC! returning WBEM_E_INVALID_PARAMETER");
  618. return WBEM_E_INVALID_PARAMETER;
  619. }
  620. // The ntlm case is more complex. There are four cases
  621. // 1) Authority = NTLMDOMAIN:name" and User = "User"
  622. // 2) Authority = NULL and User = "User"
  623. // 3) Authority = "NTLMDOMAIN:" User = "domain\user"
  624. // 4) Authority = NULL and User = "domain\user"
  625. //
  626. // first step is to determine if there is a backslash in the user name somewhere between the
  627. // second and second to last character
  628. //
  629. WCHAR * pSlashInUser = NULL;
  630. if(User)
  631. {
  632. WCHAR * pEnd = (WCHAR *)User + wcslen(User) - 1;
  633. for(pSlashInUser = (WCHAR *)User; pSlashInUser <= pEnd; pSlashInUser++)
  634. if(*pSlashInUser == L'\\') // dont think forward slash is allowed!
  635. break;
  636. if(pSlashInUser > pEnd)
  637. pSlashInUser = NULL;
  638. }
  639. //
  640. // If Authority string is passed and it is of the form "NTLMDOMAIN:XXXX", copy over "XXXX" into
  641. // AuthArg. The only other form that it could take is "NTLMDOMAIN:", in which case, we leave
  642. // AuthArg to be NULL.
  643. //
  644. if(Authority && wcslen(Authority) > 11)
  645. {
  646. if(pSlashInUser)
  647. {
  648. TRACE_CRIT(L"%!FUNC! Invalid combination of User : %ls & Authority string : %ls",User,Authority);
  649. TRACE_INFO(L"<- %!FUNC! returning WBEM_E_INVALID_PARAMETER");
  650. return WBEM_E_INVALID_PARAMETER;
  651. }
  652. if ((AuthArg = SysAllocString(Authority + 11)) == NULL)
  653. {
  654. TRACE_CRIT(L"%!FUNC! Out of memory, Memory allocation failed for Authority string : %ls",Authority + 11);
  655. TRACE_INFO(L"<- %!FUNC! returning WBEM_E_OUT_OF_MEMORY");
  656. return WBEM_E_OUT_OF_MEMORY;
  657. }
  658. if(User)
  659. {
  660. UserArg = SysAllocString(User);
  661. TRACE_CRIT(L"%!FUNC! Out of memory, Memory allocation failed for User string : %ls",User);
  662. SysFreeString(AuthArg);
  663. TRACE_INFO(L"<- %!FUNC! returning WBEM_E_OUT_OF_MEMORY");
  664. return WBEM_E_OUT_OF_MEMORY;
  665. }
  666. TRACE_INFO(L"<- %!FUNC! returning WBEM_NO_ERROR");
  667. return WBEM_NO_ERROR;
  668. }
  669. else if(pSlashInUser)
  670. {
  671. // backslash was found in "User", extract the domain name present before the backslash
  672. int iDomLen = pSlashInUser-User;
  673. WCHAR cTemp[MAX_PATH];
  674. wcsncpy(cTemp, User, iDomLen);
  675. cTemp[iDomLen] = 0;
  676. if ((AuthArg = SysAllocString(cTemp)) == NULL)
  677. {
  678. TRACE_CRIT(L"%!FUNC! Out of memory, Memory allocation failed for Authority (\"Authority\\User\") string : %ls",cTemp);
  679. TRACE_INFO(L"<- %!FUNC! returning WBEM_E_OUT_OF_MEMORY");
  680. return WBEM_E_OUT_OF_MEMORY;
  681. }
  682. if(wcslen(pSlashInUser+1))
  683. {
  684. if ((UserArg = SysAllocString(pSlashInUser+1)) == NULL)
  685. {
  686. TRACE_CRIT(L"%!FUNC! Out of memory, Memory allocation failed for Authority (\"Authority\\User\") string : %ls",pSlashInUser+1);
  687. SysFreeString(AuthArg);
  688. TRACE_INFO(L"<- %!FUNC! returning WBEM_E_OUT_OF_MEMORY");
  689. return WBEM_E_OUT_OF_MEMORY;
  690. }
  691. }
  692. }
  693. else // User name did not contain backslash (ie. domain) AND (Authority was NOT passed or was = "NTLMDOMAIN:")
  694. {
  695. if(User)
  696. {
  697. if ((UserArg = SysAllocString(User)) == NULL)
  698. {
  699. TRACE_CRIT(L"%!FUNC! Out of memory, Memory allocation failed for User (No Authority) string : %ls",User);
  700. TRACE_INFO(L"<- %!FUNC! returning WBEM_E_OUT_OF_MEMORY");
  701. return WBEM_E_OUT_OF_MEMORY;
  702. }
  703. }
  704. }
  705. TRACE_INFO(L"<- %!FUNC! returning WBEM_NO_ERROR");
  706. return WBEM_NO_ERROR;
  707. }
  708. //
  709. // Gets the list of statically-bound IP addresses for the NIC.
  710. // Sets *pNumIpAddresses to 0 if DHCP
  711. //
  712. WBEMSTATUS
  713. CfgUtilGetIpAddressesAndFriendlyName(
  714. IN LPCWSTR szNic,
  715. OUT UINT *pNumIpAddresses,
  716. OUT NLB_IP_ADDRESS_INFO **ppIpInfo, // Free using c++ delete operator.
  717. OUT LPWSTR *pszFriendlyName // Optional, Free using c++ delete
  718. )
  719. {
  720. WBEMSTATUS Status = WBEM_NO_ERROR;
  721. IWbemClassObjectPtr spObj = NULL; // smart pointer
  722. HRESULT hr;
  723. LPCWSTR pAddrs = NULL;
  724. LPCWSTR pSubnets = NULL;
  725. UINT AddrCount = 0;
  726. UINT ValidAddrCount = 0;
  727. NLB_IP_ADDRESS_INFO *pIpInfo = NULL;
  728. TRACE_INFO(L"-> %!FUNC!(Nic=%ws)", szNic);
  729. *pNumIpAddresses = NULL;
  730. *ppIpInfo = NULL;
  731. if (pszFriendlyName!=NULL)
  732. {
  733. *pszFriendlyName = NULL;
  734. }
  735. //
  736. // If not initialized, fail...
  737. //
  738. if (!g_CfgUtils.IsInitalized())
  739. {
  740. TRACE_CRIT(L"%!FUNC!(Nic=%ws) FAILING because uninitialized", szNic);
  741. Status = WBEM_E_INITIALIZATION_FAILURE;
  742. goto end;
  743. }
  744. //
  745. // Get WMI instance to specific NIC
  746. //
  747. Status = get_nic_instance(
  748. g_CfgUtils.m_spWbemServiceIF,
  749. szNic,
  750. spObj // pass by reference
  751. );
  752. if (FAILED(Status))
  753. {
  754. ASSERT(spObj == NULL);
  755. goto end;
  756. }
  757. //
  758. // Extract IP addresses and subnets.
  759. //
  760. {
  761. //
  762. // This gets the ip addresses in a 2D WCHAR array -- inner dimension
  763. // is WLBS_MAX_CLI_IP_ADDR.
  764. //
  765. Status = get_multi_string_parameter(
  766. spObj,
  767. L"IPAddress", // szParameterName,
  768. WLBS_MAX_CL_IP_ADDR, // MaxStringLen - in wchars, incl null
  769. &AddrCount,
  770. &pAddrs
  771. );
  772. if (FAILED(Status))
  773. {
  774. pAddrs = NULL;
  775. goto end;
  776. }
  777. else
  778. {
  779. TRACE_INFO("GOT %lu IP ADDRESSES!", AddrCount);
  780. }
  781. UINT SubnetCount;
  782. Status = get_multi_string_parameter(
  783. spObj,
  784. L"IPSubnet", // szParameterName,
  785. WLBS_MAX_CL_NET_MASK, // MaxStringLen - in wchars, incl null
  786. &SubnetCount,
  787. &pSubnets
  788. );
  789. if (FAILED(Status))
  790. {
  791. pSubnets = NULL;
  792. goto end;
  793. }
  794. else if (SubnetCount != AddrCount)
  795. {
  796. TRACE_CRIT("FAILING SubnetCount!=AddressCount!");
  797. goto end;
  798. }
  799. }
  800. //
  801. // Convert IP addresses to our internal form.
  802. //
  803. if (AddrCount != 0)
  804. {
  805. pIpInfo = new NLB_IP_ADDRESS_INFO[AddrCount];
  806. if (pIpInfo == NULL)
  807. {
  808. TRACE_CRIT("get_multi_str_parm: Alloc failure!");
  809. Status = WBEM_E_OUT_OF_MEMORY;
  810. goto end;
  811. }
  812. ZeroMemory(pIpInfo, AddrCount*sizeof(*pIpInfo));
  813. for (UINT u=0;u<AddrCount; u++)
  814. {
  815. //
  816. // We extrace each IP address and it's corresponding subnet mask
  817. // from the 2 2D arrays and insert it into a NLB_IP_ADDRESS_INFO
  818. // structure.
  819. //
  820. LPCWSTR pIp = pAddrs+u*WLBS_MAX_CL_IP_ADDR;
  821. LPCWSTR pSub = pSubnets+u*WLBS_MAX_CL_NET_MASK;
  822. TRACE_INFO("IPaddress: %ws; SubnetMask:%ws", pIp, pSub);
  823. UINT len = wcslen(pIp);
  824. UINT len1 = wcslen(pSub);
  825. if ( (len < WLBS_MAX_CL_IP_ADDR) && (len1 < WLBS_MAX_CL_NET_MASK))
  826. {
  827. //
  828. // We can sometimes get blank IP addresses -- if there's been
  829. // an IP address conflict. So let's skip those.
  830. //
  831. if (*pIp==0 || _wcsspnp(pIp, L".0")==NULL)
  832. {
  833. TRACE_CRIT(L"%!FUNC! ignoring blank IP address!");
  834. }
  835. else
  836. {
  837. CopyMemory(pIpInfo[u].IpAddress, pIp, (len+1)*sizeof(WCHAR));
  838. CopyMemory(pIpInfo[u].SubnetMask, pSub, (len1+1)*sizeof(WCHAR));
  839. ValidAddrCount++;
  840. }
  841. }
  842. else
  843. {
  844. //
  845. // This would be an implementation error in get_multi_string_...
  846. //
  847. ASSERT(FALSE);
  848. Status = WBEM_E_CRITICAL_ERROR;
  849. goto end;
  850. }
  851. }
  852. }
  853. if (ValidAddrCount == 0)
  854. {
  855. delete[] pIpInfo; // could be NULL.
  856. pIpInfo = NULL;
  857. }
  858. //
  859. // If requested, get friendly name.
  860. // We don't fail if there's an error, just return the empty "" string.
  861. //
  862. if (pszFriendlyName != NULL)
  863. {
  864. IWbemClassObjectPtr spAdapterObj = NULL; // smart pointer
  865. LPWSTR szFriendlyName = NULL;
  866. WBEMSTATUS TmpStatus;
  867. TRACE_INFO(L"%!FUNC!: Getting friendly name for Nic %ws", szNic);
  868. #if USE_WMI_FOR_FRIENDLY_NAME
  869. //
  870. // Enabling this code block causes us to take over 1000 times as long
  871. // to get the friendly name -- so don't enable it!
  872. // This code (i.e. the slow version) ships in .Net Server Beta3,
  873. // but is commented out and repaced by the faster registry-growelling
  874. // version.
  875. //
  876. do
  877. {
  878. TmpStatus = CfgUtilGetWmiAdapterObjFromAdapterConfigurationObj(
  879. g_CfgUtils.m_spWbemServiceIF,
  880. spObj,
  881. spAdapterObj // passed by ref
  882. );
  883. if (FAILED(TmpStatus))
  884. {
  885. break;
  886. }
  887. TmpStatus = CfgUtilGetWmiStringParam(
  888. spAdapterObj,
  889. L"NetConnectionID",
  890. &szFriendlyName
  891. );
  892. if (FAILED(TmpStatus))
  893. {
  894. TRACE_CRIT("%!FUNC! Get NetConnectionID failed error=0x%08lx\n",
  895. (UINT) TmpStatus);
  896. }
  897. } while (FALSE);
  898. #else !USE_WMI_FOR_FRIENDLY_NAME
  899. Status = get_friendly_name_from_registry(szNic, &szFriendlyName);
  900. #endif // !USE_WMI_FOR_FRIENDLY_NAME
  901. if (FAILED(Status))
  902. {
  903. TRACE_INFO(L"%!FUNC!: Got error 0x%lx attempting to get friendly name", Status);
  904. szFriendlyName = NULL;
  905. Status = WBEM_NO_ERROR; // we'll ignore this..
  906. }
  907. else
  908. {
  909. TRACE_INFO(L"%!FUNC!: Got friendly name \"%ws\" for NIC %ws",
  910. szFriendlyName ? szFriendlyName:L"<null>", szNic);
  911. }
  912. if (szFriendlyName == NULL)
  913. {
  914. //
  915. // Try to put an empty string.
  916. //
  917. szFriendlyName = new WCHAR[1];
  918. if (szFriendlyName == NULL)
  919. {
  920. Status = WBEM_E_OUT_OF_MEMORY;
  921. TRACE_CRIT("%!FUNC! Alloc failure!");
  922. goto end;
  923. }
  924. *szFriendlyName = 0; // Empty string
  925. }
  926. *pszFriendlyName = szFriendlyName;
  927. szFriendlyName = NULL;
  928. }
  929. end:
  930. if (pAddrs != NULL)
  931. {
  932. delete pAddrs;
  933. }
  934. if (pSubnets != NULL)
  935. {
  936. delete pSubnets;
  937. }
  938. if (FAILED(Status))
  939. {
  940. if (pIpInfo != NULL)
  941. {
  942. delete[] pIpInfo;
  943. pIpInfo = NULL;
  944. }
  945. ValidAddrCount = 0;
  946. }
  947. *pNumIpAddresses = ValidAddrCount;
  948. *ppIpInfo = pIpInfo;
  949. spObj = NULL; // smart pointer
  950. TRACE_INFO(L"<- %!FUNC!(Nic=%ws) returns 0x%08lx", szNic, (UINT) Status);
  951. return Status;
  952. }
  953. //
  954. // Sets the list of statically-bound IP addresses for the NIC.
  955. // if NumIpAddresses is 0, the NIC is configured for DHCP.
  956. //
  957. WBEMSTATUS
  958. CfgUtilSetStaticIpAddresses(
  959. IN LPCWSTR szNic,
  960. IN UINT NumIpAddresses,
  961. IN NLB_IP_ADDRESS_INFO *pIpInfo
  962. )
  963. {
  964. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  965. IWbemClassObjectPtr spWbemInputInstance = NULL; // smart pointer
  966. WCHAR *rgIpAddresses = NULL;
  967. WCHAR *rgIpSubnets = NULL;
  968. LPWSTR pRelPath = NULL;
  969. NLB_IP_ADDRESS_INFO AutonetIpInfo;
  970. TRACE_INFO(L"-> %!FUNC!(Nic=%ws)", szNic);
  971. //
  972. // If not initialized, fail...
  973. //
  974. if (!g_CfgUtils.IsInitalized())
  975. {
  976. TRACE_CRIT(L"%!FUNC!(Nic=%ws) FAILING because uninitialized", szNic);
  977. Status = WBEM_E_INITIALIZATION_FAILURE;
  978. goto end;
  979. }
  980. if (NumIpAddresses == 0)
  981. {
  982. //
  983. // If there are no IP addresses specified, we generate a
  984. // random autonet address. This is because the wmi set operation
  985. // below simply fails if no addresses are specified. Strictly speaking
  986. // we should try dhcp.
  987. //
  988. // AutoNet address in the address range 169.254,
  989. // and it will give itself a class B subnet mask that
  990. // is 255.255.0.0.
  991. //
  992. ZeroMemory(&AutonetIpInfo, sizeof(AutonetIpInfo));
  993. UINT u1, u2;
  994. u1 = crc16(szNic);
  995. u2 = (u1>>8)&0xff;
  996. u1 = u1&0xff;
  997. if (u1>=255) u1=254;
  998. if (u2==0) u2=1;
  999. if (u2>=255) u2=254;
  1000. StringCbPrintf(AutonetIpInfo.IpAddress, sizeof(AutonetIpInfo.IpAddress), L"169.254.%lu.%lu", u1, u2);
  1001. ARRAYSTRCPY(AutonetIpInfo.SubnetMask, L"255.255.0.0");
  1002. NumIpAddresses = 1;
  1003. pIpInfo = &AutonetIpInfo;
  1004. // SECURITY BUGBUG -- consider compiling this out...
  1005. }
  1006. if (NumIpAddresses != 0)
  1007. {
  1008. //
  1009. // Convert IP addresses from our internal form into 2D arrays.
  1010. //
  1011. rgIpAddresses = new WCHAR[NumIpAddresses * WLBS_MAX_CL_IP_ADDR];
  1012. rgIpSubnets = new WCHAR[NumIpAddresses * WLBS_MAX_CL_NET_MASK];
  1013. if (rgIpAddresses == NULL || rgIpSubnets == NULL)
  1014. {
  1015. TRACE_CRIT("SetStaticIpAddresses: Alloc failure!");
  1016. Status = WBEM_E_OUT_OF_MEMORY;
  1017. goto end;
  1018. }
  1019. for (UINT u=0;u<NumIpAddresses; u++)
  1020. {
  1021. //
  1022. // We extrace each IP address and it's corresponding subnet mask
  1023. // from the 2 2D arrays and insert it into a NLB_IP_ADDRESS_INFO
  1024. // structure.
  1025. //
  1026. LPWSTR pIpDest = rgIpAddresses+u*WLBS_MAX_CL_IP_ADDR;
  1027. LPWSTR pSubDest = rgIpSubnets+u*WLBS_MAX_CL_NET_MASK;
  1028. LPCWSTR pIpSrc = pIpInfo[u].IpAddress;
  1029. LPCWSTR pSubSrc = pIpInfo[u].SubnetMask;
  1030. UINT len = wcslen(pIpSrc);
  1031. UINT len1 = wcslen(pSubSrc);
  1032. if ( (len < WLBS_MAX_CL_IP_ADDR) && (len1 < WLBS_MAX_CL_NET_MASK))
  1033. {
  1034. CopyMemory(pIpDest, pIpSrc, (len+1)*sizeof(WCHAR));
  1035. CopyMemory(pSubDest, pSubSrc, (len1+1)*sizeof(WCHAR));
  1036. }
  1037. else
  1038. {
  1039. //
  1040. // This would be an implementation error in get_multi_string_...
  1041. //
  1042. ASSERT(FALSE);
  1043. goto end;
  1044. }
  1045. }
  1046. }
  1047. //
  1048. // Get input instance and relpath...
  1049. //
  1050. Status = CfgUtilGetWmiInputInstanceAndRelPath(
  1051. g_CfgUtils.m_spWbemServiceIF,
  1052. L"Win32_NetworkAdapterConfiguration", // szClassName
  1053. L"SettingID", // szPropertyName
  1054. szNic, // szPropertyValue
  1055. L"EnableStatic", // szMethodName,
  1056. spWbemInputInstance, // smart pointer
  1057. &pRelPath // free using delete
  1058. );
  1059. if (FAILED(Status))
  1060. {
  1061. goto end;
  1062. }
  1063. //
  1064. // Set up input parameters to the call to Enable static.
  1065. //
  1066. {
  1067. //
  1068. // This gets the ip addresses in a 2D WCHAR array -- inner dimension
  1069. // is WLBS_MAX_CLI_IP_ADDR.
  1070. //
  1071. Status = set_multi_string_parameter(
  1072. spWbemInputInstance,
  1073. L"IPAddress", // szParameterName,
  1074. WLBS_MAX_CL_IP_ADDR, // MaxStringLen - in wchars, incl null
  1075. NumIpAddresses,
  1076. rgIpAddresses
  1077. );
  1078. if (FAILED(Status))
  1079. {
  1080. goto end;
  1081. }
  1082. else
  1083. {
  1084. TRACE_INFO("SET %lu IP ADDRESSES!", NumIpAddresses);
  1085. }
  1086. Status = set_multi_string_parameter(
  1087. spWbemInputInstance,
  1088. L"SubnetMask", // szParameterName,
  1089. WLBS_MAX_CL_NET_MASK, // MaxStringLen - in wchars, incl null
  1090. NumIpAddresses,
  1091. rgIpSubnets
  1092. );
  1093. if (FAILED(Status))
  1094. {
  1095. goto end;
  1096. }
  1097. }
  1098. //
  1099. // execute method and get the output result
  1100. // WARNING: we try this a few times because the wmi call apperears to
  1101. // suffer from a recoverable error. TODO: Need to get to the bottom of
  1102. // this.
  1103. //
  1104. UINT uiMaxTries = 10;
  1105. for (UINT NumTries=uiMaxTries; NumTries--;)
  1106. {
  1107. HRESULT hr;
  1108. IWbemClassObjectPtr spWbemOutput = NULL; // smart pointer.
  1109. _variant_t v_retVal;
  1110. TRACE_CRIT("Going to call EnableStatic");
  1111. hr = g_CfgUtils.m_spWbemServiceIF->ExecMethod(
  1112. _bstr_t(pRelPath),
  1113. L"EnableStatic",
  1114. 0,
  1115. NULL,
  1116. spWbemInputInstance,
  1117. &spWbemOutput,
  1118. NULL
  1119. );
  1120. TRACE_CRIT("EnableStatic returns");
  1121. if( FAILED( hr) )
  1122. {
  1123. TRACE_CRIT("%!FUNC! IWbemServices::ExecMethod failure 0x%08lx while invoking EnableStatic", (UINT) hr);
  1124. goto end;
  1125. }
  1126. hr = spWbemOutput->Get(
  1127. L"ReturnValue",
  1128. 0,
  1129. &v_retVal,
  1130. NULL,
  1131. NULL
  1132. );
  1133. if( FAILED( hr) )
  1134. {
  1135. TRACE_CRIT("%!FUNC! IWbemClassObject::Get failure while checking status of EnableStatic call");
  1136. goto end;
  1137. }
  1138. LONG lRet = (LONG) v_retVal;
  1139. v_retVal.Clear();
  1140. if (lRet == 0)
  1141. {
  1142. TRACE_INFO("%!FUNC! EnableStatic returns SUCCESS! after %d attempts", uiMaxTries-NumTries);
  1143. Status = WBEM_NO_ERROR;
  1144. break;
  1145. }
  1146. // We failed. Sleep and try again.
  1147. Sleep(1000);
  1148. // Failures seen while testing status:
  1149. // 0x42 = Invalid subnet mask (can happen when removing IPs from adapter, if removing all of them)
  1150. // 0x51 = Unable to configure DHCP service
  1151. // 0x54 = IP not enabled on adapter (happens while the adapter is processing the request to add an IP)
  1152. // For other return codes, see http://index2. Search for EnableStatic in sdnt\admin\wmi\wbem\providers\mofs\win32_network.mof
  1153. if (lRet == 0x42 || lRet == 0x51 || lRet == 0x54) // These appear to be a recoverable errors
  1154. {
  1155. TRACE_INFO(
  1156. "%!FUNC! EnableStatic on NIC %ws returns recoverable FAILURE:0x%08lx! after %d attempts",
  1157. szNic,
  1158. lRet,
  1159. uiMaxTries-NumTries
  1160. );
  1161. Status = WBEM_E_CRITICAL_ERROR;
  1162. }
  1163. else
  1164. {
  1165. TRACE_INFO(
  1166. "%!FUNC! EnableStatic on NIC %ws returns FAILURE:0x%08lx! after %d attempts",
  1167. szNic,
  1168. lRet,
  1169. uiMaxTries-NumTries
  1170. );
  1171. Status = WBEM_E_CRITICAL_ERROR;
  1172. }
  1173. }
  1174. if (!FAILED(Status))
  1175. {
  1176. BOOL fMatch = FALSE;
  1177. UINT uMatchAttemptsLeft = 5;
  1178. do
  1179. {
  1180. fMatch = TRUE;
  1181. //
  1182. // Sometimes this function returns before the ip addresses actually
  1183. // show up in IPCONFIG. So let's check.
  1184. //
  1185. WBEMSTATUS wStat2;
  1186. UINT NumAddrs2=0;
  1187. NLB_IP_ADDRESS_INFO *pIpInfo2 = NULL;
  1188. wStat2 = CfgUtilGetIpAddressesAndFriendlyName(
  1189. szNic,
  1190. &NumAddrs2,
  1191. &pIpInfo2,
  1192. NULL // pszFriendlyName (unused)
  1193. );
  1194. if (FAILED(wStat2))
  1195. {
  1196. //
  1197. // We won't bother trying again.
  1198. //
  1199. break;
  1200. }
  1201. if (NumAddrs2 == 0)
  1202. {
  1203. pIpInfo2 = NULL;
  1204. }
  1205. //
  1206. // Check for match
  1207. //
  1208. if (NumAddrs2 != NumIpAddresses)
  1209. {
  1210. fMatch = FALSE;
  1211. }
  1212. else
  1213. {
  1214. for (UINT u=0; u<NumAddrs2; u++)
  1215. {
  1216. NLB_IP_ADDRESS_INFO *pInfoA=pIpInfo+u;
  1217. NLB_IP_ADDRESS_INFO *pInfoB=pIpInfo2+u;
  1218. if ( _wcsicmp(pInfoA->IpAddress, pInfoB->IpAddress)
  1219. || _wcsicmp(pInfoA->SubnetMask, pInfoB->SubnetMask))
  1220. {
  1221. fMatch = FALSE;
  1222. break;
  1223. }
  1224. }
  1225. }
  1226. delete[] pIpInfo2;
  1227. if (fMatch)
  1228. {
  1229. break;
  1230. }
  1231. if (uMatchAttemptsLeft)
  1232. {
  1233. uMatchAttemptsLeft--;
  1234. Sleep(2000);
  1235. }
  1236. } while (uMatchAttemptsLeft);
  1237. }
  1238. end:
  1239. if (rgIpAddresses != NULL)
  1240. {
  1241. delete[] rgIpAddresses;
  1242. }
  1243. if (rgIpSubnets != NULL)
  1244. {
  1245. delete[] rgIpSubnets;
  1246. }
  1247. if (pRelPath != NULL)
  1248. {
  1249. delete pRelPath;
  1250. }
  1251. spWbemInputInstance = NULL;
  1252. TRACE_INFO(L"<- %!FUNC!(Nic=%ws) returns 0x%08lx", szNic, (UINT) Status);
  1253. return Status;
  1254. }
  1255. //
  1256. // Sets the IP addresses for the NIC to be DHCP-assigned.
  1257. //
  1258. WBEMSTATUS
  1259. CfgUtilSetDHCP(
  1260. IN LPCWSTR szNic
  1261. )
  1262. {
  1263. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  1264. IWbemClassObjectPtr spWbemInputInstance = NULL; // smart pointer
  1265. LPWSTR pRelPath = NULL;
  1266. TRACE_INFO(L"-> %!FUNC!(Nic=%ws)", szNic);
  1267. //
  1268. // If not initialized, fail...
  1269. //
  1270. if (!g_CfgUtils.IsInitalized())
  1271. {
  1272. TRACE_CRIT(L"%!FUNC!(Nic=%ws) FAILING because uninitialized", szNic);
  1273. Status = WBEM_E_INITIALIZATION_FAILURE;
  1274. goto end;
  1275. }
  1276. //
  1277. // Get input instance and relpath...
  1278. //
  1279. Status = CfgUtilGetWmiInputInstanceAndRelPath(
  1280. g_CfgUtils.m_spWbemServiceIF,
  1281. L"Win32_NetworkAdapterConfiguration", // szClassName
  1282. L"SettingID", // szPropertyName
  1283. szNic, // szPropertyValue
  1284. L"EnableDHCP", // szMethodName,
  1285. spWbemInputInstance, // smart pointer
  1286. &pRelPath // free using delete
  1287. );
  1288. if (FAILED(Status))
  1289. {
  1290. goto end;
  1291. }
  1292. //
  1293. // No input params to setup.
  1294. //
  1295. //
  1296. // execute method and get the output result
  1297. // WARNING: we try this a few times because the wmi call apperears to
  1298. // suffer from a recoverable error. TODO: Need to get to the bottom of
  1299. // this.
  1300. //
  1301. UINT uiMaxTries = 10;
  1302. for (UINT NumTries=uiMaxTries; NumTries--;)
  1303. {
  1304. HRESULT hr;
  1305. IWbemClassObjectPtr spWbemOutput = NULL; // smart pointer.
  1306. _variant_t v_retVal;
  1307. TRACE_CRIT("Going to call EnableDHCP");
  1308. hr = g_CfgUtils.m_spWbemServiceIF->ExecMethod(
  1309. _bstr_t(pRelPath),
  1310. L"EnableDHCP",
  1311. 0,
  1312. NULL,
  1313. spWbemInputInstance,
  1314. &spWbemOutput,
  1315. NULL
  1316. );
  1317. TRACE_CRIT("EnableDHCP returns");
  1318. if( FAILED( hr) )
  1319. {
  1320. TRACE_CRIT("%!FUNC! IWbemServices::ExecMethod failure 0x%08lx while invoking EnableDHCP", (UINT) hr);
  1321. goto end;
  1322. }
  1323. hr = spWbemOutput->Get(
  1324. L"ReturnValue",
  1325. 0,
  1326. &v_retVal,
  1327. NULL,
  1328. NULL
  1329. );
  1330. if( FAILED( hr) )
  1331. {
  1332. TRACE_CRIT("%!FUNC! IWbemClassObject::Get failure while checking status of EnableDHCP call");
  1333. goto end;
  1334. }
  1335. LONG lRet = (LONG) v_retVal;
  1336. v_retVal.Clear();
  1337. if (lRet == 0)
  1338. {
  1339. TRACE_INFO("%!FUNC! EnableDHCP returns SUCCESS! after %d attempts", uiMaxTries-NumTries);
  1340. Status = WBEM_NO_ERROR;
  1341. break;
  1342. }
  1343. // We failed. Sleep and try again.
  1344. Sleep(1000);
  1345. // Failures seen while testing status:
  1346. // 0x42 = Invalid subnet mask (can happen when removing IPs from adapter, if removing all of them)
  1347. // 0x51 = Unable to configure DHCP service
  1348. // 0x54 = IP not enabled on adapter (happens while the adapter is processing the request to add an IP)
  1349. // For other return codes, see http://index2. Search for EnableStatic in sdnt\admin\wmi\wbem\providers\mofs\win32_network.mof
  1350. if (lRet == 0x42 || lRet == 0x51 || lRet == 0x54) // These appear to be a recoverable errors
  1351. {
  1352. TRACE_INFO(
  1353. "%!FUNC! EnableDHCP on NIC %ws returns recoverable FAILURE:0x%08lx! after %d attempts",
  1354. szNic,
  1355. lRet,
  1356. uiMaxTries-NumTries
  1357. );
  1358. Status = WBEM_E_CRITICAL_ERROR;
  1359. }
  1360. else
  1361. {
  1362. TRACE_INFO(
  1363. "%!FUNC! EnableDHCP on NIC %ws returns FAILURE:0x%08lx! after %d attempts",
  1364. szNic,
  1365. lRet,
  1366. uiMaxTries-NumTries
  1367. );
  1368. Status = WBEM_E_CRITICAL_ERROR;
  1369. }
  1370. }
  1371. end:
  1372. spWbemInputInstance = NULL;
  1373. TRACE_INFO(L"<- %!FUNC!(Nic=%ws) returns 0x%08lx", szNic, (UINT) Status);
  1374. return Status;
  1375. }
  1376. //
  1377. // Determines whether the specified nic is configured with DHCP or not.
  1378. //
  1379. WBEMSTATUS
  1380. CfgUtilGetDHCP(
  1381. IN LPCWSTR szNic,
  1382. OUT BOOL *pfDHCP
  1383. )
  1384. {
  1385. WBEMSTATUS Status = WBEM_NO_ERROR;
  1386. IWbemClassObjectPtr spObj = NULL; // smart pointer
  1387. HRESULT hr;
  1388. TRACE_INFO(L"-> %!FUNC!(Nic=%ws)", szNic);
  1389. *pfDHCP = FALSE;
  1390. //
  1391. // If not initialized, fail...
  1392. //
  1393. if (!g_CfgUtils.IsInitalized())
  1394. {
  1395. TRACE_CRIT(L"%!FUNC!(Nic=%ws) FAILING because uninitialized", szNic);
  1396. Status = WBEM_E_INITIALIZATION_FAILURE;
  1397. goto end;
  1398. }
  1399. //
  1400. // Get WMI instance to specific NIC
  1401. //
  1402. Status = get_nic_instance(
  1403. g_CfgUtils.m_spWbemServiceIF,
  1404. szNic,
  1405. spObj // pass by reference
  1406. );
  1407. if (FAILED(Status))
  1408. {
  1409. ASSERT(spObj == NULL);
  1410. goto end;
  1411. }
  1412. //
  1413. // Extract IP addresses and subnets.
  1414. //
  1415. Status = CfgUtilGetWmiBoolParam(
  1416. spObj,
  1417. L"DHCPEnabled", // szParameterName,
  1418. pfDHCP
  1419. );
  1420. if (Status == WBEM_E_NOT_FOUND)
  1421. {
  1422. //
  1423. // We treat not-found as no-dhcp -- this is what we see in practise.
  1424. //
  1425. *pfDHCP = FALSE;
  1426. Status = WBEM_NO_ERROR;
  1427. }
  1428. end:
  1429. spObj = NULL; // smart pointer
  1430. TRACE_INFO(L"<- %!FUNC!(Nic=%ws) returns 0x%08lx (fDHCP=%lu)",
  1431. szNic, (UINT) Status, *pfDHCP);
  1432. return Status;
  1433. }
  1434. WBEMSTATUS
  1435. CfgUtilGetNetcfgWriteLockState(
  1436. OUT BOOL *pfCanLock,
  1437. LPWSTR *pszHeldBy // OPTIONAL, free using delete[].
  1438. )
  1439. {
  1440. WBEMSTATUS Status;
  1441. Status = MyNetCfg::GetWriteLockState(pfCanLock, pszHeldBy);
  1442. return Status;
  1443. }
  1444. //
  1445. // Determines whether NLB is bound to the specified NIC.
  1446. //
  1447. WBEMSTATUS
  1448. CfgUtilCheckIfNlbBound(
  1449. IN LPCWSTR szNic,
  1450. OUT BOOL *pfBound
  1451. )
  1452. {
  1453. WBEMSTATUS Status = WBEM_NO_ERROR;
  1454. BOOL fNetCfgInitialized = FALSE;
  1455. MyNetCfg NetCfg;
  1456. BOOL fBound = FALSE;
  1457. //
  1458. // Get and initialize interface to netcfg
  1459. //
  1460. Status = NetCfg.Initialize(FALSE); // FALSE == don't get write lock.
  1461. if (FAILED(Status))
  1462. {
  1463. goto end;
  1464. }
  1465. fNetCfgInitialized = TRUE;
  1466. //
  1467. //
  1468. //
  1469. Status = NetCfg.UpdateBindingState(
  1470. szNic,
  1471. L"ms_wlbs",
  1472. MyNetCfg::NOOP,
  1473. &fBound
  1474. );
  1475. end:
  1476. if (fNetCfgInitialized)
  1477. {
  1478. NetCfg.Deinitialize();
  1479. }
  1480. *pfBound = fBound;
  1481. return Status;
  1482. }
  1483. //
  1484. // Binds/unbinds NLB to the specified NIC.
  1485. //
  1486. WBEMSTATUS
  1487. CfgUtilChangeNlbBindState(
  1488. IN LPCWSTR szNic,
  1489. IN BOOL fBind
  1490. )
  1491. {
  1492. WBEMSTATUS Status = WBEM_NO_ERROR;
  1493. BOOL fNetCfgInitialized = FALSE;
  1494. MyNetCfg NetCfg;
  1495. BOOL fBound = FALSE;
  1496. //
  1497. // Get and initialize interface to netcfg
  1498. //
  1499. Status = NetCfg.Initialize(TRUE); // TRUE == get write lock.
  1500. if (FAILED(Status))
  1501. {
  1502. goto end;
  1503. }
  1504. fNetCfgInitialized = TRUE;
  1505. //
  1506. //
  1507. //
  1508. Status = NetCfg.UpdateBindingState(
  1509. szNic,
  1510. L"ms_wlbs",
  1511. fBind ? MyNetCfg::BIND : MyNetCfg::UNBIND,
  1512. &fBound
  1513. );
  1514. end:
  1515. if (fNetCfgInitialized)
  1516. {
  1517. NetCfg.Deinitialize();
  1518. }
  1519. return Status;
  1520. }
  1521. //
  1522. // Gets the current NLB configuration for the specified NIC
  1523. //
  1524. WBEMSTATUS
  1525. CfgUtilGetNlbConfig(
  1526. IN LPCWSTR szNic,
  1527. OUT WLBS_REG_PARAMS *pParams
  1528. )
  1529. {
  1530. GUID Guid;
  1531. WBEMSTATUS Status = WBEM_NO_ERROR;
  1532. // Verify that the NLB API hooks are present
  1533. if (!g_CfgUtils.m_NLBApiHooksPresent)
  1534. {
  1535. TRACE_CRIT(L"%!FUNC! FAILING because NLB API hooks are not present");
  1536. Status = WBEM_E_INITIALIZATION_FAILURE;
  1537. goto end;
  1538. }
  1539. HRESULT hr = CLSIDFromString((LPWSTR)szNic, &Guid);
  1540. if (FAILED(hr))
  1541. {
  1542. Status = WBEM_E_INVALID_PARAMETER;
  1543. goto end;
  1544. }
  1545. //
  1546. // Read the configuration.
  1547. //
  1548. BOOL fRet = g_CfgUtils.m_pfWlbsParamReadReg(&Guid, pParams);
  1549. if (!fRet)
  1550. {
  1551. TRACE_CRIT("Could not read NLB configuration for %wsz", szNic);
  1552. Status = WBEM_E_CRITICAL_ERROR;
  1553. goto end;
  1554. }
  1555. Status = WBEM_NO_ERROR;
  1556. end:
  1557. // g_CfgUtils.mfn_Unlock();
  1558. return Status;
  1559. }
  1560. //
  1561. // Sets the current NLB configuration for the specified NIC. This
  1562. // includes notifying the driver if required.
  1563. //
  1564. WBEMSTATUS
  1565. CfgUtilSetNlbConfig(
  1566. IN LPCWSTR szNic,
  1567. IN WLBS_REG_PARAMS *pParams,
  1568. IN BOOL fJustBound
  1569. )
  1570. {
  1571. GUID Guid;
  1572. WBEMSTATUS Status = WBEM_NO_ERROR;
  1573. DWORD dwRet = 0;
  1574. WLBS_REG_PARAMS ParamsCopy;
  1575. if (fJustBound)
  1576. {
  1577. // We need to set the install_date value to the current time.
  1578. // This field is used in the heartbeats to distinguish two
  1579. // hosts.
  1580. // This is bug 480120 nlb:cluster converged when duplicate host ID exist
  1581. // (see also wlbscfg.dll (netcfgconfig.cpp:
  1582. // CNetcfgCluster::InitializeWithDefault)
  1583. time_t cur_time;
  1584. ParamsCopy = *pParams; // Struct copy.
  1585. ParamsCopy.install_date = time(& cur_time);
  1586. pParams = &ParamsCopy;
  1587. }
  1588. // Verify that the NLB API hooks are present
  1589. if (!g_CfgUtils.m_NLBApiHooksPresent)
  1590. {
  1591. TRACE_CRIT(L"%!FUNC! FAILING because NLB API hooks are not present");
  1592. Status = WBEM_E_INITIALIZATION_FAILURE;
  1593. goto end;
  1594. }
  1595. HRESULT hr = CLSIDFromString((LPWSTR)szNic, &Guid);
  1596. if (FAILED(hr))
  1597. {
  1598. Status = WBEM_E_INVALID_PARAMETER;
  1599. goto end;
  1600. }
  1601. HANDLE Nlb_driver_hdl;
  1602. // Get handle to NLB driver
  1603. if ((Nlb_driver_hdl = g_CfgUtils.m_pfWlbsOpen()) == INVALID_HANDLE_VALUE)
  1604. {
  1605. TRACE_CRIT("%!FUNC! WlbsOpen returned NULL, Could not create connection to NLB driver");
  1606. Status = WBEM_E_CRITICAL_ERROR;
  1607. goto end;
  1608. }
  1609. //
  1610. // Write the configuration.
  1611. //
  1612. dwRet = g_CfgUtils.m_pfWlbsWriteAndCommitChanges(Nlb_driver_hdl, &Guid, pParams);
  1613. if (dwRet != WLBS_OK)
  1614. {
  1615. TRACE_CRIT("Could not write NLB configuration for %wsz. Err=0x%08lx",
  1616. szNic, dwRet);
  1617. Status = WBEM_E_CRITICAL_ERROR;
  1618. }
  1619. else
  1620. {
  1621. Status = WBEM_NO_ERROR;
  1622. }
  1623. // Close handle to NLB driver
  1624. CloseHandle(Nlb_driver_hdl);
  1625. end:
  1626. return Status;
  1627. }
  1628. WBEMSTATUS
  1629. CfgUtilRegWriteParams(
  1630. IN LPCWSTR szNic,
  1631. IN WLBS_REG_PARAMS *pParams
  1632. )
  1633. //
  1634. // Just writes the current NLB configuration for the specified NIC to the
  1635. // registry. MAY BE CALLED WHEN NLB IS UNBOUND.
  1636. //
  1637. {
  1638. GUID Guid;
  1639. WLBS_REG_PARAMS TmpParams = *pParams;
  1640. WBEMSTATUS Status = WBEM_NO_ERROR;
  1641. DWORD dwRet = 0;
  1642. TRACE_INFO(L"->");
  1643. // Verify that the NLB API hooks are present
  1644. if (!g_CfgUtils.m_NLBApiHooksPresent)
  1645. {
  1646. TRACE_CRIT(L"FAILING because NLB API hooks are not present");
  1647. Status = WBEM_E_INITIALIZATION_FAILURE;
  1648. goto end;
  1649. }
  1650. HRESULT hr = CLSIDFromString((LPWSTR)szNic, &Guid);
  1651. if (FAILED(hr))
  1652. {
  1653. Status = WBEM_E_INVALID_PARAMETER;
  1654. goto end;
  1655. }
  1656. //
  1657. // Write the configuration.
  1658. //
  1659. dwRet = g_CfgUtils.m_pfWlbsParamWriteReg(Guid, &TmpParams);
  1660. if (dwRet != WLBS_OK)
  1661. {
  1662. TRACE_CRIT("Could not write NLB configuration for %wsz. Err=0x%08lx",
  1663. szNic, dwRet);
  1664. Status = WBEM_E_CRITICAL_ERROR;
  1665. }
  1666. else
  1667. {
  1668. Status = WBEM_NO_ERROR;
  1669. }
  1670. end:
  1671. TRACE_INFO(L"<- returns %lx", Status);
  1672. return Status;
  1673. }
  1674. WBEMSTATUS
  1675. CfgUtilsAnalyzeNlbUpdate(
  1676. IN const WLBS_REG_PARAMS *pCurrentParams, OPTIONAL
  1677. IN WLBS_REG_PARAMS *pNewParams,
  1678. OUT BOOL *pfConnectivityChange
  1679. )
  1680. {
  1681. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  1682. BOOL fConnectivityChange = FALSE;
  1683. //
  1684. // If not initialized, fail...
  1685. //
  1686. if (!g_CfgUtils.IsInitalized())
  1687. {
  1688. TRACE_CRIT(L"%!FUNC! FAILING because uninitialized");
  1689. Status = WBEM_E_INITIALIZATION_FAILURE;
  1690. goto end;
  1691. }
  1692. if (pCurrentParams != NULL)
  1693. {
  1694. //
  1695. // If the structures have identical content, we return S_FALSE.
  1696. // We do this check before we call ValidateParm below, because
  1697. // ValidateParam has the side effect of filling out / modifying
  1698. // certain fields.
  1699. //
  1700. if (memcmp(pCurrentParams, pNewParams, sizeof(*pCurrentParams))==0)
  1701. {
  1702. Status = WBEM_S_FALSE;
  1703. goto end;
  1704. }
  1705. }
  1706. //
  1707. // Validate pNewParams -- this may also modify pNewParams slightly, by
  1708. // re-formatting ip addresses into canonical format.
  1709. //
  1710. // Verify that the NLB API hooks are present
  1711. BOOL fRet = FALSE;
  1712. if (!g_CfgUtils.m_NLBApiHooksPresent)
  1713. {
  1714. fRet = MyWlbsValidateParams(pNewParams);
  1715. }
  1716. else
  1717. {
  1718. fRet = g_CfgUtils.m_pfWlbsValidateParams(pNewParams);
  1719. }
  1720. if (!fRet)
  1721. {
  1722. TRACE_CRIT(L"%!FUNC!FAILING because New params are invalid");
  1723. Status = WBEM_E_INVALID_PARAMETER;
  1724. goto end;
  1725. }
  1726. Status = WBEM_NO_ERROR;
  1727. if (pCurrentParams == NULL)
  1728. {
  1729. //
  1730. // NLB was not previously bound.
  1731. //
  1732. fConnectivityChange = TRUE;
  1733. goto end;
  1734. }
  1735. //
  1736. // Change in multicast modes or mac address.
  1737. //
  1738. if ( (pCurrentParams->mcast_support != pNewParams->mcast_support)
  1739. || _wcsicmp(pCurrentParams->cl_mac_addr, pNewParams->cl_mac_addr)!=0)
  1740. {
  1741. fConnectivityChange = TRUE;
  1742. }
  1743. //
  1744. // Change in primary cluster ip or subnet mask
  1745. //
  1746. if ( _wcsicmp(pCurrentParams->cl_ip_addr,pNewParams->cl_ip_addr)!=0
  1747. || _wcsicmp(pCurrentParams->cl_net_mask,pNewParams->cl_net_mask)!=0)
  1748. {
  1749. fConnectivityChange = TRUE;
  1750. }
  1751. end:
  1752. *pfConnectivityChange = fConnectivityChange;
  1753. return Status;
  1754. }
  1755. WBEMSTATUS
  1756. CfgUtilsValidateNicGuid(
  1757. IN LPCWSTR szGuid
  1758. )
  1759. //
  1760. //
  1761. {
  1762. //
  1763. // Sample GUID: {EBE09517-07B4-4E88-AAF1-E06F5540608B}
  1764. //
  1765. WBEMSTATUS Status = WBEM_E_INVALID_PARAMETER;
  1766. UINT Length = wcslen(szGuid);
  1767. #define MY_NLB_GUID_LEN 38
  1768. if (Length != MY_NLB_GUID_LEN)
  1769. {
  1770. TRACE_CRIT("Length != %d", MY_NLB_GUID_LEN);
  1771. goto end;
  1772. }
  1773. //
  1774. // Open tcpip's registry key and look for guid there -- if not found,
  1775. // we'll return WBEM_E_NOT_FOUND
  1776. //
  1777. {
  1778. WCHAR szKey[128]; // This is enough for the tcpip+guid key
  1779. ARRAYSTRCPY(szKey, L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\" );
  1780. ARRAYSTRCAT(szKey, szGuid);
  1781. HKEY hKey = NULL;
  1782. LONG lRet;
  1783. lRet = RegOpenKeyEx(
  1784. HKEY_LOCAL_MACHINE, // handle to an open key
  1785. szKey, // address of subkey name
  1786. 0, // reserved
  1787. KEY_QUERY_VALUE, // desired security access
  1788. &hKey // address of buffer for opened handle
  1789. );
  1790. if (lRet != ERROR_SUCCESS)
  1791. {
  1792. TRACE_CRIT("Guid %ws doesn't exist under tcpip", szGuid);
  1793. Status = WBEM_E_NOT_FOUND;
  1794. goto end;
  1795. }
  1796. RegCloseKey(hKey);
  1797. }
  1798. Status = WBEM_NO_ERROR;
  1799. end:
  1800. return Status;
  1801. }
  1802. #if OBSOLETE
  1803. WBEMSTATUS
  1804. get_string_parameter(
  1805. IN IWbemClassObjectPtr spObj,
  1806. IN LPCWSTR szParameterName,
  1807. OUT LPWSTR *ppStringValue
  1808. )
  1809. {
  1810. WBEMSTATUS Status = WBEM_E_NOT_FOUND;
  1811. WCHAR *pStringValue = NULL;
  1812. _variant_t v_value;
  1813. CIMTYPE v_type;
  1814. HRESULT hr;
  1815. hr = spObj->Get(
  1816. _bstr_t(szParameterName), // Name
  1817. 0, // Reserved, must be 0
  1818. &v_value, // Place to store value
  1819. &v_type, // Type of value
  1820. NULL // Flavor (unused)
  1821. );
  1822. if (FAILED(hr))
  1823. {
  1824. // Couldn't read the Setting ID field!
  1825. //
  1826. TRACE_CRIT(
  1827. "get_str_parm:Couldn't retrieve %ws from 0x%p",
  1828. szParameterName,
  1829. (PVOID) spObj
  1830. );
  1831. goto end;
  1832. }
  1833. else
  1834. {
  1835. if (v_type != VT_BSTR)
  1836. {
  1837. TRACE_CRIT(
  1838. "get_str_parm: Parm value not of string type %ws from 0x%p",
  1839. szParameterName,
  1840. (PVOID) spObj
  1841. );
  1842. Status = WBEM_E_INVALID_PARAMETER;
  1843. }
  1844. else
  1845. {
  1846. _bstr_t bstrNicGuid(v_value);
  1847. LPCWSTR sz = bstrNicGuid; // Pointer to internal buffer.
  1848. if (sz==NULL)
  1849. {
  1850. // hmm.. null value
  1851. Status = WBEM_NO_ERROR;
  1852. }
  1853. else
  1854. {
  1855. UINT len = wcslen(sz);
  1856. pStringValue = new WCHAR[len+1];
  1857. if (pStringValue == NULL)
  1858. {
  1859. TRACE_CRIT("get_str_parm: Alloc failure!");
  1860. Status = WBEM_E_OUT_OF_MEMORY;
  1861. }
  1862. else
  1863. {
  1864. CopyMemory(pStringValue, sz, (len+1)*sizeof(WCHAR));
  1865. Status = WBEM_NO_ERROR;
  1866. }
  1867. }
  1868. TRACE_VERB(
  1869. "get_str_parm: String parm %ws of 0x%p is %ws",
  1870. szParameterName,
  1871. (PVOID) spObj,
  1872. (sz==NULL) ? L"<null>" : sz
  1873. );
  1874. }
  1875. v_value.Clear(); // Must be cleared after each call to Get.
  1876. }
  1877. end:
  1878. *ppStringValue = pStringValue;
  1879. return Status;
  1880. }
  1881. #endif // OBSOLETE
  1882. WBEMSTATUS
  1883. get_nic_instance(
  1884. IN IWbemServicesPtr spWbemServiceIF,
  1885. IN LPCWSTR szNicGuid,
  1886. OUT IWbemClassObjectPtr &sprefObj
  1887. )
  1888. {
  1889. WBEMSTATUS Status = WBEM_E_NOT_FOUND;
  1890. IWbemClassObjectPtr spObj = NULL; // smart pointer.
  1891. Status = CfgUtilGetWmiObjectInstance(
  1892. spWbemServiceIF,
  1893. L"Win32_NetworkAdapterConfiguration", // szClassName
  1894. L"SettingID", // szParameterName
  1895. szNicGuid, // ParameterValue
  1896. spObj // smart pointer, passed by ref
  1897. );
  1898. if (FAILED(Status))
  1899. {
  1900. ASSERT(spObj == NULL);
  1901. goto end;
  1902. }
  1903. end:
  1904. if (FAILED(Status))
  1905. {
  1906. sprefObj = NULL;
  1907. }
  1908. else
  1909. {
  1910. sprefObj = spObj; // smart pointer.
  1911. }
  1912. return Status;
  1913. }
  1914. WBEMSTATUS
  1915. get_multi_string_parameter(
  1916. IN IWbemClassObjectPtr spObj,
  1917. IN LPCWSTR szParameterName,
  1918. IN UINT MaxStringLen, // in wchars, INCLUDING space for trailing zeros.
  1919. OUT UINT *pNumItems,
  1920. OUT LPCWSTR *ppStringValue
  1921. )
  1922. {
  1923. WBEMSTATUS Status = WBEM_E_NOT_FOUND;
  1924. WCHAR *pStringValue = NULL;
  1925. _variant_t v_value;
  1926. CIMTYPE v_type;
  1927. HRESULT hr;
  1928. LONG count = 0;
  1929. *ppStringValue = NULL;
  1930. *pNumItems = 0;
  1931. hr = spObj->Get(
  1932. _bstr_t(szParameterName),
  1933. 0, // Reserved, must be 0
  1934. &v_value, // Place to store value
  1935. &v_type, // Type of value
  1936. NULL // Flavor (unused)
  1937. );
  1938. if (FAILED(hr))
  1939. {
  1940. // Couldn't read the requested parameter.
  1941. //
  1942. TRACE_CRIT(
  1943. "get_multi_str_parm:Couldn't retrieve %ws from 0x%p",
  1944. szParameterName,
  1945. (PVOID) spObj
  1946. );
  1947. goto end;
  1948. }
  1949. {
  1950. VARIANT ipsV = v_value.Detach();
  1951. do // while false
  1952. {
  1953. BSTR* pbstr;
  1954. if (ipsV.vt == VT_NULL)
  1955. {
  1956. //
  1957. // NULL string -- this is ok
  1958. //
  1959. count = 0;
  1960. }
  1961. else
  1962. {
  1963. count = ipsV.parray->rgsabound[0].cElements;
  1964. }
  1965. if (count==0)
  1966. {
  1967. Status = WBEM_NO_ERROR;
  1968. break;
  1969. }
  1970. pStringValue = new WCHAR[count*MaxStringLen];
  1971. if (pStringValue == NULL)
  1972. {
  1973. TRACE_CRIT("get_multi_str_parm: Alloc failure!");
  1974. Status = WBEM_E_OUT_OF_MEMORY;
  1975. break;
  1976. }
  1977. ZeroMemory(pStringValue, sizeof(WCHAR)*count*MaxStringLen);
  1978. hr = SafeArrayAccessData(ipsV.parray, ( void **) &pbstr);
  1979. if(FAILED(hr))
  1980. {
  1981. Status = WBEM_E_INVALID_PARAMETER; // TODO: pick better error
  1982. break;
  1983. }
  1984. Status = WBEM_NO_ERROR;
  1985. for( LONG x = 0; x < count; x++ )
  1986. {
  1987. LPCWSTR sz = pbstr[x]; // Pointer to internal buffer.
  1988. if (sz==NULL)
  1989. {
  1990. // hmm.. null value
  1991. continue;
  1992. }
  1993. else
  1994. {
  1995. UINT len = wcslen(sz);
  1996. if ((len+1) > MaxStringLen)
  1997. {
  1998. TRACE_CRIT("get_str_parm: string size too long!");
  1999. Status = WBEM_E_INVALID_PARAMETER;
  2000. break;
  2001. }
  2002. else
  2003. {
  2004. WCHAR *pDest = pStringValue+x*MaxStringLen;
  2005. CopyMemory(pDest, sz, (len+1)*sizeof(WCHAR));
  2006. }
  2007. }
  2008. }
  2009. (VOID) SafeArrayUnaccessData( ipsV.parray );
  2010. } while (FALSE);
  2011. VariantClear( &ipsV );
  2012. }
  2013. if (FAILED(Status))
  2014. {
  2015. if (pStringValue!=NULL)
  2016. {
  2017. delete[] pStringValue;
  2018. *pStringValue = NULL;
  2019. }
  2020. }
  2021. else
  2022. {
  2023. *ppStringValue = pStringValue;
  2024. *pNumItems = count;
  2025. }
  2026. end:
  2027. return Status;
  2028. }
  2029. //
  2030. // Static method to return the state of the lock;
  2031. //
  2032. WBEMSTATUS
  2033. MyNetCfg::GetWriteLockState(
  2034. OUT BOOL *pfCanLock,
  2035. LPWSTR *pszHeldBy // OPTIONAL, free using delete[].
  2036. )
  2037. {
  2038. HRESULT hr;
  2039. INetCfg *pnc = NULL;
  2040. INetCfgLock *pncl = NULL;
  2041. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  2042. BOOL fCanLock = FALSE;
  2043. WCHAR *szLockedBy = NULL;
  2044. *pfCanLock = FALSE;
  2045. if (pszHeldBy!=NULL)
  2046. {
  2047. *pszHeldBy = NULL;
  2048. }
  2049. hr = CoCreateInstance( CLSID_CNetCfg,
  2050. NULL,
  2051. CLSCTX_SERVER,
  2052. IID_INetCfg,
  2053. (void **) &pnc);
  2054. if( !SUCCEEDED( hr ) )
  2055. {
  2056. // failure to create instance.
  2057. TRACE_CRIT("ERROR: could not get interface to Net Config");
  2058. pnc = NULL;
  2059. goto end;
  2060. }
  2061. hr = pnc->QueryInterface( IID_INetCfgLock, ( void **) &pncl );
  2062. if( !SUCCEEDED( hr ) )
  2063. {
  2064. TRACE_CRIT("ERROR: could not get interface to NetCfg Lock");
  2065. pncl = NULL;
  2066. goto end;
  2067. }
  2068. hr = pncl->AcquireWriteLock(100, NLB_CLIENT_NAME, &szLockedBy);
  2069. if(hr == S_FALSE)
  2070. {
  2071. TRACE_INFO("Write lock held by %ws",
  2072. (szLockedBy!=NULL) ? szLockedBy : L"<null>");
  2073. if (pszHeldBy!=NULL && szLockedBy != NULL)
  2074. {
  2075. LPWSTR szTmp = NULL;
  2076. UINT uLen = wcslen(szLockedBy);
  2077. szTmp = new WCHAR[uLen+1];
  2078. if (szTmp != NULL)
  2079. {
  2080. CopyMemory(szTmp, szLockedBy, (uLen+1)*sizeof(*szTmp));
  2081. }
  2082. *pszHeldBy = szTmp;
  2083. }
  2084. fCanLock = FALSE;
  2085. Status = WBEM_NO_ERROR;
  2086. }
  2087. else if (hr == S_OK)
  2088. {
  2089. //
  2090. // We could get the lock, let's release it.
  2091. //
  2092. (void) pncl->ReleaseWriteLock();
  2093. fCanLock = TRUE;
  2094. Status = WBEM_NO_ERROR;
  2095. }
  2096. else
  2097. {
  2098. TRACE_INFO("AcquireWriteLock failed with error 0x%08lx", (UINT) hr);
  2099. fCanLock = FALSE;
  2100. Status = WBEM_NO_ERROR;
  2101. }
  2102. CoTaskMemFree(szLockedBy); // szLockedBy can be NULL;
  2103. *pfCanLock = fCanLock;
  2104. end:
  2105. if (pncl!=NULL)
  2106. {
  2107. pncl->Release();
  2108. pncl=NULL;
  2109. }
  2110. if (pnc != NULL)
  2111. {
  2112. pnc->Release();
  2113. pnc= NULL;
  2114. }
  2115. return Status;
  2116. }
  2117. WBEMSTATUS
  2118. MyNetCfg::Initialize(
  2119. BOOL fWriteLock
  2120. )
  2121. {
  2122. // 2/13/02 JosephJ SECURITY BUGBUG: verify that IF this call is made from a non-admin that we fail.
  2123. //
  2124. HRESULT hr;
  2125. INetCfg *pnc = NULL;
  2126. INetCfgLock *pncl = NULL;
  2127. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  2128. BOOL fLocked = FALSE;
  2129. BOOL fInitialized=FALSE;
  2130. if (m_pINetCfg != NULL || m_pLock != NULL)
  2131. {
  2132. ASSERT(FALSE);
  2133. goto end;
  2134. }
  2135. //
  2136. // 2/13/02 JosephJ SECURITY BUGBUG: CLSCTX_SERVER -- should we be specifying something more restrictive here?
  2137. // Also: can some other COM object hijack this GUID?
  2138. //
  2139. hr = CoCreateInstance( CLSID_CNetCfg,
  2140. NULL,
  2141. CLSCTX_SERVER,
  2142. IID_INetCfg,
  2143. (void **) &pnc);
  2144. if( !SUCCEEDED( hr ) )
  2145. {
  2146. // failure to create instance.
  2147. TRACE_CRIT("ERROR: could not get interface to Net Config");
  2148. pnc = NULL;
  2149. goto end;
  2150. }
  2151. //
  2152. // If require, get the write lock
  2153. //
  2154. if (fWriteLock)
  2155. {
  2156. WCHAR *szLockedBy = NULL;
  2157. hr = pnc->QueryInterface( IID_INetCfgLock, ( void **) &pncl );
  2158. if( !SUCCEEDED( hr ) )
  2159. {
  2160. TRACE_CRIT("ERROR: could not get interface to NetCfg Lock");
  2161. pncl = NULL;
  2162. goto end;
  2163. }
  2164. hr = pncl->AcquireWriteLock( 1, // One Second
  2165. NLB_CLIENT_NAME,
  2166. &szLockedBy);
  2167. if( hr != S_OK )
  2168. {
  2169. TRACE_CRIT("Could not get write lock. Lock held by %ws",
  2170. (szLockedBy!=NULL) ? szLockedBy : L"<null>");
  2171. goto end;
  2172. }
  2173. CoTaskMemFree(szLockedBy); // szLockedBy can be NULL;
  2174. fLocked = TRUE;
  2175. }
  2176. // Initializes network configuration by loading into
  2177. // memory all basic networking information
  2178. //
  2179. hr = pnc->Initialize( NULL );
  2180. if( !SUCCEEDED( hr ) )
  2181. {
  2182. // failure to Initialize
  2183. TRACE_CRIT("INetCfg::Initialize failure ");
  2184. goto end;
  2185. }
  2186. fInitialized = TRUE;
  2187. Status = WBEM_NO_ERROR;
  2188. end:
  2189. if (FAILED(Status))
  2190. {
  2191. if (pncl!=NULL)
  2192. {
  2193. if (fLocked)
  2194. {
  2195. pncl->ReleaseWriteLock();
  2196. }
  2197. pncl->Release();
  2198. pncl=NULL;
  2199. }
  2200. if( pnc != NULL)
  2201. {
  2202. if (fInitialized)
  2203. {
  2204. pnc->Uninitialize();
  2205. }
  2206. pnc->Release();
  2207. pnc= NULL;
  2208. }
  2209. }
  2210. else
  2211. {
  2212. m_pINetCfg = pnc;
  2213. m_pLock = pncl;
  2214. }
  2215. return Status;
  2216. }
  2217. VOID
  2218. MyNetCfg::Deinitialize(
  2219. VOID
  2220. )
  2221. {
  2222. if (m_pLock!=NULL)
  2223. {
  2224. m_pLock->ReleaseWriteLock();
  2225. m_pLock->Release();
  2226. m_pLock=NULL;
  2227. }
  2228. if( m_pINetCfg != NULL)
  2229. {
  2230. m_pINetCfg->Uninitialize();
  2231. m_pINetCfg->Release();
  2232. m_pINetCfg= NULL;
  2233. }
  2234. }
  2235. WBEMSTATUS
  2236. MyNetCfg::GetNicIF(
  2237. IN LPCWSTR szNicGuid,
  2238. OUT INetCfgComponent **ppINic
  2239. )
  2240. {
  2241. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  2242. INetCfgComponent *pncc = NULL;
  2243. HRESULT hr;
  2244. IEnumNetCfgComponent* pencc = NULL;
  2245. ULONG countToFetch = 1;
  2246. ULONG countFetched;
  2247. DWORD characteristics;
  2248. if (m_pINetCfg == NULL)
  2249. {
  2250. //
  2251. // This means we're not initialized
  2252. //
  2253. ASSERT(FALSE);
  2254. goto end;
  2255. }
  2256. hr = m_pINetCfg->EnumComponents( &GUID_DEVCLASS_NET, &pencc );
  2257. if( !SUCCEEDED( hr ) )
  2258. {
  2259. // failure to Enumerate net components
  2260. TRACE_CRIT("Could not enum netcfg adapters");
  2261. pencc = NULL;
  2262. goto end;
  2263. }
  2264. while( ( hr = pencc->Next( countToFetch, &pncc, &countFetched ) )== S_OK )
  2265. {
  2266. LPWSTR szName = NULL;
  2267. hr = pncc->GetBindName( &szName );
  2268. if (!SUCCEEDED(hr))
  2269. {
  2270. TRACE_CRIT("WARNING: couldn't get bind name for 0x%p, ignoring",
  2271. (PVOID) pncc);
  2272. continue;
  2273. }
  2274. if(!_wcsicmp(szName, szNicGuid))
  2275. {
  2276. //
  2277. // Got this one!
  2278. //
  2279. CoTaskMemFree( szName );
  2280. break;
  2281. }
  2282. CoTaskMemFree( szName );
  2283. pncc->Release();
  2284. pncc=NULL;
  2285. }
  2286. if (pncc == NULL)
  2287. {
  2288. TRACE_CRIT("Could not find NIC %ws", szNicGuid);
  2289. Status = WBEM_E_NOT_FOUND;
  2290. }
  2291. else
  2292. {
  2293. Status = WBEM_NO_ERROR;
  2294. }
  2295. end:
  2296. if (pencc != NULL)
  2297. {
  2298. pencc->Release();
  2299. }
  2300. *ppINic = pncc;
  2301. return Status;
  2302. }
  2303. LPWSTR *
  2304. CfgUtilsAllocateStringArray(
  2305. UINT NumStrings,
  2306. UINT MaxStringLen // excluding ending NULL
  2307. )
  2308. /*
  2309. Allocate a single chunk of memory using the new LPWSTR[] operator.
  2310. The first NumStrings LPWSTR values of this operator contain an array
  2311. of pointers to WCHAR strings. Each of these strings
  2312. is of size (MaxStringLen+1) WCHARS.
  2313. The rest of the memory contains the strings themselve.
  2314. Return NULL if NumStrings==0 or on allocation failure.
  2315. Each of the strings are initialized to be empty strings (first char is 0).
  2316. */
  2317. {
  2318. LPWSTR *pStrings = NULL;
  2319. UINT TotalSize = 0;
  2320. if (NumStrings == 0)
  2321. {
  2322. goto end;
  2323. }
  2324. //
  2325. // Note - even if MaxStringLen is 0 we will allocate space for NumStrings
  2326. // pointers and NumStrings empty (first char is 0) strings.
  2327. //
  2328. //
  2329. // Calculate space for the array of pointers to strings...
  2330. //
  2331. TotalSize = NumStrings*sizeof(LPWSTR);
  2332. //
  2333. // Calculate space for the strings themselves...
  2334. // Remember to add +1 for each ending 0 character.
  2335. //
  2336. TotalSize += NumStrings*(MaxStringLen+1)*sizeof(WCHAR);
  2337. //
  2338. // Allocate space for *both* the array of pointers and the strings
  2339. // in one shot -- we're doing a new of type LPWSTR[] for the whole
  2340. // lot, so need to specify the size in units of LPWSTR (with an
  2341. // additional +1 in case there's roundoff.
  2342. //
  2343. pStrings = new LPWSTR[(TotalSize/sizeof(LPWSTR))+1];
  2344. if (pStrings == NULL)
  2345. {
  2346. goto end;
  2347. }
  2348. //
  2349. // Make sz point to the start of the place where we'll be placing
  2350. // the string data.
  2351. //
  2352. LPWSTR sz = (LPWSTR) (pStrings+NumStrings);
  2353. for (UINT u=0; u<NumStrings; u++)
  2354. {
  2355. *sz=NULL;
  2356. pStrings[u] = sz;
  2357. sz+=(MaxStringLen+1); // +1 for ending NULL
  2358. }
  2359. end:
  2360. return pStrings;
  2361. }
  2362. WBEMSTATUS
  2363. MyNetCfg::GetNlbCompatibleNics(
  2364. OUT LPWSTR **ppszNics,
  2365. OUT UINT *pNumNics,
  2366. OUT UINT *pNumBoundToNlb // OPTIONAL
  2367. )
  2368. /*
  2369. Returns an array of pointers to string-version of GUIDS
  2370. that represent the set of alive and healthy NICS that are
  2371. suitable for NLB to bind to -- basically alive ethernet NICs.
  2372. Delete ppNics using the delete WCHAR[] operator. Do not
  2373. delete the individual strings.
  2374. */
  2375. {
  2376. #define MY_GUID_LENGTH 38
  2377. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  2378. HRESULT hr;
  2379. IEnumNetCfgComponent* pencc = NULL;
  2380. INetCfgComponent *pncc = NULL;
  2381. ULONG countToFetch = 1;
  2382. ULONG countFetched;
  2383. UINT NumNics = 0;
  2384. LPWSTR *pszNics = NULL;
  2385. INetCfgComponentBindings *pINlbBinding=NULL;
  2386. UINT NumNlbBoundNics = 0;
  2387. typedef struct _MYNICNODE MYNICNODE;
  2388. typedef struct _MYNICNODE
  2389. {
  2390. LPWSTR szNicGuid;
  2391. MYNICNODE *pNext;
  2392. } MYNICNODE;
  2393. MYNICNODE *pNicNodeList = NULL;
  2394. MYNICNODE *pNicNode = NULL;
  2395. *ppszNics = NULL;
  2396. *pNumNics = 0;
  2397. if (pNumBoundToNlb != NULL)
  2398. {
  2399. *pNumBoundToNlb = 0;
  2400. }
  2401. if (m_pINetCfg == NULL)
  2402. {
  2403. //
  2404. // This means we're not initialized
  2405. //
  2406. ASSERT(FALSE);
  2407. goto end;
  2408. }
  2409. hr = m_pINetCfg->EnumComponents( &GUID_DEVCLASS_NET, &pencc );
  2410. if( !SUCCEEDED( hr ) )
  2411. {
  2412. // failure to Enumerate net components
  2413. TRACE_CRIT("%!FUNC! Could not enum netcfg adapters");
  2414. pencc = NULL;
  2415. goto end;
  2416. }
  2417. //
  2418. // Check if nlb is bound to the nlb component.
  2419. //
  2420. //
  2421. // If we need to count of NLB-bound nics, get instance of the nlb component
  2422. //
  2423. if (pNumBoundToNlb != NULL)
  2424. {
  2425. Status = GetBindingIF(L"ms_wlbs", &pINlbBinding);
  2426. if (FAILED(Status))
  2427. {
  2428. TRACE_CRIT("%!FUNC! WARNING: NLB doesn't appear to be installed on this machine");
  2429. pINlbBinding = NULL;
  2430. }
  2431. }
  2432. while( ( hr = pencc->Next( countToFetch, &pncc, &countFetched ) )== S_OK )
  2433. {
  2434. LPWSTR szName = NULL;
  2435. hr = pncc->GetBindName( &szName );
  2436. if (!SUCCEEDED(hr))
  2437. {
  2438. TRACE_CRIT("%!FUNC! WARNING: couldn't get bind name for 0x%p, ignoring",
  2439. (PVOID) pncc);
  2440. continue;
  2441. }
  2442. do // while FALSE -- just to allow breaking out
  2443. {
  2444. UINT Len = wcslen(szName);
  2445. if (Len != MY_GUID_LENGTH)
  2446. {
  2447. TRACE_CRIT("%!FUNC! WARNING: GUID %ws has unexpected length %ul",
  2448. szName, Len);
  2449. break;
  2450. }
  2451. DWORD characteristics = 0;
  2452. hr = pncc->GetCharacteristics( &characteristics );
  2453. if(!SUCCEEDED(hr))
  2454. {
  2455. TRACE_CRIT("%!FUNC! WARNING: couldn't get characteristics for %ws, ignoring",
  2456. szName);
  2457. break;
  2458. }
  2459. if (((characteristics & NCF_PHYSICAL) || (characteristics & NCF_VIRTUAL)) && !(characteristics & NCF_HIDDEN))
  2460. {
  2461. ULONG devstat = 0;
  2462. // This is a physical or virtual miniport that is NOT hidden. These
  2463. // are the same adapters that show up in the "Network Connections"
  2464. // dialog. Hidden devices include WAN miniports, RAS miniports and
  2465. // NLB miniports - all of which should be excluded here.
  2466. // check if the nic is enabled, we are only
  2467. // interested in enabled nics.
  2468. //
  2469. hr = pncc->GetDeviceStatus( &devstat );
  2470. if(!SUCCEEDED(hr))
  2471. {
  2472. TRACE_CRIT(
  2473. "%!FUNC! WARNING: couldn't get dev status for %ws, ignoring",
  2474. szName
  2475. );
  2476. break;
  2477. }
  2478. // if any of the nics has any of the problem codes
  2479. // then it cannot be used.
  2480. if( devstat != CM_PROB_NOT_CONFIGURED
  2481. &&
  2482. devstat != CM_PROB_FAILED_START
  2483. &&
  2484. devstat != CM_PROB_NORMAL_CONFLICT
  2485. &&
  2486. devstat != CM_PROB_NEED_RESTART
  2487. &&
  2488. devstat != CM_PROB_REINSTALL
  2489. &&
  2490. devstat != CM_PROB_WILL_BE_REMOVED
  2491. &&
  2492. devstat != CM_PROB_DISABLED
  2493. &&
  2494. devstat != CM_PROB_FAILED_INSTALL
  2495. &&
  2496. devstat != CM_PROB_FAILED_ADD
  2497. )
  2498. {
  2499. //
  2500. // No problem with this nic and also
  2501. // physical device
  2502. // thus we want it.
  2503. //
  2504. if (pINlbBinding != NULL)
  2505. {
  2506. BOOL fBound = FALSE;
  2507. hr = pINlbBinding->IsBoundTo(pncc);
  2508. if( !SUCCEEDED( hr ) )
  2509. {
  2510. TRACE_CRIT("IsBoundTo method failed for Nic %ws", szName);
  2511. goto end;
  2512. }
  2513. if( hr == S_OK )
  2514. {
  2515. TRACE_VERB("BOUND: %ws\n", szName);
  2516. NumNlbBoundNics++;
  2517. fBound = TRUE;
  2518. }
  2519. else if (hr == S_FALSE )
  2520. {
  2521. TRACE_VERB("NOT BOUND: %ws\n", szName);
  2522. fBound = FALSE;
  2523. }
  2524. }
  2525. // We allocate a little node to keep this string
  2526. // temporarily and add it to our list of nodes.
  2527. //
  2528. pNicNode = new MYNICNODE;
  2529. if (pNicNode == NULL)
  2530. {
  2531. Status = WBEM_E_OUT_OF_MEMORY;
  2532. goto end;
  2533. }
  2534. ZeroMemory(pNicNode, sizeof(*pNicNode));
  2535. pNicNode->szNicGuid = szName;
  2536. szName = NULL; // so we don't delete inside the lopp.
  2537. pNicNode->pNext = pNicNodeList;
  2538. pNicNodeList = pNicNode;
  2539. NumNics++;
  2540. }
  2541. else
  2542. {
  2543. // There is a problem...
  2544. TRACE_CRIT(
  2545. "%!FUNC! WARNING: Skipping %ws because DeviceStatus=0x%08lx",
  2546. szName, devstat
  2547. );
  2548. break;
  2549. }
  2550. }
  2551. else
  2552. {
  2553. TRACE_VERB("%!FUNC! Ignoring non-physical device %ws", szName);
  2554. }
  2555. } while (FALSE);
  2556. if (szName != NULL)
  2557. {
  2558. CoTaskMemFree( szName );
  2559. }
  2560. pncc->Release();
  2561. pncc=NULL;
  2562. }
  2563. if (pINlbBinding!=NULL)
  2564. {
  2565. pINlbBinding->Release();
  2566. pINlbBinding = NULL;
  2567. }
  2568. if (NumNics==0)
  2569. {
  2570. Status = WBEM_NO_ERROR;
  2571. goto end;
  2572. }
  2573. //
  2574. // Now let's allocate space for all the nic strings and:w
  2575. // copy them over..
  2576. //
  2577. #define MY_GUID_LENGTH 38
  2578. pszNics = CfgUtilsAllocateStringArray(NumNics, MY_GUID_LENGTH);
  2579. if (pszNics == NULL)
  2580. {
  2581. Status = WBEM_E_OUT_OF_MEMORY;
  2582. goto end;
  2583. }
  2584. pNicNode= pNicNodeList;
  2585. for (UINT u=0; u<NumNics; u++, pNicNode=pNicNode->pNext)
  2586. {
  2587. ASSERT(pNicNode != NULL); // because we just counted NumNics of em.
  2588. UINT Len = wcslen(pNicNode->szNicGuid);
  2589. if (Len != MY_GUID_LENGTH)
  2590. {
  2591. //
  2592. // We should never get here beause we checked the length earlier.
  2593. //
  2594. TRACE_CRIT("%!FUNC! ERROR: GUID %ws has unexpected length %ul",
  2595. pNicNode->szNicGuid, Len);
  2596. ASSERT(FALSE);
  2597. Status = WBEM_E_CRITICAL_ERROR;
  2598. goto end;
  2599. }
  2600. CopyMemory(
  2601. pszNics[u],
  2602. pNicNode->szNicGuid,
  2603. (MY_GUID_LENGTH+1)*sizeof(WCHAR));
  2604. ASSERT(pszNics[u][MY_GUID_LENGTH]==0);
  2605. }
  2606. Status = WBEM_NO_ERROR;
  2607. end:
  2608. //
  2609. // Now release the temporarly allocated memory.
  2610. //
  2611. pNicNode= pNicNodeList;
  2612. while (pNicNode!=NULL)
  2613. {
  2614. MYNICNODE *pTmp = pNicNode->pNext;
  2615. CoTaskMemFree(pNicNode->szNicGuid);
  2616. pNicNode->szNicGuid = NULL;
  2617. delete pNicNode;
  2618. pNicNode = pTmp;
  2619. }
  2620. if (FAILED(Status))
  2621. {
  2622. TRACE_CRIT("%!FUNC! fails with status 0x%08lx", (UINT) Status);
  2623. NumNics = 0;
  2624. if (pszNics!=NULL)
  2625. {
  2626. delete pszNics;
  2627. pszNics = NULL;
  2628. }
  2629. }
  2630. else
  2631. {
  2632. if (pNumBoundToNlb != NULL)
  2633. {
  2634. *pNumBoundToNlb = NumNlbBoundNics;
  2635. }
  2636. *ppszNics = pszNics;
  2637. *pNumNics = NumNics;
  2638. }
  2639. if (pencc != NULL)
  2640. {
  2641. pencc->Release();
  2642. }
  2643. return Status;
  2644. }
  2645. WBEMSTATUS
  2646. MyNetCfg::GetBindingIF(
  2647. IN LPCWSTR szComponent,
  2648. OUT INetCfgComponentBindings **ppIBinding
  2649. )
  2650. {
  2651. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  2652. INetCfgComponent *pncc = NULL;
  2653. INetCfgComponentBindings *pnccb = NULL;
  2654. HRESULT hr;
  2655. if (m_pINetCfg == NULL)
  2656. {
  2657. //
  2658. // This means we're not initialized
  2659. //
  2660. ASSERT(FALSE);
  2661. goto end;
  2662. }
  2663. hr = m_pINetCfg->FindComponent(szComponent, &pncc);
  2664. if (FAILED(hr))
  2665. {
  2666. TRACE_CRIT("Error checking if component %ws does not exist\n", szComponent);
  2667. pncc = NULL;
  2668. goto end;
  2669. }
  2670. else if (hr == S_FALSE)
  2671. {
  2672. Status = WBEM_E_NOT_FOUND;
  2673. TRACE_CRIT("Component %ws does not exist\n", szComponent);
  2674. goto end;
  2675. }
  2676. hr = pncc->QueryInterface( IID_INetCfgComponentBindings, (void **) &pnccb );
  2677. if( !SUCCEEDED( hr ) )
  2678. {
  2679. TRACE_CRIT("INetCfgComponent::QueryInterface failed ");
  2680. pnccb = NULL;
  2681. goto end;
  2682. }
  2683. Status = WBEM_NO_ERROR;
  2684. end:
  2685. if (pncc)
  2686. {
  2687. pncc->Release();
  2688. pncc=NULL;
  2689. }
  2690. *ppIBinding = pnccb;
  2691. return Status;
  2692. }
  2693. WBEMSTATUS
  2694. set_string_parameter(
  2695. IN IWbemClassObjectPtr spObj,
  2696. IN LPCWSTR szParameterName,
  2697. IN LPCWSTR szValue
  2698. )
  2699. {
  2700. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  2701. HRESULT hr;
  2702. {
  2703. _bstr_t bstrName = szParameterName;
  2704. _variant_t v_value = (LPWSTR) szValue; // Allocates.
  2705. hr = spObj->Put(
  2706. bstrName, // Parameter Name
  2707. 0, // Must be 0
  2708. &v_value,
  2709. 0 // Must be 0
  2710. );
  2711. v_value.Clear();
  2712. if (FAILED(hr))
  2713. {
  2714. TRACE_CRIT("Unable to put parameter %ws", szParameterName);
  2715. goto end;
  2716. }
  2717. Status = WBEM_NO_ERROR;
  2718. //
  2719. // I think bstrName releases the internally allocated string
  2720. // on exiting this block.
  2721. //
  2722. }
  2723. end:
  2724. return Status;
  2725. }
  2726. WBEMSTATUS
  2727. set_multi_string_parameter(
  2728. IN IWbemClassObjectPtr spObj,
  2729. IN LPCWSTR szParameterName,
  2730. IN UINT MaxStringLen, // in wchars, INCLUDING space for trailing zeros.
  2731. IN UINT NumItems,
  2732. IN LPCWSTR pStringValue
  2733. )
  2734. {
  2735. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  2736. SAFEARRAY *pSA = NULL;
  2737. HRESULT hr;
  2738. LONG Index = 0;
  2739. //
  2740. // Create safe array for the parameter values
  2741. //
  2742. pSA = SafeArrayCreateVector(
  2743. VT_BSTR,
  2744. 0, // lower bound
  2745. NumItems // size of the fixed-sized vector.
  2746. );
  2747. if (pSA == NULL)
  2748. {
  2749. TRACE_CRIT("Could not create safe array");
  2750. Status = WBEM_E_OUT_OF_MEMORY;
  2751. goto end;
  2752. }
  2753. //
  2754. // Place the strings into the safe array
  2755. //
  2756. {
  2757. for (Index = 0; Index<NumItems; Index++)
  2758. {
  2759. LPCWSTR sz = pStringValue + Index*MaxStringLen;
  2760. //
  2761. // SafeArrayPutElement expects the string passed in to
  2762. // be of type BSTR, which is of type wchar *, except, that
  2763. // the first 2 wchars contains length and other(?)
  2764. // information. This is why you can't simply pass in sz.
  2765. //
  2766. // So to get this we initalize an object of type _bstr_t
  2767. // based on sz. On initializaton, bstrValue allocates memory
  2768. // and copies the string.
  2769. //
  2770. _bstr_t bstrValue = sz;
  2771. wchar_t *pwchar = (wchar_t *) bstrValue; // returns internal pointer.
  2772. // bpStr[Index] = sz; // may work as well.
  2773. //
  2774. // SafeArrayPutElement internally allocates space for pwchar and
  2775. // copies over the string.
  2776. // So pSA doesn't contain a direct reference to pwchar.
  2777. //
  2778. hr = SafeArrayPutElement(pSA, &Index, pwchar);
  2779. if (FAILED(hr))
  2780. {
  2781. TRACE_CRIT("Unable to put element %wsz", sz);
  2782. (VOID) SafeArrayUnaccessData(pSA);
  2783. goto end;
  2784. }
  2785. //
  2786. // I think that bstrValue's contents are deallocated on exit of
  2787. // this block.
  2788. //
  2789. }
  2790. }
  2791. #if DBG
  2792. //
  2793. // Just check ...
  2794. //
  2795. {
  2796. BSTR *pbStr=NULL;
  2797. hr = SafeArrayAccessData(pSA, ( void **) &pbStr);
  2798. if (FAILED(hr))
  2799. {
  2800. TRACE_CRIT("Could not access data of safe array");
  2801. goto end;
  2802. }
  2803. for (UINT u = 0; u<NumItems; u++)
  2804. {
  2805. LPCWSTR sz = pbStr[u];
  2806. if (_wcsicmp(sz, (pStringValue + u*MaxStringLen)))
  2807. {
  2808. TRACE_CRIT("!!!MISMATCH!!!!");
  2809. }
  2810. else
  2811. {
  2812. TRACE_CRIT("!!!MATCH!!!!");
  2813. }
  2814. }
  2815. (VOID) SafeArrayUnaccessData(pSA);
  2816. pbStr=NULL;
  2817. }
  2818. #endif // DBG
  2819. //
  2820. // Put the parameter.
  2821. //
  2822. {
  2823. VARIANT V;
  2824. _bstr_t bstrName = szParameterName;
  2825. VariantInit(&V);
  2826. V.vt = VT_ARRAY | VT_BSTR;
  2827. V.parray = pSA;
  2828. _variant_t v_value;
  2829. v_value.Attach(V); // Takes owhership of V. V now becomes empty.
  2830. ASSERT(V.vt == VT_EMPTY);
  2831. pSA = NULL; // should be no need to delete this explicitly now.
  2832. // v_value.Clear() should delete it, I think.
  2833. hr = spObj->Put(
  2834. bstrName, // Parameter Name
  2835. 0, // Must be 0
  2836. &v_value,
  2837. 0 // Must be 0
  2838. );
  2839. v_value.Clear();
  2840. if (FAILED(hr))
  2841. {
  2842. TRACE_CRIT("Unable to put parameter %ws", szParameterName);
  2843. goto end;
  2844. }
  2845. Status = WBEM_NO_ERROR;
  2846. }
  2847. //
  2848. // ?Destroy the data?
  2849. //
  2850. if (FAILED(Status))
  2851. {
  2852. if (pSA!=NULL)
  2853. {
  2854. SafeArrayDestroy(pSA);
  2855. pSA = NULL;
  2856. }
  2857. }
  2858. end:
  2859. return Status;
  2860. }
  2861. WBEMSTATUS
  2862. MyNetCfg::UpdateBindingState(
  2863. IN LPCWSTR szNic,
  2864. IN LPCWSTR szComponent,
  2865. IN UPDATE_OP Op,
  2866. OUT BOOL *pfBound
  2867. )
  2868. {
  2869. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  2870. INetCfgComponent *pINic = NULL;
  2871. INetCfgComponentBindings *pIBinding=NULL;
  2872. BOOL fBound = FALSE;
  2873. HRESULT hr;
  2874. //
  2875. // Get instance to the NIC
  2876. //
  2877. Status = GetNicIF(szNic, &pINic);
  2878. if (FAILED(Status))
  2879. {
  2880. pINic = NULL;
  2881. goto end;
  2882. }
  2883. //
  2884. // Get instance of the nlb component
  2885. //
  2886. Status = GetBindingIF(szComponent, &pIBinding);
  2887. if (FAILED(Status))
  2888. {
  2889. pIBinding = NULL;
  2890. goto end;
  2891. }
  2892. //
  2893. // Check if nlb is bound to the nlb component.
  2894. //
  2895. hr = pIBinding->IsBoundTo(pINic);
  2896. if( !SUCCEEDED( hr ) )
  2897. {
  2898. TRACE_CRIT("IsBoundTo method failed for Nic %ws", szNic);
  2899. goto end;
  2900. }
  2901. if( hr == S_OK )
  2902. {
  2903. fBound = TRUE;
  2904. }
  2905. else if (hr == S_FALSE )
  2906. {
  2907. fBound = FALSE;
  2908. }
  2909. if ( (Op == MyNetCfg::NOOP)
  2910. || (Op == MyNetCfg::BIND && fBound)
  2911. || (Op == MyNetCfg::UNBIND && !fBound))
  2912. {
  2913. Status = WBEM_NO_ERROR;
  2914. goto end;
  2915. }
  2916. if (Op == MyNetCfg::BIND)
  2917. {
  2918. hr = pIBinding->BindTo( pINic );
  2919. }
  2920. else if (Op == MyNetCfg::UNBIND)
  2921. {
  2922. hr = pIBinding->UnbindFrom( pINic );
  2923. }
  2924. else
  2925. {
  2926. ASSERT(FALSE);
  2927. goto end;
  2928. }
  2929. if (FAILED(hr))
  2930. {
  2931. TRACE_CRIT("Error 0x%08lx %ws %ws on %ws",
  2932. (UINT) hr,
  2933. ((Op==MyNetCfg::BIND) ? L"binding" : L"unbinding"),
  2934. szComponent,
  2935. szNic
  2936. );
  2937. goto end;
  2938. }
  2939. //
  2940. // apply the binding change made.
  2941. //
  2942. hr = m_pINetCfg->Apply();
  2943. if( !SUCCEEDED( hr ) )
  2944. {
  2945. TRACE_CRIT("INetCfg::Apply failed with 0x%08lx", (UINT) hr);
  2946. goto end;
  2947. }
  2948. //
  2949. // We're done. Our state should now be toggled.
  2950. //
  2951. fBound = !fBound;
  2952. Status = WBEM_NO_ERROR;
  2953. end:
  2954. if (pINic!=NULL)
  2955. {
  2956. pINic->Release();
  2957. pINic = NULL;
  2958. }
  2959. if (pIBinding!=NULL)
  2960. {
  2961. pIBinding->Release();
  2962. pIBinding = NULL;
  2963. }
  2964. *pfBound = fBound;
  2965. return Status;
  2966. }
  2967. bool MapOpcodeToIoctl(WLBS_OPERATION_CODES Opcode, LONG *plIoctl)
  2968. {
  2969. struct OPCODE_IOCTL_MAP
  2970. {
  2971. WLBS_OPERATION_CODES Opcode;
  2972. LONG ioctl;
  2973. }
  2974. OpcodeIoctlMap[] =
  2975. {
  2976. {WLBS_START, IOCTL_CVY_CLUSTER_ON},
  2977. {WLBS_STOP, IOCTL_CVY_CLUSTER_OFF},
  2978. {WLBS_DRAIN, IOCTL_CVY_CLUSTER_DRAIN},
  2979. {WLBS_SUSPEND, IOCTL_CVY_CLUSTER_SUSPEND},
  2980. {WLBS_RESUME, IOCTL_CVY_CLUSTER_RESUME},
  2981. {WLBS_PORT_ENABLE, IOCTL_CVY_PORT_ON},
  2982. {WLBS_PORT_DISABLE, IOCTL_CVY_PORT_OFF},
  2983. {WLBS_PORT_DRAIN, IOCTL_CVY_PORT_DRAIN},
  2984. {WLBS_QUERY, IOCTL_CVY_QUERY},
  2985. {WLBS_QUERY_PORT_STATE, IOCTL_CVY_QUERY_PORT_STATE}
  2986. };
  2987. for (int i=0; i<sizeof(OpcodeIoctlMap) /sizeof(OpcodeIoctlMap[0]); i++)
  2988. {
  2989. if (OpcodeIoctlMap[i].Opcode == Opcode)
  2990. {
  2991. *plIoctl = OpcodeIoctlMap[i].ioctl;
  2992. return true;
  2993. }
  2994. }
  2995. //
  2996. // Default
  2997. //
  2998. return false;
  2999. }
  3000. WBEMSTATUS
  3001. CfgUtilControlCluster(
  3002. IN LPCWSTR szNic,
  3003. IN WLBS_OPERATION_CODES Opcode,
  3004. IN DWORD Vip,
  3005. IN DWORD PortNum,
  3006. OUT DWORD * pdwHostMap,
  3007. OUT DWORD * pdwNlbStatus
  3008. )
  3009. {
  3010. HRESULT hr;
  3011. GUID Guid;
  3012. WBEMSTATUS Status;
  3013. LONG ioctl;
  3014. TRACE_INFO(L"-> %!FUNC! szNic : %ls, Opcode: %d, Vip : 0x%x, Port : 0x%x", szNic, Opcode, Vip, PortNum);
  3015. if (pdwNlbStatus)
  3016. {
  3017. *pdwNlbStatus = WLBS_FAILURE;
  3018. }
  3019. if (!g_CfgUtils.IsInitalized())
  3020. {
  3021. TRACE_CRIT(L"%!FUNC!(Nic=%ws) FAILING because uninitialized", szNic);
  3022. Status = WBEM_E_INITIALIZATION_FAILURE;
  3023. goto end;
  3024. }
  3025. hr = CLSIDFromString((LPWSTR)szNic, &Guid);
  3026. if (FAILED(hr))
  3027. {
  3028. TRACE_CRIT(
  3029. L"CWlbsControl::Initialize failed at CLSIDFromString %ws",
  3030. szNic
  3031. );
  3032. Status = WBEM_E_INVALID_PARAMETER;
  3033. if (pdwNlbStatus)
  3034. {
  3035. *pdwNlbStatus = WLBS_BAD_PARAMS;
  3036. }
  3037. goto end;
  3038. }
  3039. // Verify that the NLB API hooks are present
  3040. if (!g_CfgUtils.m_NLBApiHooksPresent)
  3041. {
  3042. TRACE_CRIT(L"%!FUNC! FAILING because NLB API hooks are not present");
  3043. Status = WBEM_E_INITIALIZATION_FAILURE;
  3044. goto end;
  3045. }
  3046. HANDLE Nlb_driver_hdl;
  3047. // Get handle to NLB driver
  3048. if ((Nlb_driver_hdl = g_CfgUtils.m_pfWlbsOpen()) == INVALID_HANDLE_VALUE)
  3049. {
  3050. TRACE_CRIT(L"%!FUNC! WlbsOpen returned NULL, Could not create connection to NLB driver");
  3051. Status = WBEM_E_CRITICAL_ERROR;
  3052. goto end;
  3053. }
  3054. // Convert Opcode to ioctl
  3055. if (!MapOpcodeToIoctl(Opcode, &ioctl))
  3056. {
  3057. TRACE_CRIT(L"%!FUNC!: Invalid value (0x%x) for operation!",Opcode);
  3058. Status = WBEM_E_INVALID_PARAMETER;
  3059. if (pdwNlbStatus)
  3060. {
  3061. *pdwNlbStatus = WLBS_BAD_PARAMS;
  3062. }
  3063. CloseHandle(Nlb_driver_hdl);
  3064. goto end;
  3065. }
  3066. DWORD dwRet = g_CfgUtils.m_pfWlbsLocalClusterControl(Nlb_driver_hdl, &Guid, ioctl, Vip, PortNum, pdwHostMap);
  3067. if (pdwNlbStatus)
  3068. {
  3069. *pdwNlbStatus = dwRet;
  3070. }
  3071. // Close handle to NLB driver
  3072. CloseHandle(Nlb_driver_hdl);
  3073. Status = WBEM_NO_ERROR;
  3074. switch(dwRet)
  3075. {
  3076. case WLBS_ALREADY: break;
  3077. case WLBS_CONVERGED: break;
  3078. case WLBS_CONVERGING: break;
  3079. case WLBS_DEFAULT: break;
  3080. case WLBS_DRAIN_STOP: break;
  3081. case WLBS_DRAINING: break;
  3082. case WLBS_OK: break;
  3083. case WLBS_STOPPED: break;
  3084. case WLBS_SUSPENDED: break;
  3085. case NLB_PORT_RULE_NOT_FOUND: break;
  3086. case NLB_PORT_RULE_ENABLED: break;
  3087. case NLB_PORT_RULE_DISABLED: break;
  3088. case NLB_PORT_RULE_DRAINING: break;
  3089. case WLBS_BAD_PARAMS: Status = WBEM_E_INVALID_PARAMETER; break;
  3090. default: Status = WBEM_E_CRITICAL_ERROR; break;
  3091. }
  3092. end:
  3093. TRACE_INFO(L"<- %!FUNC! returns Status : 0x%x",Status);
  3094. return Status;
  3095. }
  3096. WBEMSTATUS
  3097. CfgUtilGetClusterMembers(
  3098. IN LPCWSTR szNic,
  3099. OUT DWORD *pNumMembers,
  3100. OUT NLB_CLUSTER_MEMBER_INFO **ppMembers // free using delete[]
  3101. )
  3102. {
  3103. HRESULT hr;
  3104. GUID AdapterGuid;
  3105. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  3106. DWORD dwNumHosts = CVY_MAX_HOSTS;
  3107. PWLBS_RESPONSE pResponse = NULL;
  3108. NLB_CLUSTER_MEMBER_INFO* pMembers = NULL;
  3109. TRACE_INFO(L"-> szNic : %ls", szNic);
  3110. ASSERT (pNumMembers != NULL);
  3111. ASSERT (ppMembers != NULL);
  3112. *pNumMembers = 0;
  3113. *ppMembers = NULL;
  3114. if (!g_CfgUtils.IsInitalized())
  3115. {
  3116. TRACE_CRIT(L"(Nic=%ws) FAILING because uninitialized", szNic);
  3117. Status = WBEM_E_INITIALIZATION_FAILURE;
  3118. goto end;
  3119. }
  3120. hr = CLSIDFromString((LPWSTR)szNic, &AdapterGuid);
  3121. if (FAILED(hr))
  3122. {
  3123. TRACE_CRIT(L"CLSIDFromString failed with error %ws", szNic);
  3124. Status = WBEM_E_INVALID_PARAMETER;
  3125. goto end;
  3126. }
  3127. // Verify that the NLB API hooks are present
  3128. if (!g_CfgUtils.m_NLBApiHooksPresent)
  3129. {
  3130. TRACE_CRIT(L"FAILING because NLB API hooks are not present");
  3131. Status = WBEM_E_INITIALIZATION_FAILURE;
  3132. goto end;
  3133. }
  3134. pResponse = new WLBS_RESPONSE[CVY_MAX_HOSTS];
  3135. if (pResponse == NULL)
  3136. {
  3137. TRACE_CRIT(L"FAILING because memory allocation failed");
  3138. Status = WBEM_E_OUT_OF_MEMORY;
  3139. goto end;
  3140. }
  3141. ZeroMemory(pResponse, sizeof(WLBS_RESPONSE)*CVY_MAX_HOSTS);
  3142. {
  3143. DWORD dwStatus;
  3144. dwStatus = g_CfgUtils.m_pfWlbsGetClusterMembers (
  3145. & AdapterGuid,
  3146. & dwNumHosts,
  3147. pResponse
  3148. );
  3149. //
  3150. // WLBS_TIMEOUT, i.e., 0 hosts responding is considered a failure. So the only success code is WLBS_OK.
  3151. // TODO: If we want timeout to be success, need to make a change here.
  3152. //
  3153. if (dwStatus != WLBS_OK)
  3154. {
  3155. TRACE_CRIT("error getting list of cluster members: 0x%x", dwStatus);
  3156. Status = WBEM_E_FAILED;
  3157. goto end;
  3158. }
  3159. if (dwNumHosts == 0)
  3160. {
  3161. //
  3162. // Not an error, but we exit here because there were no cluster members.
  3163. //
  3164. TRACE_INFO("WlbsGetClusterMembers returned no cluster members");
  3165. Status = WBEM_S_NO_ERROR;
  3166. goto end;
  3167. }
  3168. }
  3169. pMembers = new NLB_CLUSTER_MEMBER_INFO[dwNumHosts];
  3170. if (pMembers == NULL)
  3171. {
  3172. TRACE_CRIT("error allocating struct to host cluster member info");
  3173. Status = WBEM_E_OUT_OF_MEMORY;
  3174. goto end;
  3175. }
  3176. //
  3177. // Memory allocation succeeded, so set the size of the output array.
  3178. //
  3179. *pNumMembers = dwNumHosts;
  3180. ZeroMemory(pMembers, sizeof(NLB_CLUSTER_MEMBER_INFO)*dwNumHosts);
  3181. *ppMembers = pMembers;
  3182. for (int i=0; i < dwNumHosts; i++, pMembers++)
  3183. {
  3184. pMembers->HostId = pResponse[i].id;
  3185. AbcdWszFromIpAddress(pResponse[i].address, pMembers->DedicatedIpAddress, ASIZECCH(pMembers->DedicatedIpAddress));
  3186. if ((pResponse[i].options.query.hostname)[0] != L'\0')
  3187. {
  3188. wcsncpy(pMembers->HostName, pResponse[i].options.identity.fqdn, CVY_MAX_FQDN + 1);
  3189. pMembers->HostName[CVY_MAX_FQDN] = L'\0';
  3190. }
  3191. }
  3192. Status = WBEM_S_NO_ERROR;
  3193. end:
  3194. // Clean up the output quantities if we had an error
  3195. if (Status != WBEM_S_NO_ERROR)
  3196. {
  3197. if (pMembers != NULL)
  3198. {
  3199. delete [] pMembers;
  3200. pMembers = NULL;
  3201. }
  3202. }
  3203. if (pResponse != NULL)
  3204. {
  3205. delete [] pResponse;
  3206. pResponse = NULL;
  3207. }
  3208. TRACE_INFO(L"<- returns Status : 0x%x",Status);
  3209. return Status;
  3210. }
  3211. //
  3212. // Initializes pParams using default values.
  3213. //
  3214. VOID
  3215. CfgUtilInitializeParams(
  3216. OUT WLBS_REG_PARAMS *pParams
  3217. )
  3218. {
  3219. //
  3220. // We don't expect WlbsSetDefaults to fail (it should have been
  3221. // defined returning VOID).
  3222. //
  3223. DWORD dwRet;
  3224. // Verify that the NLB API hooks are present
  3225. if (!g_CfgUtils.m_NLBApiHooksPresent)
  3226. {
  3227. dwRet = MyWlbsSetDefaults(pParams);
  3228. }
  3229. else
  3230. {
  3231. dwRet = g_CfgUtils.m_pfWlbsSetDefaults(pParams);
  3232. }
  3233. if (dwRet != WLBS_OK)
  3234. {
  3235. ZeroMemory(pParams, sizeof(*pParams));
  3236. TRACE_CRIT("Internal error: WlbsSetDefaults failed");
  3237. ASSERT(FALSE);
  3238. }
  3239. }
  3240. //
  3241. // Converts the specified plain-text password into the hashed version
  3242. // and saves it in pParams.
  3243. //
  3244. DWORD
  3245. CfgUtilSetRemotePassword(
  3246. IN WLBS_REG_PARAMS *pParams,
  3247. IN LPCWSTR szPassword
  3248. )
  3249. {
  3250. //
  3251. // We don't expect WlbsSetDefaults to fail (it should have been
  3252. // defined returning VOID).
  3253. //
  3254. DWORD dwRet;
  3255. // Verify that the NLB API hooks are present
  3256. if (!g_CfgUtils.m_NLBApiHooksPresent)
  3257. {
  3258. TRACE_CRIT(L"%!FUNC! FAILING because NLB API hooks are not present");
  3259. dwRet = WBEM_E_INITIALIZATION_FAILURE;
  3260. goto end;
  3261. }
  3262. else
  3263. {
  3264. dwRet = g_CfgUtils.m_pfWlbsSetRemotePassword(pParams, szPassword);
  3265. }
  3266. end:
  3267. return dwRet;
  3268. }
  3269. WBEMSTATUS
  3270. CfgUtilSafeArrayFromStrings(
  3271. IN LPCWSTR *pStrings,
  3272. IN UINT NumStrings,
  3273. OUT SAFEARRAY **ppSA
  3274. )
  3275. /*
  3276. Allocates and returns a SAFEARRAY of strings -- strings are copies of
  3277. the passed in values.
  3278. Call SafeArrayDestroy when done with the array.
  3279. */
  3280. {
  3281. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  3282. SAFEARRAY *pSA = NULL;
  3283. HRESULT hr;
  3284. LONG Index = 0;
  3285. *ppSA = NULL;
  3286. //
  3287. // Create safe array for the parameter values
  3288. //
  3289. pSA = SafeArrayCreateVector(
  3290. VT_BSTR,
  3291. 0, // lower bound
  3292. NumStrings // size of the fixed-sized vector.
  3293. );
  3294. if (pSA == NULL)
  3295. {
  3296. TRACE_CRIT("Could not create safe array");
  3297. Status = WBEM_E_OUT_OF_MEMORY;
  3298. goto end;
  3299. }
  3300. //
  3301. // Place the strings into the safe array
  3302. //
  3303. {
  3304. for (Index = 0; Index<NumStrings; Index++)
  3305. {
  3306. LPCWSTR sz = pStrings[Index];
  3307. //
  3308. // SafeArrayPutElement expects the string passed in to
  3309. // be of type BSTR, which is of type wchar *, except, that
  3310. // the first 2 wchars contains length and other(?)
  3311. // information. This is why you can't simply pass in sz.
  3312. //
  3313. // So to get this we initalize an object of type _bstr_t
  3314. // based on sz. On initializaton, bstrValue allocates memory
  3315. // and copies the string.
  3316. //
  3317. _bstr_t bstrValue = sz;
  3318. wchar_t *pwchar = (wchar_t *) bstrValue; // returns internal pointer.
  3319. // bpStr[Index] = sz; // may work as well.
  3320. //
  3321. // SafeArrayPutElement internally allocates space for pwchar and
  3322. // copies over the string.
  3323. // So pSA doesn't contain a direct reference to pwchar.
  3324. //
  3325. hr = SafeArrayPutElement(pSA, &Index, pwchar);
  3326. if (FAILED(hr))
  3327. {
  3328. TRACE_CRIT("Unable to put element %wsz", sz);
  3329. (VOID) SafeArrayUnaccessData(pSA);
  3330. goto end;
  3331. }
  3332. //
  3333. // I think that bstrValue's contents are deallocated on exit of
  3334. // this block.
  3335. //
  3336. }
  3337. }
  3338. Status = WBEM_NO_ERROR;
  3339. end:
  3340. if (FAILED(Status))
  3341. {
  3342. if (pSA!=NULL)
  3343. {
  3344. SafeArrayDestroy(pSA);
  3345. pSA = NULL;
  3346. }
  3347. }
  3348. *ppSA = pSA;
  3349. return Status;
  3350. }
  3351. WBEMSTATUS
  3352. CfgUtilStringsFromSafeArray(
  3353. IN SAFEARRAY *pSA,
  3354. OUT LPWSTR **ppStrings,
  3355. OUT UINT *pNumStrings
  3356. )
  3357. /*
  3358. Extracts copies of the strings in the passed-in safe array.
  3359. Free *pStrings using the delete operator when done.
  3360. NOTE: Do NOT delete the individual strings -- they are
  3361. stored in the memory allocated for pStrings.
  3362. */
  3363. {
  3364. WBEMSTATUS Status = WBEM_E_OUT_OF_MEMORY;
  3365. LPWSTR *pStrings = NULL;
  3366. LPCWSTR csz;
  3367. LPWSTR sz;
  3368. UINT NumStrings = 0;
  3369. UINT u;
  3370. HRESULT hr;
  3371. BSTR *pbStr =NULL;
  3372. UINT TotalSize =0;
  3373. LONG UBound = 0;
  3374. *ppStrings = NULL;
  3375. *pNumStrings = 0;
  3376. hr = SafeArrayGetUBound(pSA, 1, &UBound);
  3377. if (FAILED(hr))
  3378. {
  3379. TRACE_CRIT("Could not get upper bound of safe array");
  3380. goto end;
  3381. }
  3382. NumStrings = (UINT) (UBound+1); // Convert from UpperBound to NumStrings.
  3383. if (NumStrings == 0)
  3384. {
  3385. // nothing in array -- we're done.
  3386. Status = WBEM_NO_ERROR;
  3387. goto end;
  3388. }
  3389. hr = SafeArrayAccessData(pSA, ( void **) &pbStr);
  3390. if (FAILED(hr))
  3391. {
  3392. TRACE_CRIT("Could not access data of safe array");
  3393. goto end;
  3394. }
  3395. //
  3396. // Calculate space for the array of pointers to strings...
  3397. //
  3398. TotalSize = NumStrings*sizeof(LPWSTR);
  3399. //
  3400. // Calculate space for the strings themselves...
  3401. //
  3402. for (u=0; u<NumStrings; u++)
  3403. {
  3404. csz = pbStr[u];
  3405. TotalSize += (wcslen(csz)+1)*sizeof(WCHAR);
  3406. }
  3407. //
  3408. // Allocate space for *both* the array of pointers and the strings
  3409. // in one shot -- we're doing a new of type LPWSTR[] for the whole
  3410. // lot, so need to specify the size in units of LPWSTR (with an
  3411. // additional +1 in case there's roundoff).
  3412. //
  3413. pStrings = new LPWSTR[(TotalSize/sizeof(LPWSTR))+1];
  3414. if (pStrings == NULL)
  3415. {
  3416. Status = WBEM_E_OUT_OF_MEMORY;
  3417. (VOID) SafeArrayUnaccessData(pSA);
  3418. goto end;
  3419. }
  3420. //
  3421. // Make sz point to the start of the place where we'll be placing
  3422. // the string data.
  3423. //
  3424. sz = (LPWSTR) (pStrings+NumStrings);
  3425. for (u=0; u<NumStrings; u++)
  3426. {
  3427. csz = pbStr[u];
  3428. UINT len = wcslen(csz)+1;
  3429. CopyMemory(sz, csz, len*sizeof(WCHAR));
  3430. pStrings[u] = sz;
  3431. sz+=len;
  3432. }
  3433. (VOID) SafeArrayUnaccessData(pSA);
  3434. Status = WBEM_NO_ERROR;
  3435. end:
  3436. pbStr=NULL;
  3437. if (FAILED(Status))
  3438. {
  3439. if (pStrings!=NULL)
  3440. {
  3441. delete[] pStrings;
  3442. pStrings = NULL;
  3443. }
  3444. NumStrings = 0;
  3445. }
  3446. *ppStrings = pStrings;
  3447. *pNumStrings = NumStrings;
  3448. return Status;
  3449. }
  3450. WBEMSTATUS
  3451. CfgUtilGetWmiObjectInstance(
  3452. IN IWbemServicesPtr spWbemServiceIF,
  3453. IN LPCWSTR szClassName,
  3454. IN LPCWSTR szPropertyName,
  3455. IN LPCWSTR szPropertyValue,
  3456. OUT IWbemClassObjectPtr &sprefObj // smart pointer
  3457. )
  3458. {
  3459. WBEMSTATUS Status = WBEM_E_NOT_FOUND;
  3460. HRESULT hr;
  3461. //
  3462. // TODO: consider using IWbemServices::ExecQuery
  3463. //
  3464. IEnumWbemClassObjectPtr spEnum=NULL; // smart pointer
  3465. IWbemClassObjectPtr spObj = NULL; // smart pointer.
  3466. _bstr_t bstrClassName = szClassName;
  3467. //
  3468. // get all instances of object
  3469. //
  3470. hr = spWbemServiceIF->CreateInstanceEnum(
  3471. bstrClassName,
  3472. WBEM_FLAG_RETURN_IMMEDIATELY,
  3473. NULL,
  3474. &spEnum
  3475. );
  3476. if (FAILED(hr))
  3477. {
  3478. TRACE_CRIT("IWbemServices::CreateInstanceEnum failure\n" );
  3479. spEnum = NULL;
  3480. goto end;
  3481. }
  3482. //
  3483. // Look for the object with the matching property.
  3484. //
  3485. do
  3486. {
  3487. ULONG count = 1;
  3488. hr = spEnum->Next(
  3489. INFINITE,
  3490. 1,
  3491. &spObj,
  3492. &count
  3493. );
  3494. //
  3495. // Note -- Next() returns S_OK if number asked == number returned.
  3496. // and S_FALSE if number asked < than number requested.
  3497. // Since we're asking for only ...
  3498. //
  3499. if (hr == S_OK)
  3500. {
  3501. LPWSTR szEnumValue = NULL;
  3502. Status = CfgUtilGetWmiStringParam(
  3503. spObj,
  3504. szPropertyName,
  3505. &szEnumValue // Delete when done.
  3506. );
  3507. if (FAILED(Status))
  3508. {
  3509. //
  3510. // Ignore this failure here.
  3511. //
  3512. }
  3513. else if (szEnumValue!=NULL)
  3514. {
  3515. BOOL fFound = FALSE;
  3516. if (!_wcsicmp(szEnumValue, szPropertyValue))
  3517. {
  3518. fFound = TRUE;
  3519. }
  3520. delete szEnumValue;
  3521. if (fFound)
  3522. {
  3523. break; // BREAK BREAK BREAK BREAK
  3524. }
  3525. }
  3526. }
  3527. else
  3528. {
  3529. TRACE_INFO(
  3530. "====0x%p->Next() returns Error 0x%lx; count=0x%lu", (PVOID) spObj,
  3531. (UINT) hr, count);
  3532. }
  3533. //
  3534. // Since I don't fully trust smart pointers, I'm specifically
  3535. // setting spObj to NULL here...
  3536. //
  3537. spObj = NULL; // smart pointer
  3538. } while (hr == S_OK);
  3539. if (spObj == NULL)
  3540. {
  3541. //
  3542. // We couldn't find a NIC which matches the one asked for...
  3543. //
  3544. Status = WBEM_E_NOT_FOUND;
  3545. goto end;
  3546. }
  3547. end:
  3548. if (FAILED(Status))
  3549. {
  3550. sprefObj = NULL;
  3551. }
  3552. else
  3553. {
  3554. sprefObj = spObj; // smart pointer.
  3555. }
  3556. return Status;
  3557. }
  3558. WBEMSTATUS
  3559. CfgUtilGetWmiRelPath(
  3560. IN IWbemClassObjectPtr spObj,
  3561. OUT LPWSTR * pszRelPath // free using delete
  3562. )
  3563. {
  3564. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  3565. LPWSTR pRelPath = NULL;
  3566. //
  3567. // Extract the relative path, needed for ExecMethod.
  3568. //
  3569. Status = CfgUtilGetWmiStringParam(
  3570. spObj,
  3571. L"__RELPATH", // szParameterName
  3572. &pRelPath // Delete when done.
  3573. );
  3574. if (FAILED(Status))
  3575. {
  3576. TRACE_CRIT("Couldn't get rel path");
  3577. pRelPath = NULL;
  3578. goto end;
  3579. }
  3580. else
  3581. {
  3582. if (pRelPath==NULL)
  3583. {
  3584. ASSERT(FALSE); // we don't expect this!
  3585. goto end;
  3586. }
  3587. TRACE_VERB("GOT RELATIVE PATH %ws", pRelPath);
  3588. }
  3589. end:
  3590. *pszRelPath = pRelPath;
  3591. return Status;
  3592. }
  3593. WBEMSTATUS
  3594. CfgUtilGetWmiInputInstanceAndRelPath(
  3595. IN IWbemServicesPtr spWbemServiceIF,
  3596. IN LPCWSTR szClassName,
  3597. IN LPCWSTR szPropertyName, // NULL: return Class rel path
  3598. IN LPCWSTR szPropertyValue,
  3599. IN LPCWSTR szMethodName,
  3600. OUT IWbemClassObjectPtr &spWbemInputInstance, // smart pointer
  3601. OUT LPWSTR * pszRelPath // free using delete
  3602. )
  3603. {
  3604. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  3605. IWbemClassObjectPtr spClassObj = NULL; // smart pointer
  3606. HRESULT hr;
  3607. LPWSTR pRelPath = NULL;
  3608. TRACE_INFO(L"-> %!FUNC!(PropertyValue=%ws)",
  3609. szPropertyValue==NULL ? L"<class>" : szPropertyValue);
  3610. //
  3611. // Get CLASS object
  3612. //
  3613. {
  3614. hr = spWbemServiceIF->GetObject(
  3615. _bstr_t(szClassName),
  3616. 0,
  3617. NULL,
  3618. &spClassObj,
  3619. NULL
  3620. );
  3621. if (FAILED(hr))
  3622. {
  3623. TRACE_CRIT("Couldn't get nic class object pointer");
  3624. Status = (WBEMSTATUS)hr;
  3625. goto end;
  3626. }
  3627. }
  3628. //
  3629. // Get WMI path to specific object
  3630. //
  3631. if (szPropertyName == NULL)
  3632. {
  3633. // Get WMI path to the class
  3634. Status = CfgUtilGetWmiRelPath(
  3635. spClassObj,
  3636. &pRelPath
  3637. );
  3638. if (FAILED(Status))
  3639. {
  3640. goto end;
  3641. }
  3642. }
  3643. else
  3644. {
  3645. IWbemClassObjectPtr spObj = NULL; // smart pointer
  3646. pRelPath = NULL;
  3647. Status = CfgUtilGetWmiObjectInstance(
  3648. spWbemServiceIF,
  3649. szClassName,
  3650. szPropertyName,
  3651. szPropertyValue,
  3652. spObj // smart pointer, passed by ref
  3653. );
  3654. if (FAILED(Status))
  3655. {
  3656. ASSERT(spObj == NULL);
  3657. goto end;
  3658. }
  3659. Status = CfgUtilGetWmiRelPath(
  3660. spObj,
  3661. &pRelPath
  3662. );
  3663. spObj = NULL; // smart pointer
  3664. if (FAILED(Status))
  3665. {
  3666. goto end;
  3667. }
  3668. }
  3669. //
  3670. // Get the input parameters to the call to the method
  3671. //
  3672. {
  3673. IWbemClassObjectPtr spWbemInput = NULL; // smart pointer
  3674. // check if any input parameters specified.
  3675. hr = spClassObj->GetMethod(
  3676. szMethodName,
  3677. 0,
  3678. &spWbemInput,
  3679. NULL
  3680. );
  3681. if(FAILED(hr))
  3682. {
  3683. TRACE_CRIT("IWbemClassObject::GetMethod failure");
  3684. Status = (WBEMSTATUS) hr;
  3685. goto end;
  3686. }
  3687. if (spWbemInput != NULL)
  3688. {
  3689. hr = spWbemInput->SpawnInstance( 0, &spWbemInputInstance );
  3690. if( FAILED( hr) )
  3691. {
  3692. TRACE_CRIT("IWbemClassObject::SpawnInstance failure. Unable to spawn instance." );
  3693. Status = (WBEMSTATUS) hr;
  3694. goto end;
  3695. }
  3696. }
  3697. else
  3698. {
  3699. //
  3700. // This method has no input arguments!
  3701. //
  3702. spWbemInputInstance = NULL;
  3703. }
  3704. }
  3705. Status = WBEM_NO_ERROR;
  3706. end:
  3707. if (FAILED(Status))
  3708. {
  3709. if (pRelPath != NULL)
  3710. {
  3711. delete pRelPath;
  3712. pRelPath = NULL;
  3713. }
  3714. }
  3715. *pszRelPath = pRelPath;
  3716. TRACE_INFO(L"<- %!FUNC! returns 0x%08lx", (UINT) Status);
  3717. return Status;
  3718. }
  3719. WBEMSTATUS
  3720. CfgUtilGetWmiStringParam(
  3721. IN IWbemClassObjectPtr spObj,
  3722. IN LPCWSTR szParameterName,
  3723. OUT LPWSTR *ppStringValue
  3724. )
  3725. {
  3726. WBEMSTATUS Status = WBEM_E_NOT_FOUND;
  3727. WCHAR *pStringValue = NULL;
  3728. try
  3729. {
  3730. _variant_t v_value;
  3731. CIMTYPE v_type;
  3732. HRESULT hr;
  3733. hr = spObj->Get(
  3734. _bstr_t(szParameterName), // Name
  3735. 0, // Reserved, must be 0
  3736. &v_value, // Place to store value
  3737. &v_type, // Type of value
  3738. NULL // Flavor (unused)
  3739. );
  3740. if (FAILED(hr))
  3741. {
  3742. // Couldn't read the Setting ID field!
  3743. //
  3744. TRACE_CRIT(
  3745. "get_str_parm:Couldn't retrieve %ws from 0x%p. Hr=0x%08lx",
  3746. szParameterName,
  3747. (PVOID) spObj,
  3748. hr
  3749. );
  3750. goto end;
  3751. }
  3752. else if (v_type == VT_NULL || v_value.vt == VT_NULL)
  3753. {
  3754. pStringValue = NULL;
  3755. Status = WBEM_NO_ERROR;
  3756. goto end;
  3757. }
  3758. else
  3759. {
  3760. if (v_type != VT_BSTR)
  3761. {
  3762. TRACE_CRIT(
  3763. "get_str_parm: Parm value not of string type %ws from 0x%p",
  3764. szParameterName,
  3765. (PVOID) spObj
  3766. );
  3767. Status = WBEM_E_INVALID_PARAMETER;
  3768. }
  3769. else
  3770. {
  3771. _bstr_t bstrNicGuid(v_value);
  3772. LPCWSTR sz = bstrNicGuid; // Pointer to internal buffer.
  3773. if (sz==NULL)
  3774. {
  3775. // hmm.. null value
  3776. pStringValue = NULL;
  3777. Status = WBEM_NO_ERROR;
  3778. }
  3779. else
  3780. {
  3781. UINT len = wcslen(sz);
  3782. pStringValue = new WCHAR[len+1];
  3783. if (pStringValue == NULL)
  3784. {
  3785. TRACE_CRIT("get_str_parm: Alloc failure!");
  3786. Status = WBEM_E_OUT_OF_MEMORY;
  3787. }
  3788. else
  3789. {
  3790. CopyMemory(pStringValue, sz, (len+1)*sizeof(WCHAR));
  3791. Status = WBEM_NO_ERROR;
  3792. }
  3793. }
  3794. TRACE_VERB(
  3795. "get_str_parm: String parm %ws of 0x%p is %ws",
  3796. szParameterName,
  3797. (PVOID) spObj,
  3798. (sz==NULL) ? L"<null>" : sz
  3799. );
  3800. }
  3801. v_value.Clear(); // Must be cleared after each call to Get.
  3802. }
  3803. }
  3804. catch( _com_error e )
  3805. {
  3806. TRACE_INFO(L"%!FUNC! -- com exception");
  3807. Status = WBEM_E_NOT_FOUND;
  3808. }
  3809. end:
  3810. if (!FAILED(Status) && pStringValue == NULL)
  3811. {
  3812. //
  3813. // We convert a NULL value to an empty, not NULL string.
  3814. //
  3815. pStringValue = new WCHAR[1];
  3816. if (pStringValue == NULL)
  3817. {
  3818. Status = WBEM_E_OUT_OF_MEMORY;
  3819. }
  3820. else
  3821. {
  3822. *pStringValue = 0;
  3823. Status = WBEM_NO_ERROR;
  3824. }
  3825. }
  3826. *ppStringValue = pStringValue;
  3827. return Status;
  3828. }
  3829. WBEMSTATUS
  3830. CfgUtilSetWmiStringParam(
  3831. IN IWbemClassObjectPtr spObj,
  3832. IN LPCWSTR szParameterName,
  3833. IN LPCWSTR szValue
  3834. )
  3835. {
  3836. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  3837. try
  3838. {
  3839. HRESULT hr;
  3840. _bstr_t bstrName = szParameterName;
  3841. _variant_t v_value = (LPWSTR) szValue; // Allocates.
  3842. hr = spObj->Put(
  3843. bstrName, // Parameter Name
  3844. 0, // Must be 0
  3845. &v_value,
  3846. 0 // Must be 0
  3847. );
  3848. v_value.Clear();
  3849. if (FAILED(hr))
  3850. {
  3851. TRACE_CRIT("Unable to put parameter %ws", szParameterName);
  3852. goto end;
  3853. }
  3854. Status = WBEM_NO_ERROR;
  3855. //
  3856. // I think bstrName releases the internally allocated string
  3857. // on exiting this block.
  3858. //
  3859. }
  3860. catch( _com_error e )
  3861. {
  3862. TRACE_INFO(L"%!FUNC! -- com exception");
  3863. Status = WBEM_E_INVALID_PARAMETER;
  3864. }
  3865. end:
  3866. return Status;
  3867. }
  3868. WBEMSTATUS
  3869. CfgUtilGetWmiStringArrayParam(
  3870. IN IWbemClassObjectPtr spObj,
  3871. IN LPCWSTR szParameterName,
  3872. OUT LPWSTR **ppStrings,
  3873. OUT UINT *pNumStrings
  3874. )
  3875. {
  3876. WBEMSTATUS Status = WBEM_E_NOT_FOUND;
  3877. try
  3878. {
  3879. _variant_t v_value;
  3880. CIMTYPE v_type;
  3881. HRESULT hr;
  3882. LONG count = 0;
  3883. *ppStrings = NULL;
  3884. *pNumStrings = 0;
  3885. hr = spObj->Get(
  3886. _bstr_t(szParameterName),
  3887. 0, // Reserved, must be 0
  3888. &v_value, // Place to store value
  3889. &v_type, // Type of value
  3890. NULL // Flavor (unused)
  3891. );
  3892. if (FAILED(hr))
  3893. {
  3894. // Couldn't read the requested parameter.
  3895. //
  3896. TRACE_CRIT(
  3897. "get_multi_str_parm:Couldn't retrieve %ws from 0x%p",
  3898. szParameterName,
  3899. (PVOID) spObj
  3900. );
  3901. Status = WBEM_E_INVALID_PARAMETER;
  3902. goto end;
  3903. }
  3904. if (v_type != (VT_ARRAY | VT_BSTR))
  3905. {
  3906. if (v_type == VT_NULL)
  3907. {
  3908. //
  3909. // We convert a NULL value to zero strings
  3910. //
  3911. Status = WBEM_NO_ERROR;
  3912. goto end;
  3913. }
  3914. TRACE_CRIT("vt is not of type string!");
  3915. goto end;
  3916. }
  3917. else if (v_value.vt == VT_NULL)
  3918. {
  3919. //
  3920. // I've seen this too...
  3921. //
  3922. // We convert a NULL value to zero strings
  3923. //
  3924. TRACE_CRIT("WARNING: vt is NULL!");
  3925. Status = WBEM_NO_ERROR;
  3926. goto end;
  3927. }
  3928. else
  3929. {
  3930. VARIANT ipsV = v_value.Detach();
  3931. SAFEARRAY *pSA = ipsV.parray;
  3932. Status = CfgUtilStringsFromSafeArray(
  3933. pSA,
  3934. ppStrings,
  3935. pNumStrings
  3936. );
  3937. VariantClear( &ipsV );
  3938. }
  3939. }
  3940. catch( _com_error e )
  3941. {
  3942. TRACE_INFO(L"%!FUNC! -- com exception");
  3943. Status = WBEM_E_NOT_FOUND;
  3944. }
  3945. end:
  3946. return Status;
  3947. }
  3948. WBEMSTATUS
  3949. CfgUtilSetWmiStringArrayParam(
  3950. IN IWbemClassObjectPtr spObj,
  3951. IN LPCWSTR szParameterName,
  3952. IN LPCWSTR *ppStrings,
  3953. IN UINT NumStrings
  3954. )
  3955. {
  3956. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  3957. SAFEARRAY *pSA = NULL;
  3958. try
  3959. {
  3960. HRESULT hr;
  3961. LONG Index = 0;
  3962. Status = CfgUtilSafeArrayFromStrings(
  3963. ppStrings,
  3964. NumStrings,
  3965. &pSA
  3966. );
  3967. if (FAILED(Status))
  3968. {
  3969. pSA = NULL;
  3970. goto end;
  3971. }
  3972. //
  3973. // Put the parameter.
  3974. //
  3975. {
  3976. VARIANT V;
  3977. _bstr_t bstrName = szParameterName;
  3978. VariantInit(&V);
  3979. V.vt = VT_ARRAY | VT_BSTR;
  3980. V.parray = pSA;
  3981. _variant_t v_value;
  3982. v_value.Attach(V); // Takes owhership of V. V now becomes empty.
  3983. ASSERT(V.vt == VT_EMPTY);
  3984. pSA = NULL; // should be no need to delete this explicitly now.
  3985. // v_value.Clear() should delete it, I think.
  3986. hr = spObj->Put(
  3987. bstrName, // Parameter Name
  3988. 0, // Must be 0
  3989. &v_value,
  3990. 0 // Must be 0
  3991. );
  3992. v_value.Clear();
  3993. if (FAILED(hr))
  3994. {
  3995. Status = (WBEMSTATUS) hr;
  3996. TRACE_CRIT("Unable to put parameter %ws", szParameterName);
  3997. goto end;
  3998. }
  3999. Status = WBEM_NO_ERROR;
  4000. }
  4001. }
  4002. catch( _com_error e )
  4003. {
  4004. TRACE_INFO(L"%!FUNC! -- com exception");
  4005. Status = WBEM_E_INVALID_PARAMETER;
  4006. }
  4007. end:
  4008. if (pSA!=NULL)
  4009. {
  4010. SafeArrayDestroy(pSA);
  4011. pSA = NULL;
  4012. }
  4013. return Status;
  4014. }
  4015. WBEMSTATUS
  4016. CfgUtilGetWmiDWORDParam(
  4017. IN IWbemClassObjectPtr spObj,
  4018. IN LPCWSTR szParameterName,
  4019. OUT DWORD *pValue
  4020. )
  4021. {
  4022. WBEMSTATUS Status = WBEM_E_NOT_FOUND;
  4023. DWORD Value=0;
  4024. try
  4025. {
  4026. _variant_t v_value;
  4027. CIMTYPE v_type;
  4028. HRESULT hr;
  4029. hr = spObj->Get(
  4030. _bstr_t(szParameterName), // Name
  4031. 0, // Reserved, must be 0
  4032. &v_value, // Place to store value
  4033. &v_type, // Type of value
  4034. NULL // Flavor (unused)
  4035. );
  4036. if (FAILED(hr))
  4037. {
  4038. // Couldn't read the parameter
  4039. //
  4040. TRACE_CRIT(
  4041. "GetDWORDParm:Couldn't retrieve %ws from 0x%p",
  4042. szParameterName,
  4043. (PVOID) spObj
  4044. );
  4045. goto end;
  4046. }
  4047. else
  4048. {
  4049. Value = (DWORD) (long) v_value;
  4050. v_value.Clear(); // Must be cleared after each call to Get.
  4051. Status = WBEM_NO_ERROR;
  4052. }
  4053. }
  4054. catch( _com_error e )
  4055. {
  4056. TRACE_INFO(L"%!FUNC! -- com exception");
  4057. Status = WBEM_E_NOT_FOUND;
  4058. }
  4059. end:
  4060. *pValue = Value;
  4061. return Status;
  4062. }
  4063. WBEMSTATUS
  4064. CfgUtilSetWmiDWORDParam(
  4065. IN IWbemClassObjectPtr spObj,
  4066. IN LPCWSTR szParameterName,
  4067. IN DWORD Value
  4068. )
  4069. {
  4070. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  4071. try
  4072. {
  4073. HRESULT hr;
  4074. _bstr_t bstrName = szParameterName;
  4075. _variant_t v_value = (long) Value;
  4076. hr = spObj->Put(
  4077. bstrName, // Parameter Name
  4078. 0, // Must be 0
  4079. &v_value,
  4080. 0 // Must be 0
  4081. );
  4082. v_value.Clear();
  4083. if (FAILED(hr))
  4084. {
  4085. TRACE_CRIT("Unable to put parameter %ws", szParameterName);
  4086. goto end;
  4087. }
  4088. Status = WBEM_NO_ERROR;
  4089. }
  4090. catch( _com_error e )
  4091. {
  4092. TRACE_INFO(L"%!FUNC! -- com exception");
  4093. Status = WBEM_E_INVALID_PARAMETER;
  4094. }
  4095. end:
  4096. return Status;
  4097. }
  4098. WBEMSTATUS
  4099. CfgUtilGetWmiBoolParam(
  4100. IN IWbemClassObjectPtr spObj,
  4101. IN LPCWSTR szParameterName,
  4102. OUT BOOL *pValue
  4103. )
  4104. {
  4105. WBEMSTATUS Status = WBEM_E_NOT_FOUND;
  4106. BOOL Value=0;
  4107. try
  4108. {
  4109. _variant_t v_value;
  4110. CIMTYPE v_type;
  4111. HRESULT hr;
  4112. hr = spObj->Get(
  4113. _bstr_t(szParameterName), // Name
  4114. 0, // Reserved, must be 0
  4115. &v_value, // Place to store value
  4116. &v_type, // Type of value
  4117. NULL // Flavor (unused)
  4118. );
  4119. if (FAILED(hr))
  4120. {
  4121. // Couldn't read the parameter
  4122. //
  4123. TRACE_CRIT(
  4124. "GetDWORDParm:Couldn't retrieve %ws from 0x%p",
  4125. szParameterName,
  4126. (PVOID) spObj
  4127. );
  4128. goto end;
  4129. }
  4130. else
  4131. {
  4132. Value = ((bool) v_value)!=0;
  4133. v_value.Clear(); // Must be cleared after each call to Get.
  4134. Status = WBEM_NO_ERROR;
  4135. }
  4136. }
  4137. catch( _com_error e )
  4138. {
  4139. TRACE_INFO(L"%!FUNC! -- com exception");
  4140. Status = WBEM_E_NOT_FOUND;
  4141. }
  4142. end:
  4143. *pValue = Value;
  4144. return Status;
  4145. }
  4146. WBEMSTATUS
  4147. CfgUtilSetWmiBoolParam(
  4148. IN IWbemClassObjectPtr spObj,
  4149. IN LPCWSTR szParameterName,
  4150. IN BOOL Value
  4151. )
  4152. {
  4153. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  4154. try
  4155. {
  4156. HRESULT hr;
  4157. _bstr_t bstrName = szParameterName;
  4158. _variant_t v_value = (long) Value;
  4159. hr = spObj->Put(
  4160. bstrName, // Parameter Name
  4161. 0, // Must be 0
  4162. &v_value,
  4163. 0 // Must be 0
  4164. );
  4165. v_value.Clear();
  4166. if (FAILED(hr))
  4167. {
  4168. TRACE_CRIT("Unable to put parameter %ws", szParameterName);
  4169. goto end;
  4170. }
  4171. Status = WBEM_NO_ERROR;
  4172. }
  4173. catch( _com_error e )
  4174. {
  4175. TRACE_INFO(L"%!FUNC! -- com exception");
  4176. Status = WBEM_E_INVALID_PARAMETER;
  4177. }
  4178. end:
  4179. return Status;
  4180. }
  4181. WBEMSTATUS
  4182. CfgUtilConnectToServer(
  4183. IN LPCWSTR szNetworkResource, // \\machinename\root\microsoftnlb \root\...
  4184. IN LPCWSTR szUser,
  4185. IN LPCWSTR szPassword,
  4186. IN LPCWSTR szAuthority,
  4187. OUT IWbemServices **ppWbemService // deref when done.
  4188. )
  4189. {
  4190. HRESULT hr = WBEM_E_CRITICAL_ERROR;
  4191. IWbemLocatorPtr spLocator=NULL; // Smart pointer
  4192. IWbemServices *pService=NULL;
  4193. try
  4194. {
  4195. _bstr_t serverPath(szNetworkResource);
  4196. *ppWbemService = NULL;
  4197. hr = CoCreateInstance(CLSID_WbemLocator, 0,
  4198. CLSCTX_INPROC_SERVER,
  4199. IID_IWbemLocator,
  4200. (LPVOID *) &spLocator);
  4201. if (FAILED(hr))
  4202. {
  4203. TRACE_CRIT(L"CoCreateInstance IWebmLocator failed 0x%08lx ", (UINT)hr);
  4204. goto end;
  4205. }
  4206. for (int timesToRetry=0; timesToRetry<10; timesToRetry++)
  4207. {
  4208. //
  4209. // SECURITY BUGBUG -- need to make sure that
  4210. // password is zeroed out!
  4211. //
  4212. hr = spLocator->ConnectServer(
  4213. serverPath,
  4214. // (szUser!=NULL) ? (_bstr_t(szUser)) : NULL,
  4215. _bstr_t(szUser),
  4216. // (szPassword==NULL) ? NULL : _bstr_t(szPassword),
  4217. _bstr_t(szPassword),
  4218. NULL, // Locale
  4219. 0, // Security flags
  4220. //(szAuthority==NULL) ? NULL : _bstr_t(szAuthority),
  4221. _bstr_t(szAuthority),
  4222. NULL,
  4223. &pService
  4224. );
  4225. if( !FAILED( hr) )
  4226. {
  4227. break;
  4228. }
  4229. //
  4230. // these have been found to be special cases where retrying may
  4231. // help. The errors below are not in any header file, and I searched
  4232. // the index2a sources for these constants -- no hits.
  4233. // TODO: file bug against WMI.
  4234. //
  4235. if( ( hr == 0x800706bf ) || ( hr == 0x80070767 ) || ( hr == 0x80070005 ) )
  4236. {
  4237. TRACE_CRIT(L"connectserver recoverable failure, retrying.");
  4238. Sleep(500);
  4239. }
  4240. else
  4241. {
  4242. //
  4243. // Unrecoverable error...
  4244. //
  4245. break;
  4246. }
  4247. }
  4248. if (FAILED(hr))
  4249. {
  4250. TRACE_CRIT(L"Error 0x%08lx connecting to server", (UINT) hr);
  4251. goto end;
  4252. }
  4253. else
  4254. {
  4255. TRACE_INFO(L"Successfully connected to server %s", serverPath);
  4256. }
  4257. // 2/13/02 JosephJ SECURITY BUGBUG: verify that Both calls to CoSetProxyBlanket are the right
  4258. // ones to be made, from a security perspective.
  4259. //
  4260. // If NONE of User, Password, Authority is passed, call
  4261. // CoSetProxyBlanket with AuthInfo of COLE_DEFAULT_AUTHINFO
  4262. //
  4263. if(((szUser == NULL) || (wcslen(szUser) < 1))
  4264. &&((szPassword == NULL) || (wcslen(szPassword) < 1))
  4265. &&((szAuthority == NULL) || (wcslen(szAuthority) < 1)))
  4266. {
  4267. hr = CoSetProxyBlanket(
  4268. pService,
  4269. RPC_C_AUTHN_WINNT,
  4270. RPC_C_AUTHZ_DEFAULT, // RPC_C_AUTHZ_NAME,
  4271. COLE_DEFAULT_PRINCIPAL, // NULL,
  4272. RPC_C_AUTHN_LEVEL_DEFAULT,
  4273. RPC_C_IMP_LEVEL_IMPERSONATE,
  4274. COLE_DEFAULT_AUTHINFO, // NULL,
  4275. EOAC_DEFAULT // EOAC_NONE
  4276. );
  4277. }
  4278. else // User or Authority was passed in, we need to create an authority argument for the login
  4279. {
  4280. COAUTHIDENTITY authident;
  4281. BSTR AuthArg, UserArg;
  4282. AuthArg = NULL;
  4283. UserArg = NULL;
  4284. hr = CfgUtilParseAuthorityUserArgs(AuthArg, UserArg, szAuthority, szUser);
  4285. if (FAILED(hr))
  4286. {
  4287. TRACE_CRIT(L"Error CfgUtilParseAuthorityUserArgs returns 0x%08lx", (UINT)hr);
  4288. goto end;
  4289. }
  4290. if(UserArg)
  4291. {
  4292. authident.UserLength = wcslen(UserArg);
  4293. authident.User = (LPWSTR)UserArg;
  4294. }
  4295. if(AuthArg)
  4296. {
  4297. authident.DomainLength = wcslen(AuthArg);
  4298. authident.Domain = (LPWSTR)AuthArg;
  4299. }
  4300. if(szPassword)
  4301. {
  4302. authident.PasswordLength = wcslen(szPassword);
  4303. authident.Password = (LPWSTR)szPassword;
  4304. }
  4305. authident.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
  4306. hr = CoSetProxyBlanket(
  4307. pService,
  4308. RPC_C_AUTHN_WINNT,
  4309. RPC_C_AUTHZ_DEFAULT, // RPC_C_AUTHZ_NAME,
  4310. COLE_DEFAULT_PRINCIPAL, // NULL,
  4311. RPC_C_AUTHN_LEVEL_DEFAULT,
  4312. RPC_C_IMP_LEVEL_IMPERSONATE,
  4313. &authident, // THIS IS THE DISTINGUISHING ARGUMENT
  4314. EOAC_DEFAULT // EOAC_NONE
  4315. );
  4316. if(UserArg)
  4317. SysFreeString(UserArg);
  4318. if(AuthArg)
  4319. SysFreeString(AuthArg);
  4320. }
  4321. if (FAILED(hr))
  4322. {
  4323. TRACE_CRIT(L"Error 0x%08lx setting proxy blanket", (UINT) hr);
  4324. goto end;
  4325. }
  4326. hr = WBEM_NO_ERROR;
  4327. }
  4328. catch( _com_error e )
  4329. {
  4330. TRACE_INFO(L"%!FUNC! -- com exception");
  4331. hr = WBEM_E_INVALID_PARAMETER;
  4332. }
  4333. end:
  4334. spLocator = NULL; // smart pointer.
  4335. if (FAILED(hr))
  4336. {
  4337. if (pService != NULL)
  4338. {
  4339. pService->Release();
  4340. pService=NULL;
  4341. }
  4342. }
  4343. *ppWbemService = pService;
  4344. return (WBEMSTATUS) hr;
  4345. }
  4346. WBEMSTATUS
  4347. CfgUtilGetWmiMachineName(
  4348. IN IWbemServicesPtr spWbemServiceIF,
  4349. OUT LPWSTR * pszMachineName // free using delete
  4350. )
  4351. /*
  4352. Return the machine name and (optionally) machine guid.
  4353. */
  4354. {
  4355. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  4356. IWbemClassObjectPtr spClassObj = NULL; // smart pointer
  4357. HRESULT hr;
  4358. hr = spWbemServiceIF->GetObject(
  4359. _bstr_t(L"NlbsNic"),
  4360. 0,
  4361. NULL,
  4362. &spClassObj,
  4363. NULL
  4364. );
  4365. if (FAILED(hr))
  4366. {
  4367. TRACE_CRIT("Couldn't get nic class object pointer");
  4368. Status = (WBEMSTATUS)hr;
  4369. goto end;
  4370. }
  4371. Status = CfgUtilGetWmiStringParam(
  4372. spClassObj,
  4373. L"__Server", // <-------------------------
  4374. pszMachineName
  4375. );
  4376. if (FAILED(Status))
  4377. {
  4378. TRACE_CRIT(L"%!FUNC! Attempt to read server name. Error=0x%08lx",
  4379. (UINT) Status);
  4380. *pszMachineName = NULL;
  4381. }
  4382. else
  4383. {
  4384. TRACE_CRIT(L"%!FUNC! Got __Server value:%ws", *pszMachineName);
  4385. }
  4386. end:
  4387. spClassObj = NULL; // smart pointer
  4388. return Status;
  4389. }
  4390. WBEMSTATUS
  4391. CfgUtilsGetNlbCompatibleNics(
  4392. OUT LPWSTR **ppszNics,
  4393. OUT UINT *pNumNics,
  4394. OUT UINT *pNumBoundToNlb // OPTIONAL
  4395. )
  4396. {
  4397. WBEMSTATUS Status = WBEM_NO_ERROR;
  4398. BOOL fNetCfgInitialized = FALSE;
  4399. MyNetCfg NetCfg;
  4400. BOOL fBound = FALSE;
  4401. //
  4402. // Get and initialize interface to netcfg
  4403. //
  4404. Status = NetCfg.Initialize(FALSE); // TRUE == get write lock.
  4405. if (FAILED(Status))
  4406. {
  4407. goto end;
  4408. }
  4409. fNetCfgInitialized = TRUE;
  4410. //
  4411. //
  4412. //
  4413. Status = NetCfg.GetNlbCompatibleNics(
  4414. ppszNics,
  4415. pNumNics,
  4416. pNumBoundToNlb // OPTIONAL
  4417. );
  4418. end:
  4419. if (fNetCfgInitialized)
  4420. {
  4421. NetCfg.Deinitialize();
  4422. }
  4423. return Status;
  4424. }
  4425. WBEMSTATUS
  4426. CfgUtilGetWmiAdapterObjFromAdapterConfigurationObj(
  4427. IN IWbemServicesPtr spWbemServiceIF, // smart pointer
  4428. IN IWbemClassObjectPtr spObj, // smart pointer
  4429. OUT IWbemClassObjectPtr &spAdapterObj // smart pointer, by reference
  4430. )
  4431. /*
  4432. We need to return the "Win32_NetworkAdapter" object associated with
  4433. the "Win32_NetworkAdapterConfiguration" object.
  4434. The key of Win32_NetworkAdapter is DeviceId.
  4435. The key of Win32_NetworkAdapterConfiguration is Index.
  4436. We use the "Win32_NetworkAdapterSetting" association class for this.
  4437. */
  4438. {
  4439. #define ARRAYSIZE(_arr) (sizeof(_arr)/sizeof(_arr[0]))
  4440. WCHAR sz[ 256 ];
  4441. IEnumWbemClassObject * pConfigurations = NULL;
  4442. ULONG ulReturned = 0;
  4443. DWORD dwIndex = 0;
  4444. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  4445. spAdapterObj = NULL; // smart pointer
  4446. Status = CfgUtilGetWmiDWORDParam(
  4447. spObj,
  4448. L"Index",
  4449. &dwIndex
  4450. );
  4451. if (FAILED(Status))
  4452. {
  4453. goto end;
  4454. }
  4455. StringCbPrintf(
  4456. sz,
  4457. sizeof( sz ),
  4458. L"Associators of {Win32_NetworkAdapterConfiguration.Index='%d'}"
  4459. L" where AssocClass=Win32_NetworkAdapterSetting",
  4460. dwIndex
  4461. );
  4462. Status = (WBEMSTATUS) spWbemServiceIF->ExecQuery(
  4463. _bstr_t(L"WQL"),
  4464. _bstr_t(sz) ,
  4465. WBEM_FLAG_FORWARD_ONLY,
  4466. NULL,
  4467. &pConfigurations
  4468. );
  4469. if (FAILED(Status))
  4470. {
  4471. TRACE_CRIT("%!FUNC!: ExecQuery \"%ws\" failed with error 0x%08lx",
  4472. sz,
  4473. (UINT) Status
  4474. );
  4475. pConfigurations = NULL;
  4476. goto end;
  4477. }
  4478. Status = (WBEMSTATUS) pConfigurations->Next(
  4479. WBEM_INFINITE,
  4480. 1,
  4481. &spAdapterObj,
  4482. &ulReturned
  4483. );
  4484. if ((Status != S_OK) || (ulReturned!=1))
  4485. {
  4486. TRACE_CRIT("%!FUNC!: No NetworkAdapter associated with NetworkAdapterCOnfiguration!");
  4487. ASSERT(spAdapterObj == NULL); // smart pointer.
  4488. goto end;
  4489. }
  4490. end:
  4491. if (pConfigurations!=NULL)
  4492. {
  4493. pConfigurations->Release();
  4494. pConfigurations = NULL;
  4495. }
  4496. return Status;
  4497. }
  4498. //
  4499. // Gets the port rules, if any, from the specfied nlb params structure
  4500. //
  4501. WBEMSTATUS
  4502. CfgUtilGetPortRules(
  4503. IN const WLBS_REG_PARAMS *pConstParams,
  4504. OUT WLBS_PORT_RULE **ppRules, // Free using delete
  4505. OUT UINT *pNumRules
  4506. )
  4507. {
  4508. WBEMSTATUS Status;
  4509. WLBS_REG_PARAMS *pParams = (WLBS_REG_PARAMS *) pConstParams;
  4510. *ppRules = NULL;
  4511. *pNumRules = 0;
  4512. WLBS_PORT_RULE AllPortRules[WLBS_MAX_RULES];
  4513. DWORD NumRules = WLBS_MAX_RULES;
  4514. DWORD dwRes;
  4515. // Verify that the NLB API hooks are present
  4516. if (!g_CfgUtils.m_NLBApiHooksPresent)
  4517. {
  4518. dwRes = MyWlbsEnumPortRules (pParams, AllPortRules, &NumRules);
  4519. }
  4520. else
  4521. {
  4522. dwRes = g_CfgUtils.m_pfWlbsEnumPortRules (pParams, AllPortRules, &NumRules);
  4523. }
  4524. if (dwRes != WLBS_OK)
  4525. {
  4526. Status = WBEM_E_INVALID_PARAMETER;
  4527. goto end;
  4528. }
  4529. if (NumRules!=0)
  4530. {
  4531. *ppRules = new WLBS_PORT_RULE[NumRules];
  4532. if (*ppRules == NULL)
  4533. {
  4534. Status = WBEM_E_OUT_OF_MEMORY;
  4535. goto end;
  4536. }
  4537. CopyMemory(*ppRules, AllPortRules, sizeof(WLBS_PORT_RULE)*NumRules);
  4538. *pNumRules = NumRules;
  4539. }
  4540. Status = WBEM_NO_ERROR;
  4541. end:
  4542. return Status;
  4543. }
  4544. //
  4545. // Sets the specified port rules in the specfied nlb params structure
  4546. //
  4547. WBEMSTATUS
  4548. CfgUtilSetPortRules(
  4549. IN WLBS_PORT_RULE *pRules,
  4550. IN UINT NumRules,
  4551. IN OUT WLBS_REG_PARAMS *pParams
  4552. )
  4553. {
  4554. WBEMSTATUS Status;
  4555. if (NumRules > WLBS_MAX_RULES)
  4556. {
  4557. Status = WBEM_E_INVALID_PARAMETER;
  4558. goto end;
  4559. }
  4560. // Verify that the NLB API hooks are present
  4561. if (!g_CfgUtils.m_NLBApiHooksPresent)
  4562. {
  4563. MyWlbsDeleteAllPortRules(pParams);
  4564. }
  4565. else
  4566. {
  4567. g_CfgUtils.m_pfWlbsDeleteAllPortRules(pParams);
  4568. }
  4569. for (UINT u = 0; u < NumRules; u++)
  4570. {
  4571. DWORD dwRes;
  4572. // Verify that the NLB API hooks are present
  4573. if (!g_CfgUtils.m_NLBApiHooksPresent)
  4574. {
  4575. dwRes = MyWlbsAddPortRule( pParams, pRules+u);
  4576. }
  4577. else
  4578. {
  4579. dwRes = g_CfgUtils.m_pfWlbsAddPortRule( pParams, pRules+u);
  4580. }
  4581. }
  4582. Status = WBEM_NO_ERROR;
  4583. end:
  4584. return Status;
  4585. }
  4586. BOOL
  4587. CfgUtilsGetPortRuleString(
  4588. IN PWLBS_PORT_RULE pPr,
  4589. OUT LPWSTR pString // At least NLB_MAX_PORT_STRING_SIZE wchars
  4590. )
  4591. {
  4592. const UINT cchString = NLB_MAX_PORT_STRING_SIZE;
  4593. BOOL fRet = FALSE;
  4594. HRESULT hr;
  4595. LPCWSTR szProtocol = L"";
  4596. LPCWSTR szMode = L"";
  4597. LPCWSTR szAffinity = L"";
  4598. if (cchString == 0) goto end;
  4599. ZeroMemory(pString, cchString*sizeof(WCHAR));
  4600. switch(pPr->protocol)
  4601. {
  4602. case CVY_TCP:
  4603. szProtocol = L"TCP";
  4604. break;
  4605. case CVY_UDP:
  4606. szProtocol = L"UDP";
  4607. break;
  4608. case CVY_TCP_UDP:
  4609. szProtocol = L"BOTH";
  4610. break;
  4611. default:
  4612. goto end; // bad parse
  4613. }
  4614. switch(pPr->mode)
  4615. {
  4616. case CVY_SINGLE:
  4617. szMode = L"SINGLE";
  4618. break;
  4619. case CVY_MULTI:
  4620. szMode = L"MULTIPLE";
  4621. switch(pPr->mode_data.multi.affinity)
  4622. {
  4623. case CVY_AFFINITY_NONE:
  4624. szAffinity = L"NONE";
  4625. break;
  4626. case CVY_AFFINITY_SINGLE:
  4627. szAffinity = L"SINGLE";
  4628. break;
  4629. case CVY_AFFINITY_CLASSC:
  4630. szAffinity = L"CLASSC";
  4631. break;
  4632. default:
  4633. goto end; // bad parse
  4634. }
  4635. break;
  4636. case CVY_NEVER:
  4637. szMode = L"DISABLED";
  4638. break;
  4639. default:
  4640. goto end; // bad parse
  4641. }
  4642. *pString = 0;
  4643. hr = StringCchPrintf(
  4644. pString,
  4645. cchString,
  4646. L"ip=%ws protocol=%ws start=%u end=%u mode=%ws ",
  4647. pPr->virtual_ip_addr,
  4648. szProtocol,
  4649. pPr->start_port,
  4650. pPr->end_port,
  4651. szMode
  4652. );
  4653. if (hr != S_OK)
  4654. {
  4655. goto end; // not enough space.
  4656. }
  4657. UINT Len = wcslen(pString);
  4658. if (Len >= (cchString-1))
  4659. {
  4660. goto end; // not enough space to add anything else
  4661. }
  4662. if (pPr->mode == CVY_MULTI)
  4663. {
  4664. if (pPr->mode_data.multi.equal_load)
  4665. {
  4666. hr = StringCchPrintf(
  4667. pString+Len,
  4668. (cchString-Len),
  4669. L"affinity=%ws",
  4670. szAffinity
  4671. );
  4672. }
  4673. else
  4674. {
  4675. hr = StringCchPrintf(
  4676. pString+Len,
  4677. (cchString-Len),
  4678. L"affinity=%ws load=%u",
  4679. szAffinity,
  4680. pPr->mode_data.multi.load
  4681. );
  4682. }
  4683. }
  4684. else if (pPr->mode == CVY_SINGLE)
  4685. {
  4686. hr = StringCchPrintf(
  4687. pString+Len,
  4688. (cchString-Len),
  4689. L"priority=%u",
  4690. pPr->mode_data.single.priority
  4691. );
  4692. }
  4693. if (hr == S_OK)
  4694. {
  4695. fRet = TRUE;
  4696. }
  4697. end:
  4698. return fRet;
  4699. }
  4700. BOOL
  4701. CfgUtilsSetPortRuleString(
  4702. IN LPCWSTR pString,
  4703. OUT PWLBS_PORT_RULE pPr
  4704. )
  4705. {
  4706. //
  4707. // Look for following name=value pairs
  4708. //
  4709. // ip=1.1.1.1
  4710. // protocol=[TCP|UDP|BOTH]
  4711. // start=122
  4712. // end=122
  4713. // mode=[SINGLE|MULTIPLE|DISABLED]
  4714. // affinity=[NONE|SINGLE|CLASSC]
  4715. // load=80
  4716. // priority=1"
  4717. //
  4718. #define INVALID_VALUE ((DWORD)-1)
  4719. LPWSTR psz = NULL;
  4720. WCHAR szCleanedString[2*NLB_MAX_PORT_STRING_SIZE];
  4721. WCHAR c;
  4722. BOOL fRet = FALSE;
  4723. DWORD protocol= INVALID_VALUE;
  4724. DWORD start_port= INVALID_VALUE;
  4725. DWORD end_port= INVALID_VALUE;
  4726. DWORD mode= INVALID_VALUE;
  4727. DWORD affinity= INVALID_VALUE;
  4728. DWORD load= INVALID_VALUE;
  4729. DWORD priority= INVALID_VALUE;
  4730. ZeroMemory(pPr, sizeof(*pPr));
  4731. //
  4732. // Set szCleanedString to be a version of pString in "canonical" form:
  4733. // extraneous whitespace stripped out and whitspace represented by a
  4734. // single '\b' character.
  4735. {
  4736. UINT Len = wcslen(pString);
  4737. if (Len > (sizeof(szCleanedString)/sizeof(WCHAR)))
  4738. {
  4739. goto end;
  4740. }
  4741. ARRAYSTRCPY(szCleanedString, pString);
  4742. //
  4743. // convert different forms of whitespace into blanks
  4744. //
  4745. for (psz=szCleanedString; (c=*psz)!=0; psz++)
  4746. {
  4747. if (c == ' ' || c == '\t' || c == '\n')
  4748. {
  4749. *psz = ' ';
  4750. }
  4751. }
  4752. //
  4753. // convert runs of whitespace into a single blank
  4754. // also get rid of initial whitespace
  4755. //
  4756. LPWSTR psz1 = szCleanedString;
  4757. BOOL fRun = TRUE; // initial value of TRUE gets rid of initial space
  4758. for (psz=szCleanedString; (c=*psz)!=0; psz++)
  4759. {
  4760. if (c == ' ')
  4761. {
  4762. if (fRun)
  4763. {
  4764. continue;
  4765. }
  4766. else
  4767. {
  4768. fRun = TRUE;
  4769. }
  4770. }
  4771. else if (c == '=')
  4772. {
  4773. if (fRun)
  4774. {
  4775. //
  4776. // The '=' was preceed by whitespace -- delete that
  4777. // whitespace. We keep fRun TRUE so subsequent whitespace
  4778. // is eliminated.
  4779. //
  4780. if (psz1 == szCleanedString)
  4781. {
  4782. // we're just starting, and we get an '=' -- bad
  4783. goto end;
  4784. }
  4785. psz1--;
  4786. if (*psz1 != ' ')
  4787. {
  4788. ASSERT(*psz1 == '=');
  4789. goto end; // two equals in a row, not accepted!
  4790. }
  4791. }
  4792. }
  4793. else // non blank and non '=' chracter
  4794. {
  4795. fRun = FALSE;
  4796. }
  4797. *psz1++ = c;
  4798. }
  4799. *psz1=0;
  4800. }
  4801. // wprintf(L"CLEANED: \"%ws\"\n", szCleanedString);
  4802. //
  4803. // Now actually do the parse.
  4804. //
  4805. psz = szCleanedString;
  4806. while(*psz!=0)
  4807. {
  4808. WCHAR Name[32];
  4809. WCHAR Value[32];
  4810. //
  4811. // Look for the Name in Name=Value pair.
  4812. //
  4813. if (swscanf(psz, L"%16[a-zA-Z]=%16[0-9.a-zA-Z]", Name, Value) != 2)
  4814. {
  4815. // bad parse;
  4816. goto end;
  4817. }
  4818. //
  4819. // Skip past the name=value pair -- it contains no blanks
  4820. //
  4821. for (; (c=*psz)!=NULL; psz++)
  4822. {
  4823. if (c==' ')
  4824. {
  4825. psz++; // to skip past the blank
  4826. break;
  4827. }
  4828. }
  4829. //
  4830. // Now look for the specific name/values
  4831. //
  4832. // ip=1.1.1.1
  4833. // protocol=[TCP|UDP|BOTH]
  4834. // start=122
  4835. // end=122
  4836. // mode=[SINGLE|MULTIPLE|DISABLED]
  4837. // affinity=[NONE|SINGLE|CLASSC]
  4838. // load=80
  4839. // priority=1"
  4840. //
  4841. if (!_wcsicmp(Name, L"ip"))
  4842. {
  4843. if (swscanf(Value, L"%15[0-9.]", pPr->virtual_ip_addr) != 1)
  4844. {
  4845. goto end;
  4846. }
  4847. }
  4848. else if (!_wcsicmp(Name, L"protocol"))
  4849. {
  4850. if (!_wcsicmp(Value, L"TCP"))
  4851. {
  4852. protocol = CVY_TCP;
  4853. }
  4854. else if (!_wcsicmp(Value, L"UDP"))
  4855. {
  4856. protocol = CVY_UDP;
  4857. }
  4858. else if (!_wcsicmp(Value, L"BOTH"))
  4859. {
  4860. protocol = CVY_TCP_UDP;
  4861. }
  4862. else
  4863. {
  4864. // bad parse;
  4865. goto end;
  4866. }
  4867. }
  4868. else if (!_wcsicmp(Name, L"protocol"))
  4869. {
  4870. }
  4871. else if (!_wcsicmp(Name, L"start"))
  4872. {
  4873. if (swscanf(Value, L"%u", &start_port)!=1)
  4874. {
  4875. // bad parse;
  4876. goto end;
  4877. }
  4878. if (start_port > 65535)
  4879. {
  4880. // bad parse;
  4881. goto end;
  4882. }
  4883. }
  4884. else if (!_wcsicmp(Name, L"end"))
  4885. {
  4886. if (swscanf(Value, L"%u", &end_port)!=1)
  4887. {
  4888. // bad parse;
  4889. goto end;
  4890. }
  4891. if (end_port > 65535)
  4892. {
  4893. // bad parse;
  4894. goto end;
  4895. }
  4896. }
  4897. else if (!_wcsicmp(Name, L"mode"))
  4898. {
  4899. if (!_wcsicmp(Value, L"SINGLE"))
  4900. {
  4901. mode = CVY_SINGLE;
  4902. }
  4903. else if (!_wcsicmp(Value, L"MULTIPLE"))
  4904. {
  4905. mode = CVY_MULTI;
  4906. }
  4907. else if (!_wcsicmp(Value, L"DISABLED"))
  4908. {
  4909. mode = CVY_NEVER;
  4910. }
  4911. else
  4912. {
  4913. // bad parse;
  4914. goto end;
  4915. }
  4916. }
  4917. else if (!_wcsicmp(Name, L"affinity"))
  4918. {
  4919. if (!_wcsicmp(Value, L"NONE"))
  4920. {
  4921. affinity = CVY_AFFINITY_NONE;
  4922. }
  4923. else if (!_wcsicmp(Value, L"SINGLE"))
  4924. {
  4925. affinity = CVY_AFFINITY_SINGLE;
  4926. }
  4927. else if (!_wcsicmp(Value, L"CLASSC"))
  4928. {
  4929. affinity = CVY_AFFINITY_CLASSC;
  4930. }
  4931. else
  4932. {
  4933. // bad parse;
  4934. goto end;
  4935. }
  4936. }
  4937. else if (!_wcsicmp(Name, L"load"))
  4938. {
  4939. if (swscanf(Value, L"%u", &load)!=1)
  4940. {
  4941. if (load > 100)
  4942. {
  4943. // bad parse;
  4944. goto end;
  4945. }
  4946. }
  4947. }
  4948. else if (!_wcsicmp(Name, L"priority"))
  4949. {
  4950. if (swscanf(Value, L"%u", &priority)!=1)
  4951. {
  4952. if (priority > 31)
  4953. {
  4954. // bad parse;
  4955. goto end;
  4956. }
  4957. }
  4958. }
  4959. else
  4960. {
  4961. // bad parse
  4962. goto end;
  4963. }
  4964. // printf("SUCCESSFUL PARSE: %ws = %ws\n", Name, Value);
  4965. }
  4966. //
  4967. // Set up the PARAMS structure, doing extra parameter validation along the
  4968. // way.
  4969. //
  4970. switch(mode)
  4971. {
  4972. case CVY_SINGLE:
  4973. if (load != INVALID_VALUE || affinity != INVALID_VALUE)
  4974. {
  4975. goto end; // bad parse;
  4976. }
  4977. if ((priority < CVY_MIN_PRIORITY) || (priority > CVY_MAX_PRIORITY))
  4978. {
  4979. goto end; // bad parse
  4980. }
  4981. pPr->mode_data.single.priority = priority;
  4982. break;
  4983. case CVY_MULTI:
  4984. if (priority != INVALID_VALUE)
  4985. {
  4986. goto end; // bad parse;
  4987. }
  4988. switch(affinity)
  4989. {
  4990. case CVY_AFFINITY_NONE:
  4991. break;
  4992. case CVY_AFFINITY_SINGLE:
  4993. break;
  4994. case CVY_AFFINITY_CLASSC:
  4995. break;
  4996. case INVALID_VALUE:
  4997. default:
  4998. goto end; // bad parse;
  4999. }
  5000. pPr->mode_data.multi.affinity = affinity;
  5001. if (load == INVALID_VALUE)
  5002. {
  5003. // this means it's unassigned, which means equal.
  5004. pPr->mode_data.multi.equal_load = 1;
  5005. }
  5006. else if (load > CVY_MAX_LOAD)
  5007. {
  5008. goto end; // bad parse
  5009. }
  5010. else
  5011. {
  5012. pPr->mode_data.multi.load = load;
  5013. }
  5014. break;
  5015. case CVY_NEVER:
  5016. if (load != INVALID_VALUE || affinity != INVALID_VALUE
  5017. || priority != INVALID_VALUE)
  5018. {
  5019. goto end; // bad parse;
  5020. }
  5021. break;
  5022. case INVALID_VALUE:
  5023. default:
  5024. goto end; // bad parse;
  5025. }
  5026. pPr->mode = mode;
  5027. pPr->end_port = end_port;
  5028. pPr->start_port = start_port;
  5029. pPr->protocol = protocol;
  5030. fRet = TRUE;
  5031. end:
  5032. return fRet;
  5033. }
  5034. //
  5035. // Attempts to resolve the ip address and ping the host.
  5036. //
  5037. WBEMSTATUS
  5038. CfgUtilPing(
  5039. LPCWSTR szBindString,
  5040. UINT Timeout, // In milliseconds.
  5041. OUT ULONG *pResolvedIpAddress // in network byte order.
  5042. )
  5043. {
  5044. WBEMSTATUS Status = WBEM_E_INVALID_PARAMETER;
  5045. UINT w32Status = ERROR_SUCCESS;
  5046. LONG inaddr;
  5047. char rgchBindString[1024];
  5048. TRACE_INFO("->%!FUNC!(BindString=%ws)", szBindString);
  5049. *pResolvedIpAddress = 0;
  5050. //
  5051. // Convert to ANSI.
  5052. //
  5053. {
  5054. UINT u = wcslen(szBindString);
  5055. if (u >= (sizeof(rgchBindString)/sizeof(rgchBindString[0])))
  5056. {
  5057. Status = WBEM_E_INVALID_PARAMETER;
  5058. goto end;
  5059. }
  5060. do
  5061. {
  5062. rgchBindString[u] = (char) szBindString[u];
  5063. } while (u--);
  5064. }
  5065. //
  5066. // Resolve to an IP address...
  5067. //
  5068. inaddr = inet_addr(rgchBindString);
  5069. if (inaddr == -1L)
  5070. {
  5071. struct hostent *hostp = NULL;
  5072. hostp = gethostbyname(rgchBindString);
  5073. if (hostp) {
  5074. unsigned char *pc = (unsigned char *) & inaddr;
  5075. // If we find a host entry, set up the internet address
  5076. inaddr = *(long *)hostp->h_addr;
  5077. TRACE_VERB(
  5078. L"%!FUNC! Resolved %ws to IP address %d.%d.%d.%d.\n",
  5079. szBindString,
  5080. pc[0],
  5081. pc[1],
  5082. pc[2],
  5083. pc[3]
  5084. );
  5085. } else {
  5086. // Neither dotted, not name.
  5087. w32Status = WSAGetLastError();
  5088. TRACE_CRIT(L"%!FUNC! WSA error 0x%08lx resolving address %ws.",
  5089. w32Status, szBindString);
  5090. goto end;
  5091. }
  5092. }
  5093. *pResolvedIpAddress = (ULONG) inaddr;
  5094. //
  5095. //
  5096. //
  5097. if (g_CfgUtils.DisablePing())
  5098. {
  5099. TRACE_INFO(L"%!FUNC!: ICMP ping disabled, so not actually pinging.");
  5100. Status = WBEM_NO_ERROR;
  5101. goto end;
  5102. }
  5103. //
  5104. // Send Icmp echo.
  5105. //
  5106. HANDLE IcmpHandle;
  5107. IcmpHandle = IcmpCreateFile();
  5108. if (IcmpHandle == INVALID_HANDLE_VALUE) {
  5109. w32Status = GetLastError();
  5110. TRACE_CRIT(L"%!FUNC! Unable to contact IP driver, error code %d.",w32Status);
  5111. goto end;
  5112. }
  5113. const int MinInterval = 500;
  5114. while (Timeout)
  5115. {
  5116. static BYTE SendBuffer[32];
  5117. BYTE RcvBuffer[1024];
  5118. int numberOfReplies;
  5119. numberOfReplies = IcmpSendEcho2(IcmpHandle,
  5120. 0,
  5121. NULL,
  5122. NULL,
  5123. inaddr,
  5124. SendBuffer,
  5125. sizeof(SendBuffer),
  5126. NULL,
  5127. RcvBuffer,
  5128. sizeof(RcvBuffer),
  5129. MinInterval
  5130. );
  5131. if (numberOfReplies == 0) {
  5132. int errorCode = GetLastError();
  5133. TRACE_INFO(L"%!FUNC! Got no replies yet; ICMP Error %d", errorCode);
  5134. if (Timeout > MinInterval)
  5135. {
  5136. Timeout -= MinInterval;
  5137. // TODO: look at ping sources for proper error reporting
  5138. // (host unreachable, etc...)
  5139. Sleep(MinInterval);
  5140. }
  5141. else
  5142. {
  5143. Timeout = 0;
  5144. }
  5145. }
  5146. else
  5147. {
  5148. Status = WBEM_NO_ERROR;
  5149. break;
  5150. }
  5151. }
  5152. end:
  5153. TRACE_INFO("<-%!FUNC! returns 0x%08lx", Status);
  5154. return Status;
  5155. }
  5156. //
  5157. // Validates a network address
  5158. //
  5159. WBEMSTATUS
  5160. CfgUtilsValidateNetworkAddress(
  5161. IN LPCWSTR szAddress, // format: "10.0.0.1[/255.0.0.0]"
  5162. OUT PUINT puIpAddress, // in network byte order
  5163. OUT PUINT puSubnetMask, // in network byte order (0 if unspecified)
  5164. OUT PUINT puDefaultSubnetMask // depends on class: 'a', 'b', 'c', 'd', 'e'
  5165. )
  5166. {
  5167. WBEMSTATUS Status = WBEM_E_INVALID_PARAMETER;
  5168. UINT w32Status = ERROR_SUCCESS;
  5169. UINT uIpAddress=0;
  5170. UINT uSubnetMask=0;
  5171. UINT uDefaultSubnetMask=0;
  5172. char rgchBindString[32];
  5173. char *szIpAddress = rgchBindString;
  5174. char *szSubnetMask = NULL;
  5175. //
  5176. // Take care of the fact that the following two args could be NULL
  5177. //
  5178. if (puSubnetMask == NULL)
  5179. {
  5180. puSubnetMask = &uSubnetMask;
  5181. }
  5182. if (puDefaultSubnetMask == NULL)
  5183. {
  5184. puDefaultSubnetMask = &uDefaultSubnetMask;
  5185. }
  5186. *puIpAddress = 0;
  5187. *puSubnetMask = 0;
  5188. *puDefaultSubnetMask = 0;
  5189. //
  5190. // Convert to ANSI.
  5191. //
  5192. {
  5193. UINT u = wcslen(szAddress);
  5194. if (u >= (sizeof(rgchBindString)/sizeof(rgchBindString[0])))
  5195. {
  5196. goto end;
  5197. }
  5198. do
  5199. {
  5200. char c = (char) szAddress[u];
  5201. //
  5202. // NOTE: We're counting down. Last time through, c is 0.
  5203. //
  5204. //
  5205. // We split up the network address into the ip address portion
  5206. // and the subnet portion.
  5207. //
  5208. if (c == '/')
  5209. {
  5210. if (szSubnetMask != NULL)
  5211. {
  5212. // multiple '/'s -- not good!
  5213. goto end;
  5214. }
  5215. szSubnetMask = &rgchBindString[u+1];
  5216. c = 0;
  5217. }
  5218. rgchBindString[u] = c;
  5219. } while (u--);
  5220. }
  5221. //
  5222. // Get the UINT version of ip address and subnet.
  5223. //
  5224. uIpAddress = inet_addr(szIpAddress);
  5225. if (szSubnetMask == NULL)
  5226. {
  5227. szSubnetMask = "";
  5228. }
  5229. uSubnetMask = inet_addr(szSubnetMask);
  5230. //
  5231. // Parameter validation...
  5232. //
  5233. {
  5234. if (uIpAddress==0 || uIpAddress == INADDR_NONE)
  5235. {
  5236. // ip address null, or invalid
  5237. goto end;
  5238. }
  5239. if (*szSubnetMask != 0 && uSubnetMask == INADDR_NONE)
  5240. {
  5241. // ip subnet specified, but invalid
  5242. goto end;
  5243. }
  5244. //
  5245. // Classify IP address 'a', 'b', 'c', 'd'
  5246. //
  5247. {
  5248. //
  5249. // Get msb byte in network byte order
  5250. //
  5251. unsigned char uc = (unsigned char) (uIpAddress & 0xff);
  5252. if ((uc & 0x80) == 0)
  5253. {
  5254. // class A
  5255. uDefaultSubnetMask = 0x000000ff; // network order
  5256. }
  5257. else if (( uc & 0x40) == 0)
  5258. {
  5259. // class B
  5260. uDefaultSubnetMask = 0x0000ffff; // network order
  5261. }
  5262. else if (( uc & 0x20) == 0)
  5263. {
  5264. // class C
  5265. uDefaultSubnetMask = 0x00ffffff; // network order
  5266. }
  5267. else
  5268. {
  5269. // class D or E
  5270. uDefaultSubnetMask = 0;
  5271. }
  5272. }
  5273. }
  5274. *puIpAddress = uIpAddress;
  5275. *puSubnetMask = uSubnetMask;
  5276. *puDefaultSubnetMask = uDefaultSubnetMask;
  5277. Status = WBEM_NO_ERROR;
  5278. end:
  5279. return Status;
  5280. }
  5281. /*
  5282. This function enables the "SeLoadDriverPrivilege" privilege (required to load/unload device driver)
  5283. in the access token.
  5284. What is the need for this function?
  5285. The setup/pnp apis called by the nlb manager's wmi provider to bind/unbind NLB to the nic, require that the
  5286. "SeLoadDriverPrivilege" privilege be present AND enabled in the access token of the thread.
  5287. Why is this funcion placed here (in the client) instead of the provider?
  5288. RPC not merely disables, but removes all privileges that are NOT enabled in the client and only passes along
  5289. to the server (ie. provider), those privileges that are enabled. Since "SeLoadDriverPrivilege" is not enabled
  5290. by default, RPC would not pass this privilege along to the provider. So, if this function was placed in the
  5291. provider, it would fail because the privilege is NOT present to be enabled.
  5292. This privilege needs to be enabled only when the server is located in the same machine as the client. When, the
  5293. server is remote, it was observed that the "SeLoadDriverPrivilege" privilege is enabled by default.
  5294. NOTE: When called by a non-admin, this function will fail because this privilege is not assigned to non-admins
  5295. and hence, can not be enabled.
  5296. --KarthicN, 5/7/02
  5297. */
  5298. BOOL CfgUtils_Enable_Load_Unload_Driver_Privilege(VOID)
  5299. {
  5300. HANDLE TokenHandle;
  5301. TOKEN_PRIVILEGES TP;
  5302. LUID Luid;
  5303. DWORD dwError;
  5304. TRACE_INFO("->%!FUNC!");
  5305. // Look up the LUID for "SeLoadDriverPrivilege"
  5306. if (!LookupPrivilegeValue(NULL, // lookup privilege on local system
  5307. SE_LOAD_DRIVER_NAME, // "SeLoadDriverPrivilege" : Load and unload device drivers
  5308. &Luid)) // receives LUID of privilege
  5309. {
  5310. TRACE_CRIT("%!FUNC! LookupPrivilegeValue() failed with error = %u", GetLastError() );
  5311. TRACE_INFO("<-%!FUNC! Returning FALSE");
  5312. return FALSE;
  5313. }
  5314. // Get a handle to the process access token.
  5315. if (!OpenProcessToken(GetCurrentProcess(),
  5316. TOKEN_ADJUST_PRIVILEGES,
  5317. &TokenHandle))
  5318. {
  5319. TRACE_CRIT("%!FUNC! OpenProcessToken() for TOKEN_ADJUST_PRIVILEGES failed with error = %u", GetLastError());
  5320. TRACE_INFO("<-%!FUNC! Returning FALSE");
  5321. return FALSE;
  5322. }
  5323. TP.PrivilegeCount = 1;
  5324. TP.Privileges[0].Luid = Luid;
  5325. TP.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  5326. // Enable the "SeLoadDriverPrivilege" privilege.
  5327. AdjustTokenPrivileges(TokenHandle,
  5328. FALSE,
  5329. &TP,
  5330. sizeof(TOKEN_PRIVILEGES),
  5331. NULL,
  5332. NULL);
  5333. // Call GetLastError to determine whether the function succeeded.
  5334. dwError = GetLastError();
  5335. if (dwError != ERROR_SUCCESS)
  5336. {
  5337. TRACE_CRIT("%!FUNC! AdjustTokenPrivileges() failed with error = %u", dwError );
  5338. CloseHandle(TokenHandle);
  5339. TRACE_INFO("<-%!FUNC! Returning FALSE");
  5340. return FALSE;
  5341. }
  5342. CloseHandle(TokenHandle);
  5343. TRACE_INFO("<-%!FUNC! Returning TRUE");
  5344. return TRUE;
  5345. }
  5346. USHORT crc16(LPCWSTR ptr)
  5347. {
  5348. int crc = 0; // Holds CRC
  5349. int i; //
  5350. int count; // holds len
  5351. count = wcslen(ptr);
  5352. while(--count >= 0) {
  5353. i = *ptr;
  5354. // make all uppercase // ((case insens))
  5355. i = ((i >= 'a') && (i <= 'z')) ? (i-32) : i;
  5356. crc = crc ^ (i << 8);
  5357. ptr++;
  5358. for (i=0; i<8; ++i)
  5359. if (crc & 0x8000)
  5360. crc = (crc << 1) ^ 0x1021;
  5361. else
  5362. crc = crc << 1;
  5363. }
  5364. return (crc & 0xffff);
  5365. }
  5366. WBEMSTATUS
  5367. get_friendly_name_from_registry(
  5368. LPCWSTR szGuid,
  5369. LPWSTR *pszFriendlyName
  5370. )
  5371. {
  5372. WBEMSTATUS wStat = WBEM_E_NOT_FOUND;
  5373. HKEY hkNetwork = NULL;
  5374. WCHAR adapter[200];
  5375. int ret;
  5376. wchar_t data[200];
  5377. *pszFriendlyName = NULL;
  5378. ret = RegOpenKeyEx(
  5379. HKEY_LOCAL_MACHINE,
  5380. L"SYSTEM\\CurrentControlSet\\Control\\Network",
  5381. 0,
  5382. KEY_READ,
  5383. &hkNetwork
  5384. );
  5385. if (ret != ERROR_SUCCESS)
  5386. {
  5387. TRACE_CRIT("%!FUNC! RegOpenKeyEx(Network) fails with err %lu", ret);
  5388. hkNetwork = NULL;
  5389. goto end;
  5390. }
  5391. *adapter=0;
  5392. #if OBSOLETE
  5393. for (int num=0; 1; num++)
  5394. {
  5395. HKEY hk=NULL;
  5396. FILETIME time;
  5397. *adapter=0;
  5398. DWORD dwDataBuffer=200;
  5399. ret=RegEnumKeyEx(
  5400. hkNetwork,
  5401. num,
  5402. adapter,
  5403. &dwDataBuffer,
  5404. NULL,
  5405. NULL,
  5406. NULL,
  5407. &time);
  5408. if ((ret!=ERROR_SUCCESS) && (ret!=ERROR_MORE_DATA))
  5409. {
  5410. if (ret != ERROR_NO_MORE_ITEMS)
  5411. {
  5412. TRACE_CRIT("%!FUNC! RegEnumKey(Network) returns error %lu", ret);
  5413. wStat = WBEM_E_CRITICAL_ERROR;
  5414. }
  5415. else
  5416. {
  5417. wStat = WBEM_E_NOT_FOUND;
  5418. }
  5419. break;
  5420. }
  5421. //
  5422. // open the items one by one
  5423. //
  5424. ret=RegOpenKeyEx(hkNetwork, adapter, 0, KEY_READ, &hk);
  5425. if (ret == ERROR_SUCCESS)
  5426. {
  5427. DWORD dwValueType=REG_SZ;
  5428. dwDataBuffer=200;
  5429. *data = 0;
  5430. ret = RegQueryValueEx(
  5431. hk,
  5432. L"",
  5433. 0,
  5434. &dwValueType,
  5435. (LPBYTE)data,
  5436. &dwDataBuffer
  5437. );
  5438. RegCloseKey(hk);
  5439. if (ret == ERROR_SUCCESS)
  5440. {
  5441. if (_wcsicmp(L"Network Adapters", data)==0)
  5442. {
  5443. //
  5444. // Found it!
  5445. //
  5446. break;
  5447. }
  5448. }
  5449. }
  5450. }
  5451. #endif // OBSOLETE
  5452. ARRAYSTRCPY(adapter, L"{4D36E972-E325-11CE-BFC1-08002BE10318}");
  5453. if (*adapter!=0)
  5454. {
  5455. HKEY hk = NULL;
  5456. wchar_t path[200];
  5457. //
  5458. // found the guid now
  5459. // look for friendly nic name
  5460. //
  5461. StringCbPrintf(path, sizeof(path), L"%ws\\%ws\\Connection", adapter, szGuid);
  5462. ret=RegOpenKeyEx(hkNetwork, path, 0, KEY_READ, &hk);
  5463. if (ret != ERROR_SUCCESS)
  5464. {
  5465. TRACE_CRIT("%!FUNC! Error %lu trying to open path %ws", ret, path);
  5466. }
  5467. else
  5468. {
  5469. DWORD dwDataBuffer=200;
  5470. DWORD dwValueType=REG_SZ;
  5471. *data = 0;
  5472. ret = RegQueryValueEx(
  5473. hk,
  5474. L"Name",
  5475. 0,
  5476. &dwValueType,
  5477. (LPBYTE)data,
  5478. &dwDataBuffer
  5479. );
  5480. RegCloseKey(hk);
  5481. if(ret != ERROR_SUCCESS)
  5482. {
  5483. TRACE_CRIT("%!FUNC! Error %lu trying to query Name value on path %ws", ret, path);
  5484. }
  5485. else
  5486. {
  5487. //
  5488. // We're done!
  5489. //
  5490. TRACE_CRIT("%!FUNC! Found friendly name: \"%ws\"", data);
  5491. LPWSTR szName = new WCHAR[(dwDataBuffer+1)/sizeof(WCHAR)];
  5492. if (szName == NULL)
  5493. {
  5494. TRACE_CRIT("%!FUNC! Allocation failure!");
  5495. wStat = WBEM_E_OUT_OF_MEMORY;
  5496. }
  5497. else
  5498. {
  5499. // note -- dwDataBuffer includes space for ending null.
  5500. CopyMemory(szName, data, dwDataBuffer);
  5501. *pszFriendlyName = szName;
  5502. wStat = WBEM_NO_ERROR;
  5503. }
  5504. }
  5505. }
  5506. }
  5507. end:
  5508. if (hkNetwork!=NULL)
  5509. {
  5510. RegCloseKey(hkNetwork);
  5511. }
  5512. return wStat;
  5513. }
  5514. #define STATUS_SUCCESS 0
  5515. BOOL
  5516. CfgUtilEncryptPassword(
  5517. IN LPCWSTR szPassword,
  5518. OUT UINT cchEncPwd, // size in chars of szEncPwd, inc space for ending 0
  5519. OUT LPWSTR szEncPwd
  5520. )
  5521. {
  5522. //
  5523. // Note -- buffer passed to RtlEncrypt/DecryptMemory must be
  5524. // multiples of RTL_ENCRYPT_MEMORY_SIZE -- so we must round them up
  5525. // appropriately.
  5526. //
  5527. BOOL fRet = FALSE;
  5528. UINT uLen = wcslen(szPassword);
  5529. UINT uEncryptCb = (uLen+1)*sizeof(WCHAR);
  5530. WCHAR rgPasswordCopy[64];
  5531. // Round up if required...
  5532. {
  5533. UINT mod = uEncryptCb % RTL_ENCRYPT_MEMORY_SIZE;
  5534. if (mod != 0)
  5535. {
  5536. uEncryptCb += (RTL_ENCRYPT_MEMORY_SIZE - mod);
  5537. };
  5538. }
  5539. ASSERT((uEncryptCb % RTL_ENCRYPT_MEMORY_SIZE)==0);
  5540. if (uEncryptCb > sizeof(rgPasswordCopy))
  5541. {
  5542. //
  5543. // szPassword is too large for our internal buffer ... bail
  5544. //
  5545. fRet = FALSE;
  5546. goto end;
  5547. }
  5548. //
  5549. // We're going to expand the encrypted password to make it
  5550. // printable -- so we require 2 chars for every byte
  5551. // of encrypted data. Also need the space for ending NULL char.
  5552. // Check if we have enough space...
  5553. //
  5554. if (2*uEncryptCb >= cchEncPwd)
  5555. {
  5556. // Nah, bail...
  5557. fRet = FALSE;
  5558. goto end;
  5559. }
  5560. RtlSecureZeroMemory(rgPasswordCopy, sizeof(rgPasswordCopy));
  5561. ARRAYSTRCPY(rgPasswordCopy, szPassword);
  5562. NTSTATUS ntStat;
  5563. ntStat = RtlEncryptMemory (rgPasswordCopy, uEncryptCb, 0);
  5564. if (ntStat != STATUS_SUCCESS)
  5565. {
  5566. TRACE_CRIT(L"%!FUNC! RtlEncryptMemory fails with ntStat 0x%lx", ntStat);
  5567. fRet = FALSE;
  5568. goto end;
  5569. }
  5570. //
  5571. // Now we expand the encrypted password
  5572. //
  5573. {
  5574. UINT u;
  5575. for (u=0;u<uEncryptCb;u++)
  5576. {
  5577. //
  5578. // In this loop, we treat rgPasswordCopy of a BYTE array of
  5579. // length uEncryptCb...
  5580. //
  5581. BYTE b = ((BYTE*)rgPasswordCopy)[u];
  5582. szEncPwd[2*u] = 'a' + ((b & 0xf0) >> 4);
  5583. szEncPwd[2*u+1] = 'a' + (b & 0xf);
  5584. }
  5585. ASSERT(2*u < cchEncPwd); // We already check this earlier...
  5586. szEncPwd[2*u]=0;
  5587. }
  5588. fRet = TRUE;
  5589. end:
  5590. return fRet;
  5591. }
  5592. BOOL
  5593. CfgUtilDecryptPassword(
  5594. IN LPCWSTR szEncPwd,
  5595. OUT UINT cchPwd, // size in chars of szPwd, inc space for ending 0
  5596. OUT LPWSTR szPwd
  5597. )
  5598. {
  5599. BOOL fRet = FALSE;
  5600. UINT uEncLen = wcslen(szEncPwd);
  5601. UINT cbEncPwd = uEncLen/2; // Length, in bytes, of binary form of enc pwd.
  5602. if (uEncLen == 0 || cchPwd == 0)
  5603. {
  5604. //
  5605. // Encrypted pwd and cchPwd must be non-zero,
  5606. //
  5607. fRet = FALSE;
  5608. goto end;
  5609. }
  5610. //
  5611. // uEncLen is twice the number of BYTES in the binary form of the
  5612. // encrypted password, and the latter number sould be a multiple
  5613. // of RTL_ENCRYPT_MEMORY_SIZE. Let's check this.
  5614. //
  5615. if (uEncLen % (RTL_ENCRYPT_MEMORY_SIZE*2)!=0)
  5616. {
  5617. // It's not, so we bail.
  5618. fRet = FALSE;
  5619. goto end;
  5620. }
  5621. //
  5622. // Make sure there is enough space in szPwd to store the
  5623. // binary form of the encrypted password (and the final form of
  5624. // the decrypted password, which will include the ending NULL).
  5625. //
  5626. if (cbEncPwd > cchPwd*sizeof(WCHAR))
  5627. {
  5628. // bail
  5629. fRet = FALSE;
  5630. goto end;
  5631. }
  5632. RtlSecureZeroMemory(szPwd, cchPwd*sizeof(WCHAR));
  5633. //
  5634. // Now let's translate the printable version of the encrypted password
  5635. // to the binary version...
  5636. //
  5637. {
  5638. UINT u;
  5639. for (u=0; u<cbEncPwd; u++)
  5640. {
  5641. BYTE b;
  5642. b = (BYTE) (szEncPwd[2*u] - 'a');
  5643. b <<= 4;
  5644. b |= (BYTE) (szEncPwd[2*u+1] - 'a');
  5645. ((BYTE*)szPwd)[u] = b;
  5646. }
  5647. ASSERT(u<2*cchPwd);
  5648. }
  5649. NTSTATUS ntStat;
  5650. ntStat = RtlDecryptMemory (szPwd, cbEncPwd, 0);
  5651. if (ntStat != STATUS_SUCCESS)
  5652. {
  5653. TRACE_CRIT(L"%!FUNC! RtlEncryptMemory fails with ntStat 0x%lx", ntStat);
  5654. fRet = FALSE;
  5655. goto end;
  5656. }
  5657. //
  5658. // At this point, the decrypted pwd MUST be null terminated, or we
  5659. // have some error. Note also that we have pre-zeroed out szPwd on entry,
  5660. // and checked that cchPwd is non zero.
  5661. //
  5662. if (szPwd[cchPwd-1] != 0)
  5663. {
  5664. // bad decryption...
  5665. fRet = FALSE;
  5666. }
  5667. fRet = TRUE;
  5668. end:
  5669. return fRet;
  5670. }
  5671. //
  5672. // Sets pfMSCSInstalled to TRUE if MSCS is installed, FALSE otherwise.
  5673. // Returns TRUE on success, FALSE otherwise.
  5674. //
  5675. BOOL
  5676. CfgUtilIsMSCSInstalled(VOID)
  5677. {
  5678. BOOL fRet = FALSE;
  5679. typedef DWORD (CALLBACK* LPFNGNCS)(LPCWSTR,DWORD*);
  5680. LPFNGNCS pfnGetNodeClusterState = NULL;
  5681. HINSTANCE hDll = NULL;
  5682. DWORD dwClusterState = 0;
  5683. hDll = LoadLibrary(L"clusapi.dll");
  5684. if (NULL == hDll)
  5685. {
  5686. TRACE_CRIT("%!FUNC! Load clusapi.dll failed with %d", GetLastError());
  5687. goto end;
  5688. }
  5689. pfnGetNodeClusterState = (LPFNGNCS) GetProcAddress(
  5690. hDll,
  5691. "GetNodeClusterState"
  5692. );
  5693. if (NULL == pfnGetNodeClusterState)
  5694. {
  5695. TRACE_CRIT("%!FUNC! GetProcAddress(GetNodeClusterState) failed with error %d", GetLastError());
  5696. goto end;
  5697. }
  5698. if (ERROR_SUCCESS == pfnGetNodeClusterState(NULL, &dwClusterState))
  5699. {
  5700. if ( ClusterStateNotRunning == dwClusterState
  5701. || ClusterStateRunning == dwClusterState)
  5702. {
  5703. fRet = TRUE;
  5704. TRACE_INFO("%!FUNC! MSCS IS installed.");
  5705. }
  5706. else
  5707. {
  5708. // MSCS is not installed. That's good!
  5709. TRACE_INFO("%!FUNC! MSCS Cluster state = %lu (assumed not installed)",
  5710. dwClusterState);
  5711. }
  5712. }
  5713. else
  5714. {
  5715. TRACE_CRIT("%!FUNC! error getting MSCS cluster state.");
  5716. }
  5717. (void) FreeLibrary(hDll);
  5718. end:
  5719. return fRet;
  5720. }