Windows: terminate HOSTS/LMHOSTS with newline
[openafs.git] / src / WINNT / install / loopback / wmi.cpp
1 /*
2
3 Copyright 2004 by the Massachusetts Institute of Technology
4 Copyright 2006 by Secure Endpoints Inc.
5
6 All rights reserved.
7
8 Permission to use, copy, modify, and distribute this software and its
9 documentation for any purpose and without fee is hereby granted,
10 provided that the above copyright notice appear in all copies and that
11 both that copyright notice and this permission notice appear in
12 supporting documentation, and that the name of the Massachusetts
13 Institute of Technology (M.I.T.) not be used in advertising or publicity
14 pertaining to distribution of the software without specific, written
15 prior permission.
16
17 M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
18 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
19 M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
20 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
21 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
22 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
23 SOFTWARE.
24
25 */
26
27 //**************************************************************************
28 //
29 // Description:
30 //
31 //      Call EnableStatic method of Win32_NetworkAdapterConfiguration
32 //      for some network adapter GUID.
33 //
34 // Note:
35 //
36 //      The EnableStatic method is not supported on Win9x platforms.
37 //
38 //**************************************************************************
39
40 #define _WIN32_DCOM
41 #include <windows.h>
42 #include <comdef.h>
43 #include <wbemidl.h>
44 #include <tchar.h>
45
46 #include <devguid.h>
47
48 /* __RPC__out is not defined in the v6.0 Windows SDK */
49 #ifndef __RPC__out
50 #define __RPC__out
51 #endif
52
53 /* These two are from the Windows DDK */
54 #include <netcfgx.h>
55 #include <netcfgn.h>
56
57 #include <shlobj.h>
58 //#include <objbase.h>
59
60 //#ifndef TEST
61 //inline void printf(char*, ...) {}
62 //#else
63 #include <stdio.h>
64 //#endif
65
66 #include "loopbackutils.h"
67
68 #define CLEANUP_ON_FAILURE(hr) \
69         do { if (!SUCCEEDED(hr)) {goto cleanup;} } while (0)
70
71 #define CLEANUP_ON_AND_SET(check, var, value) \
72     do { if (check) { (var) = (value); goto cleanup; } } while (0)
73
74 #define ETCDIR "\\drivers\\etc"
75
76 #define EACCES (13)
77 #define ENOENT (2)
78
79 DWORD AdjustMaxLana(DWORD dwMaxLana);
80
81 typedef
82 HRESULT
83 (*FindNetworkAdapterConfigurationInstance_t)(
84     IN  PVOID pContext,
85     IN  IWbemServices *pSvc,
86     OUT BSTR* pPath
87     );
88
89 HRESULT
90 FindNetworkAdapterConfigurationInstanceByGUID(
91     IN  PVOID pContext,
92     IN  IWbemServices *pSvc,
93     OUT BSTR* pPath
94     )
95 {
96     HRESULT hr = 0;
97     BOOL bFound = FALSE;
98     BSTR Language = 0;
99     BSTR Query = 0;
100     IEnumWbemClassObject* pEnum = 0;
101     IWbemClassObject* pObj = 0;
102     VARIANT Value;
103     VariantInit(&Value);
104     LPCWSTR adapter_guid = (LPCWSTR)pContext;
105
106     // Check arguments
107     if (!pPath || !adapter_guid || *pPath)
108         return E_INVALIDARG;
109
110     *pPath = 0;
111
112     // Query for all network adapters
113     Language = SysAllocString(L"WQL");
114     Query = SysAllocString(L"select * from Win32_NetworkAdapterConfiguration");
115
116     // Issue the query.
117     hr = pSvc->ExecQuery(Language,
118                          Query,
119                          WBEM_FLAG_FORWARD_ONLY,         // Flags
120                          0,                              // Context
121                          &pEnum);
122     if (!SUCCEEDED(hr))
123     {
124         ReportMessage(0,"ExecQuery() error",NULL,NULL, hr);
125         goto cleanup;
126     }
127
128     // Retrieve the objects in the result set.
129     while (!bFound)
130     {
131         ULONG uReturned = 0;
132
133         hr = pEnum->Next(0,                  // Time out
134                          1,                  // One object
135                          &pObj,
136                          &uReturned);
137         CLEANUP_ON_FAILURE(hr);
138
139         if (uReturned == 0)
140             break;
141
142         // Use the object.
143         hr  = pObj->Get(L"SettingID", // property name
144                         0L,
145                         &Value,       // output to this variant
146                         NULL,
147                         NULL);
148         CLEANUP_ON_FAILURE(hr);
149
150         bFound = !wcscmp(adapter_guid, V_BSTR(&Value));
151
152         if (bFound)
153         {
154             ReportMessage(1,"Found adapter", NULL,V_BSTR(&Value),0);
155             VariantClear(&Value);
156             hr = pObj->Get(L"__RELPATH", // property name
157                            0L,
158                            &Value,       // output to this variant
159                            NULL,
160                            NULL);
161             CLEANUP_ON_FAILURE(hr);
162
163             *pPath = SysAllocString(V_BSTR(&Value));
164
165         }
166
167         VariantClear(&Value);
168
169         // Release it.
170         // ===========
171         pObj->Release();    // Release objects not owned.
172         pObj = 0;
173     }
174
175
176     // All done.
177  cleanup:
178     SysFreeString(Query);
179     SysFreeString(Language);
180     VariantClear(&Value);
181     if (pEnum)
182         pEnum->Release();
183     if (pObj)
184         pObj->Release();
185
186     return *pPath ? 0 : ( SUCCEEDED(hr) ? WBEM_E_NOT_FOUND : hr );
187 }
188
189 HRESULT
190 SetupStringAsSafeArray(LPCWSTR s, VARIANT* v)
191 {
192     HRESULT hr = 0;
193     BSTR b = 0;
194     SAFEARRAY* array = 0;
195     long index[] = {0};
196
197     if (V_VT(v) != VT_EMPTY)
198         return E_INVALIDARG;
199
200     b = SysAllocString(s);
201     CLEANUP_ON_AND_SET(!b, hr, E_OUTOFMEMORY);
202
203     array = SafeArrayCreateVector(VT_BSTR, 0, 1);
204     CLEANUP_ON_AND_SET(!array, hr, E_OUTOFMEMORY);
205
206     hr = SafeArrayPutElement(array, index, b);
207     CLEANUP_ON_FAILURE(hr);
208
209     V_VT(v) = VT_ARRAY|VT_BSTR;
210     V_ARRAY(v) = array;
211
212  cleanup:
213     if (b)
214         SysFreeString(b);
215     if (!SUCCEEDED(hr))
216     {
217         if (array)
218             SafeArrayDestroy(array);
219     }
220     return hr;
221 }
222
223 static BOOL
224 IsXP(void)
225 {
226     OSVERSIONINFOEX osInfoEx;
227     memset(&osInfoEx, 0, sizeof(osInfoEx));
228     osInfoEx.dwOSVersionInfoSize = sizeof(osInfoEx);
229
230     GetVersionEx((POSVERSIONINFO)&osInfoEx);
231
232     return(osInfoEx.dwMajorVersion == 5 && osInfoEx.dwMinorVersion == 1 && osInfoEx.wServicePackMajor < 2);
233 }
234
235 static VOID
236 FixupXPDNSRegistrations(LPCWSTR pCfgGuidString)
237 {
238     // As per http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B834440
239     // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\<NetworkAdapterGUID>
240     HKEY hkInterfaces=NULL, hkAdapter=NULL;
241     DWORD dw = 0;
242
243     if (!IsXP())
244         return;         // Nothing to do
245
246     RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"),
247                  0, KEY_READ, &hkInterfaces);
248
249     RegOpenKeyEx(hkInterfaces, pCfgGuidString, 0, KEY_READ|KEY_WRITE, &hkAdapter);
250
251     RegDeleteValue(hkAdapter, TEXT("DisableDynamicUpdate"));
252     RegDeleteValue(hkAdapter, TEXT("EnableAdapterDomainNameRegistration"));
253     RegSetValueEx(hkAdapter, TEXT("RegistrationEnabled"), 0, REG_DWORD, (BYTE *)&dw, sizeof(DWORD));
254     RegSetValueEx(hkAdapter, TEXT("RegisterAdapterName"), 0, REG_DWORD, (BYTE *)&dw, sizeof(DWORD));
255
256     if (hkInterfaces)
257         RegCloseKey(hkInterfaces);
258     if (hkAdapter)
259         RegCloseKey(hkAdapter);
260 }
261
262 HRESULT
263 WMIEnableStatic(
264     FindNetworkAdapterConfigurationInstance_t pFindInstance,
265     PVOID pContext,
266     LPCWSTR ip,
267     LPCWSTR mask
268     )
269 {
270     HRESULT hr = 0, hr2 = 0;
271
272     IWbemLocator* pLocator = NULL;
273     IWbemServices* pNamespace = NULL;
274     IWbemClassObject* pClass = NULL;
275     IWbemClassObject* pOutInst = NULL;
276     IWbemClassObject* pInClass = NULL;
277     IWbemClassObject* pInInst = NULL;
278
279     BSTR NamespacePath = NULL;
280     BSTR ClassPath = NULL;
281     BSTR InstancePath = NULL;
282     BSTR MethodName = NULL; // needs to be BSTR for ExecMethod()
283
284     BOOL comInitialized = FALSE;
285
286     VARIANT v_ip_list;
287     VariantInit(&v_ip_list);
288
289     VARIANT v_mask_list;
290     VariantInit(&v_mask_list);
291
292     VARIANT v_ret_value;
293     VariantInit(&v_ret_value);
294
295     VARIANT v_reg_enabled;
296     VariantInit(&v_reg_enabled);
297
298     VARIANT v_netbios;
299     VariantInit(&v_netbios);
300
301     int count;
302
303     // end of declarations & NULL initialization
304
305     NamespacePath = SysAllocString(L"root\\cimv2");
306     CLEANUP_ON_AND_SET(!NamespacePath, hr, E_OUTOFMEMORY);
307
308     ClassPath = SysAllocString(L"Win32_NetWorkAdapterConfiguration");
309     CLEANUP_ON_AND_SET(!ClassPath, hr, E_OUTOFMEMORY);
310
311     // Initialize COM and connect up to CIMOM
312
313     ReportMessage(0, "Intializing COM", NULL, NULL, 0);
314     hr = CoInitializeEx(0, COINIT_MULTITHREADED);
315     if (hr == S_OK || hr == S_FALSE) {
316         comInitialized = TRUE;
317     } else {
318         goto cleanup;
319     }
320
321     /* When called from an MSI this will generally fail.  This should only be called once
322            per process and not surprisingly MSI beats us to it.  So ignore return value and
323            hope for the best. */
324     hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
325                               RPC_C_AUTHN_LEVEL_CONNECT,
326                               RPC_C_IMP_LEVEL_IMPERSONATE,
327                               NULL, EOAC_NONE, 0);
328
329     /* CLEANUP_ON_FAILURE(hr); */
330
331     ReportMessage(0, "Creating Wbem Locator object", NULL, NULL, 0);
332     hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
333                           IID_IWbemLocator, (LPVOID *) &pLocator);
334     CLEANUP_ON_FAILURE(hr);
335
336     ReportMessage(0, "Connecting to WMI", NULL, NULL, 0);
337     hr = pLocator->ConnectServer(NamespacePath, NULL, NULL, NULL, 0,
338                                  NULL, NULL, &pNamespace);
339     CLEANUP_ON_FAILURE(hr);
340
341     ReportMessage(0,"Connected to WMI",NULL,NULL,0);
342
343     // Set the proxy so that impersonation of the client occurs.
344     hr = CoSetProxyBlanket(pNamespace,
345                            RPC_C_AUTHN_WINNT,
346                            RPC_C_AUTHZ_NONE,
347                            NULL,
348                            RPC_C_AUTHN_LEVEL_CALL,
349                            RPC_C_IMP_LEVEL_IMPERSONATE,
350                            NULL,
351                            EOAC_NONE);
352     CLEANUP_ON_FAILURE(hr);
353
354     // Get the class object
355     hr = pNamespace->GetObject(ClassPath, 0, NULL, &pClass, NULL);
356     CLEANUP_ON_FAILURE(hr);
357
358     // Get the instance
359     hr = pFindInstance(pContext, pNamespace, &InstancePath);
360     CLEANUP_ON_FAILURE(hr);
361
362     ReportMessage(0,"Found Adapter Instance",NULL, InstancePath,0);
363
364 #if 0
365     // Use the adapter instance index to set MAXLANA in the registry.
366     {
367         DWORD dwIndex;
368         if (swscanf(InstancePath, L"Win32_NetworkAdapterConfiguration.Index=%u", &dwIndex)==1)
369         {
370             DWORD ret = 0;
371             ReportMessage(1,"Setting MAXLANA",NULL,NULL,dwIndex+1);
372             ret = AdjustMaxLana(dwIndex+1);
373             if (ret) ReportMessage(0,"AdjustMaxLana returned the error code ",NULL,NULL,ret);
374         }
375     }
376 #endif
377
378     MethodName = SysAllocString(L"EnableStatic");
379     CLEANUP_ON_AND_SET(!MethodName, hr, E_OUTOFMEMORY);
380
381     // Get the input argument and set the property
382     hr = pClass->GetMethod(MethodName, 0, &pInClass, NULL);
383     CLEANUP_ON_FAILURE(hr);
384
385     hr = pInClass->SpawnInstance(0, &pInInst);
386     CLEANUP_ON_FAILURE(hr);
387
388     // Set up parameters
389     hr = SetupStringAsSafeArray(ip, &v_ip_list);
390     CLEANUP_ON_FAILURE(hr);
391
392     hr = pInInst->Put(L"IPAddress", 0, &v_ip_list, 0);
393     CLEANUP_ON_FAILURE(hr);
394
395     hr = SetupStringAsSafeArray(mask, &v_mask_list);
396     CLEANUP_ON_FAILURE(hr);
397
398     hr = pInInst->Put(L"SubNetMask", 0, &v_mask_list, 0);
399     CLEANUP_ON_FAILURE(hr);
400
401 //    printf("Skipping ExecMethod\n");
402 //    hr = 0;
403 //    goto cleanup;
404
405     // Try up to five times, sleeping 3 seconds between tries
406     for (count=0; count<5; count++)
407     {
408         if (count>1) {
409             ReportMessage(0,"Trying again in 3 seconds...",NULL,NULL,0);
410             Sleep(3000);
411         } else if (count>0) {
412             ReportMessage(0,"Trying again in 20 seconds...",NULL,NULL,0);
413             Sleep(10000);
414             ReportMessage(0,"Trying again in 10 seconds...",NULL,NULL,0);
415             Sleep(5000);
416             ReportMessage(0,"Trying again in  5 seconds...",NULL,NULL,0);
417             Sleep(2000);
418         }
419
420         ReportMessage(0,"Calling ExecMethod EnableStatic NOW...          ",NULL,NULL,0);
421         // Call the method
422         hr = pNamespace->ExecMethod(InstancePath, MethodName, 0, NULL, pInInst,
423                                   &pOutInst, NULL);
424         if (!SUCCEEDED(hr))
425         {
426            ReportMessage(0,"ExecMethod EnableStatic failed",NULL,NULL, hr);
427            continue;
428         }
429
430         // Get the EnableStatic method return value
431         hr = pOutInst->Get(L"ReturnValue", 0, &v_ret_value, 0, 0);
432         if (!SUCCEEDED(hr))
433         {
434           ReportMessage(0,"WARNING: Could not determine return value for EnableStatic ",NULL,NULL, hr);
435           continue;
436         }
437
438         hr = V_I4(&v_ret_value);
439         if (hr != 0)
440             ReportMessage(0,"EnableStatic failed ", NULL,NULL,hr);
441         else
442         {
443             ReportMessage(0,"EnableStatic succeeded",NULL,NULL,0);
444             break;
445         }
446     }
447
448     /* if failure, skip SetDynamicDNSRegistration */
449     if (hr)
450         goto cleanup;
451
452     /* Cleanup and Prepare for SetDynamicDNSRegistration */
453     if (pInClass) {
454         pInClass->Release();
455         pInClass = NULL;
456     }
457     if (pInInst) {
458         pInInst->Release();
459         pInInst = NULL;
460     }
461     SysFreeString(MethodName);
462     VariantClear(&v_ret_value);
463
464     MethodName = SysAllocString(L"SetDynamicDNSRegistration");
465     CLEANUP_ON_AND_SET(!MethodName, hr2, E_OUTOFMEMORY);
466
467     // Get the input argument and set the property
468     hr2 = pClass->GetMethod(MethodName, 0, &pInClass, NULL);
469     CLEANUP_ON_FAILURE(hr2);
470
471     hr2 = pInClass->SpawnInstance(0, &pInInst);
472     CLEANUP_ON_FAILURE(hr2);
473
474     // Set up parameters
475     V_VT(&v_reg_enabled) = VT_BOOL;
476     V_BOOL(&v_reg_enabled) = VARIANT_FALSE;
477
478     hr2 = pInInst->Put(L"FullDNSRegistrationEnabled", 0, &v_reg_enabled, 0);
479     CLEANUP_ON_FAILURE(hr2);
480
481     hr2 = pInInst->Put(L"DomainDNSRegistrationEnabled", 0, &v_reg_enabled, 0);
482     CLEANUP_ON_FAILURE(hr2);
483
484     // Call the method
485     hr2 = pNamespace->ExecMethod(InstancePath, MethodName, 0, NULL, pInInst,
486                                  &pOutInst, NULL);
487     if (!SUCCEEDED(hr2))        {
488         ReportMessage(0,"ExecMethod SetDynamicDNSRegistration failed",NULL,NULL, hr2);
489         goto cleanup;
490     }
491
492     // Get the EnableStatic method return value
493     hr2 = pOutInst->Get(L"ReturnValue", 0, &v_ret_value, 0, 0);
494     if (!SUCCEEDED(hr2)) {
495         ReportMessage(0,"WARNING: Could not determine return value for SetDynamicDNSRegistration ",NULL,NULL, hr2);
496     } else {
497         hr2 = V_I4(&v_ret_value);
498         if (hr2 != 0)
499             ReportMessage(0,"SetDynamicDNSRegistration failed ", NULL,NULL,hr2);
500         else
501             ReportMessage(0,"SetDynamicDNSRegistration succeeded",NULL,NULL,0);
502     }
503
504     /* if failure, skip SetTcpipNetbios */
505     if (hr)
506         goto cleanup;
507
508     /* Cleanup and Prepare for SetTcpipNetbios */
509     if (pInClass) {
510         pInClass->Release();
511         pInClass = NULL;
512     }
513     if (pInInst) {
514         pInInst->Release();
515         pInInst = NULL;
516     }
517     SysFreeString(MethodName);
518     VariantClear(&v_ret_value);
519
520     ReportMessage(0,"Preparing for SetTcpipNetbios",NULL,NULL,0);
521
522     MethodName = SysAllocString(L"SetTcpipNetbios");
523     CLEANUP_ON_AND_SET(!MethodName, hr2, E_OUTOFMEMORY);
524
525     // Get the input argument and set the property
526     hr2 = pClass->GetMethod(MethodName, 0, &pInClass, NULL);
527     CLEANUP_ON_FAILURE(hr2);
528
529     hr2 = pInClass->SpawnInstance(0, &pInInst);
530     CLEANUP_ON_FAILURE(hr2);
531
532     // Set up parameters
533     V_VT(&v_netbios) = VT_BSTR;
534     V_BSTR(&v_netbios) = SysAllocString(L"1");  /* Use Netbios */
535
536     hr2 = pInInst->Put(L"TcpipNetbiosOptions", 0, &v_netbios, 0);
537     CLEANUP_ON_FAILURE(hr2);
538
539     // Call the method
540     hr2 = pNamespace->ExecMethod(InstancePath, MethodName, 0, NULL, pInInst,
541                                  &pOutInst, NULL);
542     if (!SUCCEEDED(hr2)) {
543         ReportMessage(0,"ExecMethod SetTcpipNetbios failed",NULL,NULL, hr2);
544         goto cleanup;
545     }
546
547     // Get the EnableStatic method return value
548     hr2 = pOutInst->Get(L"ReturnValue", 0, &v_ret_value, 0, 0);
549     if (!SUCCEEDED(hr2)) {
550         ReportMessage(0,"WARNING: Could not determine return value for SetTcpipNetbios ",NULL,NULL, hr2);
551     } else {
552         hr2 = V_I4(&v_ret_value);
553         if (hr2 != 0)
554             ReportMessage(0,"SetTcpipNetbios failed ", NULL,NULL,hr2);
555         else
556             ReportMessage(0,"SetTcpipNetbios succeeded",NULL,NULL,0);
557     }
558
559  cleanup:
560     // Free up resources
561     VariantClear(&v_ret_value);
562     VariantClear(&v_ip_list);
563     VariantClear(&v_mask_list);
564     VariantClear(&v_reg_enabled);
565     VariantClear(&v_netbios);
566
567     // SysFreeString is NULL safe
568     SysFreeString(NamespacePath);
569     SysFreeString(ClassPath);
570     SysFreeString(InstancePath);
571     SysFreeString(MethodName);
572
573     if (pClass) pClass->Release();
574     if (pInInst) pInInst->Release();
575     if (pInClass) pInClass->Release();
576     if (pOutInst) pOutInst->Release();
577     if (pLocator) pLocator->Release();
578     if (pNamespace) pNamespace->Release();
579
580     if (comInitialized)
581         CoUninitialize();
582
583     return hr;
584 }
585
586
587 /**********************************************************
588 * LoopbackBindings :  unbind all other
589 *       protocols except TCP/IP, netbios, netbt.
590 */
591 extern "C" HRESULT
592 LoopbackBindings (LPCWSTR loopback_guid)
593 {
594     HRESULT                     hr = 0;
595     INetCfg                     *pCfg = NULL;
596     INetCfgLock         *pLock = NULL;
597     INetCfgComponent *pAdapter = NULL;
598     IEnumNetCfgComponent *pEnumComponent = NULL;
599     BOOL                        bLockGranted = FALSE;
600     BOOL                        bInitialized = FALSE;
601     BOOL                        bConfigChanged = FALSE;
602     LPWSTR                      swName = NULL;
603     GUID            g;
604     wchar_t         device_guid[100];
605
606     ReportMessage(0,"Running LoopbackBindings()...",NULL,NULL,0);
607
608     hr = CoInitializeEx( NULL, COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED );
609     CLEANUP_ON_FAILURE(hr);
610
611     hr = CoCreateInstance( CLSID_CNetCfg, NULL, CLSCTX_INPROC_SERVER, IID_INetCfg, (void**)&pCfg );
612     CLEANUP_ON_FAILURE(hr);
613
614     hr = pCfg->QueryInterface( IID_INetCfgLock, (void**)&pLock );
615     CLEANUP_ON_FAILURE(hr);
616
617     hr = pLock->AcquireWriteLock( 1000, L"AFS Configuration", NULL );
618     CLEANUP_ON_FAILURE(hr);
619     bLockGranted = TRUE;
620
621     hr = pCfg->Initialize( NULL );
622     CLEANUP_ON_FAILURE(hr);
623     bInitialized = TRUE;
624
625     hr = pCfg->EnumComponents( &GUID_DEVCLASS_NET, &pEnumComponent );
626     CLEANUP_ON_FAILURE(hr);
627
628     while( pEnumComponent->Next( 1, &pAdapter, NULL ) == S_OK )
629     {
630         pAdapter->GetDisplayName( &swName );
631         pAdapter->GetInstanceGuid( &g );
632         StringFromGUID2(g, device_guid, 99);
633
634         if (!wcscmp( device_guid, loopback_guid )) // found loopback adapter
635         {
636             INetCfgComponentBindings *pBindings;
637             INetCfgBindingPath *pPath;
638             IEnumNetCfgBindingPath *pEnumPaths;
639             INetCfgComponent *upper;
640
641             ReportMessage(0,"LoopbackBindings found", NULL, device_guid,0 );
642
643             hr = pAdapter->QueryInterface( IID_INetCfgComponentBindings, (void**) &pBindings);
644             if (hr==S_OK)
645             {
646                 hr = pBindings->EnumBindingPaths( EBP_ABOVE, &pEnumPaths );
647                 if (hr==S_OK)
648                 {
649                     while(pEnumPaths->Next( 1, &pPath, NULL ) == S_OK)
650                     {
651                         pPath->GetOwner( &upper );
652
653                         LPWSTR swId = NULL, swName = NULL;
654
655                         upper->GetDisplayName( &swName );
656                         upper->GetId( &swId );
657
658                         ReportMessage(1,"Looking at ",NULL, swName, 0);
659
660                         {
661                             ReportMessage(1,"  Moving to the end of binding order...",NULL,NULL,0);
662                             INetCfgComponentBindings *pBindings2;
663                             hr = upper->QueryInterface( IID_INetCfgComponentBindings, (void**) &pBindings2);
664                             if (hr==S_OK)
665                             {
666                                 ReportMessage(1,"...",0,0,0);
667                                 hr = pBindings2->MoveAfter(pPath, NULL);
668                                 pBindings2->Release();
669                                 bConfigChanged=TRUE;
670                             }
671                             if (hr==S_OK) ReportMessage(1,"success",0,0,0); else ReportMessage(0,"Binding change failed",0,0,hr);
672
673                         }
674
675                         if ( !_wcsicmp(swId, L"ms_netbios")  ||
676                              !_wcsicmp(swId, L"ms_tcpip")    ||
677                              !_wcsicmp(swId, L"ms_netbt")    ||
678                              !_wcsicmp(swId, L"ms_msclient"))
679                         {
680                             if (pPath->IsEnabled()!=S_OK)
681                             {
682                                 ReportMessage(1,"  Enabling ",0,swName,0);
683                                 hr = pPath->Enable(TRUE);
684                                 if (hr==S_OK) ReportMessage(1,"success",0,0,0); else ReportMessage(0,"Proto failed",0,0,hr);
685                                 bConfigChanged=TRUE;
686                             }
687
688                         }
689                         else //if (!_wcsicmp(swId, L"ms_server") || (!_wcsicmp(swId, L"ms_msclient"))
690                         {
691                             if (pPath->IsEnabled()==S_OK)
692                             {
693                                 ReportMessage(1,"  Disabling ",0,swName,0);
694                                 hr = pPath->Enable(FALSE);
695                                 if (hr==S_OK) ReportMessage(1,"success",0,0,0); else ReportMessage(0,"Proto failed",0,0,hr);
696                                 bConfigChanged=TRUE;
697                             }
698                         }
699
700                         CoTaskMemFree( swName );
701                         CoTaskMemFree( swId );
702
703                         pPath->Release();
704                     }
705                     pEnumPaths->Release();
706                 }
707                 pBindings->Release();
708             } // hr==S_OK for QueryInterface IID_INetCfgComponentBindings
709         }
710
711         CoTaskMemFree( swName );
712
713         pAdapter->Release();
714     }
715
716     pEnumComponent->Release();
717
718     hr = 0;
719
720 cleanup:
721
722     if (bConfigChanged) pCfg->Apply();
723
724     if (pAdapter) pAdapter->Release();
725
726     if (bInitialized) pCfg->Uninitialize();
727     if (bLockGranted) pLock->ReleaseWriteLock();
728
729     if (pLock) pLock->Release();
730     if (pCfg) pCfg->Release();
731
732     if (hr) ReportMessage(0,"LoopbackBindings() is returning ",0,0,hr);
733     return hr;
734 }
735
736
737 extern "C"
738 DWORD SetIpAddress(LPCWSTR guid, LPCWSTR ip, LPCWSTR mask)
739 {
740     ReportMessage(0,"Running SetIpAddress()...",0,0,0);
741     HRESULT hr = 0;
742
743     hr = WMIEnableStatic(FindNetworkAdapterConfigurationInstanceByGUID,
744                         (PVOID)guid, ip, mask);
745     if (hr == 0)
746         FixupXPDNSRegistrations(guid);
747     return hr;
748 }
749
750 /* Set MAXLANA in the registry to the specified value, unless the existing registry value is larger */
751 static DWORD
752 AdjustMaxLana(DWORD dwMaxLana)
753 {
754
755     LONG ret = 0;
756     HKEY hNetBiosParamKey = NULL;
757     DWORD dwType, dwExistingMaxLana, dwSize;
758
759     ReportMessage(0,"Making sure MaxLana is large enough",0,0, dwMaxLana);
760
761     ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Services\\NetBIOS\\Parameters"),
762         0, KEY_ALL_ACCESS , &hNetBiosParamKey);
763     if (ret) return ret;
764
765
766
767     dwSize = 4;
768     ret = RegQueryValueEx(hNetBiosParamKey, _T("MaxLana"), 0, &dwType, (LPBYTE) &dwExistingMaxLana, &dwSize);
769     if ((ret) && (ret != ERROR_MORE_DATA) && (ret != ERROR_FILE_NOT_FOUND))
770     {
771         RegCloseKey(hNetBiosParamKey);
772         return ret;
773     }
774
775     if ((dwType != REG_DWORD) || (ret)) dwExistingMaxLana = 0;
776
777     ReportMessage (1,"MaxLana is currently",0,0, dwExistingMaxLana);
778
779     if (dwExistingMaxLana < dwMaxLana)
780     {
781         ReportMessage (1,"Changing MaxLana", 0,0,dwMaxLana);
782         ret = RegSetValueEx(hNetBiosParamKey, _T("MaxLana"), 0, REG_DWORD, (const BYTE*)&dwMaxLana, 4);
783         if (ret)
784         {
785             RegCloseKey(hNetBiosParamKey);
786             return ret;
787         }
788
789     }
790
791     RegCloseKey(hNetBiosParamKey);
792     return 0;
793
794
795 }
796
797 extern "C"
798 BOOL UpdateHostsFile( LPCWSTR swName, LPCWSTR swIp, LPCSTR szFilename, BOOL bPre )
799 {
800     char szIp[2048], szName[2048];
801     char etcPath[MAX_PATH];
802     char tempPath[MAX_PATH];
803     char buffer[2048], temp[2048];
804     char *str;
805     HRESULT rv;
806     DWORD fa,len;
807     FILE *hFile, *hTemp;
808     size_t nameLen;
809
810     _snprintf(szIp, 2047, "%S", swIp);
811     _snprintf(szName, 2047, "%S", swName);
812     strupr(szName);
813     nameLen = strlen(szName);
814     ReportMessage(0,"Starting UpdateHostsFile() on file",szFilename,0,0);
815
816     rv = SHGetFolderPathA( NULL, CSIDL_SYSTEM, NULL, SHGFP_TYPE_CURRENT, etcPath );
817     if (rv != S_OK)
818         return FALSE;
819
820     strcat( etcPath, ETCDIR );
821
822     fa = GetFileAttributesA( etcPath );
823
824     if (fa == INVALID_FILE_ATTRIBUTES)
825     {
826         // the directory doesn't exist
827         // it should be there. non-existence implies more things are wrong
828         ReportMessage(0, "Path does not exist ", etcPath,0,0 );
829         return FALSE;
830     }
831
832     strcpy( tempPath, etcPath );
833     strcat( etcPath, "\\" );
834     strcat( etcPath, szFilename );
835
836     fa = GetFileAttributesA( etcPath );
837
838     if (fa == INVALID_FILE_ATTRIBUTES)
839     {
840         ReportMessage(0, "File not found. Creating...", szFilename,0,0);
841
842         hFile = fopen( etcPath, "w" );
843         if (!hFile)
844         {
845             ReportMessage(0,"FAILED : can't create file",etcPath,0,errno);
846             return FALSE;
847         }
848
849         fprintf(hFile, "%s\t%s%s\n", szIp, szName, (bPre)?"\t#PRE":"");
850
851         fclose( hFile );
852
853         ReportMessage(1,"done",0,0,0);
854     }
855     else // the file exists. parse and update
856     {
857
858         ReportMessage(1, "Updating file ...",szFilename,0,0 );
859
860         hFile = fopen( etcPath, "r");
861         if (!hFile)
862         {
863             ReportMessage(0,"FAILED : can't open file",etcPath,0,errno);
864             return FALSE;
865         }
866
867         strcat( tempPath, szFilename );
868         strcat( tempPath, ".tmp" );
869         hTemp = fopen( tempPath, "w");
870         if (!hTemp)
871         {
872             ReportMessage(0,"FAILED : can't create temp file",tempPath,0,errno);
873             fclose(hFile);
874             return FALSE;
875         }
876
877         while(fgets( buffer, 2046, hFile))
878         {
879             size_t len;
880
881             strcpy( temp, buffer );
882             strupr( temp );
883             len = strlen(temp);
884
885             if ((len < 1) || (temp[len-1] != '\n'))
886                 strcat(temp, "\n");
887
888             if (!(str = strstr(temp, szName)))
889             {
890                 fputs( temp, hTemp );
891             }
892             else
893             {
894                 // check for FOOBAFS or AFSY
895                 if ( (str == temp) || (!str[nameLen]) || (!isspace(*(str-1))) || (!isspace(str[nameLen])) )
896                     fputs( temp, hTemp );
897             }
898         }
899
900         len = 2048;
901         GetComputerNameA( buffer, &len );
902         buffer[11] = 0;
903         fprintf( hTemp, "%s\t%s%s\n", szIp, szName, (bPre)?"\t#PRE":"");
904
905         fclose( hTemp );
906         fclose( hFile );
907
908         strcpy(buffer, etcPath);
909         strcat(buffer, ".old");
910
911         if (!DeleteFileA(buffer)) {
912             DWORD status;
913             int i;
914             char * eos;
915
916             status = GetLastError();
917             if (status == ERROR_ACCESS_DENIED) {
918                 /* try changing the file attribtues. */
919                 if (SetFileAttributesA(buffer, FILE_ATTRIBUTE_NORMAL) &&
920                     DeleteFileA(buffer)) {
921                     status = 0;
922                     ReportMessage(0,"Changed attributes and deleted back host file", buffer, 0, 0);
923                 }
924             }
925             if (status && status != ERROR_FILE_NOT_FOUND) {
926                 /* we can't delete the file.  Try to come up with
927                    a different name that's not already taken. */
928                 srand(GetTickCount());
929                 eos = buffer + strlen(buffer);
930                 for(i=0; i < 50; i++) {
931                     itoa(rand(), eos, 16);
932                     if (GetFileAttributesA(buffer) == INVALID_FILE_ATTRIBUTES &&
933                         GetLastError() == ERROR_FILE_NOT_FOUND)
934                         break;
935                 }
936                 /* At this point if we don't have a unique name, we just let the rename
937                    fail.  Too bad. */
938             }
939         }
940
941         if (!MoveFileA( etcPath, buffer )) {
942             ReportMessage(0,"FAILED: Can't rename old file", etcPath, 0, GetLastError());
943             return FALSE;
944         }
945
946         if (!MoveFileA( tempPath, etcPath ) != 0)
947         {
948             ReportMessage(0,"FAILED : Can't rename new file", tempPath, 0, GetLastError());
949             return FALSE;
950         }
951
952     }
953
954     return TRUE;
955 }
956
957 #ifdef TEST
958 #if 0
959 int
960 wmain(
961     int argc,
962     wchar_t* argv[]
963     )
964 {
965     if (argc < 3)
966     {
967         printf("usage: %S ip mask\n"
968                "  example: %S 10.0.0.1 255.0.0.0", argv[0], argv[0]);
969         return 0;
970     }
971
972     return WMIEnableStatic(FindNetworkAdapterConfigurationInstanceByGUID,
973                            L"{B4981E32-551C-4164-96B6-B8874BD2E555}",
974                            argv[1], argv[2]);
975 }
976 #else
977 int
978 wmain(
979     int argc,
980     wchar_t* argv[]
981     )
982 {
983     if (argc < 4)
984     {
985         printf("usage: %S adapter_guid ip mask\n"
986                "  example: %S {B4981E32-551C-4164-96B6-B8874BD2E555} "
987                "10.0.0.1 255.0.0.0", argv[0], argv[0]);
988         return 0;
989     }
990
991     return WMIEnableStatic(FindNetworkAdapterConfigurationInstanceByGUID,
992                            argv[1], argv[2], argv[3]);
993 }
994 #endif
995 #endif
996