[APPHELP]

- Add apphelp.dll. Patch by Mark Jansen, partially based on work by Mislav Blažević and the Wine team.
CORE-10367 #resolve

svn path=/trunk/; revision=71084
This commit is contained in:
Thomas Faber 2016-03-31 12:54:05 +00:00
parent d4705d3a33
commit 3a5f8b5d7e
8 changed files with 1162 additions and 0 deletions

View file

@ -1,5 +1,6 @@
add_subdirectory(3rdparty)
add_subdirectory(appcompat)
add_subdirectory(cpl)
add_subdirectory(directx)
add_subdirectory(keyboard)

View file

@ -0,0 +1,2 @@
add_subdirectory(apphelp)

View file

@ -0,0 +1,20 @@
spec2def(apphelp.dll apphelp.spec ADD_IMPORTLIB)
list(APPEND SOURCE
apphelp.c
sdbapi.c
layer.c
apphelp.spec
apphelp.h
${CMAKE_CURRENT_BINARY_DIR}/apphelp_stubs.c)
add_library(apphelp SHARED
${SOURCE}
${CMAKE_CURRENT_BINARY_DIR}/apphelp.def)
set_module_type(apphelp win32dll)
target_link_libraries(apphelp wine)
#add_delay_importlibs(apphelp version imagehlp user32)
add_importlibs(apphelp msvcrt kernel32 ntdll)
add_cd_file(TARGET apphelp DESTINATION reactos/system32 FOR all)

View file

@ -0,0 +1,135 @@
/*
* Copyright 2011 André Hentschel
* Copyright 2013 Mislav Blažević
* Copyright 2015 Mark Jansen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define WIN32_NO_STATUS
#include "windef.h"
#include "winbase.h"
#include "winver.h"
#include "strsafe.h"
#include "apphelp.h"
#include "wine/winternl.h"
#include "wine/debug.h"
#include "wine/unicode.h"
/* from dpfilter.h */
#define DPFLTR_APPCOMPAT_ID 123
#ifndef NT_SUCCESS
#define NT_SUCCESS(StatCode) ((NTSTATUS)(StatCode) >= 0)
#endif
ULONG g_ShimDebugLevel = 0xffffffff;
void ApphelppInitDebugLevel(void)
{
UNICODE_STRING DebugKey, DebugValue;
NTSTATUS Status;
ULONG NewLevel = 0;
WCHAR Buffer[40];
RtlInitUnicodeString(&DebugKey, L"SHIM_DEBUG_LEVEL");
DebugValue.MaximumLength = sizeof(Buffer);
DebugValue.Buffer = Buffer;
DebugValue.Length = 0;
/* Hold the lock as short as possible. */
RtlAcquirePebLock();
Status = RtlQueryEnvironmentVariable_U(NULL, &DebugKey, &DebugValue);
RtlReleasePebLock();
if (NT_SUCCESS(Status))
{
if (!NT_SUCCESS(RtlUnicodeStringToInteger(&DebugValue, 10, &NewLevel)))
NewLevel = 0;
}
g_ShimDebugLevel = NewLevel;
}
BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
{
switch (reason)
{
#ifndef __REACTOS__
case DLL_WINE_PREATTACH:
return FALSE; /* prefer native version */
#endif
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls( hinst );
SdbpHeapInit();
break;
case DLL_PROCESS_DETACH:
SdbpHeapDeinit();
break;
}
return TRUE;
}
/**
* Outputs diagnostic info.
*
* @param [in] Level The level to log this message with, choose any of [SHIM_ERR,
* SHIM_WARN, SHIM_INFO].
* @param [in] FunctionName The function this log should be attributed to.
* @param [in] Format The format string.
* @param ... Variable arguments providing additional information.
*
* @return Success: TRUE Failure: FALSE.
*/
BOOL WINAPIV ShimDbgPrint(SHIM_LOG_LEVEL Level, PCSTR FunctionName, PCSTR Format, ...)
{
char Buffer[512];
va_list ArgList;
char* Current = Buffer, *LevelStr;
size_t Length = sizeof(Buffer);
if (g_ShimDebugLevel == 0xffffffff)
ApphelppInitDebugLevel();
if (Level > g_ShimDebugLevel)
return FALSE;
switch (Level)
{
case SHIM_ERR:
LevelStr = "Err ";
Level = DPFLTR_MASK | (1 << DPFLTR_ERROR_LEVEL);
break;
case SHIM_WARN:
LevelStr = "Warn";
Level = DPFLTR_MASK | (1 << DPFLTR_WARNING_LEVEL);
break;
case SHIM_INFO:
LevelStr = "Info";
Level = DPFLTR_MASK | (1 << DPFLTR_INFO_LEVEL);
break;
default:
LevelStr = "User";
Level = DPFLTR_MASK | (1 << DPFLTR_INFO_LEVEL);
break;
}
StringCchPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, "[%s][%-20s] ", LevelStr, FunctionName);
va_start(ArgList, Format);
StringCchVPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, Format, ArgList);
va_end(ArgList);
return NT_SUCCESS(DbgPrintEx(DPFLTR_APPCOMPAT_ID, Level, "%s", Buffer));
}

