2990 lines
89 KiB
C++
2990 lines
89 KiB
C++
/*++
|
|
|
|
Copyright (C) 1997-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
WINMGMT.CPP
|
|
|
|
Abstract:
|
|
|
|
Implements the windows application or an NT service which
|
|
loads up the various transport prtocols.
|
|
|
|
If started with /exe argument, it will always run as an exe.
|
|
If started with /kill argument, it will stop any running exes or services.
|
|
If started with /? or /help dumps out information.
|
|
|
|
History:
|
|
|
|
a-davj 04-Mar-97 Created.
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <malloc.h>
|
|
#include <tchar.h>
|
|
#include <Shellapi.h>
|
|
|
|
#include <wbemidl.h>
|
|
#include <reg.h>
|
|
#include <wbemutil.h>
|
|
#include <cntserv.h>
|
|
#include <cominit.h>
|
|
#include <sync.h>
|
|
#include <lmwksta.h>
|
|
#include <lmerr.h>
|
|
#include <lmapibuf.h>
|
|
#include <utils.h>
|
|
#include <genutils.h>
|
|
#include "servutil.h"
|
|
#include <persistcfg.h>
|
|
#include "WinMgmt.h"
|
|
#include "sched.h"
|
|
#include "STRINGS.h"
|
|
#include "win9Xaut.h"
|
|
#include <wbemint.h>
|
|
#include <wbemprov.h>
|
|
#include <winntsec.h>
|
|
#include <mofcomp.h>
|
|
|
|
#include <winmgmtr.h>
|
|
#include <BackupRestore.h>
|
|
#include <arrtempl.h>
|
|
#include <corex.h>
|
|
#include "process.h"
|
|
#include "resync.h"
|
|
|
|
#define CORE_PROVIDER_UNLOAD_TIMEOUT ( 30 * 1000 )
|
|
|
|
HWND ghWnd = NULL; // handle to main window
|
|
BOOL gbShowIcon = FALSE;
|
|
BOOL g_bRemovedAppId = FALSE;
|
|
BOOL g_fDoResync = TRUE;
|
|
BOOL g_fSetup = FALSE;
|
|
#define BUFF_MAX 200
|
|
bool gbSetToRunAsApp = false;
|
|
|
|
HINSTANCE ghInstance;
|
|
HANDLE ghCoreCanUnload = NULL;
|
|
HANDLE ghProviderCanUnload = NULL;
|
|
HANDLE ghCoreUnloaded = NULL;
|
|
HANDLE ghCoreLoaded = NULL;
|
|
HANDLE ghNeedRegistration = NULL;
|
|
HANDLE ghRegistrationDone = NULL;
|
|
HANDLE ghMofDirChange = NULL;
|
|
HANDLE ghLoadCtrEvent = NULL;
|
|
HANDLE ghUnloadCtrEvent = NULL;
|
|
HANDLE ghHoldOffNewClients = NULL;
|
|
BOOL gbRunAsApp = TRUE;
|
|
|
|
TCHAR * g_szHotMofDirectory = NULL;
|
|
BOOL gbRunningAsManualService = FALSE;
|
|
bool gbShuttingDownWinMgmt = false;
|
|
BOOL gbCoreLoaded = FALSE;
|
|
HANDLE ghMainMutex;
|
|
bool bServer = true;
|
|
HANDLE g_hAbort = NULL;
|
|
void SetToAuto();
|
|
|
|
class CInMutex
|
|
{
|
|
protected:
|
|
HANDLE m_hMutex;
|
|
public:
|
|
CInMutex(HANDLE hMutex) : m_hMutex(hMutex)
|
|
{
|
|
if(m_hMutex)
|
|
WaitForSingleObject(m_hMutex, INFINITE);
|
|
}
|
|
~CInMutex()
|
|
{
|
|
if(m_hMutex)
|
|
ReleaseMutex(m_hMutex);
|
|
}
|
|
};
|
|
|
|
void DoResyncPerf();
|
|
void DoClearAdap();
|
|
int DoBackup();
|
|
int DoRestore();
|
|
void DisplayWbemError(HRESULT hresError, DWORD dwLongFormatString, DWORD dwShortFormatString, DWORD dwTitle);
|
|
|
|
void AddToAutoRecoverList(TCHAR * pFileName);
|
|
bool IsStringPresent(char * pTest, char * pMultStr);
|
|
|
|
PROG_RESOURCES pr;
|
|
|
|
void (STDAPICALLTYPE *pServiceLocalConn)(DWORD *dwSize, char * pData);
|
|
void LoadMofsInDirectory(const TCHAR *szDirectory);
|
|
BOOL CheckGlobalSetupSwitch( void );
|
|
|
|
HRESULT GetRepositoryDirectory(wchar_t wszRepositoryDirectory[MAX_PATH+1]);
|
|
HRESULT DoDeleteRepository(const wchar_t *wszExcludeFile);
|
|
HRESULT DoDeleteContentsOfDirectory(const wchar_t *wszExcludeFile, const wchar_t *wszRepositoryDirectory);
|
|
HRESULT DoDeleteDirectory(const wchar_t *wszExcludeFile, const wchar_t *wszParentDirectory, wchar_t *wszSubDirectory);
|
|
|
|
//***************************************************************************
|
|
//
|
|
// ShutDownCore
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Calls the core shutdown logic, but only if the core is loaded. Note that
|
|
// the shutdown is protected with a CS which is shared with the class factory.
|
|
// This prevents the class factory from creating a new connection during shutdown.
|
|
//
|
|
//***************************************************************************
|
|
|
|
bool ShutDownCore(BOOL bProcessShutdown)
|
|
{
|
|
SCODE sc = WBEM_E_FAILED;
|
|
HMODULE hCoreModule = LoadLibrary(__TEXT("wbemcore.dll"));
|
|
if(hCoreModule)
|
|
{
|
|
HRESULT (STDAPICALLTYPE *pfn)(DWORD);
|
|
pfn = (long (__stdcall *)(DWORD))GetProcAddress(hCoreModule, "Shutdown");
|
|
if(pfn)
|
|
{
|
|
sc = (*pfn)(bProcessShutdown);
|
|
DEBUGTRACE((LOG_WINMGMT, "core is being shut down by WinMgmt.exe, it returned 0x%x",sc));
|
|
}
|
|
|
|
FreeLibrary(hCoreModule);
|
|
}
|
|
return sc == S_OK;
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// OKToUnloadCore
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Calls the core DllCanUnloadNow function.
|
|
//
|
|
//***************************************************************************
|
|
|
|
bool OKToUnloadCore()
|
|
{
|
|
SCODE sc = WBEM_E_FAILED;
|
|
HMODULE hCoreModule = LoadLibrary(__TEXT("wbemcore.dll"));
|
|
if(hCoreModule)
|
|
{
|
|
HRESULT (STDAPICALLTYPE *pfn)();
|
|
pfn = (HRESULT (__stdcall *)())GetProcAddress(hCoreModule, "DllCanUnloadNow");
|
|
if(pfn)
|
|
{
|
|
sc = (*pfn)();
|
|
ERRORTRACE((LOG_WINMGMT, "core was asked if ok to unload and returned 0x%x", sc));
|
|
}
|
|
FreeLibrary(hCoreModule);
|
|
}
|
|
return sc == S_OK;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CreateNarrowGuidString
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Fills in the narrow buffer with a clsid. Note that pBuff must point to
|
|
// a buffer large enough to hold a the clsid.
|
|
//
|
|
//***************************************************************************
|
|
|
|
void CreateNarrowGuidString(REFCLSID rclsid, TCHAR * pBuff)
|
|
{
|
|
pBuff[0] = 0;
|
|
LPWSTR wszGuid;
|
|
StringFromCLSID(rclsid, &wszGuid);
|
|
|
|
#ifdef UNICODE
|
|
swprintf(pBuff, L"%s", wszGuid);
|
|
#else
|
|
sprintf(pBuff, "%S", wszGuid);
|
|
#endif
|
|
|
|
CoTaskMemFree(wszGuid);
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SetCLSIDToService
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Used to restore clsid keys back to a state where they can be part of
|
|
// a service.
|
|
//
|
|
//***************************************************************************
|
|
|
|
void SetCLSIDToService(TCHAR * szGuid, TCHAR * szAppIDGuid)
|
|
{
|
|
Registry rClsid;
|
|
rClsid.Open(HKEY_LOCAL_MACHINE, __TEXT("SOFTWARE\\CLASSES\\CLSID"));
|
|
rClsid.MoveToSubkey(szGuid);
|
|
rClsid.SetStr(__TEXT("AppId"), szAppIDGuid);
|
|
|
|
TCHAR cPath[MAX_PATH];
|
|
lstrcpy(cPath, __TEXT("SOFTWARE\\CLASSES\\CLSID\\"));
|
|
lstrcat(cPath, szGuid);
|
|
lstrcat(cPath, __TEXT("\\LocalServer32"));
|
|
RegDeleteKey(HKEY_LOCAL_MACHINE, cPath);
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SetCLSIDToExe
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Used to st clsid keys back to a state where they can be part of
|
|
// an exe.
|
|
//
|
|
//***************************************************************************
|
|
|
|
void SetCLSIDToExe(TCHAR * szGuid)
|
|
{
|
|
Registry rCLSID;
|
|
rCLSID.Open(HKEY_LOCAL_MACHINE, __TEXT("SOFTWARE\\CLASSES\\CLSID"));
|
|
rCLSID.MoveToSubkey(szGuid);
|
|
rCLSID.DeleteValue(__TEXT("AppId"));
|
|
|
|
TCHAR LocalServerKey[MAX_PATH];
|
|
lstrcpy(LocalServerKey, __TEXT("SOFTWARE\\CLASSES\\CLSID\\"));
|
|
lstrcat(LocalServerKey, szGuid);
|
|
Registry rLocalServer;
|
|
rLocalServer.Open(HKEY_LOCAL_MACHINE, LocalServerKey);
|
|
rLocalServer.MoveToSubkey(__TEXT("LocalServer32"));
|
|
|
|
TCHAR szPath[MAX_PATH+1];
|
|
if(GetModuleFileName(ghInstance, szPath, MAX_PATH))
|
|
rLocalServer.SetStr(NULL, szPath);
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SetToRunAsService
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Sets up the registry so that we can run as an nt service.
|
|
//
|
|
//***************************************************************************
|
|
|
|
void SetToRunAsService()
|
|
{
|
|
|
|
TCHAR szMainGuid[128];
|
|
TCHAR szBackupGuid[128];
|
|
CreateNarrowGuidString(CLSID_WbemLevel1Login, szMainGuid);
|
|
CreateNarrowGuidString(CLSID_WbemBackupRestore, szBackupGuid);
|
|
|
|
SetCLSIDToService(szMainGuid, szMainGuid);
|
|
SetCLSIDToService(szBackupGuid, szMainGuid);
|
|
|
|
Registry rAppid;
|
|
rAppid.Open(HKEY_LOCAL_MACHINE, __TEXT("SOFTWARE\\CLASSES\\APPID"));
|
|
rAppid.MoveToSubkey(szMainGuid);
|
|
rAppid.SetStr(__TEXT("LocalService"), __TEXT("WinMgmt"));
|
|
rAppid.DeleteValue(__TEXT("RunAs"));
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SetToRunAsExe
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Sets up the registry so that we can run as an exe. This is used for devs.
|
|
//
|
|
//***************************************************************************
|
|
|
|
void SetToRunAsExe()
|
|
{
|
|
// Only want to remove the APPID Value if we are running under NT.
|
|
// ===============================================================
|
|
|
|
// If the APPID value exists in the registry for PrivateWbemLevel1Login
|
|
// then remove it as we can't run as an EXE if we are setup to run
|
|
// as a DCOM service.
|
|
// =============================================================
|
|
|
|
TCHAR szMainGuid[128];
|
|
TCHAR szBackupGuid[128];
|
|
CreateNarrowGuidString(CLSID_WbemLevel1Login, szMainGuid);
|
|
CreateNarrowGuidString(CLSID_WbemBackupRestore, szBackupGuid);
|
|
|
|
SetCLSIDToExe(szMainGuid);
|
|
SetCLSIDToExe(szBackupGuid);
|
|
|
|
Registry rAppid;
|
|
rAppid.Open(HKEY_LOCAL_MACHINE, __TEXT("SOFTWARE\\CLASSES\\APPID"));
|
|
rAppid.MoveToSubkey(szMainGuid);
|
|
|
|
rAppid.DeleteValue(__TEXT("LocalService"));
|
|
rAppid.SetStr(__TEXT("RunAs"), __TEXT("Interactive User"));
|
|
gbSetToRunAsApp = true;
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// WaitingFunction
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Here is where we wait for messages and events during WinMgmt execution.
|
|
// We return from here when the program/service is being stopped.
|
|
//
|
|
//***************************************************************************
|
|
|
|
void WaitingFunction(HANDLE hTerminate)
|
|
{
|
|
|
|
CSched sched;
|
|
|
|
DEBUGTRACE((LOG_WINMGMT,"Inside the waiting function\n"));
|
|
if(!gbRunAsApp)
|
|
SetToAuto();
|
|
|
|
|
|
HANDLE hEvents[] = {hTerminate, ghCoreCanUnload, ghCoreUnloaded, ghCoreLoaded, ghNeedRegistration,
|
|
ghProviderCanUnload, ghMofDirChange, ghLoadCtrEvent, ghUnloadCtrEvent};
|
|
int iNumEvents = sizeof(hEvents) / sizeof(HANDLE);
|
|
DWORD dwFlags;
|
|
SCODE sc;
|
|
CPersistentConfig per;
|
|
per.TidyUp();
|
|
|
|
sched.SetWorkItem(PossibleStartCore, 60000);
|
|
|
|
//Load any MOFs in the MOF directory if needed...
|
|
LoadMofsInDirectory(g_szHotMofDirectory);
|
|
|
|
// resync the perf counters if win2k and we haven't turned this off for debugging
|
|
// and we are not running during setup
|
|
|
|
if(IsW2KOrMore() && g_fDoResync && !g_fSetup)
|
|
ResyncPerf( hTerminate );
|
|
|
|
SetProcessWorkingSetSize(GetCurrentProcess(), -1, -1);
|
|
|
|
while(1)
|
|
{
|
|
DWORD dwDelay = sched.GetWaitPeriod();
|
|
DWORD dwObj = WbemWaitForMultipleObjects(iNumEvents, hEvents, dwDelay);
|
|
switch (dwObj)
|
|
{
|
|
case 0: // bail out for terminate event
|
|
{
|
|
DEBUGTRACE((LOG_WINMGMT,"Got a termination event\n"));
|
|
CInMutex im(ghMainMutex);
|
|
gbShuttingDownWinMgmt = true;
|
|
Cleanup();
|
|
}
|
|
return;
|
|
case 1: // core can unload
|
|
DEBUGTRACE((LOG_WINMGMT,"Got a core can unload event\n"));
|
|
sched.SetWorkItem(FirstCoreShutdown, 30000); // 30 seconds until next unloac;
|
|
break;
|
|
case 2: // core went away
|
|
DEBUGTRACE((LOG_WINMGMT,"Got a core unloaded event\n"));
|
|
gbCoreLoaded = FALSE;
|
|
SetProcessWorkingSetSize(GetCurrentProcess(), -1, -1);
|
|
break;
|
|
|
|
case 3: // core loaded
|
|
DEBUGTRACE((LOG_WINMGMT,"Got a core loaded event\n"));
|
|
gbCoreLoaded = TRUE;
|
|
break;
|
|
|
|
case 4: // Need Registration
|
|
|
|
DEBUGTRACE((LOG_WINMGMT,"Got a NeedRegistration event\n"));
|
|
if(pr.m_pLoginFactory)
|
|
{
|
|
CoRevokeClassObject(pr.m_dwLoginClsFacReg);
|
|
pr.m_pLoginFactory->Release();
|
|
pr.m_pLoginFactory = NULL;
|
|
}
|
|
dwFlags = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER;
|
|
if(IsDcomEnabled())
|
|
dwFlags |= CLSCTX_REMOTE_SERVER;
|
|
|
|
pr.m_pLoginFactory = new CForwardFactory(CLSID_InProcWbemLevel1Login);
|
|
pr.m_pLoginFactory->AddRef();
|
|
|
|
sc = CoRegisterClassObject(CLSID_WbemLevel1Login, pr.m_pLoginFactory,
|
|
dwFlags,
|
|
REGCLS_MULTIPLEUSE, &pr.m_dwLoginClsFacReg);
|
|
|
|
SetEvent(ghRegistrationDone);
|
|
ResetEvent(ghNeedRegistration);
|
|
break;
|
|
case 5: // provider can unload
|
|
{
|
|
DEBUGTRACE((LOG_WINMGMT,"Got a provider can unload event\n"));
|
|
CInMutex im(ghMainMutex);
|
|
CoFreeUnusedLibrariesEx ( CORE_PROVIDER_UNLOAD_TIMEOUT , 0 ) ;
|
|
//
|
|
// HACKHACK: Call it again to make sure that components that
|
|
// were released by unloading the first one can be unloaded
|
|
//
|
|
CoFreeUnusedLibrariesEx ( CORE_PROVIDER_UNLOAD_TIMEOUT , 0 ) ;
|
|
SetProcessWorkingSetSize(GetCurrentProcess(), -1, -1);
|
|
sched.SetWorkItem(FinalCoreShutdown, CORE_PROVIDER_UNLOAD_TIMEOUT); // 11 minutes until next unloac;
|
|
}
|
|
break;
|
|
|
|
case 6: // change in the hot mof directory
|
|
{
|
|
DEBUGTRACE((LOG_WINMGMT,"Got change in the hot mof directory\n"));
|
|
LoadMofsInDirectory(g_szHotMofDirectory);
|
|
|
|
//Continue to monitor changes
|
|
if (!FindNextChangeNotification(ghMofDirChange))
|
|
{
|
|
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
|
|
GetCurrentProcess(), &ghMofDirChange,
|
|
0, FALSE, DUPLICATE_SAME_ACCESS);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 7: // load ctr
|
|
case 8: // unload ctr
|
|
|
|
// Don't start a resync if setup is being run or the noresync switch is set
|
|
if ( !g_fSetup && g_fDoResync )
|
|
{
|
|
ResyncPerf( hTerminate );
|
|
}
|
|
break;
|
|
|
|
case WAIT_TIMEOUT:
|
|
|
|
DEBUGTRACE((LOG_WINMGMT,"Got a TIMEOUT work item\n"));
|
|
if(sched.IsWorkItemDue(FirstCoreShutdown))
|
|
{
|
|
|
|
// All the clients have left the core and a decent time interval has passed. Set the
|
|
// WINMGMT_CORE_CAN_BACKUP event. When the core is done, it will set the WINMGMT_CORE_BACKUP_DONE
|
|
// event which will start the final unloading.
|
|
|
|
DEBUGTRACE((LOG_WINMGMT,"Got a FirstCoreShutdown work item\n"));
|
|
sched.ClearWorkItem(FirstCoreShutdown);
|
|
CoFreeUnusedLibrariesEx ( CORE_PROVIDER_UNLOAD_TIMEOUT , 0 ) ;
|
|
CoFreeUnusedLibrariesEx ( CORE_PROVIDER_UNLOAD_TIMEOUT , 0 ) ;
|
|
}
|
|
if(sched.IsWorkItemDue(FinalCoreShutdown))
|
|
{
|
|
CInMutex im(ghMainMutex);
|
|
DEBUGTRACE((LOG_WINMGMT,"Got a FinalCoreShutdown work item\n"));
|
|
CoFreeUnusedLibrariesEx ( CORE_PROVIDER_UNLOAD_TIMEOUT , 0 ) ;
|
|
//
|
|
// HACKHACK: Call it again to make sure that components that
|
|
// were released by unloading the first one can be unloaded
|
|
|
|
CoFreeUnusedLibrariesEx ( CORE_PROVIDER_UNLOAD_TIMEOUT , 0 ) ;
|
|
sched.ClearWorkItem(FinalCoreShutdown);
|
|
SetProcessWorkingSetSize(GetCurrentProcess(), -1, -1);
|
|
}
|
|
if(sched.IsWorkItemDue(PossibleStartCore))
|
|
{
|
|
CInMutex im(ghMainMutex);
|
|
sched.StartCoreIfEssNeeded();
|
|
sched.ClearWorkItem(PossibleStartCore);
|
|
SetProcessWorkingSetSize(GetCurrentProcess(), -1, -1);
|
|
}
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//***************************************************************************
|
|
// LoadMofsInDirectory
|
|
//
|
|
// Given a directory, loads all files into the MOF compiler. If successful
|
|
// places the file in a 'good' directory under the given directory, otherwise
|
|
// places it in the 'bad' directory under the given directory.
|
|
// If the file exists already in the 'good' or 'bad' directory, it will
|
|
// first delete the file.
|
|
//***************************************************************************
|
|
void LoadMofsInDirectory(const TCHAR *szDirectory)
|
|
{
|
|
if(CheckGlobalSetupSwitch())
|
|
return; // not hot compiling during setup!
|
|
TCHAR *szHotMofDirFF = new TCHAR[lstrlen(szDirectory) + lstrlen(__TEXT("\\*")) + 1];
|
|
if(!szHotMofDirFF)return;
|
|
CDeleteMe<TCHAR> delMe1(szHotMofDirFF);
|
|
|
|
TCHAR *szHotMofDirBAD = new TCHAR[lstrlen(szDirectory) + lstrlen(__TEXT("\\bad\\")) + 1];
|
|
if(!szHotMofDirBAD)return;
|
|
CDeleteMe<TCHAR> delMe2(szHotMofDirBAD);
|
|
|
|
TCHAR *szHotMofDirGOOD = new TCHAR[lstrlen(szDirectory) + lstrlen(__TEXT("\\good\\")) + 1];
|
|
if(!szHotMofDirGOOD)return;
|
|
CDeleteMe<TCHAR> delMe3(szHotMofDirGOOD);
|
|
|
|
IWinmgmtMofCompiler * pCompiler = NULL;
|
|
|
|
//Find search parameter
|
|
lstrcpy(szHotMofDirFF, szDirectory);
|
|
lstrcat(szHotMofDirFF, __TEXT("\\*"));
|
|
|
|
//Where bad mofs go
|
|
lstrcpy(szHotMofDirBAD, szDirectory);
|
|
lstrcat(szHotMofDirBAD, __TEXT("\\bad\\"));
|
|
|
|
//Where good mofs go
|
|
lstrcpy(szHotMofDirGOOD, szDirectory);
|
|
lstrcat(szHotMofDirGOOD, __TEXT("\\good\\"));
|
|
|
|
//Make sure directories exist
|
|
WbemCreateDirectory(szDirectory);
|
|
WbemCreateDirectory(szHotMofDirBAD);
|
|
WbemCreateDirectory(szHotMofDirGOOD);
|
|
|
|
//Find file...
|
|
WIN32_FIND_DATA ffd;
|
|
HANDLE hFF = FindFirstFile(szHotMofDirFF, &ffd);
|
|
|
|
if (hFF != INVALID_HANDLE_VALUE)
|
|
{
|
|
do
|
|
{
|
|
//We only process if this is a file
|
|
if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
|
{
|
|
//Create a full filename with path
|
|
TCHAR *szFullFilename = new TCHAR[lstrlen(szDirectory) + lstrlen(__TEXT("\\")) + lstrlen(ffd.cFileName) + 1];
|
|
if(!szFullFilename) return;
|
|
CDeleteMe<TCHAR> delMe4(szFullFilename);
|
|
lstrcpy(szFullFilename, szDirectory);
|
|
lstrcat(szFullFilename, __TEXT("\\"));
|
|
lstrcat(szFullFilename, ffd.cFileName);
|
|
|
|
|
|
TRACE((LOG_WBEMCORE,"Auto-loading MOF %s\n", szFullFilename));
|
|
|
|
//We need to hold off on this file until it has been finished writing
|
|
//otherwise the CompileFile will not be able to read the file!
|
|
HANDLE hMof = INVALID_HANDLE_VALUE;
|
|
DWORD dwRetry = 10;
|
|
while (hMof == INVALID_HANDLE_VALUE)
|
|
{
|
|
hMof = CreateFile(szFullFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
//If cannot open yet sleep for a while
|
|
if (hMof == INVALID_HANDLE_VALUE)
|
|
{
|
|
if (--dwRetry == 0)
|
|
break;
|
|
Sleep(1000);
|
|
}
|
|
}
|
|
|
|
DWORD dwRetCode;
|
|
WBEM_COMPILE_STATUS_INFO Info;
|
|
DWORD dwAutoRecoverRequired = 0;
|
|
if (hMof == INVALID_HANDLE_VALUE)
|
|
{
|
|
TRACE((LOG_WBEMCORE,"Auto-loading MOF %s failed because we could not open it for exclusive access\n", szFullFilename));
|
|
dwRetCode = 1;
|
|
}
|
|
else
|
|
{
|
|
CloseHandle(hMof);
|
|
|
|
//Load the MOF file
|
|
WCHAR wPath[MAX_PATH+1];
|
|
if(szFullFilename)
|
|
{
|
|
#ifdef UNICODE
|
|
wcsncpy(wPath, szFullFilename, MAX_PATH+1);
|
|
#else
|
|
mbstowcs(wPath, szFullFilename, MAX_PATH);
|
|
#endif
|
|
if (pCompiler == 0)
|
|
{
|
|
SCODE sc = CoCreateInstance(CLSID_WinmgmtMofCompiler, 0, CLSCTX_INPROC_SERVER,
|
|
IID_IWinmgmtMofCompiler, (LPVOID *) &pCompiler);
|
|
if(sc != S_OK)
|
|
return;
|
|
}
|
|
dwRetCode = pCompiler->WinmgmtCompileFile(
|
|
wPath,
|
|
NULL,
|
|
WBEM_FLAG_DONT_ADD_TO_LIST, // autocomp, check, etc
|
|
0,
|
|
0,
|
|
NULL, NULL, &Info);
|
|
}
|
|
}
|
|
|
|
TCHAR *szNewDir = (dwRetCode?szHotMofDirBAD:szHotMofDirGOOD);
|
|
TCHAR *szNewFilename = new TCHAR[lstrlen(szNewDir) + lstrlen(ffd.cFileName) + 1];
|
|
if(!szNewFilename) return;
|
|
CDeleteMe<TCHAR> delMe5(szNewFilename);
|
|
|
|
lstrcpy(szNewFilename, szNewDir);
|
|
lstrcat(szNewFilename, ffd.cFileName);
|
|
|
|
//Make sure we have access to delete the old file...
|
|
DWORD dwOldAttribs = GetFileAttributes(szNewFilename);
|
|
|
|
if (dwOldAttribs != -1)
|
|
{
|
|
dwOldAttribs &= ~FILE_ATTRIBUTE_READONLY;
|
|
SetFileAttributes(szNewFilename, dwOldAttribs);
|
|
|
|
//Move it to directory
|
|
if (DeleteFile(szNewFilename))
|
|
{
|
|
TRACE((LOG_WBEMCORE, "Removing old MOF %s\n", szNewFilename));
|
|
}
|
|
}
|
|
|
|
TRACE((LOG_WBEMCORE, "Loading of MOF %s was %s. Moving to %s\n", szFullFilename, dwRetCode?"unsuccessful":"successful", szNewFilename));
|
|
MoveFile(szFullFilename, szNewFilename);
|
|
|
|
//Now mark the file as read only so no one deletes it!!!
|
|
//Like that stops anyone deleting files :-)
|
|
dwOldAttribs = GetFileAttributes(szNewFilename);
|
|
|
|
if (dwOldAttribs != -1)
|
|
{
|
|
dwOldAttribs |= FILE_ATTRIBUTE_READONLY;
|
|
SetFileAttributes(szNewFilename, dwOldAttribs);
|
|
}
|
|
|
|
if ((dwRetCode == 0) && (Info.dwOutFlags & AUTORECOVERY_REQUIRED))
|
|
{
|
|
//We need to add this item into the registry for auto-recovery purposes
|
|
TRACE((LOG_WBEMCORE, "MOF %s had an auto-recover pragrma. Updating registry.\n", szNewFilename));
|
|
AddToAutoRecoverList(szNewFilename);
|
|
}
|
|
}
|
|
|
|
} while (FindNextFile(hFF, &ffd));
|
|
|
|
FindClose(hFF);
|
|
}
|
|
if (pCompiler)
|
|
pCompiler->Release();
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// MyService::MyService
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Constructor.
|
|
//
|
|
//***************************************************************************
|
|
|
|
MyService::MyService()
|
|
{
|
|
m_hStopEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
|
|
m_hBreakPoint = CreateEvent(NULL,TRUE,FALSE,NULL);
|
|
if(m_hStopEvent == NULL || m_hBreakPoint == NULL)
|
|
{
|
|
DEBUGTRACE((LOG_WINMGMT,"MyService could not initialize\n"));
|
|
}
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// MyService::~MyService
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Destructor.
|
|
//
|
|
//***************************************************************************
|
|
|
|
MyService::~MyService()
|
|
{
|
|
if(m_hStopEvent)
|
|
CloseHandle(m_hStopEvent);
|
|
if(m_hBreakPoint)
|
|
CloseHandle(m_hBreakPoint);
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// DWORD MyService::WorkerThread
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Where the service runs. In this case, the service just waits for
|
|
// the terminate event to be set.
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// 0
|
|
//***************************************************************************
|
|
|
|
DWORD MyService::WorkerThread()
|
|
{
|
|
DEBUGTRACE((LOG_WINMGMT,"Starting service worker thread\n"));
|
|
if(!::Initialize(pr,FALSE))
|
|
return 0;
|
|
WaitingFunction(m_hStopEvent);
|
|
DEBUGTRACE((LOG_WINMGMT,"Stopping service worker thread\n"));
|
|
return 0;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// VOID MyService::Log
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Gives the service a change to dump out trace messages.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// lpszMsg message to be dumped.
|
|
//
|
|
//***************************************************************************
|
|
|
|
VOID MyService::Log(
|
|
IN LPCSTR lpszMsg)
|
|
{
|
|
TRACE((LOG_WINMGMT,lpszMsg));
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// void MyService::UserCode
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Not used in this app, it is where user command codes which can be
|
|
// sent to service are handled.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// nCode command code.
|
|
//
|
|
//***************************************************************************
|
|
|
|
void MyService::UserCode(
|
|
IN int nCode)
|
|
{
|
|
DEBUGTRACE((LOG_WINMGMT,"just got user code of %d\n",nCode));
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CForwardFactory::AddRef()
|
|
// CForwardFactory::Release()
|
|
// CForwardFactory::QueryInterface()
|
|
// CForwardFactory::CreateInstance()
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Class factory for the exported WbemNTLMLogin interface. Note that this
|
|
// just serves as a wrapper to the factory inside the core. The reason for
|
|
// having a wrapper is that the core may not always be loaded.
|
|
//
|
|
//***************************************************************************
|
|
|
|
ULONG STDMETHODCALLTYPE CForwardFactory::AddRef()
|
|
{
|
|
return InterlockedIncrement(&m_lRef);
|
|
}
|
|
|
|
ULONG STDMETHODCALLTYPE CForwardFactory::Release()
|
|
{
|
|
long lRef = InterlockedDecrement(&m_lRef);
|
|
if(lRef == 0)
|
|
delete this;
|
|
return lRef;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CForwardFactory::QueryInterface(REFIID riid,
|
|
void** ppv)
|
|
{
|
|
if(riid == IID_IUnknown || riid == IID_IClassFactory)
|
|
{
|
|
*ppv = (IClassFactory*)this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
else return E_NOINTERFACE;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CForwardFactory::CreateInstance(IUnknown* pUnkOuter,
|
|
REFIID riid, void** ppv)
|
|
{
|
|
DEBUGTRACE((LOG_WINMGMT, "Creating an instance!\n"));
|
|
SCODE sc = S_OK;
|
|
CInMutex im(ghMainMutex);
|
|
|
|
try {
|
|
|
|
if(gbShuttingDownWinMgmt)
|
|
{
|
|
DEBUGTRACE((LOG_WINMGMT, "CreateInstance returned CO_E_SERVER_STOPPING\n"));
|
|
return CO_E_SERVER_STOPPING;
|
|
}
|
|
DWORD dwRes = WaitForSingleObject(ghHoldOffNewClients, 1000);
|
|
if(dwRes != WAIT_OBJECT_0 && dwRes != WAIT_ABANDONED)
|
|
return CO_E_SERVER_STOPPING;
|
|
ReleaseMutex(ghHoldOffNewClients);
|
|
|
|
if(m_ForwardClsid == CLSID_WbemBackupRestore)
|
|
{
|
|
CWbemBackupRestore * pObj = new CWbemBackupRestore(ghInstance);
|
|
if (!pObj)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
|
|
sc = pObj->QueryInterface(riid, ppv);
|
|
if(FAILED(sc))
|
|
delete pObj;
|
|
}
|
|
else
|
|
{
|
|
sc = CoCreateInstance(CLSID_InProcWbemLevel1Login, NULL,
|
|
CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IID_IUnknown,
|
|
(void**)ppv);
|
|
DEBUGTRACE((LOG_WINMGMT, "Inner create returned: 0x%X\n", sc));
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
ERRORTRACE((LOG_WINMGMT,"---------------\nException thrown from CreateInstance\n-------------\n"));
|
|
sc = E_NOINTERFACE;
|
|
}
|
|
return sc;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CForwardFactory::LockServer(BOOL fLock)
|
|
{
|
|
return m_pFactory->LockServer(fLock);
|
|
}
|
|
|
|
CForwardFactory::~CForwardFactory()
|
|
{
|
|
if(m_pFactory)
|
|
m_pFactory->Release();
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// PROG_RESOURCES::PROG_RESOURCES
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Constuctor.
|
|
//
|
|
//***************************************************************************
|
|
|
|
PROG_RESOURCES::PROG_RESOURCES()
|
|
{
|
|
m_hTerminateEvent = NULL;
|
|
m_hExclusive = NULL;
|
|
m_bOleInitialized = FALSE;
|
|
|
|
m_pLoginFactory = NULL;
|
|
m_pBackupFactory = NULL;
|
|
m_dwLoginClsFacReg = 0;
|
|
|
|
};
|
|
|
|
//***************************************************************************
|
|
//
|
|
// void TerminateRunning
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Stops another running copy even if it is a service.
|
|
//
|
|
//***************************************************************************
|
|
|
|
void TerminateRunning()
|
|
{
|
|
DWORD dwFlag = EVENT_MODIFY_STATE;
|
|
if(IsNT())
|
|
dwFlag |= SYNCHRONIZE;
|
|
HANDLE hTerm = OpenEvent(EVENT_MODIFY_STATE,FALSE,
|
|
TEXT("WINMGMT_MARSHALLING_SERVER_TERMINATE"));
|
|
if(hTerm)
|
|
{
|
|
SetEvent(hTerm);
|
|
CloseHandle(hTerm);
|
|
}
|
|
if(IsNT())
|
|
{
|
|
StopService(__TEXT("wmiapsrv"), 15);
|
|
StopService(__TEXT("WinMgmt"), 15);
|
|
}
|
|
return;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// void DisplayMessage
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Displays a usage message box.
|
|
//
|
|
//***************************************************************************
|
|
|
|
void DisplayMessage()
|
|
{
|
|
TCHAR tBuff[BUFF_MAX];
|
|
TCHAR tBig[1024];
|
|
tBig[0] = 0;
|
|
|
|
UINT ui;
|
|
for(ui = ID1; ui <= ID10; ui++)
|
|
{
|
|
int iRet = LoadString(ghInstance, ui, tBuff, BUFF_MAX);
|
|
if(iRet > 0)
|
|
lstrcat(tBig, tBuff);
|
|
}
|
|
if(lstrlen(tBig) > 0)
|
|
MessageBox(NULL, tBig,__TEXT("WinMgmt"), MB_OK);
|
|
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// void InitializeLaunchPermissions()
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Sets the DCOM Launch permissions.
|
|
//
|
|
//***************************************************************************
|
|
|
|
void InitializeLaunchPermissions()
|
|
{
|
|
|
|
Registry reg(__TEXT("SOFTWARE\\CLASSES\\APPID\\{8bc3f05e-d86b-11d0-a075-00c04fb68820}"));
|
|
if(reg.GetLastError() != 0)
|
|
return;
|
|
|
|
// If there already is a SD, then dont overwrite
|
|
|
|
BYTE * pData = NULL;
|
|
DWORD dwDataSize = 0;
|
|
|
|
int iRet = reg.GetBinary(__TEXT("LaunchPermission"), &pData, &dwDataSize);
|
|
if(iRet == 0)
|
|
{
|
|
delete pData;
|
|
return;
|
|
}
|
|
|
|
// Create a sd with a single entry for launch permissions.
|
|
|
|
CNtSecurityDescriptor LaunchPermSD;
|
|
|
|
|
|
// Create the raw "Everyone" SID
|
|
PSID pRawSid;
|
|
SID_IDENTIFIER_AUTHORITY id = SECURITY_WORLD_SID_AUTHORITY;;
|
|
|
|
if(AllocateAndInitializeSid( &id, 1,
|
|
0,0,0,0,0,0,0,0,&pRawSid))
|
|
{
|
|
|
|
// Create the class sids for everyone and administrators
|
|
|
|
CNtSid SidEveryone(pRawSid);
|
|
FreeSid(pRawSid);
|
|
CNtSid SidAdmins(L"Administrators");
|
|
if(SidEveryone.GetStatus() != 0 || SidEveryone.GetStatus() != 0)
|
|
return;
|
|
|
|
// Create a single ACE, and add it to the ACL
|
|
|
|
CNtAcl DestAcl;
|
|
CNtAce Users(1, ACCESS_ALLOWED_ACE_TYPE, 0, SidEveryone);
|
|
if(Users.GetStatus() != 0)
|
|
return;
|
|
DestAcl.AddAce(&Users);
|
|
if(DestAcl.GetStatus() != 0)
|
|
return;
|
|
|
|
// Set the descresionary acl, and the owner and group sids
|
|
|
|
LaunchPermSD.SetDacl(&DestAcl);
|
|
LaunchPermSD.SetOwner(&SidAdmins);
|
|
LaunchPermSD.SetGroup(&SidAdmins);
|
|
if(LaunchPermSD.GetStatus() != 0)
|
|
return;
|
|
|
|
// Write it out
|
|
|
|
reg.SetBinary(__TEXT("LaunchPermission"), (BYTE *)LaunchPermSD.GetPtr(), LaunchPermSD.GetSize());
|
|
}
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// AddClsid
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Adds a clsid entry during self registration
|
|
//
|
|
//***************************************************************************
|
|
|
|
void AddClsid(TCHAR * pszCLSIDGuid, TCHAR * pszAppIDGuid, TCHAR * pszTitle)
|
|
{
|
|
Registry rClsid;
|
|
rClsid.Open(HKEY_LOCAL_MACHINE, __TEXT("SOFTWARE\\CLASSES\\CLSID"));
|
|
rClsid.MoveToSubkey(pszCLSIDGuid);
|
|
rClsid.SetStr(NULL, pszTitle);
|
|
rClsid.SetStr(__TEXT("AppId"), pszAppIDGuid);
|
|
if(!IsNT())
|
|
SetCLSIDToExe(pszCLSIDGuid);
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SetRestart
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// win2k services have the ability to be restarted after a crash. This sets
|
|
// the config mgr for that.
|
|
//
|
|
//***************************************************************************
|
|
|
|
void SetRestart(SC_HANDLE sh)
|
|
{
|
|
|
|
if(!IsW2KOrMore())
|
|
return;
|
|
|
|
BOOL (WINAPI *pConfig)( SC_HANDLE, DWORD ,LPVOID);
|
|
|
|
HINSTANCE hLib = LoadLibrary(__TEXT("advapi32.dll"));
|
|
if(hLib)
|
|
{
|
|
(FARPROC&)pConfig = GetProcAddress(hLib, "ChangeServiceConfig2W");
|
|
if(pConfig)
|
|
{
|
|
SC_ACTION ac[2];
|
|
ac[0].Type = SC_ACTION_RESTART;
|
|
ac[0].Delay = 60000;
|
|
ac[1].Type = SC_ACTION_RESTART;
|
|
ac[1].Delay = 60000;
|
|
SERVICE_FAILURE_ACTIONS sf;
|
|
sf.dwResetPeriod = 86400;
|
|
sf.lpRebootMsg = NULL;
|
|
sf.lpCommand = NULL;
|
|
sf.cActions = 2;
|
|
sf.lpsaActions = ac;
|
|
pConfig(sh, SERVICE_CONFIG_FAILURE_ACTIONS, &sf);
|
|
}
|
|
FreeLibrary(hLib);
|
|
}}
|
|
//***************************************************************************
|
|
//
|
|
// SetToAuto
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// The first time that winmgmt is run as a service after setup, we want to set the service
|
|
// to be automatic.
|
|
//
|
|
//***************************************************************************
|
|
|
|
void SetToAuto()
|
|
{
|
|
|
|
if(g_fSetup)
|
|
return;
|
|
if(!IsNT() )
|
|
return;
|
|
|
|
DWORD dwVal = 1;
|
|
Registry rWINMGMT(WBEM_REG_WINMGMT);
|
|
if (rWINMGMT.GetDWORDStr( __TEXT("AlreadySetToAuto"), &dwVal ) == Registry::no_error)
|
|
{
|
|
if(dwVal == 1)
|
|
return;
|
|
}
|
|
|
|
SC_HANDLE schService;
|
|
SC_HANDLE schSCManager;
|
|
|
|
schSCManager = OpenSCManager(
|
|
NULL, // machine (NULL == local)
|
|
NULL, // database (NULL == default)
|
|
SC_MANAGER_ALL_ACCESS // access required
|
|
);
|
|
if ( schSCManager )
|
|
{
|
|
schService = OpenService(schSCManager, __TEXT("WinMgmt"), SERVICE_ALL_ACCESS);
|
|
|
|
if (schService)
|
|
{
|
|
|
|
if(ChangeServiceConfig( schService,
|
|
SERVICE_NO_CHANGE , // type of service
|
|
SERVICE_AUTO_START, // when to start service
|
|
SERVICE_NO_CHANGE , // severity if service fails to start
|
|
NULL, // pointer to service binary file name
|
|
NULL, // pointer to load ordering group name
|
|
NULL, // pointer to variable to get tag identifier
|
|
NULL, // pointer to array of dependency names
|
|
NULL,
|
|
NULL, // pointer to password for service account
|
|
NULL))
|
|
{
|
|
gbRunningAsManualService = FALSE;
|
|
rWINMGMT.SetDWORDStr( __TEXT("AlreadySetToAuto"), 1);
|
|
}
|
|
SetRestart(schService);
|
|
CloseServiceHandle(schService);
|
|
}
|
|
CloseServiceHandle(schSCManager);
|
|
}
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// int RegServer
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Self registers the exe.
|
|
//
|
|
//***************************************************************************
|
|
|
|
|
|
int RegServer()
|
|
{
|
|
TCHAR * pszWbemTitle = __TEXT("Windows Management Instrumentation");
|
|
TCHAR * pszBackupTitle = __TEXT("Windows Management Instrumentation Backup and Recovery");
|
|
|
|
TCHAR szMainGuid[128];
|
|
TCHAR szBackupGuid[128];
|
|
CreateNarrowGuidString(CLSID_WbemLevel1Login, szMainGuid);
|
|
CreateNarrowGuidString(CLSID_WbemBackupRestore, szBackupGuid);
|
|
|
|
AddClsid(szMainGuid, szMainGuid, pszWbemTitle);
|
|
AddClsid(szBackupGuid, szMainGuid, pszBackupTitle);
|
|
|
|
//////////////////////////////////////////////////////
|
|
|
|
if(!IsNT())
|
|
{
|
|
DWORD dwOpt = GetWin95RestartOption();
|
|
if(dwOpt == -1)
|
|
SetWin95RestartOption(0);
|
|
Registry reg(WBEM_REG_WINMGMT);
|
|
|
|
TCHAR * pStr = NULL;
|
|
long lRet = reg.GetStr(__TEXT("EnableAnonConnections"), &pStr);
|
|
if(lRet == 0 && pStr)
|
|
delete pStr;
|
|
else
|
|
reg.SetStr(__TEXT("EnableAnonConnections"), __TEXT("0"));
|
|
}
|
|
|
|
Registry rAppid;
|
|
rAppid.Open(HKEY_LOCAL_MACHINE, __TEXT("SOFTWARE\\CLASSES\\APPID"));
|
|
rAppid.MoveToSubkey(szMainGuid);
|
|
rAppid.SetStr(NULL, pszWbemTitle);
|
|
if(IsNT())
|
|
{
|
|
rAppid.SetStr(__TEXT("LocalService"), __TEXT("WinMgmt"));
|
|
InitializeLaunchPermissions();
|
|
Registry rWINMGMT(WBEM_REG_WINMGMT);
|
|
rWINMGMT.SetDWORDStr( __TEXT("AlreadySetToAuto"), 0);
|
|
}
|
|
else
|
|
{
|
|
rAppid.SetStr(__TEXT("RunAs"), __TEXT("Interactive User"));
|
|
rAppid.Open(HKEY_LOCAL_MACHINE, __TEXT("SOFTWARE\\CLASSES\\APPID"));
|
|
rAppid.MoveToSubkey(__TEXT("WinMgmt.EXE"));
|
|
rAppid.SetStr(__TEXT("AppId"), szMainGuid);
|
|
}
|
|
|
|
Registry rAppid2;
|
|
rAppid2.Open(HKEY_LOCAL_MACHINE, __TEXT("SOFTWARE\\CLASSES\\APPID"));
|
|
rAppid2.MoveToSubkey(__TEXT("winmgmt.exe"));
|
|
rAppid2.SetStr(__TEXT("AppId"), szMainGuid);
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// DeleteCLSIDEntry
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Removes a CLSID entry.
|
|
//
|
|
//***************************************************************************
|
|
|
|
void DeleteCLSIDEntry(TCHAR * szID)
|
|
{
|
|
TCHAR szCLSID[128];
|
|
HKEY hKey;
|
|
lstrcpy(szCLSID, TEXT("SOFTWARE\\CLASSES\\CLSID\\"));
|
|
lstrcat(szCLSID, szID);
|
|
|
|
// First delete the InProcServer subkey.
|
|
|
|
DWORD dwRet = RegOpenKey(HKEY_LOCAL_MACHINE, szCLSID, &hKey);
|
|
if(dwRet == NO_ERROR)
|
|
{
|
|
RegDeleteKey(hKey, __TEXT("LocalServer32"));
|
|
RegDeleteKey(hKey, __TEXT("InProcServer32"));
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
dwRet = RegOpenKey(HKEY_LOCAL_MACHINE, __TEXT("SOFTWARE\\CLASSES\\CLSID"), &hKey);
|
|
if(dwRet == NO_ERROR)
|
|
{
|
|
RegDeleteKey(hKey,szID);
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// int UnregServer
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Unregisters the exe.
|
|
//
|
|
//***************************************************************************
|
|
|
|
int UnregServer()
|
|
{
|
|
// Create the path using the CLSID
|
|
TCHAR szMainGuid[128];
|
|
TCHAR szBackupGuid[128];
|
|
CreateNarrowGuidString(CLSID_WbemLevel1Login, szMainGuid);
|
|
CreateNarrowGuidString(CLSID_WbemBackupRestore, szBackupGuid);
|
|
|
|
DeleteCLSIDEntry(szMainGuid);
|
|
DeleteCLSIDEntry(szBackupGuid);
|
|
|
|
HKEY hKey;
|
|
DWORD dwRet = RegOpenKey(HKEY_LOCAL_MACHINE, __TEXT("SOFTWARE\\CLASSES\\APPID"), &hKey);
|
|
if(dwRet == NO_ERROR)
|
|
{
|
|
RegDeleteKey(hKey,__TEXT("WinMgmt.EXE"));
|
|
RegDeleteKey(hKey,szMainGuid);
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
if(!IsNT())
|
|
{
|
|
dwRet = RegOpenKey(HKEY_LOCAL_MACHINE, WBEM_REG_WINMGMT, &hKey);
|
|
if(dwRet == NO_ERROR)
|
|
{
|
|
RegDeleteValue(hKey,__TEXT("AutostartWin9X"));
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
RemoveFromList();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
BOOL CheckNoResyncSwitch( void )
|
|
{
|
|
BOOL bRetVal = TRUE;
|
|
DWORD dwVal = 0;
|
|
Registry rCIMOM(WBEM_REG_WINMGMT);
|
|
if (rCIMOM.GetDWORDStr( WBEM_NORESYNCPERF, &dwVal ) == Registry::no_error)
|
|
{
|
|
bRetVal = !dwVal;
|
|
|
|
if ( bRetVal )
|
|
{
|
|
DEBUGTRACE((LOG_WBEMCORE, "NoResyncPerf in CIMOM is set to TRUE - ADAP will not be shelled\n"));
|
|
}
|
|
}
|
|
|
|
// If we didn't get anything there, we should try the volatile key
|
|
if ( bRetVal )
|
|
{
|
|
Registry rAdap( HKEY_LOCAL_MACHINE, KEY_READ, WBEM_REG_ADAP);
|
|
|
|
if ( rAdap.GetDWORD( WBEM_NOSHELL, &dwVal ) == Registry::no_error )
|
|
{
|
|
bRetVal = !dwVal;
|
|
|
|
if ( bRetVal )
|
|
{
|
|
DEBUGTRACE((LOG_WBEMCORE,
|
|
"NoShell in ADAP is set to TRUE - ADAP will not be shelled\n"));
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return bRetVal;
|
|
}
|
|
|
|
BOOL CheckSetupSwitch( void )
|
|
{
|
|
BOOL bRetVal = FALSE;
|
|
DWORD dwVal = 0;
|
|
Registry r(WBEM_REG_WINMGMT);
|
|
if (r.GetDWORDStr( WBEM_WMISETUP, &dwVal ) == Registry::no_error)
|
|
{
|
|
bRetVal = dwVal;
|
|
DEBUGTRACE((LOG_WBEMCORE, "Registry entry is indicating a setup is running\n"));
|
|
}
|
|
return bRetVal;
|
|
}
|
|
BOOL CheckGlobalSetupSwitch( void )
|
|
{
|
|
BOOL bRetVal = FALSE;
|
|
DWORD dwVal = 0;
|
|
Registry r(_T("system\\Setup"));
|
|
if (r.GetDWORD( _T("SystemSetupInProgress"), &dwVal ) == Registry::no_error)
|
|
{
|
|
if(dwVal == 1)
|
|
bRetVal = TRUE;
|
|
}
|
|
return bRetVal;
|
|
}
|
|
|
|
|
|
// This function will place a volatile registry key under the CIMOM key in which we will
|
|
// write a value indicating we should not shell ADAP. This way, after a setup runs, WINMGMT
|
|
// will NOT automatically shell ADAP dredges of the registry, until the system is rebooted
|
|
// and the volatile registry key is removed.
|
|
|
|
void SetNoShellADAPSwitch( void )
|
|
{
|
|
HKEY hKey = NULL;
|
|
DWORD dwDisposition = 0;
|
|
|
|
Registry r( HKEY_LOCAL_MACHINE, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, WBEM_REG_ADAP );
|
|
|
|
if ( ERROR_SUCCESS == r.GetLastError() )
|
|
{
|
|
|
|
if ( r.SetDWORD( WBEM_NOSHELL, 1 ) != Registry::no_error )
|
|
{
|
|
DEBUGTRACE( ( LOG_WINMGMT, "Failed to create NoShell value in volatile reg key: %d\n",
|
|
r.GetLastError() ) );
|
|
}
|
|
|
|
RegCloseKey( hKey );
|
|
|
|
}
|
|
else
|
|
{
|
|
DEBUGTRACE( ( LOG_WINMGMT, "Failed to create volatile ADAP reg key: %d\n", r.GetLastError() ) );
|
|
}
|
|
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// int APIENTRY WinMain
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Entry point for windows applications. If this is running under
|
|
// NT, then this will run as a service, unless the "/EXE" command line
|
|
// argument is used.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// hInstance Instance handle
|
|
// hPrevInstance not used in win32
|
|
// szCmdLine command line argument
|
|
// nCmdShow how window is to be shown(ignored)
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// 0
|
|
//***************************************************************************
|
|
|
|
int APIENTRY WinMain(
|
|
IN HINSTANCE hInstance,
|
|
IN HINSTANCE hPrevInstance,
|
|
IN LPSTR szCmdLine,
|
|
IN int nCmdShow)
|
|
{
|
|
// This should not be uninitialized! It is here to prevent the class factory from being called during
|
|
// shutdown.
|
|
|
|
ghMainMutex = CreateMutex(NULL, FALSE, NULL);
|
|
ghInstance = hInstance;
|
|
DEBUGTRACE((LOG_WINMGMT,"Starting WinMgmt, ProcID = %x, CmdLine = %s\n",
|
|
GetCurrentProcessId(), szCmdLine));
|
|
|
|
if(szCmdLine && (szCmdLine[0] == '-' || szCmdLine[0] == '/' ))
|
|
{
|
|
if(!_stricmp("RegServer",szCmdLine+1))
|
|
return RegServer();
|
|
else if(!_stricmp("UnregServer",szCmdLine+1))
|
|
return UnregServer();
|
|
else if(!_stricmp("exe",szCmdLine+1))
|
|
gbShowIcon = TRUE;
|
|
else if(!_stricmp("kill",szCmdLine+1))
|
|
{
|
|
TerminateRunning();
|
|
return 0;
|
|
}
|
|
else if (_strnicmp("backup ", szCmdLine+1, strlen("backup ")) == 0)
|
|
{
|
|
return DoBackup();
|
|
}
|
|
else if (_strnicmp("restore ", szCmdLine+1, strlen("restore ")) == 0)
|
|
{
|
|
return DoRestore();
|
|
}
|
|
else if(_strnicmp("resyncperf", szCmdLine+1, strlen("resyncperf")) == 0)
|
|
{
|
|
DoResyncPerf();
|
|
return 0;
|
|
}
|
|
else if(_strnicmp("clearadap", szCmdLine+1, strlen("clearadap")) == 0)
|
|
{
|
|
DoClearAdap();
|
|
return 0;
|
|
}
|
|
else if(_stricmp("EMBEDDING", szCmdLine+1))
|
|
{
|
|
DisplayMessage();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
BOOL bIsService = FALSE;
|
|
if (IsNT())
|
|
{
|
|
DWORD dwServiceReturn = CNtService::IsRunningAsService(bIsService);
|
|
DEBUGTRACE((LOG_WINMGMT,"WinMgmt bIsService = %d, return code from function determining if service = %d\n", bIsService, dwServiceReturn));
|
|
}
|
|
|
|
gbRunAsApp = (!IsNT() || gbShowIcon || !bIsService);
|
|
DEBUGTRACE((LOG_WINMGMT,"WinMgmt gbRunAsApp = %d\n", gbRunAsApp));
|
|
|
|
if(gbRunAsApp && IsNT())
|
|
SetToRunAsExe();
|
|
|
|
if(!gbRunAsApp && IsNT())
|
|
SetToRunAsService();
|
|
|
|
// Check if we're performing a setup so we'll know not to perform certain operations if
|
|
// necessary
|
|
g_fSetup = CheckSetupSwitch();
|
|
|
|
if ( g_fSetup )
|
|
{
|
|
SetNoShellADAPSwitch();
|
|
}
|
|
|
|
// Look in the registry to decide if we will launch a resync perf or not
|
|
g_fDoResync = CheckNoResyncSwitch();
|
|
|
|
// Run as either an app or a service. Note that Cleanup() is called during the WaitingFunction
|
|
// which is used by both apps and services.
|
|
|
|
if(gbRunAsApp)
|
|
{
|
|
if(!Initialize(pr,TRUE))
|
|
{
|
|
// if initialization failed and we are running as an app, create
|
|
// the service object with "DieImmediatly" set so that the SCM
|
|
// will be informed of the problem.
|
|
|
|
TRACE((LOG_WINMGMT,"Bailing out due to initialization failure\n"));
|
|
Cleanup();
|
|
return 1;
|
|
}
|
|
|
|
// run as minimized windows app.
|
|
|
|
ghWnd = MyCreateWindow(hInstance);
|
|
WaitingFunction(pr.m_hTerminateEvent);
|
|
}
|
|
else
|
|
{
|
|
|
|
// Run as service
|
|
|
|
MyService svc;
|
|
if(svc.bOK())
|
|
{
|
|
svc.SetPauseContinue(FALSE);
|
|
DWORD dwRet = svc.Run(__TEXT("WinMgmt"), TRUE);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// LRESULT CALLBACK WndProc
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Window procedure.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// hWnd window handle
|
|
// message message id
|
|
// wParam word parameter
|
|
// lParam long parameter
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
//
|
|
//***************************************************************************
|
|
|
|
LRESULT CALLBACK WndProc(
|
|
IN HWND hWnd,
|
|
IN UINT message,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam)
|
|
{
|
|
|
|
DEBUGTRACE((LOG_WINMGMT,"WindowProc got hWnd=%x, message=%x, wParam=%x, lParam=%x\n",
|
|
hWnd, message, wParam, lParam));
|
|
|
|
switch (message) {
|
|
|
|
case WM_QUERYOPEN: //todo, queryend session
|
|
return 0;
|
|
|
|
case WM_QUERYENDSESSION:
|
|
DEBUGTRACE((LOG_WINMGMT,"Got QueryEndSession\n"));
|
|
return TRUE;
|
|
|
|
case WM_ENDSESSION:
|
|
DEBUGTRACE((LOG_WINMGMT,"Got EndSession\n"));
|
|
if(wParam == TRUE)
|
|
{
|
|
SetEvent(pr.m_hTerminateEvent);
|
|
ShutDownCore(TRUE);
|
|
UpdateTheWin95ServiceList();
|
|
}
|
|
return 0;
|
|
|
|
case WM_DESTROY:
|
|
DEBUGTRACE((LOG_WINMGMT,"Got WM_DESTROY\n"));
|
|
PostQuitMessage(0);
|
|
SetEvent(pr.m_hTerminateEvent);
|
|
break;
|
|
|
|
default:
|
|
return (DefWindowProc(hWnd, message, wParam, lParam));
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// HWND MyCreateWindow
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Registers the window class, creates the window and shows it.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// hInstance app instance handle
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// main window handle, NULL if error.
|
|
//
|
|
//***************************************************************************
|
|
|
|
HWND MyCreateWindow(
|
|
IN HINSTANCE hInstance)
|
|
{
|
|
WNDCLASS wndclass;
|
|
wndclass.style = 0;
|
|
wndclass.lpfnWndProc = WndProc;
|
|
wndclass.cbClsExtra = 0;
|
|
wndclass.cbWndExtra = 0;
|
|
wndclass.hInstance = hInstance;
|
|
wndclass.hIcon = LoadIcon(hInstance, TEXT("WinMgmt"));
|
|
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
|
|
wndclass.lpszMenuName = NULL;
|
|
wndclass.lpszClassName = TEXT("WINMGMTCLASS");
|
|
if(!RegisterClass(&wndclass))
|
|
{
|
|
TRACE((LOG_WINMGMT,"COULD NOT REGISTER THE WINDOW CLASS\n"));
|
|
return NULL;
|
|
}
|
|
HWND hWnd = CreateWindow(TEXT("WINMGMTCLASS"),
|
|
TEXT("WINMGMT"),
|
|
WS_OVERLAPPED | WS_SYSMENU,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
NULL, NULL, hInstance, NULL);
|
|
if(hWnd == NULL)
|
|
{
|
|
TRACE((LOG_WINMGMT,"COULD NOT CREATE THE WINDOW\n"));
|
|
return NULL;
|
|
}
|
|
|
|
// This program is visible only for debug builds.
|
|
|
|
if(gbShowIcon)
|
|
{
|
|
ShowWindow(hWnd,SW_MINIMIZE);
|
|
UpdateWindow(hWnd);
|
|
HMENU hMenu = GetSystemMenu(hWnd, FALSE);
|
|
if(hMenu)
|
|
DeleteMenu(hMenu, SC_RESTORE, MF_BYCOMMAND);
|
|
}
|
|
return hWnd;
|
|
|
|
}
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// bool InitHotMofStuff
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Sets up the hot mof directory and creates an event for it.
|
|
//
|
|
// TRUE if OK.
|
|
//
|
|
//***************************************************************************
|
|
|
|
bool InitHotMofStuff()
|
|
{
|
|
|
|
// Get the installation directory
|
|
|
|
Registry r1(WBEM_REG_WBEM);
|
|
|
|
if (r1.GetStr(__TEXT("MOF Self-Install Directory"), &g_szHotMofDirectory) == Registry::failed)
|
|
{
|
|
// Look for the install directory
|
|
TCHAR * pWorkingDir;
|
|
|
|
if (r1.GetStr(__TEXT("Installation Directory"), &pWorkingDir))
|
|
{
|
|
ERRORTRACE((LOG_WINMGMT,"Unable to read 'Installation Directory' from registry\n"));
|
|
return false;
|
|
}
|
|
|
|
g_szHotMofDirectory = new TCHAR [lstrlen(pWorkingDir) + lstrlen(__TEXT("\\MOF")) +1];
|
|
if(!g_szHotMofDirectory)return false;
|
|
_stprintf(g_szHotMofDirectory, __TEXT("%s\\MOF"), pWorkingDir);
|
|
delete pWorkingDir;
|
|
if(r1.SetStr(__TEXT("MOF Self-Install Directory"), g_szHotMofDirectory) == Registry::failed)
|
|
{
|
|
ERRORTRACE((LOG_WINMGMT,"Unable to create 'Hot MOF Directory' in the registry\n"));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Construct the path to the database.
|
|
// ===================================
|
|
|
|
WbemCreateDirectory(g_szHotMofDirectory);
|
|
|
|
|
|
//Create an event on change notification for the MOF directory
|
|
|
|
ghMofDirChange = FindFirstChangeNotification(g_szHotMofDirectory, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME);
|
|
if (ghMofDirChange == INVALID_HANDLE_VALUE)
|
|
{
|
|
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
|
|
GetCurrentProcess(), &ghMofDirChange,
|
|
0, FALSE, DUPLICATE_SAME_ACCESS);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// GetServicePricipalName
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Used to establish the pricipal name for the kerberos server. This should be
|
|
// domain\machine name and is put into the pPricipal argument.
|
|
//
|
|
//***************************************************************************
|
|
|
|
void GetServicePricipalName(WCHAR * pPrincipal, DWORD dwBuffLen)
|
|
{
|
|
NET_API_STATUS (NET_API_FUNCTION *pGetInfo)(
|
|
IN LMSTR servername OPTIONAL,
|
|
IN DWORD level,
|
|
OUT LPBYTE *bufptr
|
|
);
|
|
|
|
NET_API_STATUS (NET_API_FUNCTION * pFree)(IN LPVOID Buffer);
|
|
|
|
|
|
HINSTANCE hLib = LoadLibrary(__TEXT("netapi32.dll"));
|
|
if(hLib)
|
|
{
|
|
(FARPROC&)pGetInfo = GetProcAddress(hLib, "NetWkstaGetInfo");
|
|
(FARPROC&)pFree = GetProcAddress(hLib, "NetApiBufferFree");
|
|
if(pGetInfo && pFree)
|
|
{
|
|
|
|
LPWKSTA_INFO_100 pBuf = NULL;
|
|
NET_API_STATUS nStatus;
|
|
nStatus = pGetInfo(NULL, 100, (LPBYTE *)&pBuf);
|
|
if (nStatus == NERR_Success)
|
|
{
|
|
DWORD dwLen = wcslen(pBuf->wki100_langroup) + wcslen(pBuf->wki100_computername) + 2;
|
|
if(dwLen <= dwBuffLen)
|
|
{
|
|
wcscpy(pPrincipal, pBuf->wki100_langroup);
|
|
wcscat(pPrincipal, L"\\");
|
|
wcscat(pPrincipal, pBuf->wki100_computername);
|
|
}
|
|
pFree(pBuf);
|
|
}
|
|
}
|
|
FreeLibrary(hLib);
|
|
}
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// BOOL Initialize
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Gets an inproc locator to the gateway, and then loads up each
|
|
// of the transport objects and initializes them.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// pr structure for holding system resources
|
|
// bRunAsApp set to TRUE if not running as a service
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// TRUE if OK.
|
|
//
|
|
//***************************************************************************
|
|
|
|
BOOL Initialize(
|
|
OUT IN PROG_RESOURCES & pr,
|
|
IN BOOL bRunAsApp)
|
|
{
|
|
|
|
// Set the error mode. This is used to provent the system from putting up dialog boxs to
|
|
// open files
|
|
|
|
UINT errormode = SetErrorMode(0);
|
|
errormode |= SEM_NOOPENFILEERRORBOX|SEM_FAILCRITICALERRORS;
|
|
SetErrorMode(errormode);
|
|
RegDisablePredefinedCache(); // special call as per bug wmi 1550
|
|
|
|
|
|
USES_CONVERSION;
|
|
HKEY hKey;
|
|
int iCnt;
|
|
TCHAR tcName[MAX_PATH+1];
|
|
DEBUGTRACE((LOG_WINMGMT,"Starting Initialize, ID = %x\n", GetCurrentProcessId()));
|
|
|
|
if(!InitHotMofStuff())
|
|
return FALSE;
|
|
|
|
ghCoreCanUnload = CreateEvent(NULL,FALSE,FALSE,
|
|
TEXT("WINMGMT_COREDLL_CANSHUTDOWN"));
|
|
|
|
ghProviderCanUnload = CreateEvent(NULL,FALSE,FALSE,
|
|
TEXT("WINMGMT_PROVIDER_CANSHUTDOWN"));
|
|
|
|
ghCoreUnloaded = CreateEvent(NULL,FALSE,FALSE,
|
|
TEXT("WINMGMT_COREDLL_UNLOADED"));
|
|
|
|
ghCoreLoaded = CreateEvent(NULL,FALSE,FALSE,
|
|
TEXT("WINMGMT_COREDLL_LOADED"));
|
|
|
|
// check if this is running a manual service
|
|
|
|
if(IsNT() && bRunAsApp == FALSE)
|
|
{
|
|
SC_HANDLE schService;
|
|
SC_HANDLE schSCManager;
|
|
|
|
schSCManager = OpenSCManager(
|
|
NULL, // machine (NULL == local)
|
|
NULL, // database (NULL == default)
|
|
SC_MANAGER_ALL_ACCESS // access required
|
|
);
|
|
if ( schSCManager )
|
|
{
|
|
schService = OpenService(schSCManager, __TEXT("WinMgmt"), SERVICE_ALL_ACCESS);
|
|
|
|
if (schService)
|
|
{
|
|
DWORD dwNeeded;
|
|
LPQUERY_SERVICE_CONFIG pBuff = NULL;
|
|
long lRet = QueryServiceConfig(
|
|
schService,
|
|
NULL, 0, &dwNeeded);
|
|
lRet = GetLastError();
|
|
if(lRet == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
pBuff = (LPQUERY_SERVICE_CONFIG)new BYTE[dwNeeded];
|
|
lRet = QueryServiceConfig(
|
|
schService,
|
|
pBuff, dwNeeded, &dwNeeded);
|
|
if(pBuff->dwStartType == SERVICE_DEMAND_START)
|
|
gbRunningAsManualService = TRUE;
|
|
|
|
delete pBuff;
|
|
}
|
|
CloseServiceHandle(schService);
|
|
}
|
|
|
|
CloseServiceHandle(schSCManager);
|
|
}
|
|
|
|
}
|
|
|
|
pr.m_hTerminateEvent = CreateEvent(NULL,TRUE,FALSE,
|
|
TEXT("WINMGMT_MARSHALLING_SERVER_TERMINATE"));
|
|
if(pr.m_hTerminateEvent == NULL)
|
|
{
|
|
TRACE((LOG_WINMGMT,"WINMGMT terminating because CreateEvent, last error = 0x%x\n",
|
|
GetLastError()));
|
|
return FALSE;
|
|
}
|
|
|
|
// Make sure there isnt already a copy running.
|
|
|
|
DWORD dwRet;
|
|
|
|
pr.m_hExclusive = CreateMutex( NULL, FALSE, TEXT("WINMGMT_MARSHALLING_SERVER"));
|
|
if(pr.m_hExclusive)
|
|
dwRet = WaitForSingleObject(pr.m_hExclusive, 0);
|
|
if(pr.m_hExclusive == NULL || dwRet != WAIT_OBJECT_0)
|
|
{
|
|
if(pr.m_hExclusive)
|
|
CloseHandle(pr.m_hExclusive);
|
|
pr.m_hExclusive = NULL;
|
|
TRACE((LOG_WINMGMT,"WINMGMT terminating an existing copy was detected\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
ghNeedRegistration = CreateEvent(NULL,TRUE,FALSE, __TEXT("WINMGMT_NEED_REGISTRATION"));
|
|
SetObjectAccess2(ghNeedRegistration);
|
|
ghRegistrationDone = CreateEvent(NULL,TRUE,FALSE, __TEXT("WINMGMT_REGISTRATION_DONE"));
|
|
SetObjectAccess2(ghRegistrationDone);
|
|
|
|
ghLoadCtrEvent = CreateEvent(NULL, FALSE, FALSE, __TEXT("WMI_SysEvent_LodCtr"));
|
|
ghUnloadCtrEvent = CreateEvent(NULL, FALSE, FALSE, __TEXT("WMI_SysEvent_UnLodCtr"));
|
|
|
|
ghHoldOffNewClients = CreateMutex(NULL, FALSE, __TEXT("WINMGMT_KEEP_NEW_CLIENTS_AT_BAY"));
|
|
if(ghHoldOffNewClients == NULL)
|
|
ghHoldOffNewClients = OpenMutex(SYNCHRONIZE, FALSE, __TEXT("WINMGMT_KEEP_NEW_CLIENTS_AT_BAY"));
|
|
|
|
if(ghNeedRegistration == NULL || ghRegistrationDone == NULL ||
|
|
ghLoadCtrEvent == NULL || ghUnloadCtrEvent == NULL ||
|
|
ghHoldOffNewClients == NULL)
|
|
{
|
|
TRACE((LOG_WINMGMT,"WINMGMT couldnt create the sync objects\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
SetObjectAccess2(ghLoadCtrEvent);
|
|
SetObjectAccess2(ghUnloadCtrEvent);
|
|
|
|
// Initialize Ole
|
|
|
|
SCODE sc;
|
|
|
|
sc = InitializeCom();
|
|
if(sc != S_OK)
|
|
{
|
|
TRACE((LOG_WINMGMT,"WINMGMT Could not initialize Ole\n"));
|
|
return FALSE;
|
|
}
|
|
pr.m_bOleInitialized = TRUE;
|
|
|
|
// Initialize server security
|
|
// ==========================
|
|
|
|
if(IsStandAloneWin9X())
|
|
sc = InitializeSecurity(NULL, -1, NULL, NULL,
|
|
RPC_C_AUTHN_LEVEL_NONE,
|
|
RPC_C_IMP_LEVEL_IDENTIFY,
|
|
NULL, EOAC_NONE, 0);
|
|
else if(IsKerberosAvailable())
|
|
{
|
|
// Following is EOAC_STATIC_CLOAKING
|
|
DWORD dwCloaking = 0x20;
|
|
sc = InitializeSecurity(NULL, -1, NULL, NULL,
|
|
RPC_C_AUTHN_LEVEL_CONNECT,
|
|
RPC_C_IMP_LEVEL_IDENTIFY,
|
|
NULL,
|
|
dwCloaking, // Static cloaking. The constant isn't in the current headers
|
|
0);
|
|
}
|
|
else
|
|
sc = InitializeSecurity(NULL, -1, NULL, NULL,
|
|
RPC_C_AUTHN_LEVEL_CONNECT,
|
|
RPC_C_IMP_LEVEL_IDENTIFY,
|
|
NULL,0,0);
|
|
if(FAILED(sc))
|
|
{
|
|
TRACE((LOG_WINMGMT,"WINMGMT Could not initialize security: %X\n", sc));
|
|
}
|
|
else if(sc == S_FALSE)
|
|
{
|
|
DEBUGTRACE((LOG_WINMGMT,"NT 3.51: running without security\n"));
|
|
}
|
|
|
|
DWORD dwFlags = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER;
|
|
if(IsDcomEnabled())
|
|
dwFlags |= CLSCTX_REMOTE_SERVER;
|
|
|
|
pr.m_pLoginFactory = new CForwardFactory(CLSID_InProcWbemLevel1Login);
|
|
pr.m_pLoginFactory->AddRef();
|
|
|
|
sc = CoRegisterClassObject(CLSID_WbemLevel1Login, pr.m_pLoginFactory,
|
|
dwFlags,
|
|
REGCLS_MULTIPLEUSE, &pr.m_dwLoginClsFacReg);
|
|
if(sc != S_OK)
|
|
{
|
|
TRACE((LOG_WINMGMT,"Failed to register the "
|
|
"CLSID_WbemLevel1Login class factory, "
|
|
"sc = 0x%x\n", sc));
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
DEBUGTRACE((LOG_WINMGMT, "Registered class factory with flags: 0x%X\n",
|
|
dwFlags));
|
|
}
|
|
pr.m_pBackupFactory = new CForwardFactory(CLSID_WbemBackupRestore);
|
|
pr.m_pBackupFactory->AddRef();
|
|
|
|
sc = CoRegisterClassObject(CLSID_WbemBackupRestore, pr.m_pBackupFactory,
|
|
dwFlags,
|
|
REGCLS_MULTIPLEUSE, &pr.m_dwBackupClsFacReg);
|
|
if(sc != S_OK)
|
|
{
|
|
TRACE((LOG_WINMGMT,"Failed to register the "
|
|
"Backup/recovery class factory, "
|
|
"sc = 0x%x\n", sc));
|
|
return FALSE;
|
|
}
|
|
|
|
// Get the registry key which is the root for all the transports.
|
|
// ==============================================================
|
|
|
|
long lRet = RegOpenKey(HKEY_LOCAL_MACHINE,
|
|
TEXT("Software\\Microsoft\\WBEM\\CIMOM\\TRANSPORTS"),
|
|
&hKey);
|
|
if(lRet != ERROR_SUCCESS)
|
|
{
|
|
DEBUGTRACE((LOG_WINMGMT,"RegOpenKey returned 0x%x while trying to open the transports node. Using default transports!\n",lRet));
|
|
}
|
|
else
|
|
{
|
|
// Loop through each transport subkey.
|
|
// ===================================
|
|
|
|
for(iCnt = 0;ERROR_SUCCESS == RegEnumKey(hKey,iCnt,tcName,MAX_PATH+1);
|
|
iCnt++)
|
|
{
|
|
HKEY hSubKey;
|
|
lRet = RegOpenKey(hKey,tcName,&hSubKey);
|
|
if(lRet != ERROR_SUCCESS)
|
|
continue;
|
|
DWORD bytecount = sizeof(DWORD);
|
|
DWORD dwType;
|
|
|
|
// If the Enabled value isnt 1, then the transport is disabled
|
|
// and is ignored.
|
|
// ===========================================================
|
|
|
|
char cTemp[20];
|
|
bytecount=20;
|
|
lRet = RegQueryValueEx(hSubKey, TEXT("Enabled"), NULL, &dwType,
|
|
(LPBYTE) cTemp, &bytecount);
|
|
if(lRet != ERROR_SUCCESS || dwType != REG_SZ || cTemp[0] != '1')
|
|
{
|
|
RegCloseKey(hSubKey);
|
|
continue;
|
|
}
|
|
|
|
// Read the CLSID string and convert it into an CLSID structure.
|
|
// =============================================================
|
|
|
|
WCHAR wszCLSID[50];
|
|
char szCLSID[100];
|
|
bytecount = 100;
|
|
lRet = RegQueryValueEx(hSubKey, TEXT("CLSID"), NULL, &dwType,
|
|
(LPBYTE) &szCLSID, &bytecount);
|
|
|
|
RegCloseKey(hSubKey);
|
|
if(lRet != ERROR_SUCCESS)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
CLSID clsid;
|
|
|
|
// Convert to WCS depending on if UNICODE is defined, since
|
|
// the data will be returned as an ANSI or UNICODE string
|
|
#ifndef UNICODE
|
|
wcscpy( wszCLSID, (WCHAR*) szCLSID );
|
|
#else
|
|
mbstowcs( wszCLSID, szCLSID, strlen( szCLSID ) + 1 );
|
|
#endif
|
|
|
|
sc = CLSIDFromString( wszCLSID, &clsid);
|
|
if(sc != S_OK)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Load up the transport object and then initialize it.
|
|
// ====================================================
|
|
|
|
IWbemTransport * pTransport = NULL;
|
|
sc = CoCreateInstance(clsid, 0, CLSCTX_INPROC_SERVER,
|
|
IID_IWbemTransport, (LPVOID *) &pTransport);
|
|
if(sc != S_OK || pTransport == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
sc = pTransport->Initialize();
|
|
if(sc != S_OK)
|
|
pTransport->Release();
|
|
else
|
|
pr.m_Array.Add(pTransport); // add it to the list
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
DEBUGTRACE((LOG_WINMGMT,"Initialize complete\n"));
|
|
|
|
// TO BE REPLACED WITH PROPER CODING --- FORCE CORE
|
|
// ================================================
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// void Cleanup
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Release any currently loaded transports and close Ole etc.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
//***************************************************************************
|
|
|
|
void Cleanup()
|
|
{
|
|
int iCnt;
|
|
|
|
DEBUGTRACE((LOG_WINMGMT,"Starting cleanup, ID = %x\n", GetCurrentProcessId()));
|
|
CoFreeUnusedLibrariesEx ( CORE_PROVIDER_UNLOAD_TIMEOUT , 0 ) ;
|
|
CoFreeUnusedLibrariesEx ( CORE_PROVIDER_UNLOAD_TIMEOUT , 0 ) ;
|
|
|
|
// make sure this is called just once
|
|
|
|
static iNumCalled = 0;
|
|
if(iNumCalled > 0)
|
|
return;
|
|
iNumCalled++;
|
|
|
|
for(iCnt = 0; iCnt < pr.m_Array.Size(); iCnt++)
|
|
{
|
|
IWbemTransport* pCurr = (IWbemTransport *)pr.m_Array.GetAt(iCnt);
|
|
if(pCurr)
|
|
pCurr->Release();
|
|
}
|
|
|
|
if(ghCoreCanUnload)
|
|
CloseHandle(ghCoreCanUnload);
|
|
if(ghProviderCanUnload)
|
|
CloseHandle(ghProviderCanUnload);
|
|
if(ghCoreUnloaded)
|
|
CloseHandle(ghCoreUnloaded);
|
|
if(ghCoreLoaded)
|
|
CloseHandle(ghCoreLoaded);
|
|
|
|
if(ghNeedRegistration)
|
|
CloseHandle(ghNeedRegistration);
|
|
if(ghRegistrationDone)
|
|
CloseHandle(ghRegistrationDone);
|
|
if(ghMofDirChange)
|
|
CloseHandle(ghMofDirChange);
|
|
|
|
if(ghLoadCtrEvent)
|
|
CloseHandle(ghLoadCtrEvent);
|
|
if(ghUnloadCtrEvent)
|
|
CloseHandle(ghUnloadCtrEvent);
|
|
|
|
if(ghHoldOffNewClients)
|
|
CloseHandle(ghHoldOffNewClients);
|
|
|
|
if(pr.m_hTerminateEvent)
|
|
CloseHandle(pr.m_hTerminateEvent);
|
|
if(pr.m_hExclusive)
|
|
{
|
|
ReleaseMutex(pr.m_hExclusive);
|
|
CloseHandle(pr.m_hExclusive);
|
|
}
|
|
|
|
if(g_szHotMofDirectory)
|
|
delete g_szHotMofDirectory;
|
|
|
|
// If the core is still loaded, call its shutdown function
|
|
|
|
ShutDownCore(TRUE);
|
|
|
|
if(pr.m_pLoginFactory) {
|
|
CoRevokeClassObject(pr.m_dwLoginClsFacReg);
|
|
pr.m_pLoginFactory->Release();
|
|
pr.m_pLoginFactory = NULL;
|
|
}
|
|
if(pr.m_pBackupFactory) {
|
|
CoRevokeClassObject(pr.m_dwBackupClsFacReg);
|
|
pr.m_pBackupFactory->Release();
|
|
pr.m_pBackupFactory = NULL;
|
|
}
|
|
|
|
|
|
if(pr.m_bOleInitialized)
|
|
OleUninitialize();
|
|
|
|
if(IsNT() && gbSetToRunAsApp)
|
|
SetToRunAsService();
|
|
|
|
UpdateTheWin95ServiceList();
|
|
if(IsNT())
|
|
RegCloseKey(HKEY_PERFORMANCE_DATA);
|
|
|
|
DEBUGTRACE((LOG_WINMGMT,"Ending cleanup\n"));
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// bool IsValidMulti
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Does a sanity check on a multstring.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// pMultStr Multistring to test.
|
|
// dwSize size of multistring
|
|
//
|
|
// RETURN:
|
|
//
|
|
// true if OK
|
|
//
|
|
//***************************************************************************
|
|
|
|
bool IsValidMulti(TCHAR * pMultStr, DWORD dwSize)
|
|
{
|
|
// Divide the size by the size of a tchar, in case these
|
|
// are Widestrings
|
|
dwSize /= sizeof(TCHAR);
|
|
|
|
if(pMultStr && dwSize >= 2 && pMultStr[dwSize-2]==0 && pMultStr[dwSize-1]==0)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// bool IsStringPresetn
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Searches a multstring for the presense of a string.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// pTest String to look for.
|
|
// pMultStr Multistring to test.
|
|
//
|
|
// RETURN:
|
|
//
|
|
// true if string is found
|
|
//
|
|
//***************************************************************************
|
|
|
|
bool IsStringPresent(TCHAR * pTest, TCHAR * pMultStr)
|
|
{
|
|
TCHAR * pTemp;
|
|
for(pTemp = pMultStr; *pTemp; pTemp += lstrlen(pTemp) + 1)
|
|
if(!lstrcmpi(pTest, pTemp))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// void AddToAutoRecoverList
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Adds the file to the autocompile list, if it isnt already on it.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// pFileName File to add
|
|
//
|
|
//***************************************************************************
|
|
|
|
void AddToAutoRecoverList(TCHAR * pFileName)
|
|
{
|
|
TCHAR cFullFileName[MAX_PATH+1];
|
|
TCHAR * lpFile;
|
|
DWORD dwSize;
|
|
TCHAR * pNew = NULL;
|
|
TCHAR * pTest;
|
|
DWORD dwNewSize = 0;
|
|
|
|
// Get the full file name
|
|
|
|
long lRet = GetFullPathName(pFileName, MAX_PATH, cFullFileName, &lpFile);
|
|
if(lRet == 0)
|
|
return;
|
|
|
|
bool bFound = false;
|
|
Registry r(WBEM_REG_WINMGMT);
|
|
TCHAR *pMulti = r.GetMultiStr(__TEXT("Autorecover MOFs"), dwSize);
|
|
|
|
// Ignore the empty string case
|
|
|
|
if(dwSize == 1)
|
|
{
|
|
delete pMulti;
|
|
pMulti = NULL;
|
|
}
|
|
if(pMulti)
|
|
{
|
|
if(!IsValidMulti(pMulti, dwSize))
|
|
{
|
|
delete pMulti;
|
|
return; // bail out, messed up multistring
|
|
}
|
|
bFound = IsStringPresent(cFullFileName, pMulti);
|
|
if(!bFound)
|
|
{
|
|
|
|
// The registry entry does exist, but doesnt have this name
|
|
// Make a new multistring with the file name at the end
|
|
|
|
dwNewSize = dwSize + ((lstrlen(cFullFileName) + 1) * sizeof(TCHAR));
|
|
pNew = new TCHAR[dwNewSize / sizeof(TCHAR)];
|
|
if(!pNew)
|
|
return;
|
|
memcpy(pNew, pMulti, dwSize);
|
|
|
|
// Find the double null
|
|
|
|
for(pTest = pNew; pTest[0] || pTest[1]; pTest++); // intentional semi
|
|
|
|
// Tack on the path and ensure a double null;
|
|
|
|
pTest++;
|
|
lstrcpy(pTest, cFullFileName);
|
|
pTest+= lstrlen(cFullFileName)+1;
|
|
*pTest = 0; // add second numm
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The registry entry just doesnt exist. Create it with a value equal to our name
|
|
|
|
dwNewSize = ((lstrlen(cFullFileName) + 2) * sizeof(TCHAR));
|
|
pNew = new TCHAR[dwNewSize / sizeof(TCHAR)];
|
|
if(!pNew)
|
|
return;
|
|
lstrcpy(pNew, cFullFileName);
|
|
pTest = pNew + lstrlen(pNew) + 1;
|
|
*pTest = 0; // add second null
|
|
}
|
|
|
|
if(pNew)
|
|
{
|
|
// We will cast pNew, since the underlying function will have to cast to
|
|
// LPBYTE and we will be WCHAR if UNICODE is defined
|
|
r.SetMultiStr(__TEXT("Autorecover MOFs"), pNew, dwNewSize);
|
|
delete pNew;
|
|
}
|
|
|
|
FILETIME ftCurTime;
|
|
LARGE_INTEGER liCurTime;
|
|
TCHAR szBuff[50];
|
|
GetSystemTimeAsFileTime(&ftCurTime);
|
|
liCurTime.LowPart = ftCurTime.dwLowDateTime;
|
|
liCurTime.HighPart = ftCurTime.dwHighDateTime;
|
|
_ui64tot(liCurTime.QuadPart, szBuff, 10);
|
|
r.SetStr(__TEXT("Autorecover MOFs timestamp"), szBuff);
|
|
|
|
}
|
|
|
|
HRESULT GetRepPath(wchar_t wcsPath[MAX_PATH+1], wchar_t * wcsName)
|
|
{
|
|
HKEY hKey;
|
|
long lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
L"SOFTWARE\\Microsoft\\WBEM\\CIMOM",
|
|
0, KEY_READ, &hKey);
|
|
if(lRes)
|
|
return WBEM_E_FAILED;
|
|
|
|
wchar_t wszTmp[MAX_PATH+1];
|
|
DWORD dwLen = MAX_PATH+1;
|
|
lRes = RegQueryValueExW(hKey, L"Repository Directory", NULL, NULL,
|
|
(LPBYTE)(wchar_t*)wszTmp, &dwLen);
|
|
RegCloseKey(hKey);
|
|
if(lRes)
|
|
return WBEM_E_FAILED;
|
|
|
|
if (ExpandEnvironmentStringsW(wszTmp, wcsPath, MAX_PATH+1) == 0)
|
|
return WBEM_E_FAILED;
|
|
|
|
if (wcsPath[wcslen(wcsPath)] != L'\\')
|
|
wcscat(wcsPath, L"\\");
|
|
|
|
wcscat(wcsPath, wcsName);
|
|
|
|
return WBEM_S_NO_ERROR;
|
|
|
|
}
|
|
|
|
int DoBackup()
|
|
{
|
|
int hr = WBEM_S_NO_ERROR;
|
|
|
|
//*************************************************
|
|
// Split up command line and validate parameters
|
|
//*************************************************
|
|
wchar_t *wszCommandLine = GetCommandLineW();
|
|
if (wszCommandLine == NULL)
|
|
{
|
|
DisplayWbemError(hr, ID_ERROR_LONG, ID_ERROR_SHORT, ID_BACKUP_TITLE);
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
|
|
|
|
// !!!!! ***** temporarily disabled until SVCHOST changes are checked in ***** !!!!!
|
|
hr = WBEM_E_NOT_SUPPORTED;
|
|
DisplayWbemError(hr, ID_ERROR_LONG, ID_ERROR_SHORT, ID_BACKUP_TITLE);
|
|
|
|
|
|
|
|
int nNumArgs = 0;
|
|
wchar_t **wszCommandLineArgv = NULL;
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
wszCommandLineArgv = CommandLineToArgvW(wszCommandLine, &nNumArgs);
|
|
|
|
if ((wszCommandLineArgv == NULL) || (nNumArgs != 3))
|
|
{
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
DisplayMessage();
|
|
}
|
|
}
|
|
|
|
//wszCommandLineArgv[0] = winmgmt.exe
|
|
//wszCommandLineArgv[1] = /backup
|
|
//wszCommandLineArgv[2] = <backup filename>
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
InitializeCom();
|
|
IWbemBackupRestore* pBackupRestore = NULL;
|
|
hr = CoCreateInstance(CLSID_WbemBackupRestore, 0, CLSCTX_LOCAL_SERVER,
|
|
IID_IWbemBackupRestore, (LPVOID *) &pBackupRestore);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
EnableAllPrivileges(TOKEN_PROCESS);
|
|
hr = pBackupRestore->Backup(wszCommandLineArgv[2], 0);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DisplayWbemError(hr, ID_ERROR_LONG, ID_ERROR_SHORT, ID_BACKUP_TITLE);
|
|
hr = WBEM_E_FAILED;
|
|
}
|
|
|
|
pBackupRestore->Release();
|
|
}
|
|
CoUninitialize();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
int DoRestore()
|
|
{
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
//*************************************************
|
|
// Split up command line and validate parameters
|
|
//*************************************************
|
|
wchar_t *wszCommandLine = GetCommandLineW();
|
|
if (wszCommandLine == NULL)
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
|
|
// !!!!! ***** temporarily disabled until SVCHOST changes are checked in ***** !!!!!
|
|
hr = WBEM_E_NOT_SUPPORTED;
|
|
DisplayWbemError(hr, ID_ERROR_LONG, ID_ERROR_SHORT, ID_BACKUP_TITLE);
|
|
|
|
|
|
|
|
|
|
int nNumArgs = 0;
|
|
wchar_t **wszCommandLineArgv = NULL;
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
wszCommandLineArgv = CommandLineToArgvW(wszCommandLine, &nNumArgs);
|
|
|
|
if ((wszCommandLineArgv == NULL) || (nNumArgs != 4))
|
|
{
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
//wszCommandLineArgv[0] = winmgmt.exe
|
|
//wszCommandLineArgv[1] = /restore
|
|
//wszCommandLineArgv[2] = <restore filename>
|
|
//wszcommandLineArgv[3] = <restore options>
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if ((wcscmp(wszCommandLineArgv[3], L"0") != 0) &&
|
|
(wcscmp(wszCommandLineArgv[3], L"1") != 0))
|
|
{
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
long lFlags = 0;
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
lFlags = (long) (*wszCommandLineArgv[3] - L'0');
|
|
}
|
|
|
|
//**************************************************
|
|
// Check that the user has the proper security
|
|
//**************************************************
|
|
// if (SUCCEEDED(hr))
|
|
// {
|
|
// EnableAllPrivileges(TOKEN_PROCESS);
|
|
// if(!CheckSecurity(SE_RESTORE_NAME))
|
|
// hr = WBEM_E_ACCESS_DENIED;
|
|
// }
|
|
|
|
//**************************************************
|
|
// Check that <restore filename> is a valid filename
|
|
//**************************************************
|
|
DWORD dwAttributes = 0;
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
dwAttributes = GetFileAttributesW(wszCommandLineArgv[2]);
|
|
if (dwAttributes == -1)
|
|
{
|
|
//File does not exist...
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
// The file already exists -- create mask of the attributes that would make an existing file invalid for use
|
|
DWORD dwMask = FILE_ATTRIBUTE_DEVICE |
|
|
FILE_ATTRIBUTE_DIRECTORY |
|
|
FILE_ATTRIBUTE_OFFLINE |
|
|
FILE_ATTRIBUTE_REPARSE_POINT |
|
|
FILE_ATTRIBUTE_SPARSE_FILE;
|
|
|
|
if (dwAttributes & dwMask)
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
//**************************************************
|
|
// Shutdown main WinMgmt process if it is running
|
|
// and make sure it does not start up while we are
|
|
// preparing to restore...
|
|
//**************************************************
|
|
bool bShutdown = false;
|
|
int nRetryCount = 20;
|
|
HANDLE hExclusiveMutex = 0;
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
while (!bShutdown && nRetryCount--)
|
|
{
|
|
hExclusiveMutex = CreateMutex( NULL, FALSE, TEXT("WINMGMT_MARSHALLING_SERVER"));
|
|
DWORD dwWait;
|
|
if (hExclusiveMutex != 0)
|
|
dwWait = WaitForSingleObject(hExclusiveMutex, 0);
|
|
if(hExclusiveMutex == NULL || ( dwWait != WAIT_OBJECT_0))
|
|
{
|
|
if(hExclusiveMutex)
|
|
CloseHandle(hExclusiveMutex);
|
|
if (lFlags & WBEM_FLAG_BACKUP_RESTORE_FORCE_SHUTDOWN)
|
|
{
|
|
TerminateRunning();
|
|
Sleep(3000);
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_BACKUP_RESTORE_WINMGMT_RUNNING;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
bShutdown = true;
|
|
}
|
|
|
|
if (!nRetryCount && !bShutdown)
|
|
hr = WBEM_E_TIMED_OUT;
|
|
}
|
|
|
|
//**************************************************
|
|
//Now we need to delete the existing database
|
|
//**************************************************
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = DoDeleteRepository(wszCommandLineArgv[2]);
|
|
}
|
|
|
|
//**************************************************
|
|
//Now we need to copy over the <restore file> into
|
|
//the repository directory
|
|
//**************************************************
|
|
wchar_t szRecoveryActual[MAX_PATH+1] = { 0 };
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = GetRepPath(szRecoveryActual, L"repdrvfs.rec");
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if(_wcsicmp(szRecoveryActual, wszCommandLineArgv[2]))
|
|
{
|
|
DeleteFileW(szRecoveryActual);
|
|
CopyFileW(wszCommandLineArgv[2], szRecoveryActual, FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
//**************************************************
|
|
//We need to release the exclusive mutex so that
|
|
//we can successfully connect to winmgmt
|
|
//**************************************************
|
|
if (hExclusiveMutex)
|
|
CloseHandle(hExclusiveMutex);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//**************************************************
|
|
//Connecting to winmgmt will now result in this
|
|
//backup file getting loaded
|
|
//**************************************************
|
|
InitializeCom();
|
|
|
|
{ //Scoping for destruction of COM objects before CoUninitialize!
|
|
IWbemLocator *pLocator = NULL;
|
|
hr = CoCreateInstance(CLSID_WbemLocator,NULL, CLSCTX_ALL, IID_IWbemLocator,(void**)&pLocator);
|
|
CReleaseMe relMe(pLocator);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IWbemServices *pNamespace = NULL;
|
|
BSTR tmpStr = SysAllocString(L"root");
|
|
CSysFreeMe sysFreeMe(tmpStr);
|
|
|
|
hr = pLocator->ConnectServer(tmpStr, NULL, NULL, NULL, NULL, NULL, NULL, &pNamespace);
|
|
CReleaseMe relMe4(pNamespace);
|
|
}
|
|
}
|
|
|
|
CoUninitialize();
|
|
}
|
|
|
|
//Delete the restore file
|
|
if (*szRecoveryActual)
|
|
DeleteFileW(szRecoveryActual);
|
|
|
|
//**************************************************
|
|
//All done!
|
|
//**************************************************
|
|
return hr;
|
|
}
|
|
|
|
void DisplayWbemError(HRESULT hresError, DWORD dwLongFormatString, DWORD dwShortFormatString, DWORD dwTitle)
|
|
{
|
|
WCHAR szError[2096];
|
|
szError[0] = 0;
|
|
WCHAR szFacility[2096];
|
|
szFacility[0] = 0;
|
|
TCHAR szMsg[2096];
|
|
TCHAR szFormat[100];
|
|
TCHAR szTitle[100];
|
|
IWbemStatusCodeText * pStatus = NULL;
|
|
|
|
SCODE sc = CoCreateInstance(CLSID_WbemStatusCodeText, 0, CLSCTX_INPROC_SERVER,
|
|
IID_IWbemStatusCodeText, (LPVOID *) &pStatus);
|
|
|
|
if(sc == S_OK)
|
|
{
|
|
BSTR bstr = 0;
|
|
sc = pStatus->GetErrorCodeText(hresError, 0, 0, &bstr);
|
|
if(sc == S_OK)
|
|
{
|
|
wcsncpy(szError, bstr, 2096-1);
|
|
SysFreeString(bstr);
|
|
bstr = 0;
|
|
}
|
|
sc = pStatus->GetFacilityCodeText(hresError, 0, 0, &bstr);
|
|
if(sc == S_OK)
|
|
{
|
|
wcsncpy(szFacility, bstr, 2096-1);
|
|
SysFreeString(bstr);
|
|
bstr = 0;
|
|
}
|
|
pStatus->Release();
|
|
}
|
|
if(wcslen(szFacility) == 0 || wcslen(szError) == 0)
|
|
{
|
|
LoadString(GetModuleHandle(NULL), dwShortFormatString, szFormat, 99);
|
|
_stprintf(szMsg, szFormat, hresError);
|
|
}
|
|
else
|
|
{
|
|
LoadString(GetModuleHandle(NULL), dwLongFormatString, szFormat, 99);
|
|
_stprintf(szMsg, szFormat, hresError, szFacility, szError);
|
|
}
|
|
|
|
LoadString(GetModuleHandle(NULL), dwTitle, szTitle, 99);
|
|
MessageBox(0, szMsg, szTitle, MB_ICONERROR | MB_OK);
|
|
}
|
|
|
|
void DoResyncPerf()
|
|
{
|
|
PROCESS_INFORMATION pi;
|
|
STARTUPINFO si;
|
|
memset(&si, 0, sizeof(si));
|
|
si.cb = sizeof(si);
|
|
// make a writable buffer
|
|
TCHAR pExecName[(1+sizeof(_T("WMIADAP.EXE /F")))/sizeof(TCHAR)];
|
|
lstrcpy(pExecName,_T("WMIADAP.EXE /F"));
|
|
|
|
if ( CreateProcess( NULL, pExecName, NULL, NULL, FALSE, CREATE_NO_WINDOW,
|
|
NULL, NULL, &si, &pi ) )
|
|
{
|
|
// Cleanup handles right away
|
|
// ==========================
|
|
CloseHandle( pi.hThread );
|
|
CloseHandle( pi.hProcess );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void DoClearAdap()
|
|
{
|
|
PROCESS_INFORMATION pi;
|
|
STARTUPINFO si;
|
|
memset(&si, 0, sizeof(si));
|
|
si.cb = sizeof(si);
|
|
// make a writable buffer
|
|
TCHAR pExecName[(1+sizeof(_T("WMIADAP.EXE /C")))/sizeof(TCHAR)];
|
|
lstrcpy(pExecName,_T("WMIADAP.EXE /C"));
|
|
|
|
if ( CreateProcess( NULL, pExecName, NULL, NULL, FALSE, CREATE_NO_WINDOW,
|
|
NULL, NULL, &si, &pi) )
|
|
{
|
|
// Cleanup handles right away
|
|
// ==========================
|
|
CloseHandle( pi.hThread );
|
|
CloseHandle( pi.hProcess );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* GetRepositoryDirectory
|
|
*
|
|
* Description:
|
|
* Retrieves the location of the repository directory from the registry.
|
|
*
|
|
* Parameters:
|
|
* wszRepositoryDirectory: Array to store location in.
|
|
*
|
|
* Return:
|
|
* HRESULT: WBEM_S_NO_ERROR If successful
|
|
* WBEM_E_OUT_OF_MEMORY If out of memory
|
|
* WBEM_E_FAILED If anything else failed
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
HRESULT GetRepositoryDirectory(wchar_t wszRepositoryDirectory[MAX_PATH+1])
|
|
{
|
|
HKEY hKey;
|
|
long lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
L"SOFTWARE\\Microsoft\\WBEM\\CIMOM",
|
|
0, KEY_READ, &hKey);
|
|
if(lRes)
|
|
return WBEM_E_FAILED;
|
|
|
|
wchar_t wszTmp[MAX_PATH + 1];
|
|
DWORD dwLen = MAX_PATH + 1;
|
|
lRes = RegQueryValueExW(hKey, L"Repository Directory", NULL, NULL,
|
|
(LPBYTE)wszTmp, &dwLen);
|
|
RegCloseKey(hKey);
|
|
if(lRes)
|
|
return WBEM_E_FAILED;
|
|
|
|
if (ExpandEnvironmentStringsW(wszTmp,wszRepositoryDirectory, MAX_PATH + 1) == 0)
|
|
return WBEM_E_FAILED;
|
|
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* CRepositoryPackager::DeleteRepository
|
|
*
|
|
* Description:
|
|
* Delete all files and directories under the repository directory.
|
|
* The repository directory location is retrieved from the registry.
|
|
*
|
|
* Parameters:
|
|
* <none>
|
|
*
|
|
* Return:
|
|
* HRESULT: WBEM_S_NO_ERROR If successful
|
|
* WBEM_E_OUT_OF_MEMORY If out of memory
|
|
* WBEM_E_FAILED If anything else failed
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
HRESULT DoDeleteRepository(const wchar_t *wszExcludeFile)
|
|
{
|
|
HRESULT hres = WBEM_S_NO_ERROR;
|
|
wchar_t wszRepositoryDirectory[MAX_PATH+1];
|
|
|
|
//Get the root directory of the repository
|
|
hres = GetRepositoryDirectory(wszRepositoryDirectory);
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = DoDeleteContentsOfDirectory(wszExcludeFile, wszRepositoryDirectory);
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* DoDeleteContentsOfDirectory
|
|
*
|
|
* Description:
|
|
* Given a directory, iterates through all files and directories and
|
|
* calls into the function to delete it.
|
|
*
|
|
* Parameters:
|
|
* wszRepositoryDirectory: Directory to process
|
|
*
|
|
* Return:
|
|
* HRESULT: WBEM_S_NO_ERROR If successful
|
|
* WBEM_E_OUT_OF_MEMORY If out of memory
|
|
* WBEM_E_FAILED If anything else failed
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
HRESULT DoDeleteContentsOfDirectory(const wchar_t *wszExcludeFile, const wchar_t *wszRepositoryDirectory)
|
|
{
|
|
HRESULT hres = WBEM_S_NO_ERROR;
|
|
|
|
wchar_t *wszFullFileName = new wchar_t[MAX_PATH+1];
|
|
if (wszFullFileName == NULL)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
|
|
WIN32_FIND_DATAW findFileData;
|
|
HANDLE hff = INVALID_HANDLE_VALUE;
|
|
|
|
//create file search pattern...
|
|
wchar_t *wszSearchPattern = new wchar_t[MAX_PATH+1];
|
|
if (wszSearchPattern == NULL)
|
|
hres = WBEM_E_OUT_OF_MEMORY;
|
|
else
|
|
{
|
|
wcscpy(wszSearchPattern, wszRepositoryDirectory);
|
|
wcscat(wszSearchPattern, L"\\*");
|
|
}
|
|
|
|
//Start the file iteration in this directory...
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hff = FindFirstFileW(wszSearchPattern, &findFileData);
|
|
if (hff == INVALID_HANDLE_VALUE)
|
|
{
|
|
hres = WBEM_E_FAILED;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
do
|
|
{
|
|
//If we have a filename of '.' or '..' we ignore it...
|
|
if ((wcscmp(findFileData.cFileName, L".") == 0) ||
|
|
(wcscmp(findFileData.cFileName, L"..") == 0))
|
|
{
|
|
//Do nothing with these...
|
|
}
|
|
else if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
{
|
|
//This is a directory, so we need to deal with that...
|
|
hres = DoDeleteDirectory(wszExcludeFile, wszRepositoryDirectory, findFileData.cFileName);
|
|
if (FAILED(hres))
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
//This is a file, so we need to deal with that...
|
|
wcscpy(wszFullFileName, wszRepositoryDirectory);
|
|
wcscat(wszFullFileName, L"\\");
|
|
wcscat(wszFullFileName, findFileData.cFileName);
|
|
|
|
//Make sure this is not the excluded filename...
|
|
if (_wcsicmp(wszFullFileName, wszExcludeFile) != 0)
|
|
{
|
|
if (!DeleteFileW(wszFullFileName))
|
|
{
|
|
hres = WBEM_E_FAILED;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
} while (FindNextFileW(hff, &findFileData));
|
|
}
|
|
|
|
if (wszSearchPattern)
|
|
delete [] wszSearchPattern;
|
|
|
|
if (hff != INVALID_HANDLE_VALUE)
|
|
FindClose(hff);
|
|
|
|
return hres;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* DoDeleteDirectory
|
|
*
|
|
* Description:
|
|
* This is the code which processes a directory. It iterates through
|
|
* all files and directories in that directory.
|
|
*
|
|
* Parameters:
|
|
* wszParentDirectory: Full path of parent directory
|
|
* eszSubDirectory: Name of sub-directory to process
|
|
*
|
|
* Return:
|
|
* HRESULT: WBEM_S_NO_ERROR If successful
|
|
* WBEM_E_OUT_OF_MEMORY If out of memory
|
|
* WBEM_E_FAILED If anything else failed
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
HRESULT DoDeleteDirectory(const wchar_t *wszExcludeFile, const wchar_t *wszParentDirectory, wchar_t *wszSubDirectory)
|
|
{
|
|
HRESULT hres = WBEM_S_NO_ERROR;
|
|
|
|
//Get full path of new directory...
|
|
wchar_t *wszFullDirectoryName = NULL;
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
wszFullDirectoryName = new wchar_t[MAX_PATH+1];
|
|
if (wszFullDirectoryName == NULL)
|
|
hres = WBEM_E_OUT_OF_MEMORY;
|
|
else
|
|
{
|
|
wcscpy(wszFullDirectoryName, wszParentDirectory);
|
|
wcscat(wszFullDirectoryName, L"\\");
|
|
wcscat(wszFullDirectoryName, wszSubDirectory);
|
|
}
|
|
}
|
|
|
|
//Package the contents of that directory...
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = DoDeleteContentsOfDirectory(wszExcludeFile, wszFullDirectoryName);
|
|
}
|
|
|
|
// now that the directory is empty, remove it
|
|
if (!RemoveDirectoryW(wszFullDirectoryName))
|
|
{ //If a remove directory fails, it may be because our excluded file is in it!
|
|
// hres = WBEM_E_FAILED;
|
|
}
|
|
|
|
delete [] wszFullDirectoryName;
|
|
|
|
return hres;
|
|
}
|