Windows: Windows v6.0 SDK does not define __RPC__out
[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 LoopbackBindings (LPCWSTR loopback_guid)
592 {
593     HRESULT                     hr = 0;
594     INetCfg                     *pCfg = NULL;
595     INetCfgLock         *pLock = NULL;
596     INetCfgComponent *pAdapter = NULL;
597     IEnumNetCfgComponent *pEnumComponent = NULL;
598     BOOL                        bLockGranted = FALSE;
599     BOOL                        bInitialized = FALSE;
600     BOOL                        bConfigChanged = FALSE;
601     LPWSTR                      swName = NULL;
602     GUID            g;
603     wchar_t         device_guid[100];
604     
605     ReportMessage(0,"Running LoopbackBindings()...",NULL,NULL,0);
606     
607     hr = CoInitializeEx( NULL, COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED ); 
608     CLEANUP_ON_FAILURE(hr);
609     
610     hr = CoCreateInstance( CLSID_CNetCfg, NULL, CLSCTX_INPROC_SERVER, IID_INetCfg, (void**)&pCfg );
611     CLEANUP_ON_FAILURE(hr);
612     
613     hr = pCfg->QueryInterface( IID_INetCfgLock, (void**)&pLock );
614     CLEANUP_ON_FAILURE(hr);
615     
616     hr = pLock->AcquireWriteLock( 1000, L"AFS Configuration", NULL );
617     CLEANUP_ON_FAILURE(hr);
618     bLockGranted = TRUE;
619     
620     hr = pCfg->Initialize( NULL );
621     CLEANUP_ON_FAILURE(hr);
622     bInitialized = TRUE;
623     
624     hr = pCfg->EnumComponents( &GUID_DEVCLASS_NET, &pEnumComponent );
625     CLEANUP_ON_FAILURE(hr);
626     
627     while( pEnumComponent->Next( 1, &pAdapter, NULL ) == S_OK )
628     {
629         pAdapter->GetDisplayName( &swName );
630         pAdapter->GetInstanceGuid( &g );
631         StringFromGUID2(g, device_guid, 99);
632         
633         if(!wcscmp( device_guid, loopback_guid )) // found loopback adapter
634         {
635             INetCfgComponentBindings *pBindings;
636             INetCfgBindingPath *pPath;
637             IEnumNetCfgBindingPath *pEnumPaths;
638             INetCfgComponent *upper;
639             
640             ReportMessage(0,"LoopbackBindings found", NULL, device_guid,0 );
641             
642             hr = pAdapter->QueryInterface( IID_INetCfgComponentBindings, (void**) &pBindings);
643             if(hr==S_OK)
644             {
645                 hr = pBindings->EnumBindingPaths( EBP_ABOVE, &pEnumPaths );
646                 if(hr==S_OK)
647                 {
648                     while(pEnumPaths->Next( 1, &pPath, NULL ) == S_OK)
649                     {
650                         pPath->GetOwner( &upper );
651                         
652                         LPWSTR swId = NULL, swName = NULL;
653                         
654                         upper->GetDisplayName( &swName );
655                         upper->GetId( &swId );
656                         
657                         ReportMessage(1,"Looking at ",NULL, swName, 0);
658                                                                         
659                         {
660                             ReportMessage(1,"  Moving to the end of binding order...",NULL,NULL,0);
661                             INetCfgComponentBindings *pBindings2;
662                             hr = upper->QueryInterface( IID_INetCfgComponentBindings, (void**) &pBindings2);
663                             if (hr==S_OK)
664                             {
665                                 ReportMessage(1,"...",0,0,0);
666                                 hr = pBindings2->MoveAfter(pPath, NULL);                                
667                                 pBindings2->Release();                               
668                                 bConfigChanged=TRUE;
669                             }
670                             if (hr==S_OK) ReportMessage(1,"success",0,0,0); else ReportMessage(0,"Binding change failed",0,0,hr);                                                        
671                                                                                                             
672                         }                        
673                         
674                         if ( !_wcsicmp(swId, L"ms_netbios")  || 
675                              !_wcsicmp(swId, L"ms_tcpip")    ||
676                              !_wcsicmp(swId, L"ms_netbt")    ||
677                              !_wcsicmp(swId, L"ms_msclient"))
678                         {
679                             if (pPath->IsEnabled()!=S_OK)
680                             {
681                                 ReportMessage(1,"  Enabling ",0,swName,0);
682                                 hr = pPath->Enable(TRUE);
683                                 if (hr==S_OK) ReportMessage(1,"success",0,0,0); else ReportMessage(0,"Proto failed",0,0,hr);
684                                 bConfigChanged=TRUE;
685                             }
686                             
687                         }
688                         else //if (!_wcsicmp(swId, L"ms_server") || (!_wcsicmp(swId, L"ms_msclient")) 
689                         {
690                             if (pPath->IsEnabled()==S_OK)
691                             {
692                                 ReportMessage(1,"  Disabling ",0,swName,0);
693                                 hr = pPath->Enable(FALSE);
694                                 if (hr==S_OK) ReportMessage(1,"success",0,0,0); else ReportMessage(0,"Proto failed",0,0,hr);
695                                 bConfigChanged=TRUE;
696                             }
697                         }
698                         
699                         CoTaskMemFree( swName );
700                         CoTaskMemFree( swId );
701                         
702                         pPath->Release();
703                     }
704                     pEnumPaths->Release();
705                 }
706                 pBindings->Release();
707             } // hr==S_OK for QueryInterface IID_INetCfgComponentBindings
708         }
709         
710         CoTaskMemFree( swName );
711         
712         pAdapter->Release();
713     }
714     
715     pEnumComponent->Release();    
716     
717     hr = 0;
718     
719 cleanup:
720     
721     if(bConfigChanged) pCfg->Apply();
722     
723     if(pAdapter) pAdapter->Release();
724     
725     if(bInitialized) pCfg->Uninitialize();
726     if(bLockGranted) pLock->ReleaseWriteLock();
727     
728     if(pLock) pLock->Release();
729     if(pCfg) pCfg->Release();
730     
731     if (hr) ReportMessage(0,"LoopbackBindings() is returning ",0,0,hr);
732     return hr;
733 }
734
735         
736 extern "C" DWORD SetIpAddress(LPCWSTR guid, LPCWSTR ip, LPCWSTR mask)
737 {
738     ReportMessage(0,"Running SetIpAddress()...",0,0,0);
739     HRESULT hr = 0;
740
741     hr = WMIEnableStatic(FindNetworkAdapterConfigurationInstanceByGUID,
742                         (PVOID)guid, ip, mask);
743     if (hr == 0)
744         FixupXPDNSRegistrations(guid);
745     return hr;
746 }
747
748 /* Set MAXLANA in the registry to the specified value, unless the existing registry value is larger */
749 DWORD AdjustMaxLana(DWORD dwMaxLana)
750 {
751
752     LONG ret = 0;
753     HKEY hNetBiosParamKey = NULL;
754     DWORD dwType, dwExistingMaxLana, dwSize;
755
756     ReportMessage(0,"Making sure MaxLana is large enough",0,0, dwMaxLana);
757
758     ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Services\\NetBIOS\\Parameters"), 
759         0, KEY_ALL_ACCESS , &hNetBiosParamKey);
760     if (ret) return ret;
761
762
763     
764     dwSize = 4;
765     ret = RegQueryValueEx(hNetBiosParamKey, _T("MaxLana"), 0, &dwType, (LPBYTE) &dwExistingMaxLana, &dwSize);
766     if ((ret) && (ret != ERROR_MORE_DATA) && (ret != ERROR_FILE_NOT_FOUND)) 
767     {
768         RegCloseKey(hNetBiosParamKey);
769         return ret;
770     }
771
772     if ((dwType != REG_DWORD) || (ret)) dwExistingMaxLana = 0;
773
774     ReportMessage (1,"MaxLana is currently",0,0, dwExistingMaxLana);
775
776     if (dwExistingMaxLana < dwMaxLana) 
777     {
778         ReportMessage (1,"Changing MaxLana", 0,0,dwMaxLana);
779         ret = RegSetValueEx(hNetBiosParamKey, _T("MaxLana"), 0, REG_DWORD, (const BYTE*)&dwMaxLana, 4);
780         if (ret) 
781         {
782             RegCloseKey(hNetBiosParamKey);
783             return ret;
784         }       
785
786     }
787
788     RegCloseKey(hNetBiosParamKey);
789     return 0;
790
791
792 }
793
794 extern "C" 
795 BOOL UpdateHostsFile( LPCWSTR swName, LPCWSTR swIp, LPCSTR szFilename, BOOL bPre )
796 {
797     char szIp[2048], szName[2048];
798     char etcPath[MAX_PATH];
799         char tempPath[MAX_PATH];
800         char buffer[2048], temp[2048];
801         char *str;
802         HRESULT rv;
803         DWORD fa,len;
804         FILE *hFile, *hTemp;
805         
806     _snprintf(szIp, 2047, "%S", swIp);
807     _snprintf(szName, 2047, "%S", swName);
808     strupr(szName);
809     ReportMessage(0,"Starting UpdateHostsFile() on file",szFilename,0,0);
810
811         rv = SHGetFolderPathA( NULL, CSIDL_SYSTEM, NULL, SHGFP_TYPE_CURRENT , etcPath );
812         if(rv != S_OK) return FALSE;
813
814         strcat( etcPath, ETCDIR );
815
816         fa = GetFileAttributesA( etcPath );
817
818         if(fa == INVALID_FILE_ATTRIBUTES)
819         {
820                 // the directory doesn't exist
821                 // it should be there. non-existence implies more things are wrong
822                 ReportMessage(0, "Path does not exist ", etcPath,0,0 );
823                 return FALSE;
824         }
825
826         strcpy( tempPath, etcPath );
827         strcat( etcPath, "\\" );
828         strcat( etcPath, szFilename );
829
830         fa = GetFileAttributesA( etcPath );
831
832         if(fa == INVALID_FILE_ATTRIBUTES)
833         {
834                 ReportMessage(0, "File not found. Creating...", szFilename,0,0);
835
836                 hFile = fopen( etcPath, "w" );
837                 if(!hFile)
838                 {
839                         ReportMessage(0,"FAILED : can't create file",etcPath,0,errno);
840                         return FALSE;
841                 }
842
843                 fprintf(hFile, "%s\t%s%s\n", szIp, szName, (bPre)?"\t#PRE":"");
844
845                 fclose( hFile );
846
847                 ReportMessage(1,"done",0,0,0);
848         }
849         else // the file exists. parse and update
850         {
851
852                 ReportMessage(1, "Updating file ...",szFilename,0,0 );
853
854                 hFile = fopen( etcPath, "r");
855                 if(!hFile)
856                 {
857                         ReportMessage(0,"FAILED : can't open file",etcPath,0,errno);
858                         return FALSE;
859                 }
860
861                 strcat( tempPath, szFilename );
862                 strcat( tempPath, ".tmp" );
863                 hTemp = fopen( tempPath, "w");
864                 if(!hTemp)
865                 {
866                         ReportMessage(0,"FAILED : can't create temp file",tempPath,0,errno);
867                         fclose(hFile);
868                         return FALSE;
869                 }
870
871                 while(fgets( buffer, 2046, hFile))
872                 {
873                         strcpy( temp, buffer );
874                         strupr( temp );
875
876             if ((strlen(temp)<1) || (*(temp+strlen(temp)-1)!='\n')) strcat(temp, "\n");
877
878                         if(!(str = strstr(temp, szName)))
879                         {
880                                 fputs( buffer, hTemp );
881                         }
882                         else
883                         {
884                                 // check for FOOBAFS or AFSY
885                                 //if(str <= temp || (*(str-1) != '-' && !isspace(*(str+strlen(szName)))))
886                                 if ( (str == temp) || (!*(str+strlen(szName))) || (!isspace(*(str-1))) || (!isspace(*(str+strlen(szName)))) )
887                     fputs( buffer, hTemp );
888                         }
889                 }
890
891
892                 len = 2048;
893                 GetComputerNameA( buffer, &len );
894                 buffer[11] = 0;
895                 fprintf( hTemp, "%s\t%s%s\n", szIp, szName, (bPre)?"\t#PRE":"");
896
897                 fclose( hTemp );
898                 fclose( hFile );
899
900                 strcpy(buffer, etcPath);
901                 strcat(buffer, ".old");
902
903         if(!DeleteFileA(buffer)) {
904             DWORD status;
905             int i;
906             char * eos;
907
908             status = GetLastError();
909             if(status == ERROR_ACCESS_DENIED) {
910                 /* try changing the file attribtues. */
911                 if(SetFileAttributesA(buffer, FILE_ATTRIBUTE_NORMAL) &&
912                     DeleteFileA(buffer)) {
913                     status = 0;
914                     ReportMessage(0,"Changed attributes and deleted back host file", buffer, 0, 0);
915                 }
916             }
917             if(status && status != ERROR_FILE_NOT_FOUND) {
918                 /* we can't delete the file.  Try to come up with 
919                    a different name that's not already taken. */
920                 srand(GetTickCount());
921                 eos = buffer + strlen(buffer);
922                 for(i=0; i < 50; i++) {
923                     itoa(rand(), eos, 16);
924                     if(GetFileAttributesA(buffer) == INVALID_FILE_ATTRIBUTES &&
925                         GetLastError() == ERROR_FILE_NOT_FOUND)
926                         break;
927                 }
928                 /* At this point if we don't have a unique name, we just let the rename
929                    fail.  Too bad. */
930             }
931         }
932
933         if(!MoveFileA( etcPath, buffer )) {
934             ReportMessage(0,"FAILED: Can't rename old file", etcPath, 0, GetLastError());
935             return FALSE;
936         }
937
938                 if(!MoveFileA( tempPath, etcPath ) != 0)
939                 {
940                         ReportMessage(0,"FAILED : Can't rename new file", tempPath, 0, GetLastError());
941                         return FALSE;
942                 }
943
944         }
945
946         return TRUE;
947 }
948
949 #ifdef TEST
950 #if 0
951 int
952 wmain(
953     int argc,
954     wchar_t* argv[]
955     )
956 {
957     if (argc < 3)
958     {
959         printf("usage: %S ip mask\n"
960                "  example: %S 10.0.0.1 255.0.0.0", argv[0], argv[0]);
961         return 0;
962     }
963
964     return WMIEnableStatic(FindNetworkAdapterConfigurationInstanceByGUID,
965                            L"{B4981E32-551C-4164-96B6-B8874BD2E555}",
966                            argv[1], argv[2]);
967 }
968 #else
969 int
970 wmain(
971     int argc,
972     wchar_t* argv[]
973     )
974 {
975     if (argc < 4)
976     {
977         printf("usage: %S adapter_guid ip mask\n"
978                "  example: %S {B4981E32-551C-4164-96B6-B8874BD2E555} "
979                "10.0.0.1 255.0.0.0", argv[0], argv[0]);
980         return 0;
981     }
982
983     return WMIEnableStatic(FindNetworkAdapterConfigurationInstanceByGUID,
984                            argv[1], argv[2], argv[3]);
985 }
986 #endif
987 #endif
988