3 Copyright 2004 by the Massachusetts Institute of Technology
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the name of the Massachusetts
12 Institute of Technology (M.I.T.) not be used in advertising or publicity
13 pertaining to distribution of the software without specific, written
16 M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
17 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
18 M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
19 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
26 //**************************************************************************
30 // Call EnableStatic method of Win32_NetworkAdapterConfiguration
31 // for some network adapter GUID.
35 // The EnableStatic method is notsupported on Win9x platforms.
37 //**************************************************************************
47 /* These two are from the Windows DDK */
52 //#include <objbase.h>
55 //inline void printf(char*, ...) {}
60 #include "loopbackutils.h"
62 #define CLEANUP_ON_FAILURE(hr) \
63 do { if (!SUCCEEDED(hr)) {goto cleanup;} } while (0)
65 #define CLEANUP_ON_AND_SET(check, var, value) \
66 do { if (check) { (var) = (value); goto cleanup; } } while (0)
68 #define ETCDIR "\\drivers\\etc"
73 DWORD AdjustMaxLana(DWORD dwMaxLana);
77 (*FindNetworkAdapterConfigurationInstance_t)(
79 IN IWbemServices *pSvc,
84 FindNetworkAdapterConfigurationInstanceByGUID(
86 IN IWbemServices *pSvc,
94 IEnumWbemClassObject* pEnum = 0;
95 IWbemClassObject* pObj = 0;
98 LPCWSTR adapter_guid = (LPCWSTR)pContext;
101 if (!pPath || !adapter_guid || *pPath)
106 // Query for all network adapters
107 Language = SysAllocString(L"WQL");
108 Query = SysAllocString(L"select * from Win32_NetworkAdapterConfiguration");
111 hr = pSvc->ExecQuery(Language,
113 WBEM_FLAG_FORWARD_ONLY, // Flags
118 ReportMessage(0,"ExecQuery() error",NULL,NULL, hr);
122 // Retrieve the objects in the result set.
127 hr = pEnum->Next(0, // Time out
131 CLEANUP_ON_FAILURE(hr);
137 hr = pObj->Get(L"SettingID", // property name
139 &Value, // output to this variant
142 CLEANUP_ON_FAILURE(hr);
144 bFound = !wcscmp(adapter_guid, V_BSTR(&Value));
148 ReportMessage(1,"Found adapter", NULL,V_BSTR(&Value),0);
149 VariantClear(&Value);
150 hr = pObj->Get(L"__RELPATH", // property name
152 &Value, // output to this variant
155 CLEANUP_ON_FAILURE(hr);
157 *pPath = SysAllocString(V_BSTR(&Value));
161 VariantClear(&Value);
165 pObj->Release(); // Release objects not owned.
172 SysFreeString(Query);
173 SysFreeString(Language);
174 VariantClear(&Value);
180 return *pPath ? 0 : ( SUCCEEDED(hr) ? WBEM_E_NOT_FOUND : hr );
184 SetupStringAsSafeArray(LPCWSTR s, VARIANT* v)
188 SAFEARRAY* array = 0;
191 if (V_VT(v) != VT_EMPTY)
194 b = SysAllocString(s);
195 CLEANUP_ON_AND_SET(!b, hr, E_OUTOFMEMORY);
197 array = SafeArrayCreateVector(VT_BSTR, 0, 1);
198 CLEANUP_ON_AND_SET(!array, hr, E_OUTOFMEMORY);
200 hr = SafeArrayPutElement(array, index, b);
201 CLEANUP_ON_FAILURE(hr);
203 V_VT(v) = VT_ARRAY|VT_BSTR;
212 SafeArrayDestroy(array);
220 FindNetworkAdapterConfigurationInstance_t pFindInstance,
228 IWbemLocator* pLocator = 0;
229 IWbemServices* pNamespace = 0;
230 IWbemClassObject* pClass = 0;
231 IWbemClassObject* pOutInst = 0;
232 IWbemClassObject* pInClass = 0;
233 IWbemClassObject* pInInst = 0;
235 BSTR NamespacePath = 0;
237 BSTR InstancePath = 0;
238 BSTR MethodName = 0; // needs to be BSTR for ExecMethod()
240 BOOL comInitialized = FALSE;
243 VariantInit(&v_ip_list);
246 VariantInit(&v_mask_list);
249 VariantInit(&v_ret_value);
253 // end of declarations & NULL initialization
255 NamespacePath = SysAllocString(L"root\\cimv2");
256 CLEANUP_ON_AND_SET(!NamespacePath, hr, E_OUTOFMEMORY);
258 ClassPath = SysAllocString(L"Win32_NetWorkAdapterConfiguration");
259 CLEANUP_ON_AND_SET(!ClassPath, hr, E_OUTOFMEMORY);
261 MethodName = SysAllocString(L"EnableStatic");
262 CLEANUP_ON_AND_SET(!MethodName, hr, E_OUTOFMEMORY);
264 // Initialize COM and connect up to CIMOM
266 ReportMessage(0, "Intializing COM", NULL, NULL, 0);
267 hr = CoInitializeEx(0, COINIT_MULTITHREADED);
268 if (hr == S_OK || hr == S_FALSE) {
269 comInitialized = TRUE;
274 /* When called from an MSI this will generally fail. This should only be called once
275 per process and not surprisingly MSI beats us to it. So ignore return value and
276 hope for the best. */
277 hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
278 RPC_C_AUTHN_LEVEL_CONNECT,
279 RPC_C_IMP_LEVEL_IMPERSONATE,
282 /* CLEANUP_ON_FAILURE(hr); */
284 ReportMessage(0, "Creating Wbem Locator object", NULL, NULL, 0);
285 hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
286 IID_IWbemLocator, (LPVOID *) &pLocator);
287 CLEANUP_ON_FAILURE(hr);
289 ReportMessage(0, "Connecting to WMI", NULL, NULL, 0);
290 hr = pLocator->ConnectServer(NamespacePath, NULL, NULL, NULL, 0,
291 NULL, NULL, &pNamespace);
292 CLEANUP_ON_FAILURE(hr);
294 ReportMessage(0,"Connected to WMI",NULL,NULL,0);
296 // Set the proxy so that impersonation of the client occurs.
297 hr = CoSetProxyBlanket(pNamespace,
301 RPC_C_AUTHN_LEVEL_CALL,
302 RPC_C_IMP_LEVEL_IMPERSONATE,
305 CLEANUP_ON_FAILURE(hr);
307 // Get the class object
308 hr = pNamespace->GetObject(ClassPath, 0, NULL, &pClass, NULL);
309 CLEANUP_ON_FAILURE(hr);
312 hr = pFindInstance(pContext, pNamespace, &InstancePath);
313 CLEANUP_ON_FAILURE(hr);
315 ReportMessage(0,"Found Adapter Instance",NULL, InstancePath,0);
318 // Use the adapter instance index to set MAXLANA in the registry.
321 if (swscanf(InstancePath, L"Win32_NetworkAdapterConfiguration.Index=%u", &dwIndex)==1)
324 ReportMessage(1,"Setting MAXLANA",NULL,NULL,dwIndex+1);
325 ret = AdjustMaxLana(dwIndex+1);
326 if (ret) ReportMessage(0,"AdjustMaxLana returned the error code ",NULL,NULL,ret);
331 // Get the input argument and set the property
332 hr = pClass->GetMethod(MethodName, 0, &pInClass, NULL);
333 CLEANUP_ON_FAILURE(hr);
335 hr = pInClass->SpawnInstance(0, &pInInst);
336 CLEANUP_ON_FAILURE(hr);
339 hr = SetupStringAsSafeArray(ip, &v_ip_list);
340 CLEANUP_ON_FAILURE(hr);
342 hr = pInInst->Put(L"IPAddress", 0, &v_ip_list, 0);
343 CLEANUP_ON_FAILURE(hr);
345 hr = SetupStringAsSafeArray(mask, &v_mask_list);
346 CLEANUP_ON_FAILURE(hr);
348 hr = pInInst->Put(L"SubNetMask", 0, &v_mask_list, 0);
349 CLEANUP_ON_FAILURE(hr);
351 // Sleep for a twenty seconds
352 ReportMessage(0,"Calling ExecMethod in 20 seconds...",NULL,NULL,0);
354 ReportMessage(0,"Calling ExecMethod in 10 seconds...",NULL,NULL,0);
356 ReportMessage(0,"Calling ExecMethod in 5 seconds...",NULL,NULL,0);
359 // printf("Skipping ExecMethod\n");
363 // Try up to five times, sleeping 3 seconds between tries
364 for (count=0; count<5; count++)
366 if (count>0) ReportMessage(0,"Trying again in 3 seconds...",NULL,NULL,0);
370 ReportMessage(0,"Calling ExecMethod NOW... ",NULL,NULL,0);
374 hr = pNamespace->ExecMethod(InstancePath, MethodName, 0, NULL, pInInst,
379 ReportMessage(0,"ExecMethod failed",NULL,NULL, hr);
383 // Get the EnableStatic method return value
384 hr = pOutInst->Get(L"ReturnValue", 0, &v_ret_value, 0, 0);
388 ReportMessage(0,"WARNING: Could not determine return value for EnableStatic ",NULL,NULL, hr);
392 hr = V_I4(&v_ret_value);
396 ReportMessage(0,"EnableStatic failed ", NULL,NULL,hr);
399 ReportMessage(0,"EnableStatic succeeded",NULL,NULL,0);
409 VariantClear(&v_ret_value);
410 VariantClear(&v_ip_list);
411 VariantClear(&v_mask_list);
413 // SysFreeString is NULL safe
414 SysFreeString(NamespacePath);
415 SysFreeString(ClassPath);
416 SysFreeString(InstancePath);
417 SysFreeString(MethodName);
419 if (pClass) pClass->Release();
420 if (pInInst) pInInst->Release();
421 if (pInClass) pInClass->Release();
422 if (pOutInst) pOutInst->Release();
423 if (pLocator) pLocator->Release();
424 if (pNamespace) pNamespace->Release();
433 /**********************************************************
434 * LoopbackBindings : unbind all other
435 * protocols except TCP/IP, netbios, netbt.
437 extern "C" HRESULT LoopbackBindings (LPCWSTR loopback_guid)
440 INetCfg *pCfg = NULL;
441 INetCfgLock *pLock = NULL;
442 INetCfgComponent *pAdapter = NULL;
443 IEnumNetCfgComponent *pEnumComponent = NULL;
444 BOOL bLockGranted = FALSE;
445 BOOL bInitialized = FALSE;
446 BOOL bConfigChanged = FALSE;
447 LPWSTR swName = NULL;
449 wchar_t device_guid[100];
452 ReportMessage(0,"Running LoopbackBindings()...",NULL,NULL,0);
454 hr = CoInitializeEx( NULL, COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED );
455 CLEANUP_ON_FAILURE(hr);
457 hr = CoCreateInstance( CLSID_CNetCfg, NULL, CLSCTX_INPROC_SERVER, IID_INetCfg, (void**)&pCfg );
458 CLEANUP_ON_FAILURE(hr);
460 hr = pCfg->QueryInterface( IID_INetCfgLock, (void**)&pLock );
461 CLEANUP_ON_FAILURE(hr);
463 hr = pLock->AcquireWriteLock( 1000, L"AFS Configuration", NULL );
464 CLEANUP_ON_FAILURE(hr);
467 hr = pCfg->Initialize( NULL );
468 CLEANUP_ON_FAILURE(hr);
471 hr = pCfg->EnumComponents( &GUID_DEVCLASS_NET, &pEnumComponent );
472 CLEANUP_ON_FAILURE(hr);
475 while( pEnumComponent->Next( 1, &pAdapter, NULL ) == S_OK )
477 pAdapter->GetDisplayName( &swName );
478 pAdapter->GetInstanceGuid( &g );
479 StringFromGUID2(g, device_guid, 99);
481 if(!wcscmp( device_guid, loopback_guid )) // found loopback adapter
483 INetCfgComponentBindings *pBindings;
484 INetCfgBindingPath *pPath;
485 IEnumNetCfgBindingPath *pEnumPaths;
486 INetCfgComponent *upper;
488 ReportMessage(0,"LoopbackBindings found", NULL, device_guid,0 );
490 hr = pAdapter->QueryInterface( IID_INetCfgComponentBindings, (void**) &pBindings);
493 hr = pBindings->EnumBindingPaths( EBP_ABOVE, &pEnumPaths );
496 while(pEnumPaths->Next( 1, &pPath, NULL ) == S_OK)
498 pPath->GetOwner( &upper );
500 LPWSTR swId = NULL, swName = NULL;
502 upper->GetDisplayName( &swName );
503 upper->GetId( &swId );
505 ReportMessage(1,"Looking at ",NULL, swName, 0);
508 ReportMessage(1," Moving to the end of binding order...",NULL,NULL,0);
509 INetCfgComponentBindings *pBindings2;
510 hr = upper->QueryInterface( IID_INetCfgComponentBindings, (void**) &pBindings2);
513 ReportMessage(1,"...",0,0,0);
514 hr = pBindings2->MoveAfter(pPath, NULL);
515 pBindings2->Release();
518 if (hr==S_OK) ReportMessage(1,"success",0,0,0); else ReportMessage(0,"Binding change failed",0,0,hr);
522 if ( !_wcsicmp(swId, L"ms_netbios") ||
523 !_wcsicmp(swId, L"ms_tcpip") ||
524 !_wcsicmp(swId, L"ms_netbt") ||
525 !_wcsicmp(swId, L"ms_msclient"))
527 if (pPath->IsEnabled()!=S_OK)
529 ReportMessage(1," Enabling ",0,swName,0);
530 hr = pPath->Enable(TRUE);
531 if (hr==S_OK) ReportMessage(1,"success",0,0,0); else ReportMessage(0,"Proto failed",0,0,hr);
536 else //if (!_wcsicmp(swId, L"ms_server") || (!_wcsicmp(swId, L"ms_msclient"))
538 if (pPath->IsEnabled()==S_OK)
540 ReportMessage(1," Disabling ",0,swName,0);
541 hr = pPath->Enable(FALSE);
542 if (hr==S_OK) ReportMessage(1,"success",0,0,0); else ReportMessage(0,"Proto failed",0,0,hr);
547 CoTaskMemFree( swName );
548 CoTaskMemFree( swId );
552 pEnumPaths->Release();
554 pBindings->Release();
555 } // hr==S_OK for QueryInterface IID_INetCfgComponentBindings
558 CoTaskMemFree( swName );
563 pEnumComponent->Release();
569 if(bConfigChanged) pCfg->Apply();
571 if(pAdapter) pAdapter->Release();
573 if(bInitialized) pCfg->Uninitialize();
574 if(bLockGranted) pLock->ReleaseWriteLock();
576 if(pLock) pLock->Release();
577 if(pCfg) pCfg->Release();
579 if (hr) ReportMessage(0,"LoopbackBindings() is returning ",0,0,hr);
592 ReportMessage(0,"Running SetIpAddress()...",0,0,0);
595 hr = WMIEnableStatic(FindNetworkAdapterConfigurationInstanceByGUID,
596 (PVOID)guid, ip, mask);
600 /* Set MAXLANA in the registry to the specified value, unless the existing registry value is larger */
601 DWORD AdjustMaxLana(DWORD dwMaxLana)
605 HKEY hNetBiosParamKey = NULL;
606 DWORD dwType, dwExistingMaxLana, dwSize;
608 ReportMessage(0,"Making sure MaxLana is large enough",0,0, dwMaxLana);
610 ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Services\\NetBIOS\\Parameters"),
611 0, KEY_ALL_ACCESS , &hNetBiosParamKey);
617 ret = RegQueryValueEx(hNetBiosParamKey, _T("MaxLana"), 0, &dwType, (LPBYTE) &dwExistingMaxLana, &dwSize);
618 if ((ret) && (ret != ERROR_MORE_DATA) && (ret != ERROR_FILE_NOT_FOUND))
620 RegCloseKey(hNetBiosParamKey);
624 if ((dwType != REG_DWORD) || (ret)) dwExistingMaxLana = 0;
626 ReportMessage (1,"MaxLana is currently",0,0, dwExistingMaxLana);
628 if (dwExistingMaxLana < dwMaxLana)
630 ReportMessage (1,"Changing MaxLana", 0,0,dwMaxLana);
631 ret = RegSetValueEx(hNetBiosParamKey, _T("MaxLana"), 0, REG_DWORD, (const BYTE*)&dwMaxLana, 4);
634 RegCloseKey(hNetBiosParamKey);
640 RegCloseKey(hNetBiosParamKey);
647 BOOL UpdateHostsFile( LPCWSTR swName, LPCWSTR swIp, LPCSTR szFilename, BOOL bPre )
649 char szIp[2048], szName[2048];
650 char etcPath[MAX_PATH];
651 char tempPath[MAX_PATH];
652 char buffer[2048], temp[2048];
658 _snprintf(szIp, 2047, "%S", swIp);
659 _snprintf(szName, 2047, "%S", swName);
661 ReportMessage(0,"Starting UpdateHostsFile() on file",szFilename,0,0);
663 rv = SHGetFolderPathA( NULL, CSIDL_SYSTEM, NULL, SHGFP_TYPE_CURRENT , etcPath );
664 if(rv != S_OK) return FALSE;
666 strcat( etcPath, ETCDIR );
668 fa = GetFileAttributesA( etcPath );
670 if(fa == INVALID_FILE_ATTRIBUTES)
672 // the directory doesn't exist
673 // it should be there. non-existence implies more things are wrong
674 ReportMessage(0, "Path does not exist ", etcPath,0,0 );
678 strcpy( tempPath, etcPath );
679 strcat( etcPath, "\\" );
680 strcat( etcPath, szFilename );
682 fa = GetFileAttributesA( etcPath );
684 if(fa == INVALID_FILE_ATTRIBUTES)
686 ReportMessage(0, "File not found. Creating...", szFilename,0,0);
688 hFile = fopen( etcPath, "w" );
691 ReportMessage(0,"FAILED : can't create file",etcPath,0,errno);
695 fprintf(hFile, "%s\t%s%s\n", szIp, szName, (bPre)?"\t#PRE":"");
699 ReportMessage(1,"done",0,0,0);
701 else // the file exists. parse and update
704 ReportMessage(1, "Updating file ...",szFilename,0,0 );
706 hFile = fopen( etcPath, "r");
709 ReportMessage(0,"FAILED : can't open file",etcPath,0,errno);
713 strcat( tempPath, szFilename );
714 strcat( tempPath, ".tmp" );
715 hTemp = fopen( tempPath, "w");
718 ReportMessage(0,"FAILED : can't create temp file",tempPath,0,errno);
723 while(fgets( buffer, 2046, hFile))
725 strcpy( temp, buffer );
728 if ((strlen(temp)<1) || (*(temp+strlen(temp)-1)!='\n')) strcat(temp, "\n");
730 if(!(str = strstr(temp, szName)))
732 fputs( buffer, hTemp );
736 // check for FOOBAFS or AFSY
737 //if(str <= temp || (*(str-1) != '-' && !isspace(*(str+strlen(szName)))))
738 if ( (str == temp) || (!*(str+strlen(szName))) || (!isspace(*(str-1))) || (!isspace(*(str+strlen(szName)))) )
739 fputs( buffer, hTemp );
745 GetComputerNameA( buffer, &len );
747 fprintf( hTemp, "%s\t%s%s\n", szIp, szName, (bPre)?"\t#PRE":"");
752 strcpy(buffer, etcPath);
753 strcat(buffer, ".old");
755 if(!DeleteFileA(buffer)) {
760 status = GetLastError();
761 if(status == ERROR_ACCESS_DENIED) {
762 /* try changing the file attribtues. */
763 if(SetFileAttributesA(buffer, FILE_ATTRIBUTE_NORMAL) &&
764 DeleteFileA(buffer)) {
766 ReportMessage(0,"Changed attributes and deleted back host file", buffer, 0, 0);
769 if(status && status != ERROR_FILE_NOT_FOUND) {
770 /* we can't delete the file. Try to come up with
771 a different name that's not already taken. */
772 srand(GetTickCount());
773 eos = buffer + strlen(buffer);
774 for(i=0; i < 50; i++) {
775 itoa(rand(), eos, 16);
776 if(GetFileAttributesA(buffer) == INVALID_FILE_ATTRIBUTES &&
777 GetLastError() == ERROR_FILE_NOT_FOUND)
780 /* At this point if we don't have a unique name, we just let the rename
785 if(!MoveFileA( etcPath, buffer )) {
786 ReportMessage(0,"FAILED: Can't rename old file", etcPath, 0, GetLastError());
790 if(!MoveFileA( tempPath, etcPath ) != 0)
792 ReportMessage(0,"FAILED : Can't rename new file", tempPath, 0, GetLastError());
811 printf("usage: %S ip mask\n"
812 " example: %S 10.0.0.1 255.0.0.0", argv[0], argv[0]);
816 return WMIEnableStatic(FindNetworkAdapterConfigurationInstanceByGUID,
817 L"{B4981E32-551C-4164-96B6-B8874BD2E555}",
829 printf("usage: %S adapter_guid ip mask\n"
830 " example: %S {B4981E32-551C-4164-96B6-B8874BD2E555} "
831 "10.0.0.1 255.0.0.0", argv[0], argv[0]);
835 return WMIEnableStatic(FindNetworkAdapterConfigurationInstanceByGUID,
836 argv[1], argv[2], argv[3]);