Index: dll/win32/apphelp/CMakeLists.txt =================================================================== --- dll/win32/apphelp/CMakeLists.txt (revision 0) +++ dll/win32/apphelp/CMakeLists.txt (working copy) @@ -0,0 +1,20 @@ + +spec2def(apphelp.dll apphelp.spec) + +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) Index: dll/win32/apphelp/apphelp.c =================================================================== --- dll/win32/apphelp/apphelp.c (revision 0) +++ dll/win32/apphelp/apphelp.c (working copy) @@ -0,0 +1,132 @@ +/* + * 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 + +#define STATUS_SUCCESS ((NTSTATUS)0) + +ULONG g_ShimDebugLevel = 0xffffffff; + +void ApphelppInitDebugLevel() +{ + UNICODE_STRING DebugKey, DebugValue; + HRESULT hr; + ULONG NewLevel = 0; + + RtlInitUnicodeString(&DebugKey, L"SHIM_DEBUG_LEVEL"); + DebugValue.MaximumLength = 40 * sizeof(WCHAR); + DebugValue.Buffer = SdbAlloc(DebugValue.MaximumLength); + DebugValue.Length = 0; + + /* Hold the lock as short as possible. */ + RtlAcquirePebLock(); + hr = RtlQueryEnvironmentVariable_U(NULL, &DebugKey, &DebugValue); + RtlReleasePebLock(); + + if (SUCCEEDED(hr)) + { + if (FAILED(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 SUCCEEDED(DbgPrintEx(DPFLTR_APPCOMPAT_ID, Level, "%s", Buffer)); +} + Index: dll/win32/apphelp/apphelp.h =================================================================== --- dll/win32/apphelp/apphelp.h (revision 0) +++ dll/win32/apphelp/apphelp.h (working copy) @@ -0,0 +1,59 @@ +/* + * 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 + */ + + +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 SdbpHeapDeinit(); +#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 Index: dll/win32/apphelp/apphelp.spec =================================================================== --- dll/win32/apphelp/apphelp.spec (revision 0) +++ dll/win32/apphelp/apphelp.spec (working copy) @@ -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) Index: dll/win32/apphelp/layer.c =================================================================== --- dll/win32/apphelp/layer.c (revision 0) +++ dll/win32/apphelp/layer.c (working copy) @@ -0,0 +1,552 @@ +/* + * 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 +#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[]){' ','!',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[4] = { '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() +{ + if (g_QueryFlag == 0xffffffff) + { + ULONG_PTR pbi = { 0 }; + NTSTATUS hr = NtQueryInformationProcess(NtCurrentProcess(), ProcessWow64Information, &pbi, sizeof(pbi), NULL); + g_QueryFlag = (SUCCEEDED(hr) && pbi != 0) ? KEY_WOW64_64KEY : 0; + } + return g_QueryFlag; +} + +HRESULT 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); + HRESULT hr = E_FAIL; + FullPath->Buffer = NULL; + FullPath->Length = FullPath->MaximumLength = 0; + if (bMachine) + { + RtlInitUnicodeString(&BasePath, REGISTRY_MACHINE); + } + else + { + hr = RtlFormatCurrentUserKeyPath(&BasePath); + if (!SUCCEEDED(hr)) + { + SHIM_ERR("Unable to aquire user registry key, Error: 0x%lx\n", hr); + return hr; + } + } + FullPath->MaximumLength = BasePath.Length + wcslen(LayersKey) * sizeof(WCHAR)+sizeof(WCHAR); + FullPath->Buffer = SdbAlloc(FullPath->MaximumLength); + FullPath->Length = 0; + RtlAppendUnicodeStringToString(FullPath, &BasePath); + if (!bMachine) + RtlFreeUnicodeString(&BasePath); + RtlAppendUnicodeToString(FullPath, LayersKey); + + hr = NtOpenKey(KeyHandle, Access | QueryFlag(), &ObjectLayer); + if (FAILED(hr)) + { + SHIM_ERR("Unable to open Key \"%wZ\" Status 0x%lx\n", FullPath, hr); + SdbFree(FullPath->Buffer); + FullPath->Buffer = NULL; + } + return hr; +} + + +BOOL SdbpGetPermLayersInternal(PUNICODE_STRING FullPath, PWSTR pwszLayers, PDWORD pdwBytes, BOOL bMachine) +{ + UNICODE_STRING FullKey; + CHAR ValueBuffer[MAX_LAYER_LENGTH * sizeof(WCHAR)+sizeof(KEY_VALUE_PARTIAL_INFORMATION)]; + PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)ValueBuffer; + ULONG Length = 0; + HANDLE KeyHandle; + HRESULT hr; + + hr = SdbpOpenKey(&FullKey, bMachine, KEY_QUERY_VALUE, &KeyHandle); + if (SUCCEEDED(hr)) + { + hr = NtQueryValueKey(KeyHandle, FullPath, KeyValuePartialInformation, PartialInfo, sizeof(ValueBuffer), &Length); + if (SUCCEEDED(hr)) + { + 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, hr); + } + NtClose(KeyHandle); + SdbFree(FullKey.Buffer); + } + return SUCCEEDED(hr); +} + +BOOL SdbDeletePermLayerKeys(PCWSTR wszPath, BOOL bMachine) +{ + UNICODE_STRING FullKey; + SDB_TMP_STR LongPath; + HANDLE KeyHandle; + HRESULT hr; + + if (!SdbpResolvePath(&LongPath, wszPath)) + return FALSE; + + hr = SdbpOpenKey(&FullKey, bMachine, KEY_SET_VALUE, &KeyHandle); + if (SUCCEEDED(hr)) + { + hr = NtDeleteValueKey(KeyHandle, &LongPath.Str); + if (!SUCCEEDED(hr)) + { + SHIM_INFO("Failed to delete value from Key \"%wZ\" Status 0x%lx\n", &FullKey, hr); + /* This is what we want, so if the key didnt exist, we should not fail :) */ + if (hr == STATUS_OBJECT_NAME_NOT_FOUND) + hr = S_OK; + } + NtClose(KeyHandle); + SdbFree(FullKey.Buffer); + } + SdbpFreeTempStr(&LongPath); + return SUCCEEDED(hr); +} + +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) +{ + HRESULT hr = S_OK; + if (target[0]) + hr = StringCbCatW(target, len, SPACE_ONLY); + + if(SUCCEEDED(hr)) + { + if (end) + hr = StringCbCatNW(target, len, layer, (end-layer) * sizeof(WCHAR)); + else + hr = StringCbCatW(target, len, layer); + } + + return SUCCEEDED(hr); +} + + +/** + * 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[4] = { '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; + HRESULT hr; + + if (!wszLayers || *wszLayers == '\0') + return SdbDeletePermLayerKeys(wszPath, bMachine); + + if (!SdbpResolvePath(&LongPath, wszPath)) + return FALSE; + + hr = SdbpOpenKey(&FullKey, bMachine, KEY_SET_VALUE, &KeyHandle); + if (SUCCEEDED(hr)) + { + hr = NtSetValueKey(KeyHandle, &LongPath.Str, 0, REG_SZ, (PVOID)wszLayers, wcslen(wszLayers) * sizeof(WCHAR)+sizeof(WCHAR)); + if (!SUCCEEDED(hr)) + { + SHIM_INFO("Failed to write a value to Key \"%wZ\" Status 0x%lx\n", &FullKey, hr); + if (hr == STATUS_OBJECT_NAME_NOT_FOUND) + hr = S_OK; + } + NtClose(KeyHandle); + SdbFree(FullKey.Buffer); + } + SdbpFreeTempStr(&LongPath); + return SUCCEEDED(hr); +} + +/** + * 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); +} Index: dll/win32/apphelp/sdbapi.c =================================================================== --- dll/win32/apphelp/sdbapi.c (revision 0) +++ dll/win32/apphelp/sdbapi.c (working copy) @@ -0,0 +1,202 @@ +/* + * 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(); + +#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() +{ +#if SDBAPI_DEBUG_ALLOC + RtlInitializeGenericTableAvl(&g_SdbpAllocationTable, ShimAllocCompareRoutine, + ShimAllocAllocateRoutine, ShimAllocFreeRoutine, NULL); +#endif + g_Heap = HeapCreate(0, 0x10000, 0); +} + +void SdbpHeapDeinit() +{ +#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() +{ + 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); +} Index: dll/win32/CMakeLists.txt =================================================================== --- dll/win32/CMakeLists.txt (revision 69817) +++ dll/win32/CMakeLists.txt (working copy) @@ -5,6 +5,7 @@ add_subdirectory(actxprxy) add_subdirectory(advapi32) add_subdirectory(advpack) +add_subdirectory(apphelp) add_subdirectory(atl) add_subdirectory(atl100) add_subdirectory(atl80)