DARWIN: On macOS 12, mount afs on user's directory
[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     MethodName = SysAllocString(L"EnableStatic");
365     CLEANUP_ON_AND_SET(!MethodName, hr, E_OUTOFMEMORY);
366
367     // Get the input argument and set the property
368     hr = pClass->GetMethod(MethodName, 0, &pInClass, NULL);
369     CLEANUP_ON_FAILURE(hr);
370
371     hr = pInClass->SpawnInstance(0, &pInInst);
372     CLEANUP_ON_FAILURE(hr);
373
374     // Set up parameters
375     hr = SetupStringAsSafeArray(ip, &v_ip_list);
376     CLEANUP_ON_FAILURE(hr);
377
378     hr = pInInst->Put(L"IPAddress", 0, &v_ip_list, 0);
379     CLEANUP_ON_FAILURE(hr);
380
381     hr = SetupStringAsSafeArray(mask, &v_mask_list);
382     CLEANUP_ON_FAILURE(hr);
383
384     hr = pInInst->Put(L"SubNetMask", 0, &v_mask_list, 0);
385     CLEANUP_ON_FAILURE(hr);
386
387 //    printf("Skipping ExecMethod\n");
388 //    hr = 0;
389 //    goto cleanup;
390
391     // Try up to five times, sleeping 3 seconds between tries
392     for (count=0; count<5; count++)
393     {
394         if (count>1) {
395             ReportMessage(0,"Trying again in 3 seconds...",NULL,NULL,0);
396             Sleep(3000);
397         } else if (count>0) {
398             ReportMessage(0,"Trying again in 20 seconds...",NULL,NULL,0);
399             Sleep(10000);
400             ReportMessage(0,"Trying again in 10 seconds...",NULL,NULL,0);
401             Sleep(5000);
402             ReportMessage(0,"Trying again in  5 seconds...",NULL,NULL,0);
403             Sleep(2000);
404         }
405
406         ReportMessage(0,"Calling ExecMethod EnableStatic NOW...          ",NULL,NULL,0);
407         // Call the method
408         hr = pNamespace->ExecMethod(InstancePath, MethodName, 0, NULL, pInInst,
409                                   &pOutInst, NULL);
410         if (!SUCCEEDED(hr))
411         {
412            ReportMessage(0,"ExecMethod EnableStatic failed",NULL,NULL, hr);
413            continue;
414         }
415
416         // Get the EnableStatic method return value
417         hr = pOutInst->Get(L"ReturnValue", 0, &v_ret_value, 0, 0);
418         if (!SUCCEEDED(hr))
419         {
420           ReportMessage(0,"WARNING: Could not determine return value for EnableStatic ",NULL,NULL, hr);
421           continue;
422         }
423
424         hr = V_I4(&v_ret_value);
425         if (hr != 0)
426             ReportMessage(0,"EnableStatic failed ", NULL,NULL,hr);
427         else
428         {
429             ReportMessage(0,"EnableStatic succeeded",NULL,NULL,0);
430             break;
431         }
432     }
433
434     /* if failure, skip SetDynamicDNSRegistration */
435     if (hr)
436         goto cleanup;
437
438     /* Cleanup and Prepare for SetDynamicDNSRegistration */
439     if (pInClass) {
440         pInClass->Release();
441         pInClass = NULL;
442     }
443     if (pInInst) {
444         pInInst->Release();
445         pInInst = NULL;
446     }
447     SysFreeString(MethodName);
448     VariantClear(&v_ret_value);
449
450     MethodName = SysAllocString(L"SetDynamicDNSRegistration");
451     CLEANUP_ON_AND_SET(!MethodName, hr2, E_OUTOFMEMORY);
452
453     // Get the input argument and set the property
454     hr2 = pClass->GetMethod(MethodName, 0, &pInClass, NULL);
455     CLEANUP_ON_FAILURE(hr2);
456
457     hr2 = pInClass->SpawnInstance(0, &pInInst);
458     CLEANUP_ON_FAILURE(hr2);
459
460     // Set up parameters
461     V_VT(&v_reg_enabled) = VT_BOOL;
462     V_BOOL(&v_reg_enabled) = VARIANT_FALSE;
463
464     hr2 = pInInst->Put(L"FullDNSRegistrationEnabled", 0, &v_reg_enabled, 0);
465     CLEANUP_ON_FAILURE(hr2);
466
467     hr2 = pInInst->Put(L"DomainDNSRegistrationEnabled", 0, &v_reg_enabled, 0);
468     CLEANUP_ON_FAILURE(hr2);
469
470     // Call the method
471     hr2 = pNamespace->ExecMethod(InstancePath, MethodName, 0, NULL, pInInst,
472                                  &pOutInst, NULL);
473     if (!SUCCEEDED(hr2))        {
474         ReportMessage(0,"ExecMethod SetDynamicDNSRegistration failed",NULL,NULL, hr2);
475         goto cleanup;
476     }
477
478     // Get the EnableStatic method return value
479     hr2 = pOutInst->Get(L"ReturnValue", 0, &v_ret_value, 0, 0);
480     if (!SUCCEEDED(hr2)) {
481         ReportMessage(0,"WARNING: Could not determine return value for SetDynamicDNSRegistration ",NULL,NULL, hr2);
482     } else {
483         hr2 = V_I4(&v_ret_value);
484         if (hr2 != 0)
485             ReportMessage(0,"SetDynamicDNSRegistration failed ", NULL,NULL,hr2);
486         else
487             ReportMessage(0,"SetDynamicDNSRegistration succeeded",NULL,NULL,0);
488     }
489
490     /* if failure, skip SetTcpipNetbios */
491     if (hr)
492         goto cleanup;
493
494     /* Cleanup and Prepare for SetTcpipNetbios */
495     if (pInClass) {
496         pInClass->Release();
497         pInClass = NULL;
498     }
499     if (pInInst) {
500         pInInst->Release();
501         pInInst = NULL;
502     }
503     SysFreeString(MethodName);
504     VariantClear(&v_ret_value);
505
506     ReportMessage(0,"Preparing for SetTcpipNetbios",NULL,NULL,0);
507
508     MethodName = SysAllocString(L"SetTcpipNetbios");
509     CLEANUP_ON_AND_SET(!MethodName, hr2, E_OUTOFMEMORY);
510
511     // Get the input argument and set the property
512     hr2 = pClass->GetMethod(MethodName, 0, &pInClass, NULL);
513     CLEANUP_ON_FAILURE(hr2);
514
515     hr2 = pInClass->SpawnInstance(0, &pInInst);
516     CLEANUP_ON_FAILURE(hr2);
517
518     // Set up parameters
519     V_VT(&v_netbios) = VT_BSTR;
520     V_BSTR(&v_netbios) = SysAllocString(L"1");  /* Use Netbios */
521
522     hr2 = pInInst->Put(L"TcpipNetbiosOptions", 0, &v_netbios, 0);
523     CLEANUP_ON_FAILURE(hr2);
524
525     // Call the method
526     hr2 = pNamespace->ExecMethod(InstancePath, MethodName, 0, NULL, pInInst,
527                                  &pOutInst, NULL);
528     if (!SUCCEEDED(hr2)) {
529         ReportMessage(0,"ExecMethod SetTcpipNetbios failed",NULL,NULL, hr2);
530         goto cleanup;
531     }
532
533     // Get the EnableStatic method return value
534     hr2 = pOutInst->Get(L"ReturnValue", 0, &v_ret_value, 0, 0);
535     if (!SUCCEEDED(hr2)) {
536         ReportMessage(0,"WARNING: Could not determine return value for SetTcpipNetbios ",NULL,NULL, hr2);
537     } else {
538         hr2 = V_I4(&v_ret_value);
539         if (hr2 != 0)
540             ReportMessage(0,"SetTcpipNetbios failed ", NULL,NULL,hr2);
541         else
542             ReportMessage(0,"SetTcpipNetbios succeeded",NULL,NULL,0);
543     }
544
545  cleanup:
546     // Free up resources
547     VariantClear(&v_ret_value);
548     VariantClear(&v_ip_list);
549     VariantClear(&v_mask_list);
550     VariantClear(&v_reg_enabled);
551     VariantClear(&v_netbios);
552
553     // SysFreeString is NULL safe
554     SysFreeString(NamespacePath);
555     SysFreeString(ClassPath);
556     SysFreeString(InstancePath);
557     SysFreeString(MethodName);
558
559     if (pClass) pClass->Release();
560     if (pInInst) pInInst->Release();
561     if (pInClass) pInClass->Release();
562     if (pOutInst) pOutInst->Release();
563     if (pLocator) pLocator->Release();
564     if (pNamespace) pNamespace->Release();
565
566     if (comInitialized)
567         CoUninitialize();
568
569     return hr;
570 }
571
572
573 /**********************************************************
574 * LoopbackBindings :  unbind all other
575 *       protocols except TCP/IP, netbios, netbt.
576 */
577 extern "C" HRESULT
578 LoopbackBindings (LPCWSTR loopback_guid)
579 {
580     HRESULT                     hr = 0;
581     INetCfg                     *pCfg = NULL;
582     INetCfgLock         *pLock = NULL;
583     INetCfgComponent *pAdapter = NULL;
584     IEnumNetCfgComponent *pEnumComponent = NULL;
585     BOOL                        bLockGranted = FALSE;
586     BOOL                        bInitialized = FALSE;
587     BOOL                        bConfigChanged = FALSE;
588     LPWSTR                      swName = NULL;
589     GUID            g;
590     wchar_t         device_guid[100];
591
592     ReportMessage(0,"Running LoopbackBindings()...",NULL,NULL,0);
593
594     hr = CoInitializeEx( NULL, COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED );
595     CLEANUP_ON_FAILURE(hr);
596
597     hr = CoCreateInstance( CLSID_CNetCfg, NULL, CLSCTX_INPROC_SERVER, IID_INetCfg, (void**)&pCfg );
598     CLEANUP_ON_FAILURE(hr);
599
600     hr = pCfg->QueryInterface( IID_INetCfgLock, (void**)&pLock );
601     CLEANUP_ON_FAILURE(hr);
602
603     hr = pLock->AcquireWriteLock( 1000, L"AFS Configuration", NULL );
604     CLEANUP_ON_FAILURE(hr);
605     bLockGranted = TRUE;
606
607     hr = pCfg->Initialize( NULL );
608     CLEANUP_ON_FAILURE(hr);
609     bInitialized = TRUE;
610
611     hr = pCfg->EnumComponents( &GUID_DEVCLASS_NET, &pEnumComponent );
612     CLEANUP_ON_FAILURE(hr);
613
614     while( pEnumComponent->Next( 1, &pAdapter, NULL ) == S_OK )
615     {
616         pAdapter->GetDisplayName( &swName );
617         pAdapter->GetInstanceGuid( &g );
618         StringFromGUID2(g, device_guid, 99);
619
620         if (!wcscmp( device_guid, loopback_guid )) // found loopback adapter
621         {
622             INetCfgComponentBindings *pBindings;
623             INetCfgBindingPath *pPath;
624             IEnumNetCfgBindingPath *pEnumPaths;
625             INetCfgComponent *upper;
626
627             ReportMessage(0,"LoopbackBindings found", NULL, device_guid,0 );
628
629             hr = pAdapter->QueryInterface( IID_INetCfgComponentBindings, (void**) &pBindings);
630             if (hr==S_OK)
631             {
632                 hr = pBindings->EnumBindingPaths( EBP_ABOVE, &pEnumPaths );
633                 if (hr==S_OK)
634                 {
635                     while(pEnumPaths->Next( 1, &pPath, NULL ) == S_OK)
636                     {
637                         pPath->GetOwner( &upper );
638
639                         LPWSTR swId = NULL, swName = NULL;
640
641                         upper->GetDisplayName( &swName );
642                         upper->GetId( &swId );
643
644                         ReportMessage(1,"Looking at ",NULL, swName, 0);
645
646                         {
647                             ReportMessage(1,"  Moving to the end of binding order...",NULL,NULL,0);
648                             INetCfgComponentBindings *pBindings2;
649                             hr = upper->QueryInterface( IID_INetCfgComponentBindings, (void**) &pBindings2);
650                             if (hr==S_OK)
651                             {
652                                 ReportMessage(1,"...",0,0,0);
653                                 hr = pBindings2->MoveAfter(pPath, NULL);
654                                 pBindings2->Release();
655                                 bConfigChanged=TRUE;
656                             }
657                             if (hr==S_OK) ReportMessage(1,"success",0,0,0); else ReportMessage(0,"Binding change failed",0,0,hr);
658
659                         }
660
661                         if ( !_wcsicmp(swId, L"ms_netbios")  ||
662                              !_wcsicmp(swId, L"ms_tcpip")    ||
663                              !_wcsicmp(swId, L"ms_netbt")    ||
664                              !_wcsicmp(swId, L"ms_msclient"))
665                         {
666                             if (pPath->IsEnabled()!=S_OK)
667                             {
668                                 ReportMessage(1,"  Enabling ",0,swName,0);
669                                 hr = pPath->Enable(TRUE);
670                                 if (hr==S_OK) ReportMessage(1,"success",0,0,0); else ReportMessage(0,"Proto failed",0,0,hr);
671                                 bConfigChanged=TRUE;
672                             }
673
674                         }
675                         else //if (!_wcsicmp(swId, L"ms_server") || (!_wcsicmp(swId, L"ms_msclient"))
676                         {
677                             if (pPath->IsEnabled()==S_OK)
678                             {
679                                 ReportMessage(1,"  Disabling ",0,swName,0);
680                                 hr = pPath->Enable(FALSE);
681                                 if (hr==S_OK) ReportMessage(1,"success",0,0,0); else ReportMessage(0,"Proto failed",0,0,hr);
682                                 bConfigChanged=TRUE;
683                             }
684                         }
685
686                         CoTaskMemFree( swName );
687                         CoTaskMemFree( swId );
688
689                         pPath->Release();
690                     }
691                     pEnumPaths->Release();
692                 }
693                 pBindings->Release();
694             } // hr==S_OK for QueryInterface IID_INetCfgComponentBindings
695         }
696
697         CoTaskMemFree( swName );
698
699         pAdapter->Release();
700     }
701
702     pEnumComponent->Release();
703
704     hr = 0;
705
706 cleanup:
707
708     if (bConfigChanged) pCfg->Apply();
709
710     if (pAdapter) pAdapter->Release();
711
712     if (bInitialized) pCfg->Uninitialize();
713     if (bLockGranted) pLock->ReleaseWriteLock();
714
715     if (pLock) pLock->Release();
716     if (pCfg) pCfg->Release();
717
718     if (hr) ReportMessage(0,"LoopbackBindings() is returning ",0,0,hr);
719     return hr;
720 }
721
722
723 extern "C"
724 DWORD SetIpAddress(LPCWSTR guid, LPCWSTR ip, LPCWSTR mask)
725 {
726     ReportMessage(0,"Running SetIpAddress()...",0,0,0);
727     HRESULT hr = 0;
728
729     hr = WMIEnableStatic(FindNetworkAdapterConfigurationInstanceByGUID,
730                         (PVOID)guid, ip, mask);
731     if (hr == 0)
732         FixupXPDNSRegistrations(guid);
733     return hr;
734 }
735
736 /* Set MAXLANA in the registry to the specified value, unless the existing registry value is larger */
737 static DWORD
738 AdjustMaxLana(DWORD dwMaxLana)
739 {
740
741     LONG ret = 0;
742     HKEY hNetBiosParamKey = NULL;
743     DWORD dwType, dwExistingMaxLana, dwSize;
744
745     ReportMessage(0,"Making sure MaxLana is large enough",0,0, dwMaxLana);
746
747     ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Services\\NetBIOS\\Parameters"),
748         0, KEY_ALL_ACCESS , &hNetBiosParamKey);
749     if (ret) return ret;
750
751
752
753     dwSize = 4;
754     ret = RegQueryValueEx(hNetBiosParamKey, _T("MaxLana"), 0, &dwType, (LPBYTE) &dwExistingMaxLana, &dwSize);
755     if ((ret) && (ret != ERROR_MORE_DATA) && (ret != ERROR_FILE_NOT_FOUND))
756     {
757         RegCloseKey(hNetBiosParamKey);
758         return ret;
759     }
760
761     if ((dwType != REG_DWORD) || (ret)) dwExistingMaxLana = 0;
762
763     ReportMessage (1,"MaxLana is currently",0,0, dwExistingMaxLana);
764
765     if (dwExistingMaxLana < dwMaxLana)
766     {
767         ReportMessage (1,"Changing MaxLana", 0,0,dwMaxLana);
768         ret = RegSetValueEx(hNetBiosParamKey, _T("MaxLana"), 0, REG_DWORD, (const BYTE*)&dwMaxLana, 4);
769         if (ret)
770         {
771             RegCloseKey(hNetBiosParamKey);
772             return ret;
773         }
774
775     }
776
777     RegCloseKey(hNetBiosParamKey);
778     return 0;
779
780
781 }
782
783 extern "C"
784 BOOL UpdateHostsFile( LPCWSTR swName, LPCWSTR swIp, LPCSTR szFilename, BOOL bPre )
785 {
786     char szIp[2048], szName[2048];
787     char etcPath[MAX_PATH];
788     char tempPath[MAX_PATH];
789     char buffer[2048], temp[2048];
790     char *str;
791     HRESULT rv;
792     DWORD fa,len;
793     FILE *hFile, *hTemp;
794     size_t nameLen;
795
796     _snprintf(szIp, 2047, "%S", swIp);
797     _snprintf(szName, 2047, "%S", swName);
798     strupr(szName);
799     nameLen = strlen(szName);
800     ReportMessage(0,"Starting UpdateHostsFile() on file",szFilename,0,0);
801
802     rv = SHGetFolderPathA( NULL, CSIDL_SYSTEM, NULL, SHGFP_TYPE_CURRENT, etcPath );
803     if (rv != S_OK)
804         return FALSE;
805
806     strcat( etcPath, ETCDIR );
807
808     fa = GetFileAttributesA( etcPath );
809
810     if (fa == INVALID_FILE_ATTRIBUTES)
811     {
812         // the directory doesn't exist
813         // it should be there. non-existence implies more things are wrong
814         ReportMessage(0, "Path does not exist ", etcPath,0,0 );
815         return FALSE;
816     }
817
818     strcpy( tempPath, etcPath );
819     strcat( etcPath, "\\" );
820     strcat( etcPath, szFilename );
821
822     fa = GetFileAttributesA( etcPath );
823
824     if (fa == INVALID_FILE_ATTRIBUTES)
825     {
826         ReportMessage(0, "File not found. Creating...", szFilename,0,0);
827
828         hFile = fopen( etcPath, "w" );
829         if (!hFile)
830         {
831             ReportMessage(0,"FAILED : can't create file",etcPath,0,errno);
832             return FALSE;
833         }
834
835         fprintf(hFile, "%s\t%s%s\n", szIp, szName, (bPre)?"\t#PRE":"");
836
837         fclose( hFile );
838
839         ReportMessage(1,"done",0,0,0);
840     }
841     else // the file exists. parse and update
842     {
843
844         ReportMessage(1, "Updating file ...",szFilename,0,0 );
845
846         hFile = fopen( etcPath, "r");
847         if (!hFile)
848         {
849             ReportMessage(0,"FAILED : can't open file",etcPath,0,errno);
850             return FALSE;
851         }
852
853         strcat( tempPath, szFilename );
854         strcat( tempPath, ".tmp" );
855         hTemp = fopen( tempPath, "w");
856         if (!hTemp)
857         {
858             ReportMessage(0,"FAILED : can't create temp file",tempPath,0,errno);
859             fclose(hFile);
860             return FALSE;
861         }
862
863         while(fgets( buffer, 2046, hFile))
864         {
865             size_t len;
866
867             strcpy( temp, buffer );
868             strupr( temp );
869             len = strlen(temp);
870
871             if ((len < 1) || (temp[len-1] != '\n'))
872                 strcat(temp, "\n");
873
874             if (!(str = strstr(temp, szName)))
875             {
876                 fputs( temp, hTemp );
877             }
878             else
879             {
880                 // check for FOOBAFS or AFSY
881                 if ( (str == temp) || (!str[nameLen]) || (!isspace(*(str-1))) || (!isspace(str[nameLen])) )
882                     fputs( temp, hTemp );
883             }
884         }
885
886         len = 2048;
887         GetComputerNameA( buffer, &len );
888         buffer[11] = 0;
889         fprintf( hTemp, "%s\t%s%s\n", szIp, szName, (bPre)?"\t#PRE":"");
890
891         fclose( hTemp );
892         fclose( hFile );
893
894         strcpy(buffer, etcPath);
895         strcat(buffer, ".old");
896
897         if (!DeleteFileA(buffer)) {
898             DWORD status;
899             int i;
900             char * eos;
901
902             status = GetLastError();
903             if (status == ERROR_ACCESS_DENIED) {
904                 /* try changing the file attribtues. */
905                 if (SetFileAttributesA(buffer, FILE_ATTRIBUTE_NORMAL) &&
906                     DeleteFileA(buffer)) {
907                     status = 0;
908                     ReportMessage(0,"Changed attributes and deleted back host file", buffer, 0, 0);
909                 }
910             }
911             if (status && status != ERROR_FILE_NOT_FOUND) {
912                 /* we can't delete the file.  Try to come up with
913                    a different name that's not already taken. */
914                 srand(GetTickCount());
915                 eos = buffer + strlen(buffer);
916                 for(i=0; i < 50; i++) {
917                     itoa(rand(), eos, 16);
918                     if (GetFileAttributesA(buffer) == INVALID_FILE_ATTRIBUTES &&
919                         GetLastError() == ERROR_FILE_NOT_FOUND)
920                         break;
921                 }
922                 /* At this point if we don't have a unique name, we just let the rename
923                    fail.  Too bad. */
924             }
925         }
926
927         if (!MoveFileA( etcPath, buffer )) {
928             ReportMessage(0,"FAILED: Can't rename old file", etcPath, 0, GetLastError());
929             return FALSE;
930         }
931
932         if (!MoveFileA( tempPath, etcPath ) != 0)
933         {
934             ReportMessage(0,"FAILED : Can't rename new file", tempPath, 0, GetLastError());
935             return FALSE;
936         }
937
938     }
939
940     return TRUE;
941 }
942
943 #ifdef TEST
944 int
945 wmain(
946     int argc,
947     wchar_t* argv[]
948     )
949 {
950     if (argc < 4)
951     {
952         printf("usage: %S adapter_guid ip mask\n"
953                "  example: %S {B4981E32-551C-4164-96B6-B8874BD2E555} "
954                "10.0.0.1 255.0.0.0", argv[0], argv[0]);
955         return 0;
956     }
957
958     return WMIEnableStatic(FindNetworkAdapterConfigurationInstanceByGUID,
959                            argv[1], argv[2], argv[3]);
960 }
961 #endif
962