View file

@ -0,0 +1,71 @@
/*
* Copyright 2013 Mislav Blažević
* Copyright 2015 Mark Jansen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef APPHELP_H
#define APPHELP_H
#ifdef __cplusplus
extern "C" {
#endif
typedef enum _SHIM_LOG_LEVEL {
SHIM_ERR = 1,
SHIM_WARN = 2,
SHIM_INFO = 3,
}SHIM_LOG_LEVEL;
/* apphelp.c */
BOOL WINAPIV ShimDbgPrint(SHIM_LOG_LEVEL Level, PCSTR FunctionName, PCSTR Format, ...);
extern ULONG g_ShimDebugLevel;
#define SHIM_ERR(fmt, ...) do { if (g_ShimDebugLevel) ShimDbgPrint(SHIM_ERR, __FUNCTION__, fmt, ##__VA_ARGS__ ); } while (0)
#define SHIM_WARN(fmt, ...) do { if (g_ShimDebugLevel) ShimDbgPrint(SHIM_WARN, __FUNCTION__, fmt, ##__VA_ARGS__ ); } while (0)
#define SHIM_INFO(fmt, ...) do { if (g_ShimDebugLevel) ShimDbgPrint(SHIM_INFO, __FUNCTION__, fmt, ##__VA_ARGS__ ); } while (0)
/* sdbapi.c */
void SdbpHeapInit(void);
void SdbpHeapDeinit(void);
#if SDBAPI_DEBUG_ALLOC
LPVOID SdbpAlloc(SIZE_T size, int line, const char* file);
LPVOID SdbpReAlloc(LPVOID mem, SIZE_T size, int line, const char* file);
void SdbpFree(LPVOID mem, int line, const char* file);
#define SdbAlloc(size) SdbpAlloc(size, __LINE__, __FILE__)
#define SdbReAlloc(mem, size) SdbpReAlloc(mem, size, __LINE__, __FILE__)
#define SdbFree(mem) SdbpFree(mem, __LINE__, __FILE__)
#else
LPVOID SdbpAlloc(SIZE_T size);
LPVOID SdbpReAlloc(LPVOID mem, SIZE_T size);
void SdbpFree(LPVOID mem);
#define SdbAlloc(size) SdbpAlloc(size)
#define SdbReAlloc(mem, size) SdbpReAlloc(mem, size)
#define SdbFree(mem) SdbpFree(mem)
#endif
#ifdef __cplusplus
} // extern "C"
#endif
#endif // APPHELP_H

View file

