344 lines
8.1 KiB
C++
344 lines
8.1 KiB
C++
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Environment.Cpp
|
|
|
|
Abstract:
|
|
|
|
Various environment-related function
|
|
|
|
Notes:
|
|
|
|
Cloning environment for the purpose of using it in Rtl* environment-related functions
|
|
|
|
History:
|
|
|
|
10/26/00 VadimB Created
|
|
|
|
--*/
|
|
|
|
|
|
#include "precomp.h"
|
|
|
|
IMPLEMENT_SHIM_BEGIN(Win2kPropagateLayer)
|
|
#include "ShimHookMacro.h"
|
|
|
|
#include "Win2kPropagateLayer.h"
|
|
//
|
|
// This is so we can compare offsets if we know the segments are equal
|
|
//
|
|
|
|
#define OFFSET(x) (LOWORD((DWORD)(x)))
|
|
//
|
|
// I'm cheating here to make some functions a little faster;
|
|
// we won't have to push a word on the stack every time
|
|
//
|
|
|
|
static WORD gwMatch;
|
|
|
|
//
|
|
// ChrCmp - Case sensitive character comparison for DBCS
|
|
// Assumes w1, gwMatch are characters to be compared
|
|
// Return FALSE if they match, TRUE if no match
|
|
//
|
|
|
|
static BOOL ChrCmp( WORD w1 )
|
|
{
|
|
//
|
|
// Most of the time this won't match, so test it first for speed.
|
|
//
|
|
|
|
if( LOBYTE( w1 ) == LOBYTE( gwMatch ) )
|
|
{
|
|
if( IsDBCSLeadByte( LOBYTE( w1 ) ) )
|
|
{
|
|
return( w1 != gwMatch );
|
|
}
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// StrRChr - Find last occurrence of character in string
|
|
// Assumes lpStart points to start of string
|
|
// lpEnd points to end of string (NOT included in search)
|
|
// wMatch is the character to match
|
|
// returns ptr to the last occurrence of ch in str, NULL if not found.
|
|
//
|
|
|
|
static LPSTR StrRChr( LPSTR lpStart, LPSTR lpEnd, WORD wMatch )
|
|
{
|
|
LPSTR lpFound = NULL;
|
|
|
|
if( !lpEnd )
|
|
lpEnd = lpStart + strlen( lpStart );
|
|
|
|
gwMatch = wMatch;
|
|
|
|
for( ; OFFSET( lpStart ) < OFFSET( lpEnd ); lpStart = CharNextA( lpStart ) )
|
|
{
|
|
if( !ChrCmp( *(LPWORD)lpStart ) )
|
|
lpFound = lpStart;
|
|
}
|
|
|
|
return( lpFound );
|
|
}
|
|
|
|
|
|
//
|
|
// Find environment variable pszName within the buffer pszEnv
|
|
// ppszVal receives pointer to the variable's value
|
|
//
|
|
|
|
PSZ
|
|
ShimFindEnvironmentVar(
|
|
PSZ pszName,
|
|
PSZ pszEnv,
|
|
PSZ* ppszVal
|
|
)
|
|
{
|
|
int nNameLen = strlen(pszName);
|
|
PSZ pTemp;
|
|
|
|
if (pszEnv != NULL) {
|
|
|
|
while (*pszEnv != '\0') {
|
|
//
|
|
// Check the first char to be speedy.
|
|
//
|
|
if (*pszName == *pszEnv) {
|
|
//
|
|
// Compare the rest now.
|
|
//
|
|
if ((pTemp = StrRChr(pszEnv, NULL, '=')) != NULL &&
|
|
(int)(pTemp - pszEnv) == nNameLen &&
|
|
!_strnicmp(pszEnv, pszName, nNameLen)) {
|
|
|
|
//
|
|
// Found it.
|
|
//
|
|
if (ppszVal != NULL) {
|
|
*ppszVal = pTemp + 1;
|
|
}
|
|
return pszEnv;
|
|
}
|
|
}
|
|
|
|
pszEnv += strlen(pszEnv) + 1;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// returns size in characters
|
|
// of an env block
|
|
// pStrCount receives the number of env strings
|
|
//
|
|
DWORD
|
|
ShimGetEnvironmentSize(
|
|
PSZ pszEnv,
|
|
LPDWORD pStrCount
|
|
)
|
|
{
|
|
PSZ pTemp = pszEnv;
|
|
DWORD dwCount = 0;
|
|
|
|
while (*pTemp != '\0') {
|
|
dwCount++;
|
|
pTemp += strlen(pTemp) + 1;
|
|
}
|
|
|
|
pTemp++;
|
|
|
|
if (pStrCount != NULL) {
|
|
*pStrCount = dwCount;
|
|
}
|
|
return (DWORD)(pTemp - pszEnv);
|
|
}
|
|
|
|
// returns size (in characters) of an environment block
|
|
|
|
DWORD
|
|
ShimGetEnvironmentSize(
|
|
WCHAR* pwszEnv,
|
|
LPDWORD pStrCount
|
|
)
|
|
{
|
|
WCHAR* pTemp = pwszEnv;
|
|
DWORD dwCount = 0;
|
|
|
|
while(*pTemp != L'\0') {
|
|
dwCount++;
|
|
pTemp += wcslen(pTemp) + 1;
|
|
}
|
|
|
|
pTemp++; // include terminating '\0'
|
|
|
|
if (pStrCount != NULL) {
|
|
*pStrCount = dwCount;
|
|
}
|
|
|
|
return (DWORD)(pTemp - pwszEnv);
|
|
|
|
}
|
|
|
|
//
|
|
// returns cloned (unicode) environment
|
|
//
|
|
|
|
NTSTATUS
|
|
ShimCloneEnvironment(
|
|
LPVOID* ppEnvOut,
|
|
LPVOID lpEnvironment,
|
|
BOOL bUnicode
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
|
DWORD dwEnvSize = 0;
|
|
LPVOID lpEnvNew = NULL;
|
|
|
|
MEMORY_BASIC_INFORMATION MemoryInformation;
|
|
|
|
if (lpEnvironment == NULL) {
|
|
Status = RtlCreateEnvironment(TRUE, &lpEnvNew);
|
|
} else {
|
|
|
|
//
|
|
// Find the environment's size in characters but recalc in unicode.
|
|
//
|
|
dwEnvSize = (bUnicode ? ShimGetEnvironmentSize((WCHAR*)lpEnvironment, NULL) :
|
|
ShimGetEnvironmentSize((PSZ)lpEnvironment, NULL));
|
|
|
|
//
|
|
// Allocate memory -- using Zw routines (that is what rtl is using).
|
|
//
|
|
MemoryInformation.RegionSize = (dwEnvSize + 2) * sizeof(UNICODE_NULL);
|
|
Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
|
|
&lpEnvNew,
|
|
0,
|
|
&MemoryInformation.RegionSize,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
LOGN(
|
|
eDbgLevelError,
|
|
"[ShimCloneEnvironment] Failed to allocate %d bytes for the environment block.",
|
|
dwEnvSize * sizeof(UNICODE_NULL));
|
|
return Status;
|
|
}
|
|
|
|
if (bUnicode) {
|
|
//
|
|
// Unicode, just copy the environment
|
|
//
|
|
RtlMoveMemory(lpEnvNew, lpEnvironment, dwEnvSize * sizeof(UNICODE_NULL));
|
|
|
|
} else {
|
|
|
|
//
|
|
// The environment is ANSI, so we need to convert.
|
|
//
|
|
UNICODE_STRING UnicodeBuffer;
|
|
ANSI_STRING AnsiBuffer;
|
|
|
|
AnsiBuffer.Buffer = (CHAR*)lpEnvironment;
|
|
AnsiBuffer.Length = AnsiBuffer.MaximumLength = (USHORT)dwEnvSize; // size in bytes = size in chars, includes \0\0
|
|
|
|
UnicodeBuffer.Buffer = (WCHAR*)lpEnvNew;
|
|
UnicodeBuffer.Length = (USHORT)dwEnvSize * sizeof(UNICODE_NULL);
|
|
UnicodeBuffer.MaximumLength = (USHORT)(dwEnvSize + 2) * sizeof(UNICODE_NULL); // leave room for \0
|
|
|
|
Status = RtlAnsiStringToUnicodeString(&UnicodeBuffer, &AnsiBuffer, FALSE);
|
|
if (!NT_SUCCESS(Status)) {
|
|
LOGN(
|
|
eDbgLevelError,
|
|
"[ShimCloneEnvironment] Failed to convert ANSI environment to UNICODE. Status = 0x%x",
|
|
Status);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
*ppEnvOut = lpEnvNew;
|
|
|
|
} else {
|
|
|
|
if (lpEnvNew != NULL) {
|
|
RtlDestroyEnvironment(lpEnvNew);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
ShimFreeEnvironment(
|
|
LPVOID lpEnvironment
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
__try {
|
|
|
|
Status = RtlDestroyEnvironment(lpEnvironment);
|
|
if (!NT_SUCCESS(Status)) {
|
|
LOGN(
|
|
eDbgLevelError,
|
|
"[ShimFreeEnvironment] RtlDestroyEnvironment failed. Status = 0x%x",
|
|
Status);
|
|
}
|
|
} __except(WOWPROCESSHISTORYEXCEPTIONFILTER) {
|
|
|
|
Status = STATUS_ACCESS_VIOLATION;
|
|
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Set environment variable, possibly create or clone provided environment
|
|
//
|
|
|
|
NTSTATUS
|
|
ShimSetEnvironmentVar(
|
|
LPVOID* ppEnvironment,
|
|
WCHAR* pwszVarName,
|
|
WCHAR* pwszVarValue
|
|
)
|
|
{
|
|
UNICODE_STRING ustrVarName;
|
|
UNICODE_STRING ustrVarValue;
|
|
NTSTATUS Status;
|
|
|
|
RtlInitUnicodeString(&ustrVarName, pwszVarName);
|
|
|
|
if (NULL != pwszVarValue) {
|
|
RtlInitUnicodeString(&ustrVarValue, pwszVarValue);
|
|
}
|
|
|
|
Status = RtlSetEnvironmentVariable(ppEnvironment,
|
|
&ustrVarName,
|
|
(NULL == pwszVarValue) ? NULL : &ustrVarValue);
|
|
if (!NT_SUCCESS(Status)) {
|
|
LOGN(
|
|
eDbgLevelError,
|
|
"[ShimSetEnvironmentVar] RtlSetEnvironmentVariable failed. Status = 0x%x",
|
|
Status);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
IMPLEMENT_SHIM_END
|
|
|