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