@ -0,0 +1,175 @@
@ stdcall AllowPermLayer(wstr)
@ stub ApphelpCheckExe
@ stub ApphelpCheckInstallShieldPackage
@ stub ApphelpCheckMsiPackage
@ stub ApphelpCheckRunApp
@ stub ApphelpCheckRunAppEx
@ stub ApphelpCheckShellObject
@ stub ApphelpCreateAppcompatData
@ stub ApphelpFixMsiPackage
@ stub ApphelpFixMsiPackageExe
@ stub ApphelpFreeFileAttributes
@ stub ApphelpGetFileAttributes
@ stub ApphelpGetMsiProperties
@ stub ApphelpGetNTVDMInfo
@ stub ApphelpParseModuleData
@ stub ApphelpQueryModuleData
@ stub ApphelpQueryModuleDataEx
@ stub ApphelpUpdateCacheEntry
@ stub GetPermLayers
@ stub SdbAddLayerTagRefToQuery
@ stub SdbApphelpNotify
@ stub SdbApphelpNotifyExSdbApphelpNotifyEx
@ stub SdbBeginWriteListTag
@ stub SdbBuildCompatEnvVariables
@ stub SdbCloseApphelpInformation
@ stub SdbCloseDatabase
@ stub SdbCloseDatabaseWrite
@ stub SdbCloseLocalDatabase
@ stub SdbCommitIndexes
@ stub SdbCreateDatabase
@ stub SdbCreateHelpCenterURL
@ stub SdbCreateMsiTransformFile
@ stub SdbDeclareIndex
@ stub SdbDumpSearchPathPartCaches
@ stub SdbEnumMsiTransforms
@ stub SdbEndWriteListTag
@ stub SdbEscapeApphelpURL
@ stub SdbFindFirstDWORDIndexedTag
@ stub SdbFindFirstMsiPackage
@ stub SdbFindFirstMsiPackage_Str
@ stub SdbFindFirstNamedTag
@ stub SdbFindFirstStringIndexedTag
@ stub SdbFindFirstTag
@ stub SdbFindFirstTagRef
@ stub SdbFindNextDWORDIndexedTag
@ stub SdbFindNextMsiPackage
@ stub SdbFindNextStringIndexedTag
@ stub SdbFindNextTag
@ stub SdbFindNextTagRef
@ stub SdbFreeDatabaseInformation
@ stub SdbFreeFileAttributes
@ stub SdbFreeFileInfo
@ stub SdbFreeFlagInfo
@ stub SdbGetAppCompatDataSize
@ stub SdbGetAppPatchDir
@ stub SdbGetBinaryTagData
@ stub SdbGetDatabaseID
@ stub SdbGetDatabaseInformation
@ stub SdbGetDatabaseInformationByName
@ stub SdbGetDatabaseMatch
@ stub SdbGetDatabaseVersion
@ stub SdbGetDllPath
@ stub SdbGetEntryFlags
@ stub SdbGetFileAttributes
@ stub SdbGetFileImageType
@ stub SdbGetFileImageTypeEx
@ stub SdbGetFileInfo
@ stub SdbGetFirstChild
@ stub SdbGetIndex
@ stub SdbGetItemFromItemRef
@ stub SdbGetLayerName
@ stub SdbGetLayerTagRef
@ stub SdbGetLocalPDB
@ stub SdbGetMatchingExe
@ stub SdbGetMsiPackageInformation
@ stub SdbGetNamedLayer
@ stub SdbGetNextChild
@ stub SdbGetNthUserSdb
@ stdcall SdbGetPermLayerKeys(wstr wstr ptr long)
@ stub SdbGetShowDebugInfoOption
@ stub SdbGetShowDebugInfoOptionValue
@ stub SdbGetStandardDatabaseGUID
@ stub SdbGetStringTagPtr
@ stub SdbGetTagDataSize
@ stub SdbGetTagFromTagID
@ stub SdbGrabMatchingInfo
@ stub SdbGrabMatchingInfoEx
@ stub SdbGUIDFromString
@ stub SdbGUIDToString
@ stub SdbInitDatabase
@ stub SdbInitDatabaseEx
@ stub SdbIsNullGUID
@ stub SdbIsStandardDatabase
@ stub SdbIsTagrefFromLocalDB
@ stub SdbIsTagrefFromMainDB
@ stub SdbLoadString
@ stub SdbMakeIndexKeyFromString
@ stub SdbOpenApphelpDetailsDatabase
@ stub SdbOpenApphelpDetailsDatabaseSP
@ stub SdbOpenApphelpInformation
@ stub SdbOpenApphelpInformationByID
@ stub SdbOpenApphelpResourceFile
@ stub SdbOpenDatabase
@ stub SdbOpenDbFromGuid
@ stub SdbOpenLocalDatabase
@ stub SdbPackAppCompatData
@ stub SdbQueryApphelpInformation
@ stub SdbQueryBlockUpgrade
@ stub SdbQueryContext
@ stub SdbQueryData
@ stub SdbQueryDataEx
@ stub SdbQueryDataExTagID
@ stub SdbQueryFlagInfo
@ stub SdbQueryName
@ stub SdbQueryReinstallUpgrade
@ stub SdbReadApphelpData
@ stub SdbReadApphelpDetailsData
@ stub SdbReadBinaryTag
@ stub SdbReadBYTETag
@ stub SdbReadDWORDTag
@ stub SdbReadDWORDTagRef
@ stub SdbReadEntryInformation
@ stub SdbReadMsiTransformInfo
@ stub SdbReadPatchBits
@ stub SdbReadQWORDTag
@ stub SdbReadQWORDTagRef
@ stub SdbReadStringTag
@ stub SdbReadStringTagRef
@ stub SdbReadWORDTag
@ stub SdbReadWORDTagRef
@ stub SdbRegisterDatabase
@ stub SdbReleaseDatabase
@ stub SdbReleaseMatchingExe
@ stub SdbResolveDatabase
@ stub SdbSetApphelpDebugParameters
@ stub SdbSetEntryFlags
@ stub SdbSetImageType
@ stdcall SdbSetPermLayerKeys(wstr wstr long)
@ stub SdbShowApphelpDialog
@ stub SdbShowApphelpFromQuery
@ stub SdbStartIndexing
@ stub SdbStopIndexing
@ stub SdbStringDuplicate
@ stub SdbStringReplace
@ stub SdbStringReplaceArray
@ stub SdbTagIDToTagRef
@ stub SdbTagRefToTagID
@ stub SdbTagToString
@ stub SdbUnregisterDatabase
@ stub SdbWriteBinaryTag
@ stub SdbWriteBinaryTagFromFile
@ stub SdbWriteBYTETag
@ stub SdbWriteDWORDTag
@ stub SdbWriteNULLTag
@ stub SdbWriteQWORDTag
@ stub SdbWriteStringRefTag
@ stub SdbWriteStringTag
@ stub SdbWriteStringTagDirect
@ stub SdbWriteWORDTag
@ stub SE_DllLoaded
@ stub SE_DllUnloaded
@ stub SE_GetHookAPIs
@ stub SE_GetMaxShimCount
@ stub SE_GetProcAddressLoad
@ stub SE_GetShimCount
@ stub SE_InstallAfterInit
@ stub SE_InstallBeforeInit
@ stub SE_IsShimDll
@ stub SE_LdrEntryRemoved
@ stub SE_ProcessDying
@ stub SetPermLayers
@ cdecl ShimDbgPrint(long str str)
@ stub ShimDumpCache
@ stub ShimFlushCache
@ stdcall SetPermLayerState(wstr wstr long long long)

View file

