Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1261 lines
37 KiB

/********************************************************************
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"
#include <ercommon.h>
#include <strsafe.h>
const WCHAR c_wszRKSetup[] = L"System\\Setup";
const WCHAR c_wszRVSetupNow[] = L"SystemSetupInProgress";
const WCHAR c_wszRVMiniSetupNow[] = L"MiniSetupInProgress";
const WCHAR c_wszRVOOBESetupNow[] = L"OobeInProgress";
/////////////////////////////////////////////////////////////////////////////
// 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;
};
DWORD SetupIsInProgress(void)
{
DWORD retval = SIIP_NO_SETUP;
HRESULT hr;
HKEY hkey = NULL;
DWORD dw;
USE_TRACING("SetupIsInProgress");
TESTERR(hr, RegOpenKeyExW(HKEY_LOCAL_MACHINE, c_wszRKSetup, 0, KEY_READ,
&hkey));
if (SUCCEEDED(hr))
{
DWORD cbData;
DWORD dwData;
// Are we in GUI mode setup?
cbData = sizeof(dwData);
dwData = 0;
dw = RegQueryValueExW(hkey, c_wszRVSetupNow, NULL, NULL,
(LPBYTE)&dwData, &cbData);
if (dw == ERROR_SUCCESS && dwData != 0)
{
retval = SIIP_GUI_SETUP;
// make certain this is not the OEM mini setup?
cbData = sizeof(dwData);
dwData = 0;
dw = RegQueryValueExW(hkey, c_wszRVMiniSetupNow, NULL, NULL,
(LPBYTE)&dwData, &cbData);
if (dw == ERROR_SUCCESS && dwData != 0)
retval=SIIP_OOBE_SETUP;
}
else
{
/*
* We are not in GUI mode, but it might be the OOBE movie
* or the activation that faulted, and we don't want the DW-UI
* then either as it will halt unattended setup.
*/
cbData = sizeof(dwData);
dwData = 0;
dw = RegQueryValueExW(hkey, c_wszRVOOBESetupNow, NULL, NULL,
(LPBYTE)&dwData, &cbData);
if (dw == ERROR_SUCCESS || dwData != 0)
retval=SIIP_OOBE_SETUP;
}
RegCloseKey(hkey);
}
DBG_MSG(retval ? "Setup in progress" : "Setup not running");
return retval;
}
//////////////////////////////////////////////////////////////////////////////
// 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+1) * sizeof(WCHAR)); }
__except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { wszPathToDel = NULL; }
if (wszPathToDel == NULL)
{
SetLastError(ERROR_OUTOFMEMORY);
goto done;
}
StringCchCopyW(wszPathToDel, cchPath+1, wszPath);
// XXX can hang for up to 25m. In the case of a service, it could prevent its restart for 25m, thus creating a potential vulnerability.
// delete the actual file
if (fFilePresent)
{
if (!DeleteFileW(wszPathToDel))
{
int i=0;
while (i < 300)
{
if (!DeleteFileW(wszPathToDel))
{
Sleep(5000);
i++;
}
else
{
i = 5000;
}
}
}
// 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, cFilePathLength;
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...
cFilePathLength = 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++;
// create the temp dir (in case it is not)
// ignoring the result (bug 526753)
CreateDirectoryW(wszFilePath, NULL);
__try { wszTemp = (WCHAR *)_alloca(cch * sizeof(WCHAR)); }
__except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { wszTemp = NULL; }
if (wszTemp == NULL)
{
SetLastError(ERROR_OUTOFMEMORY);
goto done;
}
StringCchCopyW(wszTemp, cch, wszFilePath);
}
cch = GetTempFileNameW(wszTemp, L"WER", 0, wszFilePath);
if (cch == 0)
goto done;
cch = wcslen(wszFilePath);
if (cch >= cFilePathLength)
{
goto done;
}
StringCchCopyW(&wszFilePath[cch], cFilePathLength - 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 && cch < cFilePathLength)
{
wszFilePath[cch++] = L'\\';
StringCchCopyW(&wszFilePath[cch], cFilePathLength - 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;
}
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 == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { wszFullMinidump = NULL; }
if (wszFullMinidump)
{
LPWSTR wszFileExt = NULL;
// Build Dump-with-heap path
StringCchCopyW(wszFullMinidump, cch, wszPath);
wszFileExt = wszFullMinidump + wcslen(wszFullMinidump) - sizeofSTRW(c_wszDumpSuffix) + 1;
if (!wcscmp(wszFileExt, c_wszDumpSuffix))
{
*wszFileExt = L'\0';
}
StringCchCatW(wszFullMinidump, cch, c_wszHeapDumpSuffix);
fRet = DeleteFileW(wszFullMinidump);
} else
{
fRet = FALSE;
}
return fRet;
}
////////////////////////////////////////////////////////////////////////////
// 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;
ULONG IsMember;
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;
// 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;
#if 0
// XXX - a simpler way??
if (CheckTokenMembership(hToken, psidAdm, &IsMember))
{
return IsMember;
}
#endif
cbSD = sizeof(SECURITY_DESCRIPTOR) + sizeof(ACCESS_ALLOWED_ACE) +
sizeof(ACL) + 3 * GetLengthSid(psidAdm);
__try { psdAdm = (SECURITY_DESCRIPTOR *)_alloca(cbSD); }
__except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { 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));
}
ErrorTrace(0, "OpenRegKey = [%S], %s", wszSubKey, FAILED(hr) ? "fail": "success");
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;
// ErrorTrace(0, "ReadRegEntry = %S", wszValName);
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=ERROR_SUCCESS, i;
VALIDATEPARM(hr, (rghkey == NULL || wszValName == NULL));
if (FAILED(hr))
goto done;
// ErrorTrace(0, "ReadRegEntryPolicy = %S", wszValName);
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;
// ErrorTrace(0, " found value [0x%x] in %s", (DWORD*) *pbDefault, i?"registry" : "policy");
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;
// ErrorTrace(0, " not found, applying default [0x%x]", (DWORD*) *pbDefault);
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))
{
ErrorTrace(0, " failed to find module \'%s\', hr=", wszAppPath, 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 == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { 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 == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { 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';
StringCchCatW(wszModK32, cchNeed, 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))
{
ErrorTrace(0, " failed to find module \'%s\', hr=", wszAppPath, 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 == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { 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++)
{
StringCchPrintfW(wszQueryString, sizeof(wszQueryString)/sizeof(WCHAR),
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:
StringCchPrintfW(wszQueryString, sizeof(wszQueryString)/sizeof(WCHAR),
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® Windows®'
if (MyStrStrIW(pwszName, L"Microsoft® Windows®") != NULL)
{
dwRet |= APP_WINCOMP;
break;
}
// ok, didn't match the words 'Microsoft® Windows®', 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:
ErrorTrace(0, "results for module \'%S\', dwRet=%d", wszAppPath, dwRet);
return dwRet;
}