1159 lines
32 KiB
C++
1159 lines
32 KiB
C++
/********************************************************************
|
||
|
||
Copyright (c) 1999-2000 Microsoft Corporation
|
||
|
||
Module Name:
|
||
util.cpp
|
||
|
||
Abstract:
|
||
utility functions implementation
|
||
|
||
Revision History:
|
||
DerekM created 05/01/99
|
||
|
||
********************************************************************/
|
||
|
||
#include "stdafx.h"
|
||
#include "util.h"
|
||
#ifdef MANIFEST_HEAP
|
||
#include <ercommon.h>
|
||
#endif // MANIFEST_HEAP
|
||
|
||
/////////////////////////////////////////////////////////////////////////////
|
||
// tracing
|
||
|
||
#ifdef THIS_FILE
|
||
#undef THIS_FILE
|
||
#endif
|
||
static char __szTraceSourceFile[] = __FILE__;
|
||
#define THIS_FILE __szTraceSourceFile
|
||
|
||
HANDLE g_hPFPrivateHeap = NULL;
|
||
|
||
struct SLangCodepage
|
||
{
|
||
WORD wLanguage;
|
||
WORD wCodePage;
|
||
};
|
||
|
||
|
||
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
// string stuff
|
||
|
||
// ***************************************************************************
|
||
WCHAR *MyStrStrIW(const WCHAR *wcs1, const WCHAR *wcs2)
|
||
{
|
||
WCHAR *cp = (WCHAR *)wcs1;
|
||
WCHAR *s1, *s2;
|
||
|
||
while (*cp != '\0')
|
||
{
|
||
s1 = cp;
|
||
s2 = (WCHAR *) wcs2;
|
||
|
||
while (*s1 != '\0' && *s2 !='\0' && (towlower(*s1) - towlower(*s2)) == 0)
|
||
s1++, s2++;
|
||
|
||
if (*s2 == '\0')
|
||
return(cp);
|
||
|
||
cp++;
|
||
}
|
||
|
||
return(NULL);
|
||
}
|
||
|
||
// ***************************************************************************
|
||
CHAR *MyStrStrIA(const CHAR *cs1, const CHAR *cs2)
|
||
{
|
||
CHAR *cp = (CHAR *)cs1;
|
||
CHAR *s1, *s2;
|
||
|
||
while (*cp != '\0')
|
||
{
|
||
s1 = cp;
|
||
s2 = (CHAR *) cs2;
|
||
|
||
while (*s1 != '\0' && *s2 !='\0' && (tolower(*s1) - tolower(*s2)) == 0)
|
||
s1++, s2++;
|
||
|
||
if (*s2 == '\0')
|
||
return(cp);
|
||
|
||
cp++;
|
||
}
|
||
|
||
return(NULL);
|
||
}
|
||
|
||
|
||
////////////////////////////////////////////////////////////////////////////
|
||
// temp file stuff
|
||
|
||
// ***************************************************************************
|
||
BOOL DeleteTempDirAndFile(LPCWSTR wszPath, BOOL fFilePresent)
|
||
{
|
||
LPWSTR wszPathToDel = NULL, pwsz;
|
||
DWORD cchPath;
|
||
BOOL fRet = FALSE;
|
||
|
||
if (wszPath == NULL)
|
||
{
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
goto done;
|
||
}
|
||
|
||
cchPath = wcslen(wszPath);
|
||
__try { wszPathToDel = (LPWSTR)_alloca(cchPath * sizeof(WCHAR)); }
|
||
__except(EXCEPTION_EXECUTE_HANDLER) { wszPathToDel = NULL; }
|
||
if (wszPathToDel == NULL)
|
||
{
|
||
SetLastError(ERROR_OUTOFMEMORY);
|
||
goto done;
|
||
}
|
||
|
||
wcscpy(wszPathToDel, wszPath);
|
||
|
||
// delete the actual file
|
||
if (fFilePresent)
|
||
{
|
||
DeleteFileW(wszPathToDel);
|
||
|
||
// next, delete the directory that we put it in
|
||
for(pwsz = wszPathToDel + cchPath - 1;
|
||
*pwsz != L'\\' && pwsz > wszPathToDel;
|
||
pwsz--);
|
||
if (*pwsz != L'\\' || pwsz <= wszPathToDel)
|
||
goto done;
|
||
}
|
||
else
|
||
{
|
||
pwsz = wszPathToDel + cchPath;
|
||
}
|
||
|
||
*pwsz = L'\0';
|
||
RemoveDirectoryW(wszPathToDel);
|
||
|
||
for(pwsz = pwsz - 1;
|
||
*pwsz != L'.' && pwsz > wszPathToDel;
|
||
pwsz--);
|
||
if (*pwsz == L'.' && pwsz > wszPathToDel)
|
||
{
|
||
*pwsz = L'\0';
|
||
DeleteFileW(wszPathToDel);
|
||
}
|
||
|
||
fRet = TRUE;
|
||
|
||
done:
|
||
return fRet;
|
||
}
|
||
|
||
// ***************************************************************************
|
||
DWORD CreateTempDirAndFile(LPCWSTR wszTempDir, LPCWSTR wszName,
|
||
LPWSTR *pwszPath)
|
||
{
|
||
LPWSTR wszFilePath = NULL;
|
||
WCHAR *wszTemp = NULL;
|
||
DWORD cch = 0, cchDir = 0, iSuffix = 0, cSuffix = 0;
|
||
WCHAR wsz[1024];
|
||
BOOL fRet = FALSE;
|
||
|
||
if (pwszPath == NULL)
|
||
{
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
goto done;
|
||
}
|
||
|
||
*pwszPath = NULL;
|
||
|
||
if (wszTempDir != NULL)
|
||
cch = wcslen(wszTempDir);
|
||
if (cch == 0)
|
||
{
|
||
cch = GetTempPathW(0, NULL);
|
||
if (cch == 0)
|
||
goto done;
|
||
}
|
||
|
||
// compute the size of the buffer for the string we're going
|
||
// to generate. The 20 includes the following:
|
||
// max size of the temp filename
|
||
// extra space for the NULL terminator.
|
||
cch += (16 + sizeofSTRW(c_wszDirSuffix));
|
||
if (wszName != NULL)
|
||
cch += wcslen(wszName);
|
||
|
||
// ok, so GetTempFileName likes to write MAX_PATH characters to the buffer,
|
||
// so make sure it's at least MAX_PATH in size...
|
||
cch = MyMax(cch, MAX_PATH + 1);
|
||
|
||
wszFilePath = (LPWSTR)MyAlloc(cch * sizeof(WCHAR));
|
||
if (wszFilePath == NULL)
|
||
{
|
||
SetLastError(ERROR_OUTOFMEMORY);
|
||
goto done;
|
||
}
|
||
|
||
if (wszTempDir != NULL && wszTempDir[0] != L'\0')
|
||
{
|
||
cch = wcslen(wszTempDir);
|
||
wszTemp = (LPWSTR)wszTempDir;
|
||
}
|
||
else
|
||
{
|
||
cch = GetTempPathW(cch, wszFilePath);
|
||
if (cch == 0)
|
||
goto done;
|
||
|
||
cch++;
|
||
__try { wszTemp = (WCHAR *)_alloca(cch * sizeof(WCHAR)); }
|
||
__except(EXCEPTION_EXECUTE_HANDLER) { wszTemp = NULL; }
|
||
if (wszTemp == NULL)
|
||
{
|
||
SetLastError(ERROR_OUTOFMEMORY);
|
||
goto done;
|
||
}
|
||
|
||
wcscpy(wszTemp, wszFilePath);
|
||
}
|
||
cch = GetTempFileNameW(wszTemp, L"WER", 0, wszFilePath);
|
||
if (cch == 0)
|
||
goto done;
|
||
|
||
cch = wcslen(wszFilePath);
|
||
wcscpy(&wszFilePath[cch], c_wszDirSuffix);
|
||
|
||
// iSuffix points to the first digit of the '00' at the end of
|
||
// c_wszDirSuffix
|
||
iSuffix = cch + sizeofSTRW(c_wszDirSuffix) - 3;
|
||
cSuffix = 1;
|
||
do
|
||
{
|
||
fRet = CreateDirectoryW(wszFilePath, NULL);
|
||
if (fRet)
|
||
break;
|
||
|
||
wszFilePath[iSuffix] = L'0' + (WCHAR)(cSuffix / 10);
|
||
wszFilePath[iSuffix + 1] = L'0' + (WCHAR)(cSuffix % 10);
|
||
cSuffix++;
|
||
}
|
||
while (cSuffix <= 100);
|
||
|
||
// hmm, couldn't create the directory...
|
||
if (cSuffix > 100)
|
||
{
|
||
cchDir = cch;
|
||
cch = 0;
|
||
goto done;
|
||
}
|
||
|
||
|
||
cch += (sizeofSTRW(c_wszDirSuffix) - 1);
|
||
if (wszName != NULL)
|
||
{
|
||
wszFilePath[cch++] = L'\\';
|
||
wcscpy(&wszFilePath[cch], wszName);
|
||
cch += wcslen(wszName);
|
||
}
|
||
|
||
*pwszPath = wszFilePath;
|
||
wszFilePath = NULL;
|
||
|
||
fRet = TRUE;
|
||
|
||
done:
|
||
if (wszFilePath != NULL)
|
||
{
|
||
if (cchDir > 0)
|
||
{
|
||
wszFilePath[cchDir] = L'\0';
|
||
DeleteFileW(wszFilePath);
|
||
}
|
||
MyFree(wszFilePath);
|
||
}
|
||
|
||
return cch;
|
||
}
|
||
|
||
#ifdef MANIFEST_HEAP
|
||
BOOL
|
||
DeleteFullAndTriageMiniDumps(
|
||
LPCWSTR wszPath
|
||
)
|
||
//
|
||
// We create a FullMinidump file along with triage minidump in the same dir
|
||
// This routine cleans up both those files
|
||
//
|
||
{
|
||
LPWSTR wszFullMinidump = NULL;
|
||
DWORD cch;
|
||
BOOL fRet;
|
||
|
||
fRet = DeleteFileW(wszPath);
|
||
cch = wcslen(wszPath) + sizeofSTRW(c_wszHeapDumpSuffix);
|
||
__try { wszFullMinidump = (WCHAR *)_alloca(cch * sizeof(WCHAR)); }
|
||
__except(EXCEPTION_STACK_OVERFLOW) { wszFullMinidump = NULL; }
|
||
if (wszFullMinidump)
|
||
{
|
||
LPWSTR wszFileExt = NULL;
|
||
|
||
// Build Dump-with-heap path
|
||
wcsncpy(wszFullMinidump, wszPath, cch);
|
||
wszFileExt = wszFullMinidump + wcslen(wszFullMinidump) - sizeofSTRW(c_wszDumpSuffix) + 1;
|
||
if (!wcscmp(wszFileExt, c_wszDumpSuffix))
|
||
{
|
||
*wszFileExt = L'\0';
|
||
}
|
||
wcsncat(wszFullMinidump, c_wszHeapDumpSuffix, cch);
|
||
|
||
|
||
fRet = DeleteFileW(wszFullMinidump);
|
||
|
||
} else
|
||
{
|
||
fRet = FALSE;
|
||
}
|
||
return fRet;
|
||
}
|
||
#endif // MANIFEST_HEAP
|
||
|
||
////////////////////////////////////////////////////////////////////////////
|
||
// File mapping
|
||
|
||
// **************************************************************************
|
||
HRESULT OpenFileMapped(LPWSTR wszFile, LPVOID *ppvFile, DWORD *pcbFile)
|
||
{
|
||
USE_TRACING("OpenFileMapped");
|
||
|
||
HRESULT hr = NOERROR;
|
||
HANDLE hMMF = NULL;
|
||
HANDLE hFile = INVALID_HANDLE_VALUE;
|
||
LPVOID pvFile = NULL;
|
||
DWORD cbFile = 0;
|
||
|
||
VALIDATEPARM(hr, (wszFile == NULL || ppvFile == NULL));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
*ppvFile = NULL;
|
||
if (pcbFile != NULL)
|
||
*pcbFile = 0;
|
||
|
||
hFile = CreateFileW(wszFile, GENERIC_READ, FILE_SHARE_READ, NULL,
|
||
OPEN_EXISTING, 0, NULL);
|
||
TESTBOOL(hr, (hFile != INVALID_HANDLE_VALUE));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
cbFile = GetFileSize(hFile, NULL);
|
||
TESTBOOL(hr, (cbFile != (DWORD)-1));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
hMMF = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, cbFile, NULL);
|
||
TESTBOOL(hr, (hMMF != NULL));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
pvFile = MapViewOfFile(hMMF, FILE_MAP_READ, 0, 0, 0);
|
||
TESTBOOL(hr, (pvFile != NULL));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
*ppvFile = pvFile;
|
||
if (pcbFile != NULL)
|
||
*pcbFile = cbFile;
|
||
|
||
done:
|
||
if (hMMF != NULL)
|
||
CloseHandle(hMMF);
|
||
if (hFile != NULL)
|
||
CloseHandle(hFile);
|
||
|
||
return hr;
|
||
}
|
||
|
||
// **************************************************************************
|
||
HRESULT DeleteTempFile(LPWSTR wszFile)
|
||
{
|
||
USE_TRACING("DeleteTempFile");
|
||
|
||
HRESULT hr = NOERROR;
|
||
WCHAR *pwsz;
|
||
|
||
if (wszFile == NULL)
|
||
return NOERROR;
|
||
|
||
// strip off the extension at the end (if it's not a .tmp)
|
||
for(pwsz = wszFile + wcslen(wszFile); *pwsz != L'.' && pwsz > wszFile; pwsz--);
|
||
if (pwsz > wszFile && _wcsicmp(pwsz, L".tmp") != 0)
|
||
*pwsz = L'\0';
|
||
|
||
if (DeleteFileW(wszFile) == FALSE)
|
||
hr = Err2HR(GetLastError());
|
||
|
||
// can do this even if the extension was a tmp since the value pointed to
|
||
// by pwsz is '.' if it's greater than wszFile...
|
||
if (pwsz > wszFile)
|
||
*pwsz = L'.';
|
||
|
||
return hr;
|
||
}
|
||
|
||
// **************************************************************************
|
||
HRESULT MyCallNamedPipe(LPCWSTR wszPipe, LPVOID pvIn, DWORD cbIn,
|
||
LPVOID pvOut, DWORD cbOut, DWORD *pcbRead,
|
||
DWORD dwWaitPipe, DWORD dwWaitRead)
|
||
{
|
||
HRESULT hr = NOERROR;
|
||
HANDLE hPipe = INVALID_HANDLE_VALUE;
|
||
HANDLE hev = NULL;
|
||
DWORD dwStart = GetTickCount(), dwNow, dw;
|
||
BOOL fRet;
|
||
|
||
USE_TRACING("MyCallNamedPipe");
|
||
|
||
VALIDATEPARM(hr, (wszPipe == NULL || pvIn == NULL || pvOut == NULL || pcbRead == NULL));
|
||
if (FAILED(hr))
|
||
{
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
hr = E_INVALIDARG;
|
||
goto done;
|
||
}
|
||
|
||
*pcbRead = 0;
|
||
|
||
for(;;)
|
||
{
|
||
hPipe = CreateFileW(wszPipe, GENERIC_READ | GENERIC_WRITE,
|
||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
NULL, OPEN_EXISTING,
|
||
FILE_FLAG_OVERLAPPED | SECURITY_IDENTIFICATION |
|
||
SECURITY_SQOS_PRESENT | SECURITY_CONTEXT_TRACKING,
|
||
NULL);
|
||
if (hPipe != INVALID_HANDLE_VALUE)
|
||
break;
|
||
|
||
// if we get ACCESS_DENIED to the above, then WaitNamedPipe will
|
||
// return SUCCESS, so we get stuck until the timeout expires. Better
|
||
// to just bail now.
|
||
if (GetLastError() == ERROR_ACCESS_DENIED)
|
||
goto done;
|
||
|
||
TESTBOOL(hr, WaitNamedPipeW(wszPipe, dwWaitPipe));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
dwNow = GetTickCount();
|
||
if (dwNow < dwStart)
|
||
dw = ((DWORD)-1 - dwStart) + dwNow;
|
||
else
|
||
dw = dwNow - dwStart;
|
||
if (dw >= dwWaitPipe)
|
||
dwWaitPipe = 0;
|
||
else
|
||
dwWaitPipe -= dw;
|
||
|
||
if (dwWaitPipe == 0)
|
||
{
|
||
SetLastError(ERROR_TIMEOUT);
|
||
goto done;
|
||
}
|
||
}
|
||
|
||
|
||
__try
|
||
{
|
||
OVERLAPPED ol;
|
||
DWORD dwMode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
|
||
DWORD cbRead = 0;
|
||
|
||
// Default open is readmode byte stream- change to message mode.
|
||
TESTBOOL(hr, SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL))
|
||
if (FAILED(hr))
|
||
__leave;
|
||
|
||
// we need an event for the overlapped structure
|
||
hev = CreateEventW(NULL, TRUE, FALSE, NULL);
|
||
TESTBOOL(hr, (hev != NULL));
|
||
if (FAILED(hr))
|
||
__leave;
|
||
|
||
// populate the overlapped stuff
|
||
ZeroMemory(&ol, sizeof(ol));
|
||
ol.hEvent = hev;
|
||
|
||
fRet = TransactNamedPipe(hPipe, pvIn, cbIn, pvOut, cbOut, &cbRead,
|
||
&ol);
|
||
if (GetLastError() != ERROR_IO_PENDING)
|
||
{
|
||
if (fRet)
|
||
{
|
||
SetEvent(hev);
|
||
}
|
||
else
|
||
{
|
||
hr = Err2HR(GetLastError());
|
||
__leave;
|
||
}
|
||
}
|
||
|
||
dw = WaitForSingleObject(hev, dwWaitRead);
|
||
if (dw != WAIT_OBJECT_0)
|
||
{
|
||
hr = (dw == WAIT_TIMEOUT) ? Err2HR(WAIT_TIMEOUT) :
|
||
Err2HR(GetLastError());
|
||
__leave;
|
||
}
|
||
|
||
TESTBOOL(hr, GetOverlappedResult(hPipe, &ol, &cbRead, FALSE));
|
||
if (FAILED(hr))
|
||
__leave;
|
||
|
||
*pcbRead = cbRead;
|
||
|
||
hr = NOERROR;
|
||
}
|
||
|
||
__finally
|
||
{
|
||
}
|
||
|
||
done:
|
||
dw = GetLastError();
|
||
|
||
if (hPipe != INVALID_HANDLE_VALUE)
|
||
CloseHandle(hPipe);
|
||
if (hev != NULL)
|
||
CloseHandle(hev);
|
||
|
||
SetLastError(dw);
|
||
|
||
return hr;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
// Security stuff
|
||
|
||
// ***************************************************************************
|
||
#define MEMBER_ACCESS 1
|
||
BOOL IsUserAnAdmin(HANDLE hToken)
|
||
{
|
||
SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
|
||
SECURITY_DESCRIPTOR *psdAdm = NULL;
|
||
GENERIC_MAPPING gm;
|
||
PRIVILEGE_SET *pPS;
|
||
HANDLE hTokenImp = NULL;
|
||
DWORD cbSD, cbPS, dwGranted = 0;
|
||
BYTE rgBuf[sizeof(PRIVILEGE_SET) + 3 * sizeof(LUID_AND_ATTRIBUTES)];
|
||
BOOL fRet = FALSE, fStatus;
|
||
PSID psidAdm = NULL;
|
||
PACL pACL = NULL;
|
||
HRESULT hr;
|
||
|
||
USE_TRACING("IsUserAnAdmin");
|
||
|
||
gm.GenericRead = GENERIC_READ;
|
||
gm.GenericWrite = GENERIC_WRITE;
|
||
gm.GenericExecute = GENERIC_EXECUTE;
|
||
gm.GenericAll = GENERIC_ALL;
|
||
pPS = (PRIVILEGE_SET *)rgBuf;
|
||
cbPS = sizeof(rgBuf);
|
||
|
||
// AccessCheck() reqires an impersonation token...
|
||
TESTBOOL(hr, DuplicateToken(hToken, SecurityImpersonation, &hTokenImp));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
fRet = FALSE;
|
||
|
||
// construct a SID that contains the administrator's group.
|
||
TESTBOOL(hr, AllocateAndInitializeSid(&sia, 2, SECURITY_BUILTIN_DOMAIN_RID,
|
||
DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
|
||
0, &psidAdm));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
cbSD = sizeof(SECURITY_DESCRIPTOR) + sizeof(ACCESS_ALLOWED_ACE) +
|
||
sizeof(ACL) + 3 * GetLengthSid(psidAdm);
|
||
|
||
__try { psdAdm = (SECURITY_DESCRIPTOR *)_alloca(cbSD); }
|
||
__except(EXCEPTION_STACK_OVERFLOW) { psdAdm = NULL; }
|
||
if (psdAdm == NULL)
|
||
goto done;
|
||
|
||
ZeroMemory(psdAdm, cbSD);
|
||
pACL = (PACL)(psdAdm + 1);
|
||
|
||
TESTBOOL(hr, InitializeSecurityDescriptor(psdAdm, SECURITY_DESCRIPTOR_REVISION));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
TESTBOOL(hr, SetSecurityDescriptorOwner(psdAdm, psidAdm, FALSE));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
TESTBOOL(hr, SetSecurityDescriptorGroup(psdAdm, psidAdm, FALSE));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
TESTBOOL(hr, InitializeAcl(pACL, cbSD - sizeof(SECURITY_DESCRIPTOR), ACL_REVISION));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
TESTBOOL(hr, AddAccessAllowedAce(pACL, ACL_REVISION, MEMBER_ACCESS, psidAdm));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
TESTBOOL(hr, SetSecurityDescriptorDacl(psdAdm, TRUE, pACL, FALSE));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
TESTBOOL(hr, AccessCheck(psdAdm, hTokenImp, MEMBER_ACCESS, &gm, pPS, &cbPS,
|
||
&dwGranted, &fStatus));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
fRet = (fStatus && dwGranted == MEMBER_ACCESS);
|
||
|
||
done:
|
||
if (psidAdm != NULL)
|
||
FreeSid(psidAdm);
|
||
if (hTokenImp != NULL)
|
||
CloseHandle(hTokenImp);
|
||
|
||
return fRet;
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
BOOL AllocSD(SECURITY_DESCRIPTOR *psd, DWORD dwOLs, DWORD dwAd, DWORD dwWA)
|
||
{
|
||
SID_IDENTIFIER_AUTHORITY siaCreate = SECURITY_CREATOR_SID_AUTHORITY;
|
||
SID_IDENTIFIER_AUTHORITY siaWorld = SECURITY_WORLD_SID_AUTHORITY;
|
||
SID_IDENTIFIER_AUTHORITY siaNT = SECURITY_NT_AUTHORITY;
|
||
DWORD cb, dw;
|
||
PACL pacl = NULL;
|
||
PSID psidOwner = NULL;
|
||
PSID psidLS = NULL;
|
||
PSID psidWorld = NULL;
|
||
PSID psidAnon = NULL;
|
||
PSID psidAdm = NULL;
|
||
BOOL fRet = FALSE;
|
||
|
||
if (psd == NULL)
|
||
{
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
goto done;
|
||
}
|
||
|
||
fRet = InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION);
|
||
if (fRet == FALSE)
|
||
goto done;
|
||
|
||
|
||
// get the SID for local system acct
|
||
fRet = AllocateAndInitializeSid(&siaNT, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0,
|
||
0, 0, 0, 0, 0, &psidLS);
|
||
if (fRet == FALSE)
|
||
goto done;
|
||
|
||
// get the SID for the creator
|
||
fRet = AllocateAndInitializeSid(&siaCreate, 1, SECURITY_CREATOR_OWNER_RID,
|
||
0, 0, 0, 0, 0, 0, 0, &psidOwner);
|
||
if (fRet == FALSE)
|
||
goto done;
|
||
|
||
cb = sizeof(ACL) + GetLengthSid(psidLS) + GetLengthSid(psidOwner) +
|
||
2 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD));
|
||
|
||
// if we have an access mask to apply for the administrators group, then
|
||
// we need it's SID.
|
||
if (dwAd != 0)
|
||
{
|
||
// get the SID for the local administrators group
|
||
fRet = AllocateAndInitializeSid(&siaNT, 2, SECURITY_BUILTIN_DOMAIN_RID,
|
||
DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
|
||
0, &psidAdm);
|
||
if (fRet == FALSE)
|
||
goto done;
|
||
|
||
cb += (GetLengthSid(psidAdm) + sizeof(ACCESS_ALLOWED_ACE) -
|
||
sizeof(DWORD));
|
||
}
|
||
|
||
// if we have an access mask to apply for world / anonymous, then we need
|
||
// their SIDs
|
||
if (dwWA != 0)
|
||
{
|
||
// get the SID for the world (everyone)
|
||
fRet = AllocateAndInitializeSid(&siaNT, 1, SECURITY_ANONYMOUS_LOGON_RID,
|
||
0, 0, 0, 0, 0, 0, 0, &psidWorld);
|
||
|
||
|
||
// get the SID for the anonymous users acct
|
||
fRet = AllocateAndInitializeSid(&siaWorld, 1, SECURITY_WORLD_RID,
|
||
0, 0, 0, 0, 0, 0, 0, &psidAnon);
|
||
if (fRet == FALSE)
|
||
goto done;
|
||
|
||
cb += GetLengthSid(psidWorld) + GetLengthSid(psidAnon) +
|
||
2 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD));
|
||
}
|
||
|
||
// make the DACL
|
||
pacl = (PACL)MyAlloc(cb);
|
||
if (pacl == NULL)
|
||
{
|
||
SetLastError(ERROR_OUTOFMEMORY);
|
||
fRet = FALSE;
|
||
goto done;
|
||
}
|
||
|
||
fRet = InitializeAcl(pacl, cb, ACL_REVISION);
|
||
if (fRet == FALSE)
|
||
goto done;
|
||
|
||
fRet = AddAccessAllowedAce(pacl, ACL_REVISION, dwOLs, psidOwner);
|
||
if (fRet == FALSE)
|
||
goto done;
|
||
|
||
fRet = AddAccessAllowedAce(pacl, ACL_REVISION, dwOLs, psidLS);
|
||
if (fRet == FALSE)
|
||
goto done;
|
||
|
||
// if we have an administrator access mask, then apply it
|
||
if (dwAd != 0)
|
||
{
|
||
fRet = AddAccessAllowedAce(pacl, ACL_REVISION, dwAd, psidAdm);
|
||
if (fRet == FALSE)
|
||
goto done;
|
||
}
|
||
|
||
// if we have a world / anonymous access mask, then apply it
|
||
if (dwWA != 0)
|
||
{
|
||
fRet = AddAccessAllowedAce(pacl, ACL_REVISION, dwWA, psidWorld);
|
||
if (fRet == FALSE)
|
||
goto done;
|
||
|
||
fRet = AddAccessAllowedAce(pacl, ACL_REVISION, dwWA, psidAnon);
|
||
if (fRet == FALSE)
|
||
goto done;
|
||
}
|
||
|
||
// set the SD dacl
|
||
fRet = SetSecurityDescriptorDacl(psd, TRUE, pacl, FALSE);
|
||
if (fRet == FALSE)
|
||
goto done;
|
||
|
||
pacl = NULL;
|
||
|
||
done:
|
||
dw = GetLastError();
|
||
|
||
if (psidLS != NULL)
|
||
FreeSid(psidLS);
|
||
if (psidWorld != NULL)
|
||
FreeSid(psidWorld);
|
||
if (psidAnon != NULL)
|
||
FreeSid(psidAnon);
|
||
if (psidAdm != NULL)
|
||
FreeSid(psidAdm);
|
||
if (psidOwner != NULL)
|
||
FreeSid(psidOwner);
|
||
if (pacl != NULL)
|
||
MyFree(pacl);
|
||
|
||
SetLastError(dw);
|
||
|
||
return fRet;
|
||
}
|
||
|
||
// ***************************************************************************
|
||
void FreeSD(SECURITY_DESCRIPTOR *psd)
|
||
{
|
||
PSID psid = NULL;
|
||
PACL pacl = NULL;
|
||
BOOL f, f2;
|
||
|
||
if (psd == NULL)
|
||
return;
|
||
|
||
if (GetSecurityDescriptorDacl(psd, &f, &pacl, &f2) && pacl != NULL)
|
||
MyFree(pacl);
|
||
}
|
||
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
// Registry stuff
|
||
|
||
// **************************************************************************
|
||
HRESULT OpenRegKey(HKEY hkeyMain, LPCWSTR wszSubKey, DWORD dwOpt,
|
||
HKEY *phkey)
|
||
{
|
||
USE_TRACING("OpenRegKey");
|
||
|
||
HRESULT hr = NOERROR;
|
||
REGSAM samDesired;
|
||
DWORD dwErr;
|
||
|
||
VALIDATEPARM(hr, (hkeyMain == NULL || wszSubKey == NULL || phkey == NULL));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
*phkey = NULL;
|
||
|
||
samDesired = ((dwOpt & orkWantWrite) != 0) ? KEY_ALL_ACCESS : KEY_READ;
|
||
samDesired |= ((dwOpt & orkUseWOW64) != 0) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
|
||
|
||
// first try calling RegCreateKeyEx to make sure we create the key if
|
||
// it doesn't exist
|
||
TESTERR(hr, RegCreateKeyExW(hkeyMain, wszSubKey, 0, NULL, 0, samDesired,
|
||
NULL, phkey, NULL));
|
||
if (FAILED(hr))
|
||
{
|
||
// ok, that didn't work, so try opening the key instead
|
||
TESTERR(hr, RegOpenKeyExW(hkeyMain, wszSubKey, 0, samDesired, phkey));
|
||
}
|
||
|
||
done:
|
||
return hr;
|
||
}
|
||
|
||
// **************************************************************************
|
||
HRESULT ReadRegEntry(HKEY hkey, LPCWSTR wszValName, DWORD *pdwType,
|
||
PBYTE pbBuffer, DWORD *pcbBuffer, PBYTE pbDefault,
|
||
DWORD cbDefault)
|
||
{
|
||
USE_TRACING("ReadRegEntry");
|
||
|
||
HRESULT hr = NOERROR;
|
||
DWORD dwErr;
|
||
|
||
VALIDATEPARM(hr, (hkey == NULL || wszValName == NULL));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
dwErr = RegQueryValueExW(hkey, wszValName, 0, pdwType, pbBuffer,
|
||
pcbBuffer);
|
||
VALIDATEEXPR(hr, (dwErr != ERROR_PATH_NOT_FOUND &&
|
||
dwErr != ERROR_FILE_NOT_FOUND &&
|
||
dwErr != ERROR_SUCCESS), Err2HR(dwErr));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
if (dwErr != ERROR_SUCCESS && pbDefault != NULL)
|
||
{
|
||
VALIDATEPARM(hr, (pcbBuffer == NULL && pbBuffer != NULL));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
// if the receiving buffer is NULL, just return the error that
|
||
// RegQueryValueEx gave us cuz the user doesn't really want the
|
||
// value anyway
|
||
VALIDATEEXPR(hr, (pcbBuffer == NULL), Err2HR(dwErr));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
if (pbBuffer == NULL)
|
||
{
|
||
*pcbBuffer = cbDefault;
|
||
hr = NOERROR;
|
||
goto done;
|
||
}
|
||
else if (cbDefault > *pcbBuffer)
|
||
{
|
||
*pcbBuffer = cbDefault;
|
||
hr = Err2HR(ERROR_MORE_DATA);
|
||
goto done;
|
||
}
|
||
|
||
CopyMemory(pbBuffer, pbDefault, cbDefault);
|
||
*pcbBuffer = cbDefault;
|
||
if (pdwType != NULL)
|
||
*pdwType = REG_BINARY;
|
||
|
||
hr = NOERROR;
|
||
goto done;
|
||
}
|
||
done:
|
||
return hr;
|
||
}
|
||
|
||
// **************************************************************************
|
||
HRESULT ReadRegEntry(HKEY *rghkey, DWORD cKeys, LPCWSTR wszValName,
|
||
DWORD *pdwType, PBYTE pbBuffer, DWORD *pcbBuffer,
|
||
PBYTE pbDefault, DWORD cbDefault, DWORD *piKey)
|
||
{
|
||
USE_TRACING("ReadRegEntryPolicy");
|
||
|
||
HRESULT hr = NOERROR;
|
||
DWORD dwErr=0, i;
|
||
|
||
VALIDATEPARM(hr, (rghkey == NULL || wszValName == NULL));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
for(i = 0; i < cKeys; i++)
|
||
{
|
||
dwErr = RegQueryValueExW(rghkey[i], wszValName, 0, pdwType, pbBuffer,
|
||
pcbBuffer);
|
||
VALIDATEEXPR(hr, (dwErr != ERROR_PATH_NOT_FOUND &&
|
||
dwErr != ERROR_FILE_NOT_FOUND &&
|
||
dwErr != ERROR_SUCCESS), Err2HR(dwErr));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
if (dwErr == ERROR_SUCCESS)
|
||
{
|
||
if (piKey != NULL)
|
||
*piKey = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (dwErr != ERROR_SUCCESS && pbDefault != NULL)
|
||
{
|
||
VALIDATEPARM(hr, (pcbBuffer == NULL && pbBuffer != NULL));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
// if the receiving buffer is NULL, just return the error that
|
||
// RegQueryValueEx gave us cuz the user doesn't really want the
|
||
// value anyway
|
||
VALIDATEEXPR(hr, (pcbBuffer == NULL), Err2HR(dwErr));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
if (pbBuffer == NULL)
|
||
{
|
||
*pcbBuffer = cbDefault;
|
||
hr = NOERROR;
|
||
goto done;
|
||
}
|
||
else if (cbDefault > *pcbBuffer)
|
||
{
|
||
*pcbBuffer = cbDefault;
|
||
hr = Err2HR(ERROR_MORE_DATA);
|
||
goto done;
|
||
}
|
||
|
||
CopyMemory(pbBuffer, pbDefault, cbDefault);
|
||
*pcbBuffer = cbDefault;
|
||
if (pdwType != NULL)
|
||
*pdwType = REG_BINARY;
|
||
|
||
if (piKey != NULL)
|
||
*piKey = cKeys;
|
||
|
||
hr = NOERROR;
|
||
goto done;
|
||
}
|
||
done:
|
||
return hr;
|
||
}
|
||
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
// version info stuff
|
||
|
||
// **************************************************************************
|
||
DWORD IsMicrosoftApp(LPWSTR wszAppPath, PBYTE pbAppInfo, DWORD cbAppInfo)
|
||
{
|
||
USE_TRACING("IsMicrosoftApp");
|
||
|
||
SLangCodepage *plc;
|
||
HRESULT hr = NOERROR;
|
||
LPWSTR pwszName, pwszNameK32, wszModK32;
|
||
WCHAR wszQueryString[128];
|
||
DWORD cbFVI, cbFVIK32, dwJunk, dwRet = 0;
|
||
PBYTE pbFVI = NULL, pbFVIK32 = NULL;
|
||
UINT cb, cbVerInfo, i, cchNeed, cch;
|
||
|
||
VALIDATEPARM(hr, (wszAppPath == NULL &&
|
||
(pbAppInfo == NULL || cbAppInfo == 0)));
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
if (pbAppInfo == NULL)
|
||
{
|
||
// dwJunk is a useful parameter. Gotta pass it in so the function call
|
||
// set it to 0. Gee this would make a great (tho non-efficient)
|
||
// way to set DWORDs to 0. Much better than saying dwJunk = 0 by itself.
|
||
cbFVI = GetFileVersionInfoSizeW(wszAppPath, &dwJunk);
|
||
TESTBOOL(hr, (cbFVI != 0));
|
||
if (FAILED(hr))
|
||
{
|
||
// if it fails, assume the file doesn't have any version info &
|
||
// return S_FALSE
|
||
hr = S_FALSE;
|
||
goto done;
|
||
}
|
||
|
||
// alloca only throws exceptions so gotta catch 'em here....
|
||
__try { pbFVI = (PBYTE)_alloca(cbFVI); }
|
||
__except(EXCEPTION_STACK_OVERFLOW) { pbFVI = NULL; }
|
||
VALIDATEEXPR(hr, (pbFVI == NULL), E_OUTOFMEMORY);
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
cb = cbFVI;
|
||
TESTBOOL(hr, GetFileVersionInfoW(wszAppPath, 0, cbFVI, (LPVOID *)pbFVI));
|
||
if (FAILED(hr))
|
||
{
|
||
// if it fails, assume the file doesn't have any version info &
|
||
// return S_FALSE
|
||
hr = S_FALSE;
|
||
goto done;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pbFVI = pbAppInfo;
|
||
cbFVI = cbAppInfo;
|
||
}
|
||
|
||
// get the info for kernel32.dll
|
||
cchNeed = GetSystemDirectoryW(NULL, 0);
|
||
if (cchNeed == 0)
|
||
goto done;
|
||
|
||
cchNeed += (sizeofSTRW(L"\\kernel32.dll") + 1);
|
||
__try { wszModK32 = (LPWSTR)_alloca(cchNeed * sizeof(WCHAR)); }
|
||
__except(EXCEPTION_STACK_OVERFLOW) { wszModK32 = NULL; }
|
||
VALIDATEEXPR(hr, (wszModK32 == NULL), E_OUTOFMEMORY);
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
// get the info for kernel32.dll
|
||
cch = GetSystemDirectoryW(wszModK32, cchNeed);
|
||
if (cch == 0)
|
||
goto done;
|
||
if (*(wszModK32 + cch - 1) == L'\\')
|
||
*(wszModK32 + cch - 1) = L'\0';
|
||
wcscat(wszModK32, L"\\kernel32.dll");
|
||
|
||
|
||
// dwJunk is a useful parameter. Gotta pass it in so the function call
|
||
// set it to 0. Gee this would make a great (tho non-efficient)
|
||
// way to set DWORDs to 0. Much better than saying dwJunk = 0 by itself.
|
||
cbFVIK32 = GetFileVersionInfoSizeW(wszModK32, &dwJunk);
|
||
TESTBOOL(hr, (cbFVIK32 != 0));
|
||
if (FAILED(hr))
|
||
{
|
||
// if it fails, assume the file doesn't have any version info &
|
||
// return S_FALSE
|
||
hr = S_FALSE;
|
||
goto done;
|
||
}
|
||
|
||
// alloca only throws exceptions so gotta catch 'em here....
|
||
__try { pbFVIK32 = (PBYTE)_alloca(cbFVIK32); }
|
||
__except(EXCEPTION_STACK_OVERFLOW) { pbFVIK32 = NULL; }
|
||
VALIDATEEXPR(hr, (pbFVIK32 == NULL), E_OUTOFMEMORY);
|
||
if (FAILED(hr))
|
||
goto done;
|
||
|
||
cb = cbFVI;
|
||
TESTBOOL(hr, GetFileVersionInfoW(wszModK32, 0, cbFVIK32, (LPVOID *)pbFVIK32));
|
||
if (FAILED(hr))
|
||
{
|
||
// if it fails, assume the file doesn't have any version info &
|
||
// return S_FALSE
|
||
hr = S_FALSE;
|
||
goto done;
|
||
}
|
||
|
||
// Ok, since we can have any number of languages in the module, gotta
|
||
// grep thru all of them & see if the company name field includes
|
||
// 'Microsoft'.
|
||
TESTBOOL(hr, VerQueryValueW(pbFVI, L"\\VarFileInfo\\Translation",
|
||
(LPVOID *)&plc, &cbVerInfo));
|
||
if (FAILED(hr))
|
||
{
|
||
// if it fails, assume the file doesn't have any version info &
|
||
// return S_FALSE
|
||
hr = S_FALSE;
|
||
goto done;
|
||
}
|
||
|
||
// Read the file description for each language and code page.
|
||
for(i = 0; i < (cbVerInfo / sizeof(SLangCodepage)); i++)
|
||
{
|
||
wsprintfW(wszQueryString, L"\\StringFileInfo\\%04x%04x\\CompanyName",
|
||
plc[i].wLanguage, plc[i].wCodePage);
|
||
|
||
// Retrieve file description for language and code page "i".
|
||
TESTBOOL(hr, VerQueryValueW(pbFVI, wszQueryString,
|
||
(LPVOID *)&pwszName, &cb));
|
||
if (FAILED(hr))
|
||
continue;
|
||
|
||
// see if the string contains the word 'Microsoft'
|
||
if (MyStrStrIW(pwszName, L"Microsoft") != NULL)
|
||
{
|
||
dwRet |= APP_MSAPP;
|
||
goto doneCompany;
|
||
}
|
||
|
||
// ok, didn't match the word 'Microsoft', so instead, see if it matches
|
||
// the string in kernel32.dll
|
||
TESTBOOL(hr, VerQueryValueW(pbFVIK32, wszQueryString,
|
||
(LPVOID *)&pwszNameK32, &cb));
|
||
if (FAILED(hr))
|
||
continue;
|
||
|
||
if (CompareStringW(MAKELCID(plc[i].wLanguage, SORT_DEFAULT),
|
||
NORM_IGNORECASE | NORM_IGNOREKANATYPE |
|
||
NORM_IGNOREWIDTH | SORT_STRINGSORT,
|
||
pwszName, -1, pwszNameK32, -1) == CSTR_EQUAL)
|
||
dwRet |= APP_MSAPP;
|
||
else
|
||
continue;
|
||
|
||
doneCompany:
|
||
wsprintfW(wszQueryString, L"\\StringFileInfo\\%04x%04x\\ProductName",
|
||
plc[i].wLanguage, plc[i].wCodePage);
|
||
|
||
// Retrieve file description for language and code page "i".
|
||
TESTBOOL(hr, VerQueryValueW(pbFVI, wszQueryString,
|
||
(LPVOID *)&pwszName, &cb));
|
||
if (FAILED(hr))
|
||
continue;
|
||
|
||
// see if the string contains the words 'Microsoft<66> Windows<77>'
|
||
if (MyStrStrIW(pwszName, L"Microsoft<EFBFBD> Windows<77>") != NULL)
|
||
{
|
||
dwRet |= APP_WINCOMP;
|
||
break;
|
||
}
|
||
|
||
// ok, didn't match the words 'Microsoft<66> Windows<77>', so instead, see if
|
||
// it matches the string in kernel32.dll
|
||
TESTBOOL(hr, VerQueryValueW(pbFVIK32, wszQueryString,
|
||
(LPVOID *)&pwszNameK32, &cb));
|
||
if (FAILED(hr))
|
||
continue;
|
||
|
||
if (CompareStringW(MAKELCID(plc[i].wLanguage, SORT_DEFAULT),
|
||
NORM_IGNORECASE | NORM_IGNOREKANATYPE |
|
||
NORM_IGNOREWIDTH | SORT_STRINGSORT,
|
||
pwszName, -1, pwszNameK32, -1) == CSTR_EQUAL)
|
||
{
|
||
dwRet |= APP_WINCOMP;
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
hr = S_FALSE;
|
||
|
||
done:
|
||
return dwRet;
|
||
}
|
||
|