@ -0,0 +1,554 @@
/*
* Copyright 2015 Mark Jansen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define WIN32_NO_STATUS
#include "windef.h"
#include "winbase.h"
#include "strsafe.h"
#include <ntndk.h>
#include "apphelp.h"
#define GPLK_USER 1
#define GPLK_MACHINE 2
#define MAX_LAYER_LENGTH 256
#define LAYER_APPLY_TO_SYSTEM_EXES 1
#define LAYER_UNK_FLAG2 2
#ifndef REG_SZ
#define REG_SZ 1
#endif
#if defined(__GNUC__)
#define APPCOMPAT_LAYER_KEY (const WCHAR[]){'\\','S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','A','p','p','C','o','m','p','a','t','F','l','a','g','s','\\','L','a','y','e','r','s',0}
#define REGISTRY_MACHINE (const WCHAR[]){'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',0}
#define SPACE_ONLY (const WCHAR[]){' ',0}
#define DISALLOWED_LAYER_CHARS (const WCHAR[]){' ','#','!',0}
#define LAYER_SEPARATORS (const WCHAR[]){' ','\t',0}
#define SIGN_MEDIA_FMT (const WCHAR[]){'S','I','G','N','.','M','E','D','I','A','=','%','X',' ','%','s',0}
#else
#define APPCOMPAT_LAYER_KEY L"\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"
#define REGISTRY_MACHINE L"\\Registry\\Machine"
#define SPACE_ONLY L" "
#define DISALLOWED_LAYER_CHARS L" #!"
#define LAYER_SEPARATORS L" \t"
#define SIGN_MEDIA_FMT L"SIGN.MEDIA=%X %s"
#endif
typedef struct SDB_TMP_STR
{
UNICODE_STRING Str;
WCHAR FixedBuffer[MAX_PATH];
} SDB_TMP_STR, *PSDB_TMP_STR;
void SdbpInitTempStr(PSDB_TMP_STR String)
{
String->Str.Buffer = String->FixedBuffer;
String->Str.Length = 0;
String->Str.MaximumLength = sizeof(String->FixedBuffer);
}
void SdbpFreeTempStr(PSDB_TMP_STR String)
{
if (String->Str.Buffer != String->FixedBuffer)
{
SdbFree(String->Str.Buffer);
}
}
void SdbpResizeTempStr(PSDB_TMP_STR String, WORD newLength)
{
if (newLength > String->Str.MaximumLength)
{
SdbpFreeTempStr(String);
String->Str.MaximumLength = newLength * sizeof(WCHAR);
String->Str.Buffer = SdbAlloc(String->Str.MaximumLength);
String->Str.Length = 0;
}
}
BOOL SdbpGetLongPathName(PCWSTR wszPath, PSDB_TMP_STR Result)
{
DWORD max = Result->Str.MaximumLength / 2;
DWORD ret = GetLongPathNameW(wszPath, Result->Str.Buffer, max);
if (ret)
{
if (ret >= max)
{
SdbpResizeTempStr(Result, ret);
max = Result->Str.MaximumLength / 2;
ret = GetLongPathNameW(wszPath, Result->Str.Buffer, max);
}
if (ret && ret < max)
{
Result->Str.Length = ret * 2;
return TRUE;
}
}
SHIM_ERR("Failed to convert short path to long path error 0x%lx\n", GetLastError());
return FALSE;
}
BOOL SdbpIsPathOnRemovableMedia(PCWSTR Path)
{
WCHAR tmp[] = { 'A',':','\\',0 };
ULONG type;
if (!Path)
{
SHIM_ERR("Invalid argument\n");
return FALSE;
}
switch (Path[1])
{
case L':':
break;
case L'\\':
SHIM_INFO("\"%S\" is a network path.\n", Path);
return FALSE;
default:
SHIM_INFO("\"%S\" not a full path we can operate on.\n", Path);
return FALSE;
}
tmp[0] = Path[0];
type = GetDriveTypeW(tmp);
return type == DRIVE_REMOVABLE || type == DRIVE_CDROM;
}
BOOL SdbpBuildSignMediaId(PSDB_TMP_STR LongPath)
{
SDB_TMP_STR Scratch;
PWCHAR Ptr;
SdbpInitTempStr(&Scratch);
SdbpResizeTempStr(&Scratch, LongPath->Str.Length / sizeof(WCHAR) + 30);
StringCbCopyNW(Scratch.Str.Buffer, Scratch.Str.MaximumLength, LongPath->Str.Buffer, LongPath->Str.Length);
Ptr = wcsrchr(LongPath->Str.Buffer, '\\');
if (Ptr)
{
HANDLE FindHandle;
WIN32_FIND_DATAW FindData;
Ptr[1] = '*';
Ptr[2] = '\0';
FindHandle = FindFirstFileW(LongPath->Str.Buffer, &FindData);
if (FindHandle != INVALID_HANDLE_VALUE)
{
DWORD SignMedia = 0;
do
{
if (!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && FindData.nFileSizeLow)
SignMedia = SignMedia << 1 ^ FindData.nFileSizeLow;
} while (FindNextFileW(FindHandle, &FindData));
FindClose(FindHandle);
SdbpResizeTempStr(LongPath, (LongPath->Str.Length >> 1) + 20);
StringCbPrintfW(LongPath->Str.Buffer, LongPath->Str.MaximumLength, SIGN_MEDIA_FMT, SignMedia, Scratch.Str.Buffer + 3);
LongPath->Str.Length = wcslen(LongPath->Str.Buffer) * sizeof(WCHAR);
SdbpFreeTempStr(&Scratch);
return TRUE;
}
}
SdbpFreeTempStr(&Scratch);
SdbpFreeTempStr(LongPath);
return FALSE;
}
BOOL SdbpResolvePath(PSDB_TMP_STR LongPath, PCWSTR wszPath)
{
SdbpInitTempStr(LongPath);
if (!SdbpGetLongPathName(wszPath, LongPath))
{
SdbpFreeTempStr(LongPath);
return FALSE;
}
if (SdbpIsPathOnRemovableMedia(LongPath->Str.Buffer))
{
return SdbpBuildSignMediaId(LongPath);
}
return TRUE;
}
static ACCESS_MASK g_QueryFlag = 0xffffffff;
ACCESS_MASK QueryFlag(void)
{
if (g_QueryFlag == 0xffffffff)
{
ULONG_PTR wow64_ptr = 0;
NTSTATUS Status = NtQueryInformationProcess(NtCurrentProcess(), ProcessWow64Information, &wow64_ptr, sizeof(wow64_ptr), NULL);
g_QueryFlag = (NT_SUCCESS(Status) && wow64_ptr != 0) ? KEY_WOW64_64KEY : 0;
}
return g_QueryFlag;
}
NTSTATUS SdbpOpenKey(PUNICODE_STRING FullPath, BOOL bMachine, ACCESS_MASK Access, PHANDLE KeyHandle)
{
UNICODE_STRING BasePath;
const WCHAR* LayersKey = APPCOMPAT_LAYER_KEY;
OBJECT_ATTRIBUTES ObjectLayer = RTL_INIT_OBJECT_ATTRIBUTES(FullPath, OBJ_CASE_INSENSITIVE);
NTSTATUS Status;
FullPath->Buffer = NULL;
FullPath->Length = FullPath->MaximumLength = 0;
if (bMachine)
{
RtlInitUnicodeString(&BasePath, REGISTRY_MACHINE);
}
else
{
Status = RtlFormatCurrentUserKeyPath(&BasePath);
if (!NT_SUCCESS(Status))
{
SHIM_ERR("Unable to aquire user registry key, Error: 0x%lx\n", Status);
return Status;
}
}
FullPath->MaximumLength = BasePath.Length + (wcslen(LayersKey) + 1) * sizeof(WCHAR);
FullPath->Buffer = SdbAlloc(FullPath->MaximumLength);
FullPath->Length = 0;
RtlAppendUnicodeStringToString(FullPath, &BasePath);
if (!bMachine)
RtlFreeUnicodeString(&BasePath);
RtlAppendUnicodeToString(FullPath, LayersKey);
Status = NtOpenKey(KeyHandle, Access | QueryFlag(), &ObjectLayer);
if (!NT_SUCCESS(Status))
{
SHIM_ERR("Unable to open Key \"%wZ\" Status 0x%lx\n", FullPath, Status);
SdbFree(FullPath->Buffer);
FullPath->Buffer = NULL;
}
return Status;
}
BOOL SdbpGetPermLayersInternal(PUNICODE_STRING FullPath, PWSTR pwszLayers, PDWORD pdwBytes, BOOL bMachine)
{
UNICODE_STRING FullKey;
ULONG ValueBuffer[(MAX_LAYER_LENGTH * sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG) - 1) / sizeof(ULONG)];
PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)ValueBuffer;
ULONG Length = 0;
HANDLE KeyHandle;
NTSTATUS Status;
Status = SdbpOpenKey(&FullKey, bMachine, KEY_QUERY_VALUE, &KeyHandle);
if (NT_SUCCESS(Status))
{
Status = NtQueryValueKey(KeyHandle, FullPath, KeyValuePartialInformation, PartialInfo, sizeof(ValueBuffer), &Length);
if (NT_SUCCESS(Status))
{
StringCbCopyNW(pwszLayers, *pdwBytes, (PCWSTR)PartialInfo->Data, PartialInfo->DataLength);
*pdwBytes = PartialInfo->DataLength;
}
else
{
SHIM_INFO("Failed to read value info from Key \"%wZ\" Status 0x%lx\n", &FullKey, Status);
}
NtClose(KeyHandle);
SdbFree(FullKey.Buffer);
}
return NT_SUCCESS(Status);
}
BOOL SdbDeletePermLayerKeys(PCWSTR wszPath, BOOL bMachine)
{
UNICODE_STRING FullKey;
SDB_TMP_STR LongPath;
HANDLE KeyHandle;
NTSTATUS Status;
if (!SdbpResolvePath(&LongPath, wszPath))
return FALSE;
Status = SdbpOpenKey(&FullKey, bMachine, KEY_SET_VALUE, &KeyHandle);
if (NT_SUCCESS(Status))
{
Status = NtDeleteValueKey(KeyHandle, &LongPath.Str);
if (!NT_SUCCESS(Status))
{
SHIM_INFO("Failed to delete value from Key \"%wZ\" Status 0x%lx\n", &FullKey, Status);
/* This is what we want, so if the key didnt exist, we should not fail :) */
if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
Status = STATUS_SUCCESS;
}
NtClose(KeyHandle);
SdbFree(FullKey.Buffer);
}
SdbpFreeTempStr(&LongPath);
return NT_SUCCESS(Status);
}
BOOL SdbpMatchLayer(PCWSTR start, PCWSTR end, PCWSTR compare)
{
size_t len;
if (!end)
return !wcsicmp(start, compare);
len = end - start;
return wcslen(compare) == len && !_wcsnicmp(start, compare, len);
}
BOOL SdbpAppendLayer(PWSTR target, DWORD len, PCWSTR layer, PCWSTR end)
{
NTSTATUS Status = STATUS_SUCCESS;
if (target[0])
Status = StringCbCatW(target, len, SPACE_ONLY);
if (NT_SUCCESS(Status))
{
if (end)
Status = StringCbCatNW(target, len, layer, (end - layer) * sizeof(WCHAR));
else
Status = StringCbCatW(target, len, layer);
}
return NT_SUCCESS(Status);
}
/**
* Determine if we allow permission layers to apply on this file.
*
* @param [in] Path Full pathname of the file, only the drive part is used.
*
* @return TRUE if we allow permission layer, FALSE if not.
*/
BOOL WINAPI AllowPermLayer(PCWSTR Path)
{
WCHAR tmp[] = { 'A',':','\\', 0 };
ULONG type;
if (!Path)
{
SHIM_ERR("Invalid argument\n");
return FALSE;
}
switch (Path[1])
{
case L':':
break;
case L'\\':
SHIM_INFO("\"%S\" is a network path.\n", Path);
return FALSE;
default:
SHIM_INFO("\"%S\" not a full path we can operate on.\n", Path);
return FALSE;
}
tmp[0] = Path[0];
type = GetDriveTypeW(tmp);
if (type == DRIVE_REMOTE)
{
/* The logging here indicates that it does not like a CDROM or removable media, but it only
seems to bail out on a media that reports it is remote...
I have included correct logging, I doubt anyone would parse the logging, so this shouldnt break anything. */
SHIM_INFO("\"%S\" is on a remote drive.\n", Path);
return FALSE;
}
return TRUE;
}
/**
* Read the layers specified for the application.
*
* @param [in] wszPath Full pathname of the file.
* @param [out] pwszLayers On return, the layers set on the file.
* @param pdwBytes The size of the pwszLayers buffer in bytes, and on return the size of
* the data written (in bytes)
* @param [in] dwFlags The flags, [GPLK_USER | GPLK_MACHINE].
*
* @return TRUE if it succeeds, FALSE if it fails.
*/
BOOL WINAPI SdbGetPermLayerKeys(PCWSTR wszPath, PWSTR pwszLayers, PDWORD pdwBytes, DWORD dwFlags)
{
BOOL Result = FALSE;
SDB_TMP_STR LongPath;
DWORD dwBytes, dwTotal = 0;
if (!wszPath || !pdwBytes)
{
SHIM_ERR("NULL parameter passed for wszPath or pdwBytes.\n");
return FALSE;
}
if (!SdbpResolvePath(&LongPath, wszPath))
return FALSE;
dwBytes = *pdwBytes;
if (dwFlags & GPLK_MACHINE)
{
if (SdbpGetPermLayersInternal(&LongPath.Str, pwszLayers, &dwBytes, TRUE))
{
Result = TRUE;
dwTotal = dwBytes - sizeof(WCHAR); /* Compensate for the nullterm. */
pwszLayers += dwTotal / sizeof(WCHAR);
dwBytes = *pdwBytes - dwBytes;
if (dwFlags & GPLK_USER)
{
*(pwszLayers++) = L' ';
*pwszLayers = L'\0';
dwBytes -= sizeof(WCHAR);
dwTotal += sizeof(WCHAR);
}
}
}
if (dwFlags & GPLK_USER)
{
if (SdbpGetPermLayersInternal(&LongPath.Str, pwszLayers, &dwBytes, FALSE))
{
Result = TRUE;
dwTotal += dwBytes - sizeof(WCHAR); /* Compensate for the nullterm. */
}
else if (dwTotal > 0 && pwszLayers[-1] == L' ')
{
pwszLayers[-1] = '\0';
dwTotal -= sizeof(WCHAR);
}
}
if (dwTotal)
dwTotal += sizeof(WCHAR);
*pdwBytes = dwTotal;
SdbpFreeTempStr(&LongPath);
return Result;
}
/**
* Set or clear the Layer key.
*
* @param [in] wszPath Full pathname of the file.
* @param [in] wszLayers The layers to add (space separated), or an empty string / NULL to
* remove all layers.
* @param [in] bMachine TRUE to machine.
*
* @return TRUE if it succeeds, FALSE if it fails.
*/
BOOL WINAPI SdbSetPermLayerKeys(PCWSTR wszPath, PCWSTR wszLayers, BOOL bMachine)
{
UNICODE_STRING FullKey;
SDB_TMP_STR LongPath;
HANDLE KeyHandle;
NTSTATUS Status;
if (!wszLayers || *wszLayers == '\0')
return SdbDeletePermLayerKeys(wszPath, bMachine);
if (!SdbpResolvePath(&LongPath, wszPath))
return FALSE;
Status = SdbpOpenKey(&FullKey, bMachine, KEY_SET_VALUE, &KeyHandle);
if (NT_SUCCESS(Status))
{
Status = NtSetValueKey(KeyHandle, &LongPath.Str, 0, REG_SZ, (PVOID)wszLayers, (wcslen(wszLayers)+1) * sizeof(WCHAR));
if (!NT_SUCCESS(Status))
{
SHIM_INFO("Failed to write a value to Key \"%wZ\" Status 0x%lx\n", &FullKey, Status);
if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
Status = STATUS_SUCCESS;
}
NtClose(KeyHandle);
SdbFree(FullKey.Buffer);
}
SdbpFreeTempStr(&LongPath);
return NT_SUCCESS(Status);
}
/**
* Adds or removes a single layer entry.
*
* @param [in] wszPath Full pathname of the file.
* @param [in] wszLayer The layer to add or remove.
* @param [in] dwFlags Additional flags to add / remove [LAYER_APPLY_TO_SYSTEM_EXES | ???].
* @param [in] bMachine When TRUE, the setting applies to all users, when FALSE only applies
* to the current user.
* @param [in] bEnable TRUE to enable, FALSE to disable a layer / flag specified.
*
* @return TRUE if it succeeds, FALSE if it fails.
*/
BOOL WINAPI SetPermLayerState(PCWSTR wszPath, PCWSTR wszLayer, DWORD dwFlags, BOOL bMachine, BOOL bEnable)
{
WCHAR fullLayer[MAX_LAYER_LENGTH] = { 0 };
WCHAR newLayer[MAX_LAYER_LENGTH] = { 0 };
DWORD dwBytes = sizeof(fullLayer), dwWriteFlags = 0;
PWSTR start, p;
if (!wszLayer)
{
SHIM_ERR("Invalid argument\n");
return FALSE;
}
if (dwFlags & ~(LAYER_APPLY_TO_SYSTEM_EXES | LAYER_UNK_FLAG2))
{
SHIM_ERR("Invalid flags\n");
return FALSE;
}
p = wcspbrk(wszLayer, DISALLOWED_LAYER_CHARS);
if (p)
{
switch (*p)
{
case ' ':
SHIM_ERR("Only one layer can be passed in at a time.\n");
return FALSE;
case '#':
case '!':
SHIM_ERR("Flags cannot be passed in with the layer name.\n");
return FALSE;
}
}
if (!SdbGetPermLayerKeys(wszPath, fullLayer, &dwBytes, bMachine ? GPLK_MACHINE : GPLK_USER))
{
fullLayer[0] = '\0';
dwBytes = sizeof(fullLayer);
}
start = fullLayer;
while (*start == '!' || *start == '#' || *start == ' ' || *start == '\t')
{
if (*start == '#')
dwWriteFlags |= LAYER_APPLY_TO_SYSTEM_EXES;
else if (*start == '!')
dwWriteFlags |= LAYER_UNK_FLAG2;
start++;
}
if (bEnable)
dwWriteFlags |= dwFlags;
else
dwWriteFlags &= ~dwFlags;
p = newLayer;
if (dwWriteFlags & LAYER_UNK_FLAG2)
*(p++) = '!';
if (dwWriteFlags & LAYER_APPLY_TO_SYSTEM_EXES)
*(p++) = '#';
do
{
while (*start == ' ' || *start == '\t')
++start;
if (*start == '\0')
break;
p = wcspbrk(start, LAYER_SEPARATORS);
if (!SdbpMatchLayer(start, p, wszLayer))
{
SdbpAppendLayer(newLayer, sizeof(newLayer), start, p);
}
start = p + 1;
} while (p);
if (bEnable && wszLayer[0])
{
SdbpAppendLayer(newLayer, sizeof(newLayer), wszLayer, NULL);
}
return SdbSetPermLayerKeys(wszPath, newLayer, bMachine);
}

