From 8810aa8908ed7887616d86dd5fb821fcfa92f444 Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Fri, 3 Jun 2022 17:50:22 -0500 Subject: Update Burn algorithm for picking elevated temp path to use SystemTemp. --- src/libs/dutil/WixToolset.DUtil/dutil.vcxproj | 2 + .../dutil/WixToolset.DUtil/dutil.vcxproj.filters | 6 + src/libs/dutil/WixToolset.DUtil/env2util.cpp | 80 ++++++++++++ src/libs/dutil/WixToolset.DUtil/inc/envutil.h | 11 ++ src/libs/dutil/WixToolset.DUtil/inc/pathutil.h | 9 ++ src/libs/dutil/WixToolset.DUtil/inc/polcutil.h | 14 ++ src/libs/dutil/WixToolset.DUtil/inc/procutil.h | 10 ++ src/libs/dutil/WixToolset.DUtil/path2utl.cpp | 38 ++++++ src/libs/dutil/WixToolset.DUtil/path3utl.cpp | 143 +++++++++++++++++++++ src/libs/dutil/WixToolset.DUtil/pathutil.cpp | 80 ------------ src/libs/dutil/WixToolset.DUtil/polcutil.cpp | 43 +++++++ src/libs/dutil/WixToolset.DUtil/procutil.cpp | 68 ++++++++++ .../dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj | 3 +- .../DUtilUnitTest/DUtilUnitTest.vcxproj.filters | 3 + src/libs/dutil/test/DUtilUnitTest/EnvUtilTests.cpp | 45 +++++++ src/libs/dutil/test/DUtilUnitTest/ProcUtilTest.cpp | 42 ++++++ src/libs/dutil/test/DUtilUnitTest/precomp.h | 2 + 17 files changed, 518 insertions(+), 81 deletions(-) create mode 100644 src/libs/dutil/WixToolset.DUtil/env2util.cpp create mode 100644 src/libs/dutil/WixToolset.DUtil/path3utl.cpp create mode 100644 src/libs/dutil/test/DUtilUnitTest/ProcUtilTest.cpp (limited to 'src/libs/dutil') diff --git a/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj b/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj index 9d057461..3100768d 100644 --- a/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj +++ b/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj @@ -65,6 +65,7 @@ Create 4091;4458 + @@ -82,6 +83,7 @@ + diff --git a/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters b/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters index 556468b7..c966c965 100644 --- a/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters +++ b/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters @@ -66,6 +66,9 @@ Source Files + + Source Files + Source Files @@ -111,6 +114,9 @@ Source Files + + Source Files + Source Files diff --git a/src/libs/dutil/WixToolset.DUtil/env2util.cpp b/src/libs/dutil/WixToolset.DUtil/env2util.cpp new file mode 100644 index 00000000..21bbd101 --- /dev/null +++ b/src/libs/dutil/WixToolset.DUtil/env2util.cpp @@ -0,0 +1,80 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +// Exit macros +#define EnvExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_ENVUTIL, x, s, __VA_ARGS__) +#define EnvExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_ENVUTIL, x, s, __VA_ARGS__) +#define EnvExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_ENVUTIL, x, s, __VA_ARGS__) +#define EnvExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_ENVUTIL, x, s, __VA_ARGS__) +#define EnvExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_ENVUTIL, x, s, __VA_ARGS__) +#define EnvExitWithRootFailure(x, e, s, ...) ExitWithRootFailureSource(DUTIL_SOURCE_ENVUTIL, x, e, s, __VA_ARGS__) +#define EnvExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_ENVUTIL, x, s, __VA_ARGS__) +#define EnvExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_ENVUTIL, p, x, e, s, __VA_ARGS__) +#define EnvExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_ENVUTIL, p, x, s, __VA_ARGS__) +#define EnvExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_ENVUTIL, p, x, e, s, __VA_ARGS__) +#define EnvExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_ENVUTIL, p, x, s, __VA_ARGS__) +#define EnvExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_ENVUTIL, e, x, s, __VA_ARGS__) +#define EnvExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_ENVUTIL, g, x, s, __VA_ARGS__) + +#define ENV2_GOOD_ENOUGH 64 + +DAPI_(HRESULT) EnvExpandEnvironmentStringsForUser( + __in_opt HANDLE hToken, + __in LPCWSTR wzSource, + __out LPWSTR* psczExpanded, + __out_opt SIZE_T* pcchExpanded + ) +{ + HRESULT hr = S_OK; + DWORD cchExpanded = 0; + SIZE_T cchMax = 0; + const DWORD dwMaxAttempts = 20; + + if (*psczExpanded) + { + hr = StrMaxLength(*psczExpanded, &cchMax); + EnvExitOnFailure(hr, "Failed to get max length of input buffer."); + + cchExpanded = (DWORD)min(DWORD_MAX, cchMax); + } + else + { + cchExpanded = ENV2_GOOD_ENOUGH; + + hr = StrAlloc(psczExpanded, cchExpanded); + EnvExitOnFailure(hr, "Failed to allocate space for expanded path."); + } + + for (DWORD i = 0; i < dwMaxAttempts; ++i) + { + if (::ExpandEnvironmentStringsForUserW(hToken, wzSource, *psczExpanded, cchExpanded)) + { + break; + } + + hr = HRESULT_FROM_WIN32(::GetLastError()); + if (E_INSUFFICIENT_BUFFER != hr || (dwMaxAttempts - 1) == i) + { + EnvExitWithRootFailure(hr, hr, "Failed to expand environment variables in string: %ls", wzSource); + } + + cchExpanded *= 2; + + hr = StrAlloc(psczExpanded, cchExpanded); + EnvExitOnFailure(hr, "Failed to re-allocate more space for expanded path."); + } + + if (pcchExpanded) + { + hr = ::StringCchLengthW(*psczExpanded, STRSAFE_MAX_LENGTH, reinterpret_cast(pcchExpanded)); + EnvExitOnFailure(hr, "Failed to get max length of written input buffer."); + + // Add 1 for null terminator. + *pcchExpanded += 1; + } + +LExit: + return hr; +} diff --git a/src/libs/dutil/WixToolset.DUtil/inc/envutil.h b/src/libs/dutil/WixToolset.DUtil/inc/envutil.h index 8491b27b..4e4f6197 100644 --- a/src/libs/dutil/WixToolset.DUtil/inc/envutil.h +++ b/src/libs/dutil/WixToolset.DUtil/inc/envutil.h @@ -16,6 +16,17 @@ HRESULT DAPI EnvExpandEnvironmentStrings( __out_opt SIZE_T* pcchExpanded ); +/******************************************************************** + EnvExpandEnvironmentStringsForUser - Wrapper for ::ExpandEnvironmentStringsForUser. + + *******************************************************************/ +HRESULT DAPI EnvExpandEnvironmentStringsForUser( + __in_opt HANDLE hToken, + __in LPCWSTR wzSource, + __out LPWSTR* psczExpanded, + __out_opt SIZE_T* pcchExpanded + ); + #ifdef __cplusplus } #endif diff --git a/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h b/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h index 875cfafb..f36e6ebc 100644 --- a/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h +++ b/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h @@ -204,6 +204,15 @@ DAPI_(HRESULT) PathGetTempPath( __out_z LPWSTR* psczTempPath ); +/******************************************************************* + PathSystemWindowsSubdirectory - returns the path to the Windows folder + or a subdirectory of that folder that is backslash terminated. +*******************************************************************/ +DAPI_(HRESULT) PathSystemWindowsSubdirectory( + __in_z_opt LPCWSTR wzSubdirectory, + __out_z LPWSTR* psczFullPath + ); + /******************************************************************* PathGetSystemTempPaths - returns the paths to system temp folders that are backslash terminated with higher preference first. diff --git a/src/libs/dutil/WixToolset.DUtil/inc/polcutil.h b/src/libs/dutil/WixToolset.DUtil/inc/polcutil.h index 13618043..7c873b80 100644 --- a/src/libs/dutil/WixToolset.DUtil/inc/polcutil.h +++ b/src/libs/dutil/WixToolset.DUtil/inc/polcutil.h @@ -34,6 +34,20 @@ HRESULT DAPI PolcReadString( __deref_out_z LPWSTR* pscz ); +/******************************************************************** +PolcReadUnexpandedString - reads a string from policy, without expanding it. + +NOTE: S_FALSE returned if policy not set. +NOTE: out is set to default on S_FALSE or any error. +********************************************************************/ +HRESULT DAPI PolcReadUnexpandedString( + __in_z LPCWSTR wzPolicyPath, + __in_z LPCWSTR wzPolicyName, + __in_z_opt LPCWSTR wzDefault, + __inout BOOL* pfNeedsExpansion, + __deref_out_z LPWSTR* pscz + ); + #ifdef __cplusplus } #endif diff --git a/src/libs/dutil/WixToolset.DUtil/inc/procutil.h b/src/libs/dutil/WixToolset.DUtil/inc/procutil.h index 4f49313b..d5ab9242 100644 --- a/src/libs/dutil/WixToolset.DUtil/inc/procutil.h +++ b/src/libs/dutil/WixToolset.DUtil/inc/procutil.h @@ -18,6 +18,16 @@ HRESULT DAPI ProcElevated( __out BOOL* pfElevated ); +HRESULT DAPI ProcSystem( + __in HANDLE hProcess, + __out BOOL* pfSystem + ); + +HRESULT DAPI ProcTokenUser( + __in HANDLE hProcess, + __out TOKEN_USER** ppTokenUser + ); + HRESULT DAPI ProcWow64( __in HANDLE hProcess, __out BOOL* pfWow64 diff --git a/src/libs/dutil/WixToolset.DUtil/path2utl.cpp b/src/libs/dutil/WixToolset.DUtil/path2utl.cpp index 9e48f9d5..c6ff608c 100644 --- a/src/libs/dutil/WixToolset.DUtil/path2utl.cpp +++ b/src/libs/dutil/WixToolset.DUtil/path2utl.cpp @@ -246,3 +246,41 @@ LExit: ReleaseStr(sczCanonicalizedDirectory); return hr; } + + +DAPI_(HRESULT) PathSystemWindowsSubdirectory( + __in_z_opt LPCWSTR wzSubdirectory, + __out_z LPWSTR* psczFullPath + ) +{ + HRESULT hr = S_OK; + WCHAR wzTempPath[MAX_PATH + 1] = { }; + DWORD cch = 0; + + cch = ::GetSystemWindowsDirectoryW(wzTempPath, countof(wzTempPath)); + if (!cch) + { + PathExitWithLastError(hr, "Failed to get Windows directory path."); + } + else if (cch >= countof(wzTempPath)) + { + PathExitWithRootFailure(hr, E_INSUFFICIENT_BUFFER, "Windows directory path too long."); + } + + if (wzSubdirectory) + { + hr = PathConcatRelativeToBase(wzTempPath, wzSubdirectory, psczFullPath); + PathExitOnFailure(hr, "Failed to concat subdirectory on Windows directory path."); + } + else + { + hr = StrAllocString(psczFullPath, wzTempPath, 0); + PathExitOnFailure(hr, "Failed to copy Windows directory path."); + } + + hr = PathBackslashTerminate(psczFullPath); + PathExitOnFailure(hr, "Failed to terminate Windows directory path with backslash."); + +LExit: + return hr; +} diff --git a/src/libs/dutil/WixToolset.DUtil/path3utl.cpp b/src/libs/dutil/WixToolset.DUtil/path3utl.cpp new file mode 100644 index 00000000..cb6ce6d5 --- /dev/null +++ b/src/libs/dutil/WixToolset.DUtil/path3utl.cpp @@ -0,0 +1,143 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +// Exit macros +#define PathExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_PATHUTIL, x, s, __VA_ARGS__) +#define PathExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_PATHUTIL, x, s, __VA_ARGS__) +#define PathExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_PATHUTIL, x, s, __VA_ARGS__) +#define PathExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_PATHUTIL, x, s, __VA_ARGS__) +#define PathExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_PATHUTIL, x, s, __VA_ARGS__) +#define PathExitWithRootFailure(x, e, s, ...) ExitWithRootFailureSource(DUTIL_SOURCE_PATHUTIL, x, e, s, __VA_ARGS__) +#define PathExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_PATHUTIL, x, s, __VA_ARGS__) +#define PathExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_PATHUTIL, p, x, e, s, __VA_ARGS__) +#define PathExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_PATHUTIL, p, x, s, __VA_ARGS__) +#define PathExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_PATHUTIL, p, x, e, s, __VA_ARGS__) +#define PathExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_PATHUTIL, p, x, s, __VA_ARGS__) +#define PathExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_PATHUTIL, e, x, s, __VA_ARGS__) +#define PathExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_PATHUTIL, g, x, s, __VA_ARGS__) + +static HRESULT GetTempPathFromSystemEnvironmentVariable( + __in HKEY hKey, + __in_z LPCWSTR wzName, + __out_z LPWSTR* psczPath + ); + +DAPI_(HRESULT) PathGetSystemTempPaths( + __inout_z LPWSTR** prgsczSystemTempPaths, + __inout DWORD* pcSystemTempPaths + ) +{ + HRESULT hr = S_OK; + HMODULE hModule = NULL; + BOOL fSystem = FALSE; + HKEY hKey = NULL; + LPWSTR sczTemp = NULL; + + // Follow documented precedence rules for SystemTemp/%TMP%/%TEMP% from ::GetTempPath2. + hr = LoadSystemLibrary(L"kernel32.dll", &hModule); + PathExitOnFailure(hr, "Failed to load kernel32.dll"); + + // The SystemTemp folder was added at the same time as ::GetTempPath2. + if (::GetProcAddress(hModule, "GetTempPath2W")) + { + hr = ProcSystem(::GetCurrentProcess(), &fSystem); + PathExitOnFailure(hr, "Failed to check if running as system."); + + if (fSystem) + { + hr = PathSystemWindowsSubdirectory(L"SystemTemp", &sczTemp); + PathExitOnFailure(hr, "Failed to get system Windows subdirectory path SystemTemp."); + + hr = MemEnsureArraySizeForNewItems(reinterpret_cast(prgsczSystemTempPaths), *pcSystemTempPaths, 1, sizeof(LPWSTR), 4); + PathExitOnFailure(hr, "Failed to ensure array size for Windows\\SystemTemp value."); + + (*prgsczSystemTempPaths)[*pcSystemTempPaths] = sczTemp; + sczTemp = NULL; + *pcSystemTempPaths += 1; + } + } + + // There is no documented API to get system environment variables, so read them from the registry. + hr = RegOpen(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\Session Manager\\Environment", KEY_READ, &hKey); + if (E_FILENOTFOUND != hr) + { + PathExitOnFailure(hr, "Failed to open system environment registry key."); + + hr = GetTempPathFromSystemEnvironmentVariable(hKey, L"TMP", &sczTemp); + PathExitOnFailure(hr, "Failed to get temp path from system TMP."); + + if (S_FALSE != hr) + { + hr = MemEnsureArraySizeForNewItems(reinterpret_cast(prgsczSystemTempPaths), *pcSystemTempPaths, 1, sizeof(LPWSTR), 3); + PathExitOnFailure(hr, "Failed to ensure array size for system TMP value."); + + (*prgsczSystemTempPaths)[*pcSystemTempPaths] = sczTemp; + sczTemp = NULL; + *pcSystemTempPaths += 1; + } + + hr = GetTempPathFromSystemEnvironmentVariable(hKey, L"TEMP", &sczTemp); + PathExitOnFailure(hr, "Failed to get temp path from system TEMP."); + + if (S_FALSE != hr) + { + hr = MemEnsureArraySizeForNewItems(reinterpret_cast(prgsczSystemTempPaths), *pcSystemTempPaths, 1, sizeof(LPWSTR), 2); + PathExitOnFailure(hr, "Failed to ensure array size for system TEMP value."); + + (*prgsczSystemTempPaths)[*pcSystemTempPaths] = sczTemp; + sczTemp = NULL; + *pcSystemTempPaths += 1; + } + } + + hr = PathSystemWindowsSubdirectory(L"TEMP", &sczTemp); + PathExitOnFailure(hr, "Failed to get system Windows subdirectory path TEMP."); + + hr = MemEnsureArraySizeForNewItems(reinterpret_cast(prgsczSystemTempPaths), *pcSystemTempPaths, 1, sizeof(LPWSTR), 1); + PathExitOnFailure(hr, "Failed to ensure array size for Windows\\TEMP value."); + + (*prgsczSystemTempPaths)[*pcSystemTempPaths] = sczTemp; + sczTemp = NULL; + *pcSystemTempPaths += 1; + +LExit: + ReleaseRegKey(hKey); + ReleaseStr(sczTemp); + + return hr; +} + +static HRESULT GetTempPathFromSystemEnvironmentVariable( + __in HKEY hKey, + __in_z LPCWSTR wzName, + __out_z LPWSTR* psczPath + ) +{ + HRESULT hr = S_OK; + LPWSTR sczValue = NULL; + BOOL fNeedsExpansion = FALSE; + + // Read the value unexpanded so that it can be expanded with system environment variables. + hr = RegReadUnexpandedString(hKey, wzName, &fNeedsExpansion, &sczValue); + if (E_FILENOTFOUND == hr) + { + ExitFunction1(hr = S_FALSE); + } + PathExitOnFailure(hr, "Failed to get system '%ls' value.", wzName); + + if (fNeedsExpansion) + { + hr = EnvExpandEnvironmentStringsForUser(NULL, sczValue, psczPath, NULL); + PathExitOnFailure(hr, "Failed to expand environment variables for system in string: %ls", sczValue); + } + + hr = PathBackslashTerminate(psczPath); + PathExitOnFailure(hr, "Failed to backslash terminate system '%ls' value.", wzName); + +LExit: + ReleaseStr(sczValue); + + return hr; +} diff --git a/src/libs/dutil/WixToolset.DUtil/pathutil.cpp b/src/libs/dutil/WixToolset.DUtil/pathutil.cpp index becfc67e..0e2a5dec 100644 --- a/src/libs/dutil/WixToolset.DUtil/pathutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/pathutil.cpp @@ -894,86 +894,6 @@ LExit: } -DAPI_(HRESULT) PathGetSystemTempPaths( - __inout_z LPWSTR** prgsczSystemTempPaths, - __inout DWORD* pcSystemTempPaths - ) -{ - HRESULT hr = S_OK; - HKEY hKey = NULL; - LPWSTR sczTemp = NULL; - WCHAR wzTempPath[MAX_PATH + 1] = { }; - DWORD cch = 0; - - // There is no documented API to get system environment variables, so read them from the registry. - hr = RegOpen(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\Session Manager\\Environment", KEY_READ, &hKey); - if (E_FILENOTFOUND != hr) - { - PathExitOnFailure(hr, "Failed to open system environment registry key."); - - // Follow documented precedence rules for TMP/TEMP from ::GetTempPath. - // TODO: values will be expanded with the current environment variables instead of the system environment variables. - hr = RegReadString(hKey, L"TMP", &sczTemp); - if (E_FILENOTFOUND != hr) - { - PathExitOnFailure(hr, "Failed to get system TMP value."); - - hr = PathBackslashTerminate(&sczTemp); - PathExitOnFailure(hr, "Failed to backslash terminate system TMP value."); - - hr = MemEnsureArraySizeForNewItems(reinterpret_cast(prgsczSystemTempPaths), *pcSystemTempPaths, 1, sizeof(LPWSTR), 3); - PathExitOnFailure(hr, "Failed to ensure array size for system TMP value."); - - (*prgsczSystemTempPaths)[*pcSystemTempPaths] = sczTemp; - sczTemp = NULL; - *pcSystemTempPaths += 1; - } - - hr = RegReadString(hKey, L"TEMP", &sczTemp); - if (E_FILENOTFOUND != hr) - { - PathExitOnFailure(hr, "Failed to get system TEMP value."); - - hr = PathBackslashTerminate(&sczTemp); - PathExitOnFailure(hr, "Failed to backslash terminate system TEMP value."); - - hr = MemEnsureArraySizeForNewItems(reinterpret_cast(prgsczSystemTempPaths), *pcSystemTempPaths, 1, sizeof(LPWSTR), 2); - PathExitOnFailure(hr, "Failed to ensure array size for system TEMP value."); - - (*prgsczSystemTempPaths)[*pcSystemTempPaths] = sczTemp; - sczTemp = NULL; - *pcSystemTempPaths += 1; - } - } - - cch = ::GetSystemWindowsDirectoryW(wzTempPath, countof(wzTempPath)); - if (!cch) - { - PathExitWithLastError(hr, "Failed to get Windows directory path."); - } - else if (cch >= countof(wzTempPath)) - { - PathExitWithRootFailure(hr, E_INSUFFICIENT_BUFFER, "Windows directory path too long."); - } - - hr = PathConcat(wzTempPath, L"TEMP\\", &sczTemp); - PathExitOnFailure(hr, "Failed to concat Temp directory on Windows directory path."); - - hr = MemEnsureArraySizeForNewItems(reinterpret_cast(prgsczSystemTempPaths), *pcSystemTempPaths, 1, sizeof(LPWSTR), 1); - PathExitOnFailure(hr, "Failed to ensure array size for Windows\\TEMP value."); - - (*prgsczSystemTempPaths)[*pcSystemTempPaths] = sczTemp; - sczTemp = NULL; - *pcSystemTempPaths += 1; - -LExit: - ReleaseRegKey(hKey); - ReleaseStr(sczTemp); - - return hr; -} - - DAPI_(HRESULT) PathGetKnownFolder( __in int csidl, __out LPWSTR* psczKnownFolder diff --git a/src/libs/dutil/WixToolset.DUtil/polcutil.cpp b/src/libs/dutil/WixToolset.DUtil/polcutil.cpp index 1fdfa18c..c2247bc1 100644 --- a/src/libs/dutil/WixToolset.DUtil/polcutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/polcutil.cpp @@ -102,6 +102,49 @@ LExit: return hr; } +extern "C" HRESULT DAPI PolcReadUnexpandedString( + __in_z LPCWSTR wzPolicyPath, + __in_z LPCWSTR wzPolicyName, + __in_z_opt LPCWSTR wzDefault, + __inout BOOL* pfNeedsExpansion, + __deref_out_z LPWSTR* pscz + ) +{ + HRESULT hr = S_OK; + HKEY hk = NULL; + + hr = OpenPolicyKey(wzPolicyPath, &hk); + if (E_FILENOTFOUND == hr || E_PATHNOTFOUND == hr) + { + ExitFunction1(hr = S_FALSE); + } + PolcExitOnFailure(hr, "Failed to open policy key: %ls", wzPolicyPath); + + hr = RegReadUnexpandedString(hk, wzPolicyName, pfNeedsExpansion, pscz); + if (E_FILENOTFOUND == hr || E_PATHNOTFOUND == hr) + { + ExitFunction1(hr = S_FALSE); + } + PolcExitOnFailure(hr, "Failed to open policy key: %ls, name: %ls", wzPolicyPath, wzPolicyName); + +LExit: + ReleaseRegKey(hk); + + if (S_FALSE == hr || FAILED(hr)) + { + if (NULL == wzDefault) + { + ReleaseNullStr(*pscz); + } + else + { + hr = StrAllocString(pscz, wzDefault, 0); + } + } + + return hr; +} + // internal functions diff --git a/src/libs/dutil/WixToolset.DUtil/procutil.cpp b/src/libs/dutil/WixToolset.DUtil/procutil.cpp index a3131b7a..340a0cda 100644 --- a/src/libs/dutil/WixToolset.DUtil/procutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/procutil.cpp @@ -9,6 +9,7 @@ #define ProcExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_PROCUTIL, x, s, __VA_ARGS__) #define ProcExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_PROCUTIL, x, s, __VA_ARGS__) #define ProcExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_PROCUTIL, x, s, __VA_ARGS__) +#define ProcExitWithRootFailure(x, e, s, ...) ExitWithRootFailureSource(DUTIL_SOURCE_PROCUTIL, x, e, s, __VA_ARGS__) #define ProcExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_PROCUTIL, x, s, __VA_ARGS__) #define ProcExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_PROCUTIL, p, x, e, s, __VA_ARGS__) #define ProcExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_PROCUTIL, p, x, s, __VA_ARGS__) @@ -75,6 +76,73 @@ LExit: return hr; } +extern "C" HRESULT DAPI ProcSystem( + __in HANDLE hProcess, + __out BOOL* pfSystem + ) +{ + HRESULT hr = S_OK; + TOKEN_USER* pTokenUser = NULL; + + hr = ProcTokenUser(hProcess, &pTokenUser); + ProcExitOnFailure(hr, "Failed to get TokenUser from process token."); + + *pfSystem = ::IsWellKnownSid(pTokenUser->User.Sid, WinLocalSystemSid); + +LExit: + ReleaseMem(pTokenUser); + + return hr; +} + +extern "C" HRESULT DAPI ProcTokenUser( + __in HANDLE hProcess, + __out TOKEN_USER** ppTokenUser + ) +{ + HRESULT hr = S_OK; + DWORD er = ERROR_SUCCESS; + HANDLE hToken = NULL; + TOKEN_USER* pTokenUser = NULL; + DWORD cbToken = 0; + + if (!::OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) + { + ProcExitWithLastError(hr, "Failed to open process token."); + } + + if (::GetTokenInformation(hToken, TokenUser, pTokenUser, 0, &cbToken)) + { + er = ERROR_SUCCESS; + } + else + { + er = ::GetLastError(); + } + + if (er != ERROR_INSUFFICIENT_BUFFER) + { + ProcExitOnWin32Error(er, hr, "Failed to get user from process token size."); + } + + pTokenUser = reinterpret_cast(MemAlloc(cbToken, TRUE)); + ProcExitOnNull(pTokenUser, hr, E_OUTOFMEMORY, "Failed to allocate token information."); + + if (!::GetTokenInformation(hToken, TokenUser, pTokenUser, cbToken, &cbToken)) + { + ProcExitWithLastError(hr, "Failed to get user from process token."); + } + + *ppTokenUser = pTokenUser; + pTokenUser = NULL; + +LExit: + ReleaseMem(pTokenUser); + ReleaseHandle(hToken); + + return hr; +} + extern "C" HRESULT DAPI ProcWow64( __in HANDLE hProcess, __out BOOL* pfWow64 diff --git a/src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj b/src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj index ee9f505e..a1f13239 100644 --- a/src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj +++ b/src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj @@ -40,7 +40,7 @@ ..\..\WixToolset.DUtil\inc - rpcrt4.lib;Mpr.lib;Ws2_32.lib;shlwapi.lib;urlmon.lib;wininet.lib + rpcrt4.lib;Mpr.lib;Ws2_32.lib;shlwapi.lib;urlmon.lib;userenv.lib;wininet.lib @@ -57,6 +57,7 @@ + Create diff --git a/src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj.filters b/src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj.filters index bcda6df0..cb0c8a73 100644 --- a/src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj.filters +++ b/src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj.filters @@ -54,6 +54,9 @@ Source Files + + Source Files + Source Files diff --git a/src/libs/dutil/test/DUtilUnitTest/EnvUtilTests.cpp b/src/libs/dutil/test/DUtilUnitTest/EnvUtilTests.cpp index 76dfa774..94b9ab8e 100644 --- a/src/libs/dutil/test/DUtilUnitTest/EnvUtilTests.cpp +++ b/src/libs/dutil/test/DUtilUnitTest/EnvUtilTests.cpp @@ -3,8 +3,10 @@ #include "precomp.h" using namespace System; +using namespace System::Collections; using namespace Xunit; using namespace WixBuildTools::TestSupport; +using namespace WixBuildTools::TestSupport::XunitExtensions; namespace DutilTests { @@ -46,5 +48,48 @@ namespace DutilTests ReleaseStr(sczExpanded); } } + + [SkippableFact] + void EnvExpandEnvironmentStringsForUserTest() + { + HRESULT hr = S_OK; + LPWSTR sczExpanded = NULL; + SIZE_T cchExpanded = 0; + String^ variableName = nullptr; + String^ variableValue = nullptr; + + // Find a system environment variable that doesn't have variables in its value; + for each (DictionaryEntry^ entry in Environment::GetEnvironmentVariables(EnvironmentVariableTarget::Machine)) + { + variableValue = (String^)entry->Value; + if (variableValue->Contains("%")) + { + continue; + } + + variableName = (String^)entry->Key; + break; + } + + if (nullptr == variableName) + { + WixAssert::Skip("No suitable system environment variables"); + } + + pin_ptr wzUnexpanded = PtrToStringChars("%" + variableName + "%_%USERNAME%"); + String^ expandedValue = variableValue + "_SYSTEM"; + + try + { + hr = EnvExpandEnvironmentStringsForUser(NULL, wzUnexpanded, &sczExpanded, &cchExpanded); + NativeAssert::Succeeded(hr, "Failed to expand %ls.", wzUnexpanded); + WixAssert::StringEqual(expandedValue, gcnew String(sczExpanded), false); + NativeAssert::Equal(expandedValue->Length + 1, cchExpanded); + } + finally + { + ReleaseStr(sczExpanded); + } + } }; } diff --git a/src/libs/dutil/test/DUtilUnitTest/ProcUtilTest.cpp b/src/libs/dutil/test/DUtilUnitTest/ProcUtilTest.cpp new file mode 100644 index 00000000..297d90f4 --- /dev/null +++ b/src/libs/dutil/test/DUtilUnitTest/ProcUtilTest.cpp @@ -0,0 +1,42 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +using namespace System; +using namespace System::Security::Principal; +using namespace Xunit; +using namespace WixBuildTools::TestSupport; + +namespace DutilTests +{ + public ref class ProcUtil + { + public: + [Fact] + void ProcTokenUserTest() + { + HRESULT hr = S_OK; + TOKEN_USER* pTokenUser = NULL; + LPWSTR sczSid = NULL; + + try + { + hr = ProcTokenUser(::GetCurrentProcess(), &pTokenUser); + NativeAssert::Succeeded(hr, "Failed to get TokenUser for current process."); + + if (!::ConvertSidToStringSidW(pTokenUser->User.Sid, &sczSid)) + { + hr = HRESULT_FROM_WIN32(::GetLastError()); + NativeAssert::Succeeded(hr, "Failed to get string SID from TokenUser SID."); + } + + Assert::Equal(WindowsIdentity::GetCurrent()->User->Value, gcnew String(sczSid)); + } + finally + { + ReleaseMem(pTokenUser); + ReleaseStr(sczSid); + } + } + }; +} diff --git a/src/libs/dutil/test/DUtilUnitTest/precomp.h b/src/libs/dutil/test/DUtilUnitTest/precomp.h index bc628816..ac57cdd4 100644 --- a/src/libs/dutil/test/DUtilUnitTest/precomp.h +++ b/src/libs/dutil/test/DUtilUnitTest/precomp.h @@ -5,6 +5,7 @@ #include #include #include +#include // Include error.h before dutil.h #include @@ -21,6 +22,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3-55-g6feb