loopback-install-20040804
[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     VARIANT v_ip_list;
241     VariantInit(&v_ip_list);
242
243     VARIANT v_mask_list;
244     VariantInit(&v_mask_list);
245
246     VARIANT v_ret_value;
247     VariantInit(&v_ret_value);
248
249     int count;
250
251     // end of declarations & NULL initialization
252
253     NamespacePath = SysAllocString(L"root\\cimv2");
254     CLEANUP_ON_AND_SET(!NamespacePath, hr, E_OUTOFMEMORY);
255
256     ClassPath = SysAllocString(L"Win32_NetWorkAdapterConfiguration");
257     CLEANUP_ON_AND_SET(!ClassPath, hr, E_OUTOFMEMORY);
258
259     MethodName = SysAllocString(L"EnableStatic");
260     CLEANUP_ON_AND_SET(!MethodName, hr, E_OUTOFMEMORY);
261
262     // Initialize COM and connect up to CIMOM
263
264     hr = CoInitializeEx(0, COINIT_MULTITHREADED);
265     CLEANUP_ON_FAILURE(hr);
266
267     /* When called from an MSI this will generally fail.  This should only be called once
268            per process and not surprisingly MSI beats us to it.  So ignore return value and
269            hope for the best. */
270     hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
271                               RPC_C_AUTHN_LEVEL_CONNECT,
272                               RPC_C_IMP_LEVEL_IMPERSONATE,
273                               NULL, EOAC_NONE, 0);
274     /* CLEANUP_ON_FAILURE(hr); */
275
276     hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
277                           IID_IWbemLocator, (LPVOID *) &pLocator);
278     CLEANUP_ON_FAILURE(hr);
279
280     hr = pLocator->ConnectServer(NamespacePath, NULL, NULL, NULL, 0,
281                                  NULL, NULL, &pNamespace);
282     CLEANUP_ON_FAILURE(hr);
283
284     ReportMessage(0,"Connected to WMI",NULL,NULL,0);
285
286     // Set the proxy so that impersonation of the client occurs.
287     hr = CoSetProxyBlanket(pNamespace,
288                            RPC_C_AUTHN_WINNT,
289                            RPC_C_AUTHZ_NONE,
290                            NULL,
291                            RPC_C_AUTHN_LEVEL_CALL,
292                            RPC_C_IMP_LEVEL_IMPERSONATE,
293                            NULL,
294                            EOAC_NONE);
295     CLEANUP_ON_FAILURE(hr);
296
297     // Get the class object
298     hr = pNamespace->GetObject(ClassPath, 0, NULL, &pClass, NULL);
299     CLEANUP_ON_FAILURE(hr);
300
301     // Get the instance
302     hr = pFindInstance(pContext, pNamespace, &InstancePath);
303     CLEANUP_ON_FAILURE(hr);
304
305     ReportMessage(0,"Found Adapter Instance",NULL, InstancePath,0);
306
307 #if 0
308     // Use the adapter instance index to set MAXLANA in the registry.
309     {
310         DWORD dwIndex;
311         if (swscanf(InstancePath, L"Win32_NetworkAdapterConfiguration.Index=%u", &dwIndex)==1)
312         {
313             DWORD ret = 0; 
314             ReportMessage(1,"Setting MAXLANA",NULL,NULL,dwIndex+1);
315             ret = AdjustMaxLana(dwIndex+1);
316             if (ret) ReportMessage(0,"AdjustMaxLana returned the error code ",NULL,NULL,ret);
317         }
318     }
319 #endif
320
321     // Get the input argument and set the property
322     hr = pClass->GetMethod(MethodName, 0, &pInClass, NULL);
323     CLEANUP_ON_FAILURE(hr);
324
325     hr = pInClass->SpawnInstance(0, &pInInst);
326     CLEANUP_ON_FAILURE(hr);
327
328     // Set up parameters
329     hr = SetupStringAsSafeArray(ip, &v_ip_list);
330     CLEANUP_ON_FAILURE(hr);
331
332     hr = pInInst->Put(L"IPAddress", 0, &v_ip_list, 0);
333     CLEANUP_ON_FAILURE(hr);
334
335     hr = SetupStringAsSafeArray(mask, &v_mask_list);
336     CLEANUP_ON_FAILURE(hr);
337
338     hr = pInInst->Put(L"SubNetMask", 0, &v_mask_list, 0);
339     CLEANUP_ON_FAILURE(hr);
340
341     // Sleep for a twenty seconds
342     ReportMessage(0,"Calling ExecMethod in 20 seconds...",NULL,NULL,0);
343     Sleep(10000);
344     ReportMessage(0,"Calling ExecMethod in 10 seconds...",NULL,NULL,0);
345     Sleep(5000);  
346     ReportMessage(0,"Calling ExecMethod in  5 seconds...",NULL,NULL,0);
347     Sleep(2000);
348
349 //    printf("Skipping ExecMethod\n");
350 //    hr = 0;
351 //    goto cleanup;
352
353     // Try up to five times, sleeping 3 seconds between tries
354     for (count=0; count<5; count++)
355     {
356         if (count>0) ReportMessage(0,"Trying again in 3 seconds...",NULL,NULL,0);
357
358         Sleep(3000);
359   
360         ReportMessage(0,"Calling ExecMethod NOW...          ",NULL,NULL,0);     
361
362         // Call the method
363
364         hr = pNamespace->ExecMethod(InstancePath, MethodName, 0, NULL, pInInst,
365                                   &pOutInst, NULL);   
366
367         if (!SUCCEEDED(hr))
368         {
369            ReportMessage(0,"ExecMethod failed",NULL,NULL, hr);
370            continue;
371         }
372
373         // Get the EnableStatic method return value
374         hr = pOutInst->Get(L"ReturnValue", 0, &v_ret_value, 0, 0);
375
376         if (!SUCCEEDED(hr))
377         {
378           ReportMessage(0,"WARNING: Could not determine return value for EnableStatic ",NULL,NULL, hr);
379           continue;
380         }
381
382         hr = V_I4(&v_ret_value);                
383
384
385         if(hr != 0)
386             ReportMessage(0,"EnableStatic failed ", NULL,NULL,hr);
387         else
388         {
389             ReportMessage(0,"EnableStatic succeeded",NULL,NULL,0);
390             break;
391         }
392
393     }
394
395
396
397  cleanup:
398     // Free up resources
399     VariantClear(&v_ret_value);
400     VariantClear(&v_ip_list);
401     VariantClear(&v_mask_list);
402
403     SysFreeString(NamespacePath);
404     SysFreeString(ClassPath);
405     SysFreeString(InstancePath);
406     SysFreeString(MethodName);
407
408     if (pClass) pClass->Release();
409     if (pInInst) pInInst->Release();
410     if (pInClass) pInClass->Release();
411     if (pOutInst) pOutInst->Release();
412     if (pLocator) pLocator->Release();
413     if (pNamespace) pNamespace->Release();
414
415     CoUninitialize();
416     return hr;
417 }
418
419
420 /**********************************************************
421 * LoopbackBindings :  unbind all other 
422 *       protocols except TCP/IP, netbios, netbt. 
423 */
424 extern "C" HRESULT LoopbackBindings (LPCWSTR loopback_guid)
425 {
426     HRESULT                     hr = 0;
427     INetCfg                     *pCfg = NULL;
428     INetCfgLock         *pLock = NULL;
429     INetCfgComponent *pAdapter = NULL;
430     IEnumNetCfgComponent *pEnumComponent = NULL;
431     BOOL                        bLockGranted = FALSE;
432     BOOL                        bInitialized = FALSE;
433     BOOL                        bConfigChanged = FALSE;
434     LPWSTR                      swName = NULL;
435     GUID            g;
436     wchar_t         device_guid[100];
437     DWORD                       lenDeviceId;    
438     
439     ReportMessage(0,"Running LoopbackBindings()...",NULL,NULL,0);
440     
441     hr = CoInitializeEx( NULL, COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED ); 
442     CLEANUP_ON_FAILURE(hr);
443     
444     hr = CoCreateInstance( CLSID_CNetCfg, NULL, CLSCTX_INPROC_SERVER, IID_INetCfg, (void**)&pCfg );
445     CLEANUP_ON_FAILURE(hr);
446     
447     hr = pCfg->QueryInterface( IID_INetCfgLock, (void**)&pLock );
448     CLEANUP_ON_FAILURE(hr);
449     
450     hr = pLock->AcquireWriteLock( 1000, L"AFS Configuration", NULL );
451     CLEANUP_ON_FAILURE(hr);
452     bLockGranted = TRUE;
453     
454     hr = pCfg->Initialize( NULL );
455     CLEANUP_ON_FAILURE(hr);
456     bInitialized = TRUE;
457     
458     hr = pCfg->EnumComponents( &GUID_DEVCLASS_NET, &pEnumComponent );
459     CLEANUP_ON_FAILURE(hr);
460     
461     
462     while( pEnumComponent->Next( 1, &pAdapter, NULL ) == S_OK )
463     {
464         pAdapter->GetDisplayName( &swName );
465         pAdapter->GetInstanceGuid( &g );
466         StringFromGUID2(g, device_guid, 99);
467         
468         if(!wcscmp( device_guid, loopback_guid )) // found loopback adapter
469         {
470             INetCfgComponentBindings *pBindings;
471             INetCfgBindingPath *pPath;
472             IEnumNetCfgBindingPath *pEnumPaths;
473             INetCfgComponent *upper;
474             
475             ReportMessage(0,"LoopbackBindings found", NULL, device_guid,0 );
476             
477             hr = pAdapter->QueryInterface( IID_INetCfgComponentBindings, (void**) &pBindings);
478             if(hr==S_OK)
479             {
480                 hr = pBindings->EnumBindingPaths( EBP_ABOVE, &pEnumPaths );
481                 if(hr==S_OK)
482                 {
483                     while(pEnumPaths->Next( 1, &pPath, NULL ) == S_OK)
484                     {
485                         pPath->GetOwner( &upper );
486                         
487                         LPWSTR swId = NULL, swName = NULL;
488                         
489                         upper->GetDisplayName( &swName );
490                         upper->GetId( &swId );
491                         
492                         ReportMessage(1,"Looking at ",NULL, swName, 0);
493                                                                         
494                         {
495                             ReportMessage(1,"  Moving to the end of binding order...",NULL,NULL,0);
496                             INetCfgComponentBindings *pBindings2;
497                             hr = upper->QueryInterface( IID_INetCfgComponentBindings, (void**) &pBindings2);
498                             if (hr==S_OK)
499                             {
500                                 ReportMessage(1,"...",0,0,0);
501                                 hr = pBindings2->MoveAfter(pPath, NULL);                                
502                                 pBindings2->Release();                               
503                                 bConfigChanged=TRUE;
504                             }
505                             if (hr==S_OK) ReportMessage(1,"success",0,0,0); else ReportMessage(0,"Binding change failed",0,0,hr);                                                        
506                                                                                                             
507                         }                        
508                         
509                         if ( !_wcsicmp(swId, L"ms_netbios")  || 
510                             !_wcsicmp(swId, L"ms_tcpip")    ||
511                             !_wcsicmp(swId, L"ms_netbt")      )
512                         {
513                             if (pPath->IsEnabled()!=S_OK)
514                             {
515                                 ReportMessage(1,"  Enabling ",0,swName,0);
516                                 hr = pPath->Enable(TRUE);
517                                 if (hr==S_OK) ReportMessage(1,"success",0,0,0); else ReportMessage(0,"Proto failed",0,0,hr);
518                                 bConfigChanged=TRUE;
519                             }
520                             
521                             
522                         }
523                         else //if (!_wcsicmp(swId, L"ms_server") || (!_wcsicmp(swId, L"ms_msclient")) 
524                         {
525                             if (pPath->IsEnabled()==S_OK)
526                             {
527                                 ReportMessage(1,"  Disabling ",0,swName,0);
528                                 hr = pPath->Enable(FALSE);
529                                 if (hr==S_OK) ReportMessage(1,"success",0,0,0); else ReportMessage(0,"Proto failed",0,0,hr);
530                                 bConfigChanged=TRUE;
531                             }
532                         }
533                         
534                         CoTaskMemFree( swName );
535                         CoTaskMemFree( swId );
536                         
537                         pPath->Release();
538                     }
539                     pEnumPaths->Release();
540                 }
541                 pBindings->Release();
542             } // hr==S_OK for QueryInterface IID_INetCfgComponentBindings
543         }
544         
545         CoTaskMemFree( swName );
546         
547         pAdapter->Release();
548     }
549     
550     pEnumComponent->Release();    
551     
552     hr = 0;
553     
554 cleanup:
555     
556     if(bConfigChanged) pCfg->Apply();
557     
558     if(pAdapter) pAdapter->Release();
559     
560     if(bInitialized) pCfg->Uninitialize();
561     if(bLockGranted) pLock->ReleaseWriteLock();
562     
563     if(pLock) pLock->Release();
564     if(pCfg) pCfg->Release();
565     
566     if (hr) ReportMessage(0,"LoopbackBindings() is returning ",0,0,hr);
567     return hr;
568 }
569
570         
571         extern "C"
572             DWORD
573 SetIpAddress(
574     LPCWSTR guid,
575     LPCWSTR ip,
576     LPCWSTR mask
577     )
578 {
579     ReportMessage(0,"Running SetIpAddress()...",0,0,0);
580     HRESULT hr = 0;
581
582     hr = WMIEnableStatic(FindNetworkAdapterConfigurationInstanceByGUID,
583                         (PVOID)guid, ip, mask);
584     return hr;
585 }
586
587 /* Set MAXLANA in the registry to the specified value, unless the existing registry value is larger */
588 DWORD AdjustMaxLana(DWORD dwMaxLana)
589 {
590
591     LONG ret = 0;
592     HKEY hNetBiosParamKey = NULL;
593     DWORD dwType, dwExistingMaxLana, dwSize;
594
595     ReportMessage(0,"Making sure MaxLana is large enough",0,0, dwMaxLana);
596
597     ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Services\\NetBIOS\\Parameters"), 
598         0, KEY_ALL_ACCESS , &hNetBiosParamKey);
599     if (ret) return ret;
600
601
602     
603     dwSize = 4;
604     ret = RegQueryValueEx(hNetBiosParamKey, _T("MaxLana"), 0, &dwType, (LPBYTE) &dwExistingMaxLana, &dwSize);
605     if ((ret) && (ret != ERROR_MORE_DATA) && (ret != ERROR_FILE_NOT_FOUND)) 
606     {
607         RegCloseKey(hNetBiosParamKey);
608         return ret;
609     }
610
611     if ((dwType != REG_DWORD) || (ret)) dwExistingMaxLana = 0;
612
613     ReportMessage (1,"MaxLana is currently",0,0, dwExistingMaxLana);
614
615     if (dwExistingMaxLana < dwMaxLana) 
616     {
617         ReportMessage (1,"Changing MaxLana", 0,0,dwMaxLana);
618         ret = RegSetValueEx(hNetBiosParamKey, _T("MaxLana"), 0, REG_DWORD, (const BYTE*)&dwMaxLana, 4);
619         if (ret) 
620         {
621             RegCloseKey(hNetBiosParamKey);
622             return ret;
623         }       
624
625     }
626
627     RegCloseKey(hNetBiosParamKey);
628     return 0;
629
630
631 }
632
633 extern "C" 
634 BOOL UpdateHostsFile( LPCWSTR swName, LPCWSTR swIp, LPCSTR szFilename, BOOL bPre )
635 {
636     char szIp[2048], szName[2048];
637     char etcPath[MAX_PATH];
638         char tempPath[MAX_PATH];
639         char buffer[2048], temp[2048];
640         char *str;
641         HRESULT rv;
642         DWORD fa,len;
643         FILE *hFile, *hTemp;
644         
645     _snprintf(szIp, 2047, "%S", swIp);
646     _snprintf(szName, 2047, "%S", swName);
647     strupr(szName);
648     ReportMessage(0,"Starting UpdateHostsFile() on file",szFilename,0,0);
649
650         rv = SHGetFolderPathA( NULL, CSIDL_SYSTEM, NULL, SHGFP_TYPE_CURRENT , etcPath );
651         if(rv != S_OK) return FALSE;
652
653         strcat( etcPath, ETCDIR );
654
655         fa = GetFileAttributesA( etcPath );
656
657         if(fa == INVALID_FILE_ATTRIBUTES)
658         {
659                 // the directory doesn't exist
660                 // it should be there. non-existence implies more things are wrong
661                 ReportMessage(0, "Path does not exist ", etcPath,0,0 );
662                 return FALSE;
663         }
664
665         strcpy( tempPath, etcPath );
666         strcat( etcPath, "\\" );
667         strcat( etcPath, szFilename );
668
669         fa = GetFileAttributesA( etcPath );
670
671         if(fa == INVALID_FILE_ATTRIBUTES)
672         {
673                 ReportMessage(0, "File not found. Creating...", szFilename,0,0);
674
675                 hFile = fopen( etcPath, "w" );
676                 if(!hFile)
677                 {
678                         ReportMessage(0,"FAILED : can't create file",etcPath,0,errno);
679                         return FALSE;
680                 }
681
682                 fprintf(hFile, "%s\t%s%s\n", szIp, szName, (bPre)?"\t#PRE":"");
683
684                 fclose( hFile );
685
686                 ReportMessage(1,"done",0,0,0);
687         }
688         else // the file exists. parse and update
689         {
690
691                 ReportMessage(1, "Updating file ...",szFilename,0,0 );
692
693                 hFile = fopen( etcPath, "r");
694                 if(!hFile)
695                 {
696                         ReportMessage(0,"FAILED : can't open file",etcPath,0,errno);
697                         return FALSE;
698                 }
699
700                 strcat( tempPath, szFilename );
701                 strcat( tempPath, ".tmp" );
702                 hTemp = fopen( tempPath, "w");
703                 if(!hTemp)
704                 {
705                         ReportMessage(0,"FAILED : can't create temp file",tempPath,0,errno);
706                         fclose(hFile);
707                         return FALSE;
708                 }
709
710                 while(fgets( buffer, 2046, hFile))
711                 {
712                         strcpy( temp, buffer );
713                         strupr( temp );
714
715             if ((strlen(temp)<1) || (*(temp+strlen(temp)-1)!='\n')) strcat(temp, "\n");
716
717                         if(!(str = strstr(temp, szName)))
718                         {
719                                 fputs( buffer, hTemp );
720                         }
721                         else
722                         {
723                                 // check for FOOBAFS or AFSY
724                                 //if(str <= temp || (*(str-1) != '-' && !isspace(*(str+strlen(szName)))))
725                                 if ( (str == temp) || (!*(str+strlen(szName))) || (!isspace(*(str-1))) || (!isspace(*(str+strlen(szName)))) )
726                     fputs( buffer, hTemp );
727                         }
728                 }
729
730
731                 len = 2048;
732                 GetComputerNameA( buffer, &len );
733                 buffer[11] = 0;
734                 fprintf( hTemp, "%s\t%s%s\n", szIp, szName, (bPre)?"\t#PRE":"");
735
736                 fclose( hTemp );
737                 fclose( hFile );
738
739                 strcpy(buffer, etcPath);
740                 strcat(buffer, ".old");
741
742         if(!DeleteFileA(buffer)) {
743             DWORD status;
744             int i;
745             char * eos;
746
747             status = GetLastError();
748             if(status == ERROR_ACCESS_DENIED) {
749                 /* try changing the file attribtues. */
750                 if(SetFileAttributesA(buffer, FILE_ATTRIBUTE_NORMAL) &&
751                     DeleteFileA(buffer)) {
752                     status = 0;
753                     ReportMessage(0,"Changed attributes and deleted back host file", buffer, 0, 0);
754                 }
755             }
756             if(status && status != ERROR_FILE_NOT_FOUND) {
757                 /* we can't delete the file.  Try to come up with 
758                    a different name that's not already taken. */
759                 srand(GetTickCount());
760                 eos = buffer + strlen(buffer);
761                 for(i=0; i < 50; i++) {
762                     itoa(rand(), eos, 16);
763                     if(GetFileAttributesA(buffer) == INVALID_FILE_ATTRIBUTES &&
764                         GetLastError() == ERROR_FILE_NOT_FOUND)
765                         break;
766                 }
767                 /* At this point if we don't have a unique name, we just let the rename
768                    fail.  Too bad. */
769             }
770         }
771
772         if(!MoveFileA( etcPath, buffer )) {
773             ReportMessage(0,"FAILED: Can't rename old file", etcPath, 0, GetLastError());
774             return FALSE;
775         }
776
777                 if(!MoveFileA( tempPath, etcPath ) != 0)
778                 {
779                         ReportMessage(0,"FAILED : Can't rename new file", tempPath, 0, GetLastError());
780                         return FALSE;
781                 }
782
783         }
784
785         return TRUE;
786 }
787
788 #ifdef TEST
789 #if 0
790 int
791 wmain(
792     int argc,
793     wchar_t* argv[]
794     )
795 {
796     if (argc < 3)
797     {
798         printf("usage: %S ip mask\n"
799                "  example: %S 10.0.0.1 255.0.0.0", argv[0], argv[0]);
800         return 0;
801     }
802
803     return WMIEnableStatic(FindNetworkAdapterConfigurationInstanceByGUID,
804                            L"{B4981E32-551C-4164-96B6-B8874BD2E555}",
805                            argv[1], argv[2]);
806 }
807 #else
808 int
809 wmain(
810     int argc,
811     wchar_t* argv[]
812     )
813 {
814     if (argc < 4)
815     {
816         printf("usage: %S adapter_guid ip mask\n"
817                "  example: %S {B4981E32-551C-4164-96B6-B8874BD2E555} "
818                "10.0.0.1 255.0.0.0", argv[0], argv[0]);
819         return 0;
820     }
821
822     return WMIEnableStatic(FindNetworkAdapterConfigurationInstanceByGUID,
823                            argv[1], argv[2], argv[3]);
824 }
825 #endif
826 #endif
827