windows-nt/Source/XPSP1/NT/admin/wmi/wbem/winmgmt/winmgmt2/mofdutil.cpp
2020-09-26 16:20:57 +08:00

835 lines
22 KiB
C++

#include "precomp.h"
#include <tchar.h>
#include <malloc.h>
#include <mofcomp.h> // for AUTORECOVERY_REQUIRED
#include "winmgmt.h" // this project
#include "arrtempl.h" // for CDeleteMe
//
//
// CheckNoResyncSwitch
//
//////////////////////////////////////////////////////////////////
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;
}
//
//
// CheckNoResyncSwitch
//
//////////////////////////////////////////////////////////////////
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;
}
//
//
// CheckGlobalSetupSwitch
//
//////////////////////////////////////////////////////////////////
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() ) );
}
}
//
//
// bool IsValidMulti
//
//
// Does a sanity check on a multstring.
//
//////////////////////////////////////////////////////////////////////
BOOL IsValidMulti(TCHAR * pMultStr, DWORD dwSize)
{
// Divide the size by the size of a tchar, in case these
// are WCHAR strings
dwSize /= sizeof(TCHAR);
if(pMultStr && dwSize >= 2 && pMultStr[dwSize-2]==0 && pMultStr[dwSize-1]==0)
return TRUE;
return FALSE;
}
//
//
// BOOL IsStringPresetn
//
//
// Searches a multstring for the presense of a string.
//
//
////////////////////////////////////////////////////////////////////
BOOL IsStringPresent(TCHAR * pTest, TCHAR * pMultStr)
{
TCHAR * pTemp;
for(pTemp = pMultStr; *pTemp; pTemp += lstrlen(pTemp) + 1)
if(!lstrcmpi(pTest, pTemp))
return TRUE;
return FALSE;
}
//
//
// AddToAutoRecoverList
//
//
////////////////////////////////////////////////////////////////////
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);
}
//
// LoadMofsInDirectory
//
//
////////////////////////////////////////////////////////////////////////////////////////
void LoadMofsInDirectory(const TCHAR *szDirectory)
{
if (NULL == szDirectory)
return;
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
if(szFullFilename)
{
if (pCompiler == 0)
{
SCODE sc = CoCreateInstance(CLSID_WinmgmtMofCompiler,
0,
CLSCTX_INPROC_SERVER,
IID_IWinmgmtMofCompiler,
(LPVOID *) &pCompiler);
if(sc != S_OK)
return;
}
dwRetCode = pCompiler->WinmgmtCompileFile(
szFullFilename,
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();
}
//
//
// bool InitHotMofStuff
//
//
//////////////////////////////////////////////////////////////////
BOOL InitHotMofStuff( IN OUT struct _PROG_RESOURCES * pProgRes)
{
// Get the installation directory
if (pProgRes->szHotMofDirectory)
{
delete [] pProgRes->szHotMofDirectory;
}
Registry r1(WBEM_REG_WBEM);
if (r1.GetStr(__TEXT("MOF Self-Install Directory"), &pProgRes->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;
}
pProgRes->szHotMofDirectory = new TCHAR [lstrlen(pWorkingDir) + lstrlen(__TEXT("\\MOF")) +1];
if(!pProgRes->szHotMofDirectory)return false;
_stprintf(pProgRes->szHotMofDirectory, __TEXT("%s\\MOF"), pWorkingDir);
delete pWorkingDir;
if(r1.SetStr(__TEXT("MOF Self-Install Directory"), pProgRes->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(pProgRes->szHotMofDirectory);
//Create an event on change notification for the MOF directory
pProgRes->ghMofDirChange = FindFirstChangeNotification(pProgRes->szHotMofDirectory,
FALSE,
FILE_NOTIFY_CHANGE_FILE_NAME);
if (pProgRes->ghMofDirChange == INVALID_HANDLE_VALUE)
{
pProgRes->ghMofDirChange = CreateEvent(NULL, FALSE, FALSE, NULL);
if (pProgRes->ghMofDirChange == NULL)
return false;
}
return true;
}
DWORD
BuildSD( OUT PSECURITY_DESCRIPTOR *ppSD,
DWORD dwSids,
PSID * ArraySids,
DWORD AccessType)
{
BOOL Status;
ULONG SDLength;
PACL pEventDacl = NULL;
PSECURITY_DESCRIPTOR pEventSD = NULL;
ULONG ulWorldAccess = 0;
ULONG ulAdminAccess = 0;
if (!ppSD)
{
return ERROR_INVALID_PARAMETER;
}
DWORD i;
DWORD dwLenSids = 0;
for (i=0;i<dwSids;i++)
{
dwLenSids += GetLengthSid(ArraySids[i]);
}
SDLength = sizeof(SECURITY_DESCRIPTOR) +
(ULONG) sizeof(ACL) +
(dwSids * ((ULONG) sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG))) + dwLenSids;
pEventSD = (PSECURITY_DESCRIPTOR) HeapAlloc(GetProcessHeap(),0,SDLength);
if (pEventSD == NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
pEventDacl = (PACL) ((PBYTE) pEventSD + sizeof(SECURITY_DESCRIPTOR));
Status = InitializeAcl( pEventDacl,
SDLength - sizeof(SECURITY_DESCRIPTOR),
ACL_REVISION);
if (Status)
{
for (i=0; (i<dwSids) && Status; i++)
{
Status = AddAccessAllowedAce (
pEventDacl,
ACL_REVISION,
AccessType,
ArraySids[i]);
}
}
//
// Now initialize security descriptors
// that export this protection
//
if (Status)
{
Status = InitializeSecurityDescriptor(pEventSD,
SECURITY_DESCRIPTOR_REVISION1);
if (Status)
{
Status = SetSecurityDescriptorDacl(
pEventSD,
TRUE, // DaclPresent
pEventDacl,
FALSE); // DaclDefaulted
}
}
if (Status)
{
*ppSD = pEventSD;
return NO_ERROR;
}
else
{
HeapFree(GetProcessHeap(),0,pEventSD);
return GetLastError();
}
}
BOOL
SetEventDacl(HANDLE hEvent,DWORD Permission){
BOOL bRet = FALSE;
PSID pSidLocalSvc = NULL;
SID_IDENTIFIER_AUTHORITY id = SECURITY_NT_AUTHORITY;
bRet = AllocateAndInitializeSid( &id, 1,
SECURITY_LOCAL_SERVICE_RID,0,0,0,0,0,0,0,&pSidLocalSvc);
PSID pSidSystem = NULL;
SID_IDENTIFIER_AUTHORITY id2 = SECURITY_NT_AUTHORITY;
if (bRet)
{
bRet = AllocateAndInitializeSid( &id2, 1,
SECURITY_LOCAL_SYSTEM_RID,0,0,0,0,0,0,0,&pSidSystem);
};
PSID pSidAdmins = NULL;
SID_IDENTIFIER_AUTHORITY id3 = SECURITY_NT_AUTHORITY;
if (bRet)
{
bRet = AllocateAndInitializeSid( &id3, 2,
SECURITY_BUILTIN_DOMAIN_RID,DOMAIN_ALIAS_RID_ADMINS,0,0,0,0,0,0,&pSidAdmins);
};
PSID ArraySid[] = {pSidLocalSvc,pSidSystem,pSidAdmins};
if (bRet)
{
PSECURITY_DESCRIPTOR pSD = NULL;
if (NO_ERROR == BuildSD(&pSD,sizeof(ArraySid)/sizeof(PSID),ArraySid,Permission))
{
bRet = SetKernelObjectSecurity(hEvent,
DACL_SECURITY_INFORMATION,
pSD);
HeapFree(GetProcessHeap(),0,pSD);
}
}
DWORD i;
for (i=0;i<sizeof(ArraySid)/sizeof(PSID);i++)
{
if (ArraySid[i])
{
FreeSid(ArraySid[i]);
}
}
return bRet;
}
DWORD
BuildACL( DWORD dwSids,
PSID * ArraySids,
DWORD * AccessType,
DWORD * Flags,
OUT PACL * ppACL,
OUT DWORD * nBytes)
{
BOOL Status;
ULONG ACLLength;
PACL pDacl = NULL;
ULONG ulWorldAccess = 0;
ULONG ulAdminAccess = 0;
if (!ppACL)
{
return ERROR_INVALID_PARAMETER;
}
DWORD i;
DWORD dwLenSids = 0;
for (i=0;i<dwSids;i++)
{
dwLenSids += GetLengthSid(ArraySids[i]);
}
ACLLength = (ULONG) sizeof(ACL) +
(dwSids * ((ULONG) sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG))) + dwLenSids;
pDacl = (PACL) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,ACLLength);
if (pDacl == NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
Status = InitializeAcl( pDacl,
ACLLength,
ACL_REVISION);
if (Status)
{
for (i=0; (i<dwSids) && Status; i++)
{
Status = AddAccessAllowedAceEx (
pDacl,
ACL_REVISION,
Flags[i],
AccessType[i],
ArraySids[i]);
}
}
if (Status)
{
*ppACL = pDacl;
return NO_ERROR;
}
else
{
HeapFree(GetProcessHeap(),0,pDacl);
return GetLastError();
}
}
/*BOOL
AddAccountToDacl(HANDLE hToken,
BYTE SubCount,
DWORD dw0,
DWORD dw1,
DWORD dw2,
DWORD dw3,
DWORD dw4,
DWORD dw5,
DWORD dw6,
DWORD dw7,
DWORD dwAccess,
DWORD AceFlag){
BOOL bRet = FALSE;
DWORD i;
PSID pSidAccount = NULL;
SID_IDENTIFIER_AUTHORITY id = SECURITY_NT_AUTHORITY;
bRet = AllocateAndInitializeSid( &id, SubCount,
dw0,dw1,dw2,dw3,dw4,dw5,dw6,dw7,&pSidAccount);
//
//
//
PACL pDacl;
if (bRet)
{
DWORD dwReq = 0;
bRet = GetTokenInformation(hToken,
TokenDefaultDacl,
NULL,
0,
&dwReq);
if ((FALSE == bRet) &&
(ERROR_INSUFFICIENT_BUFFER == GetLastError()))
{
TOKEN_DEFAULT_DACL * pTDD = (TOKEN_DEFAULT_DACL *)_alloca(dwReq+sizeof(void*));
bRet = GetTokenInformation(hToken,
TokenDefaultDacl,
pTDD,
dwReq,
&dwReq);
pDacl = pTDD->DefaultDacl;
}
}
if (!bRet)
{
return FALSE;
}
IVAN, if you plan to use this, please make sure that pDacl is
initialized in all cases. There was a prefix bug on this
WORD Count = pDacl->AceCount;
PSID * ArraySid = (PSID *)_alloca((Count+1)*sizeof(PSID));
DWORD * Access = (DWORD *)_alloca((Count+1)*sizeof(DWORD));
DWORD * AceFlags = (DWORD *)_alloca((Count+1)*sizeof(DWORD));
for(i=0;i<Count;i++)
{
ACCESS_ALLOWED_ACE * pAce;
if (GetAce(pDacl,i,(PVOID *)&pAce))
{
PSID pSid;
AllocateAndInitializeSid(&id,8,0,0,0,0,0,0,0,0,&pSid);
CopySid(40,pSid,(PSID)(&pAce->SidStart));
ArraySid[i] = pSid;
Access[i] = pAce->Mask;
AceFlags[i] = pAce->Header.AceFlags;
};
};
ArraySid[i] = pSidAccount;
Access[i] = dwAccess;
AceFlags[i] = AceFlag;
PACL pACL = NULL;
DWORD dwBytes;
if (NO_ERROR == BuildACL((Count+1),ArraySid,Access,AceFlags,&pACL,&dwBytes))
{
TOKEN_DEFAULT_DACL tddNew;
tddNew.DefaultDacl = pACL;
bRet = SetTokenInformation(hToken,
TokenDefaultDacl,
&tddNew,
dwBytes);
HeapFree(GetProcessHeap(),0,pACL);
}
for (i=0;i<(DWORD)(Count+1);i++)
{
if (ArraySid[i])
{
FreeSid(ArraySid[i]);
}
}
return bRet;
}
*/