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