View file

@ -0,0 +1,204 @@
/*
* Copyright 2011 André Hentschel
* Copyright 2013 Mislav Blažević
* Copyright 2015 Mark Jansen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define WIN32_NO_STATUS
#include "windows.h"
#include "ntndk.h"
#include "strsafe.h"
#include "apphelp.h"
#include "wine/unicode.h"
static HANDLE SdbpHeap(void);
#if SDBAPI_DEBUG_ALLOC
typedef struct SHIM_ALLOC_ENTRY
{
PVOID Address;
SIZE_T Size;
int Line;
const char* File;
PVOID Next;
PVOID Prev;
} SHIM_ALLOC_ENTRY, *PSHIM_ALLOC_ENTRY;
static RTL_AVL_TABLE g_SdbpAllocationTable;
static RTL_GENERIC_COMPARE_RESULTS
NTAPI ShimAllocCompareRoutine(_In_ PRTL_AVL_TABLE Table, _In_ PVOID FirstStruct, _In_ PVOID SecondStruct)
{
PVOID First = ((PSHIM_ALLOC_ENTRY)FirstStruct)->Address;
PVOID Second = ((PSHIM_ALLOC_ENTRY)SecondStruct)->Address;
if (First < Second)
return GenericLessThan;
else if (First == Second)
return GenericEqual;
return GenericGreaterThan;
}
static PVOID NTAPI ShimAllocAllocateRoutine(_In_ PRTL_AVL_TABLE Table, _In_ CLONG ByteSize)
{
return HeapAlloc(SdbpHeap(), HEAP_ZERO_MEMORY, ByteSize);
}
static VOID NTAPI ShimAllocFreeRoutine(_In_ PRTL_AVL_TABLE Table, _In_ PVOID Buffer)
{
HeapFree(SdbpHeap(), 0, Buffer);
}
static void SdbpInsertAllocation(PVOID address, SIZE_T size, int line, const char* file)
{
SHIM_ALLOC_ENTRY Entry = {0};
Entry.Address = address;
Entry.Size = size;
Entry.Line = line;
Entry.File = file;
RtlInsertElementGenericTableAvl(&g_SdbpAllocationTable, &Entry, sizeof(Entry), NULL);
}
static void SdbpUpdateAllocation(PVOID address, PVOID newaddress, SIZE_T size, int line, const char* file)
{
SHIM_ALLOC_ENTRY Lookup = {0};
PSHIM_ALLOC_ENTRY Entry;
Lookup.Address = address;
Entry = RtlLookupElementGenericTableAvl(&g_SdbpAllocationTable, &Lookup);
if (address == newaddress)
{
Entry->Size = size;
}
else
{
Lookup.Address = newaddress;
Lookup.Size = size;
Lookup.Line = line;
Lookup.File = file;
Lookup.Prev = address;
RtlInsertElementGenericTableAvl(&g_SdbpAllocationTable, &Lookup, sizeof(Lookup), NULL);
Entry->Next = newaddress;
}
}
static void SdbpRemoveAllocation(PVOID address, int line, const char* file)
{
char buf[512];
SHIM_ALLOC_ENTRY Lookup = {0};
PSHIM_ALLOC_ENTRY Entry;
sprintf(buf, "\r\n===============\r\n%s(%d): SdbpFree called, tracing alloc:\r\n", file, line);
OutputDebugStringA(buf);
Lookup.Address = address;
while (Lookup.Address)
{
Entry = RtlLookupElementGenericTableAvl(&g_SdbpAllocationTable, &Lookup);
if (Entry)
{
Lookup = *Entry;
RtlDeleteElementGenericTableAvl(&g_SdbpAllocationTable, Entry);
sprintf(buf, " > %s(%d): %s%sAlloc( %d ) ==> %p\r\n", Lookup.File, Lookup.Line,
Lookup.Next ? "Invalidated " : "", Lookup.Prev ? "Re" : "", Lookup.Size, Lookup.Address);
OutputDebugStringA(buf);
Lookup.Address = Lookup.Prev;
}
else
{
Lookup.Address = NULL;
}
}
sprintf(buf, "\r\n===============\r\n");
OutputDebugStringA(buf);
}
#endif
static HANDLE g_Heap;
void SdbpHeapInit(void)
{
#if SDBAPI_DEBUG_ALLOC
RtlInitializeGenericTableAvl(&g_SdbpAllocationTable, ShimAllocCompareRoutine,
ShimAllocAllocateRoutine, ShimAllocFreeRoutine, NULL);
#endif
g_Heap = HeapCreate(0, 0x10000, 0);
}
void SdbpHeapDeinit(void)
{
#if SDBAPI_DEBUG_ALLOC
if (g_SdbpAllocationTable.NumberGenericTableElements != 0)
__debugbreak();
#endif
HeapDestroy(g_Heap);
}
DWORD SdbpStrlen(PCWSTR string)
{
return (lstrlenW(string) + 1) * sizeof(WCHAR);
}
static HANDLE SdbpHeap(void)
{
return g_Heap;
}
LPVOID SdbpAlloc(SIZE_T size
#if SDBAPI_DEBUG_ALLOC
, int line, const char* file
#endif
)
{
LPVOID mem = HeapAlloc(SdbpHeap(), HEAP_ZERO_MEMORY, size);
#if SDBAPI_DEBUG_ALLOC
SdbpInsertAllocation(mem, size, line, file);
#endif
return mem;
}
LPVOID SdbpReAlloc(LPVOID mem, SIZE_T size
#if SDBAPI_DEBUG_ALLOC
, int line, const char* file
#endif
)
{
LPVOID newmem = HeapReAlloc(SdbpHeap(), HEAP_ZERO_MEMORY, mem, size);
#if SDBAPI_DEBUG_ALLOC
SdbpUpdateAllocation(mem, newmem, size, line, file);
#endif
return newmem;
}
void SdbpFree(LPVOID mem
#if SDBAPI_DEBUG_ALLOC
, int line, const char* file
#endif
)
{
#if SDBAPI_DEBUG_ALLOC
SdbpRemoveAllocation(mem, line, file);
#endif
HeapFree(SdbpHeap(), 0, mem);
}