aboutsummaryrefslogtreecommitdiff
path: root/src/libs/dutil
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2022-06-03 17:50:22 -0500
committerSean Hall <r.sean.hall@gmail.com>2022-06-07 19:44:36 -0500
commit8810aa8908ed7887616d86dd5fb821fcfa92f444 (patch)
tree8bc05667c36cc0d3db73504c867e85b01f1a79b0 /src/libs/dutil
parent266b097c0b0a13dd4934f55f61cad62ffcbb953d (diff)
downloadwix-8810aa8908ed7887616d86dd5fb821fcfa92f444.tar.gz
wix-8810aa8908ed7887616d86dd5fb821fcfa92f444.tar.bz2
wix-8810aa8908ed7887616d86dd5fb821fcfa92f444.zip
Update Burn algorithm for picking elevated temp path to use SystemTemp.
Diffstat (limited to 'src/libs/dutil')
-rw-r--r--src/libs/dutil/WixToolset.DUtil/dutil.vcxproj2
-rw-r--r--src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters6
-rw-r--r--src/libs/dutil/WixToolset.DUtil/env2util.cpp80
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/envutil.h11
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/pathutil.h9
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/polcutil.h14
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/procutil.h10
-rw-r--r--src/libs/dutil/WixToolset.DUtil/path2utl.cpp38
-rw-r--r--src/libs/dutil/WixToolset.DUtil/path3utl.cpp143
-rw-r--r--src/libs/dutil/WixToolset.DUtil/pathutil.cpp80
-rw-r--r--src/libs/dutil/WixToolset.DUtil/polcutil.cpp43
-rw-r--r--src/libs/dutil/WixToolset.DUtil/procutil.cpp68
-rw-r--r--src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj3
-rw-r--r--src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj.filters3
-rw-r--r--src/libs/dutil/test/DUtilUnitTest/EnvUtilTests.cpp45
-rw-r--r--src/libs/dutil/test/DUtilUnitTest/ProcUtilTest.cpp42
-rw-r--r--src/libs/dutil/test/DUtilUnitTest/precomp.h2
17 files changed, 518 insertions, 81 deletions
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 @@
65 <PrecompiledHeader>Create</PrecompiledHeader> 65 <PrecompiledHeader>Create</PrecompiledHeader>
66 <DisableSpecificWarnings>4091;4458</DisableSpecificWarnings> 66 <DisableSpecificWarnings>4091;4458</DisableSpecificWarnings>
67 </ClCompile> 67 </ClCompile>
68 <ClCompile Include="env2util.cpp" />
68 <ClCompile Include="envutil.cpp" /> 69 <ClCompile Include="envutil.cpp" />
69 <ClCompile Include="eseutil.cpp" /> 70 <ClCompile Include="eseutil.cpp" />
70 <ClCompile Include="file2utl.cpp" /> 71 <ClCompile Include="file2utl.cpp" />
@@ -82,6 +83,7 @@
82 <ClCompile Include="monutil.cpp" /> 83 <ClCompile Include="monutil.cpp" />
83 <ClCompile Include="osutil.cpp" /> 84 <ClCompile Include="osutil.cpp" />
84 <ClCompile Include="path2utl.cpp" /> 85 <ClCompile Include="path2utl.cpp" />
86 <ClCompile Include="path3utl.cpp" />
85 <ClCompile Include="pathutil.cpp" /> 87 <ClCompile Include="pathutil.cpp" />
86 <ClCompile Include="perfutil.cpp" /> 88 <ClCompile Include="perfutil.cpp" />
87 <ClCompile Include="polcutil.cpp" /> 89 <ClCompile Include="polcutil.cpp" />
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 @@
66 <ClCompile Include="dutil.cpp"> 66 <ClCompile Include="dutil.cpp">
67 <Filter>Source Files</Filter> 67 <Filter>Source Files</Filter>
68 </ClCompile> 68 </ClCompile>
69 <ClCompile Include="env2util.cpp">
70 <Filter>Source Files</Filter>
71 </ClCompile>
69 <ClCompile Include="envutil.cpp"> 72 <ClCompile Include="envutil.cpp">
70 <Filter>Source Files</Filter> 73 <Filter>Source Files</Filter>
71 </ClCompile> 74 </ClCompile>
@@ -111,6 +114,9 @@
111 <ClCompile Include="osutil.cpp"> 114 <ClCompile Include="osutil.cpp">
112 <Filter>Source Files</Filter> 115 <Filter>Source Files</Filter>
113 </ClCompile> 116 </ClCompile>
117 <ClCompile Include="path3utl.cpp">
118 <Filter>Source Files</Filter>
119 </ClCompile>
114 <ClCompile Include="path2utl.cpp"> 120 <ClCompile Include="path2utl.cpp">
115 <Filter>Source Files</Filter> 121 <Filter>Source Files</Filter>
116 </ClCompile> 122 </ClCompile>
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 @@
1// 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.
2
3#include "precomp.h"
4
5
6// Exit macros
7#define EnvExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_ENVUTIL, x, s, __VA_ARGS__)
8#define EnvExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_ENVUTIL, x, s, __VA_ARGS__)
9#define EnvExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_ENVUTIL, x, s, __VA_ARGS__)
10#define EnvExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_ENVUTIL, x, s, __VA_ARGS__)
11#define EnvExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_ENVUTIL, x, s, __VA_ARGS__)
12#define EnvExitWithRootFailure(x, e, s, ...) ExitWithRootFailureSource(DUTIL_SOURCE_ENVUTIL, x, e, s, __VA_ARGS__)
13#define EnvExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_ENVUTIL, x, s, __VA_ARGS__)
14#define EnvExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_ENVUTIL, p, x, e, s, __VA_ARGS__)
15#define EnvExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_ENVUTIL, p, x, s, __VA_ARGS__)
16#define EnvExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_ENVUTIL, p, x, e, s, __VA_ARGS__)
17#define EnvExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_ENVUTIL, p, x, s, __VA_ARGS__)
18#define EnvExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_ENVUTIL, e, x, s, __VA_ARGS__)
19#define EnvExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_ENVUTIL, g, x, s, __VA_ARGS__)
20
21#define ENV2_GOOD_ENOUGH 64
22
23DAPI_(HRESULT) EnvExpandEnvironmentStringsForUser(
24 __in_opt HANDLE hToken,
25 __in LPCWSTR wzSource,
26 __out LPWSTR* psczExpanded,
27 __out_opt SIZE_T* pcchExpanded
28 )
29{
30 HRESULT hr = S_OK;
31 DWORD cchExpanded = 0;
32 SIZE_T cchMax = 0;
33 const DWORD dwMaxAttempts = 20;
34
35 if (*psczExpanded)
36 {
37 hr = StrMaxLength(*psczExpanded, &cchMax);
38 EnvExitOnFailure(hr, "Failed to get max length of input buffer.");
39
40 cchExpanded = (DWORD)min(DWORD_MAX, cchMax);
41 }
42 else
43 {
44 cchExpanded = ENV2_GOOD_ENOUGH;
45
46 hr = StrAlloc(psczExpanded, cchExpanded);
47 EnvExitOnFailure(hr, "Failed to allocate space for expanded path.");
48 }
49
50 for (DWORD i = 0; i < dwMaxAttempts; ++i)
51 {
52 if (::ExpandEnvironmentStringsForUserW(hToken, wzSource, *psczExpanded, cchExpanded))
53 {
54 break;
55 }
56
57 hr = HRESULT_FROM_WIN32(::GetLastError());
58 if (E_INSUFFICIENT_BUFFER != hr || (dwMaxAttempts - 1) == i)
59 {
60 EnvExitWithRootFailure(hr, hr, "Failed to expand environment variables in string: %ls", wzSource);
61 }
62
63 cchExpanded *= 2;
64
65 hr = StrAlloc(psczExpanded, cchExpanded);
66 EnvExitOnFailure(hr, "Failed to re-allocate more space for expanded path.");
67 }
68
69 if (pcchExpanded)
70 {
71 hr = ::StringCchLengthW(*psczExpanded, STRSAFE_MAX_LENGTH, reinterpret_cast<size_t*>(pcchExpanded));
72 EnvExitOnFailure(hr, "Failed to get max length of written input buffer.");
73
74 // Add 1 for null terminator.
75 *pcchExpanded += 1;
76 }
77
78LExit:
79 return hr;
80}
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(
16 __out_opt SIZE_T* pcchExpanded 16 __out_opt SIZE_T* pcchExpanded
17 ); 17 );
18 18
19/********************************************************************
20 EnvExpandEnvironmentStringsForUser - Wrapper for ::ExpandEnvironmentStringsForUser.
21
22 *******************************************************************/
23HRESULT DAPI EnvExpandEnvironmentStringsForUser(
24 __in_opt HANDLE hToken,
25 __in LPCWSTR wzSource,
26 __out LPWSTR* psczExpanded,
27 __out_opt SIZE_T* pcchExpanded
28 );
29
19#ifdef __cplusplus 30#ifdef __cplusplus
20} 31}
21#endif 32#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
@@ -205,6 +205,15 @@ DAPI_(HRESULT) PathGetTempPath(
205 ); 205 );
206 206
207/******************************************************************* 207/*******************************************************************
208 PathSystemWindowsSubdirectory - returns the path to the Windows folder
209 or a subdirectory of that folder that is backslash terminated.
210*******************************************************************/
211DAPI_(HRESULT) PathSystemWindowsSubdirectory(
212 __in_z_opt LPCWSTR wzSubdirectory,
213 __out_z LPWSTR* psczFullPath
214 );
215
216/*******************************************************************
208 PathGetSystemTempPaths - returns the paths to system temp folders 217 PathGetSystemTempPaths - returns the paths to system temp folders
209 that are backslash terminated with higher preference first. 218 that are backslash terminated with higher preference first.
210*******************************************************************/ 219*******************************************************************/
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(
34 __deref_out_z LPWSTR* pscz 34 __deref_out_z LPWSTR* pscz
35 ); 35 );
36 36
37/********************************************************************
38PolcReadUnexpandedString - reads a string from policy, without expanding it.
39
40NOTE: S_FALSE returned if policy not set.
41NOTE: out is set to default on S_FALSE or any error.
42********************************************************************/
43HRESULT DAPI PolcReadUnexpandedString(
44 __in_z LPCWSTR wzPolicyPath,
45 __in_z LPCWSTR wzPolicyName,
46 __in_z_opt LPCWSTR wzDefault,
47 __inout BOOL* pfNeedsExpansion,
48 __deref_out_z LPWSTR* pscz
49 );
50
37#ifdef __cplusplus 51#ifdef __cplusplus
38} 52}
39#endif 53#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(
18 __out BOOL* pfElevated 18 __out BOOL* pfElevated
19 ); 19 );
20 20
21HRESULT DAPI ProcSystem(
22 __in HANDLE hProcess,
23 __out BOOL* pfSystem
24 );
25
26HRESULT DAPI ProcTokenUser(
27 __in HANDLE hProcess,
28 __out TOKEN_USER** ppTokenUser
29 );
30
21HRESULT DAPI ProcWow64( 31HRESULT DAPI ProcWow64(
22 __in HANDLE hProcess, 32 __in HANDLE hProcess,
23 __out BOOL* pfWow64 33 __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:
246 ReleaseStr(sczCanonicalizedDirectory); 246 ReleaseStr(sczCanonicalizedDirectory);
247 return hr; 247 return hr;
248} 248}
249
250
251DAPI_(HRESULT) PathSystemWindowsSubdirectory(
252 __in_z_opt LPCWSTR wzSubdirectory,
253 __out_z LPWSTR* psczFullPath
254 )
255{
256 HRESULT hr = S_OK;
257 WCHAR wzTempPath[MAX_PATH + 1] = { };
258 DWORD cch = 0;
259
260 cch = ::GetSystemWindowsDirectoryW(wzTempPath, countof(wzTempPath));
261 if (!cch)
262 {
263 PathExitWithLastError(hr, "Failed to get Windows directory path.");
264 }
265 else if (cch >= countof(wzTempPath))
266 {
267 PathExitWithRootFailure(hr, E_INSUFFICIENT_BUFFER, "Windows directory path too long.");
268 }
269
270 if (wzSubdirectory)
271 {
272 hr = PathConcatRelativeToBase(wzTempPath, wzSubdirectory, psczFullPath);
273 PathExitOnFailure(hr, "Failed to concat subdirectory on Windows directory path.");
274 }
275 else
276 {
277 hr = StrAllocString(psczFullPath, wzTempPath, 0);
278 PathExitOnFailure(hr, "Failed to copy Windows directory path.");
279 }
280
281 hr = PathBackslashTerminate(psczFullPath);
282 PathExitOnFailure(hr, "Failed to terminate Windows directory path with backslash.");
283
284LExit:
285 return hr;
286}
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 @@
1// 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.
2
3#include "precomp.h"
4
5
6// Exit macros
7#define PathExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_PATHUTIL, x, s, __VA_ARGS__)
8#define PathExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_PATHUTIL, x, s, __VA_ARGS__)
9#define PathExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_PATHUTIL, x, s, __VA_ARGS__)
10#define PathExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_PATHUTIL, x, s, __VA_ARGS__)
11#define PathExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_PATHUTIL, x, s, __VA_ARGS__)
12#define PathExitWithRootFailure(x, e, s, ...) ExitWithRootFailureSource(DUTIL_SOURCE_PATHUTIL, x, e, s, __VA_ARGS__)
13#define PathExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_PATHUTIL, x, s, __VA_ARGS__)
14#define PathExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_PATHUTIL, p, x, e, s, __VA_ARGS__)
15#define PathExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_PATHUTIL, p, x, s, __VA_ARGS__)
16#define PathExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_PATHUTIL, p, x, e, s, __VA_ARGS__)
17#define PathExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_PATHUTIL, p, x, s, __VA_ARGS__)
18#define PathExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_PATHUTIL, e, x, s, __VA_ARGS__)
19#define PathExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_PATHUTIL, g, x, s, __VA_ARGS__)
20
21static HRESULT GetTempPathFromSystemEnvironmentVariable(
22 __in HKEY hKey,
23 __in_z LPCWSTR wzName,
24 __out_z LPWSTR* psczPath
25 );
26
27DAPI_(HRESULT) PathGetSystemTempPaths(
28 __inout_z LPWSTR** prgsczSystemTempPaths,
29 __inout DWORD* pcSystemTempPaths
30 )
31{
32 HRESULT hr = S_OK;
33 HMODULE hModule = NULL;
34 BOOL fSystem = FALSE;
35 HKEY hKey = NULL;
36 LPWSTR sczTemp = NULL;
37
38 // Follow documented precedence rules for SystemTemp/%TMP%/%TEMP% from ::GetTempPath2.
39 hr = LoadSystemLibrary(L"kernel32.dll", &hModule);
40 PathExitOnFailure(hr, "Failed to load kernel32.dll");
41
42 // The SystemTemp folder was added at the same time as ::GetTempPath2.
43 if (::GetProcAddress(hModule, "GetTempPath2W"))
44 {
45 hr = ProcSystem(::GetCurrentProcess(), &fSystem);
46 PathExitOnFailure(hr, "Failed to check if running as system.");
47
48 if (fSystem)
49 {
50 hr = PathSystemWindowsSubdirectory(L"SystemTemp", &sczTemp);
51 PathExitOnFailure(hr, "Failed to get system Windows subdirectory path SystemTemp.");
52
53 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczSystemTempPaths), *pcSystemTempPaths, 1, sizeof(LPWSTR), 4);
54 PathExitOnFailure(hr, "Failed to ensure array size for Windows\\SystemTemp value.");
55
56 (*prgsczSystemTempPaths)[*pcSystemTempPaths] = sczTemp;
57 sczTemp = NULL;
58 *pcSystemTempPaths += 1;
59 }
60 }
61
62 // There is no documented API to get system environment variables, so read them from the registry.
63 hr = RegOpen(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\Session Manager\\Environment", KEY_READ, &hKey);
64 if (E_FILENOTFOUND != hr)
65 {
66 PathExitOnFailure(hr, "Failed to open system environment registry key.");
67
68 hr = GetTempPathFromSystemEnvironmentVariable(hKey, L"TMP", &sczTemp);
69 PathExitOnFailure(hr, "Failed to get temp path from system TMP.");
70
71 if (S_FALSE != hr)
72 {
73 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczSystemTempPaths), *pcSystemTempPaths, 1, sizeof(LPWSTR), 3);
74 PathExitOnFailure(hr, "Failed to ensure array size for system TMP value.");
75
76 (*prgsczSystemTempPaths)[*pcSystemTempPaths] = sczTemp;
77 sczTemp = NULL;
78 *pcSystemTempPaths += 1;
79 }
80
81 hr = GetTempPathFromSystemEnvironmentVariable(hKey, L"TEMP", &sczTemp);
82 PathExitOnFailure(hr, "Failed to get temp path from system TEMP.");
83
84 if (S_FALSE != hr)
85 {
86 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczSystemTempPaths), *pcSystemTempPaths, 1, sizeof(LPWSTR), 2);
87 PathExitOnFailure(hr, "Failed to ensure array size for system TEMP value.");
88
89 (*prgsczSystemTempPaths)[*pcSystemTempPaths] = sczTemp;
90 sczTemp = NULL;
91 *pcSystemTempPaths += 1;
92 }
93 }
94
95 hr = PathSystemWindowsSubdirectory(L"TEMP", &sczTemp);
96 PathExitOnFailure(hr, "Failed to get system Windows subdirectory path TEMP.");
97
98 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczSystemTempPaths), *pcSystemTempPaths, 1, sizeof(LPWSTR), 1);
99 PathExitOnFailure(hr, "Failed to ensure array size for Windows\\TEMP value.");
100
101 (*prgsczSystemTempPaths)[*pcSystemTempPaths] = sczTemp;
102 sczTemp = NULL;
103 *pcSystemTempPaths += 1;
104
105LExit:
106 ReleaseRegKey(hKey);
107 ReleaseStr(sczTemp);
108
109 return hr;
110}
111
112static HRESULT GetTempPathFromSystemEnvironmentVariable(
113 __in HKEY hKey,
114 __in_z LPCWSTR wzName,
115 __out_z LPWSTR* psczPath
116 )
117{
118 HRESULT hr = S_OK;
119 LPWSTR sczValue = NULL;
120 BOOL fNeedsExpansion = FALSE;
121
122 // Read the value unexpanded so that it can be expanded with system environment variables.
123 hr = RegReadUnexpandedString(hKey, wzName, &fNeedsExpansion, &sczValue);
124 if (E_FILENOTFOUND == hr)
125 {
126 ExitFunction1(hr = S_FALSE);
127 }
128 PathExitOnFailure(hr, "Failed to get system '%ls' value.", wzName);
129
130 if (fNeedsExpansion)
131 {
132 hr = EnvExpandEnvironmentStringsForUser(NULL, sczValue, psczPath, NULL);
133 PathExitOnFailure(hr, "Failed to expand environment variables for system in string: %ls", sczValue);
134 }
135
136 hr = PathBackslashTerminate(psczPath);
137 PathExitOnFailure(hr, "Failed to backslash terminate system '%ls' value.", wzName);
138
139LExit:
140 ReleaseStr(sczValue);
141
142 return hr;
143}
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:
894} 894}
895 895
896 896
897DAPI_(HRESULT) PathGetSystemTempPaths(
898 __inout_z LPWSTR** prgsczSystemTempPaths,
899 __inout DWORD* pcSystemTempPaths
900 )
901{
902 HRESULT hr = S_OK;
903 HKEY hKey = NULL;
904 LPWSTR sczTemp = NULL;
905 WCHAR wzTempPath[MAX_PATH + 1] = { };
906 DWORD cch = 0;
907
908 // There is no documented API to get system environment variables, so read them from the registry.
909 hr = RegOpen(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\Session Manager\\Environment", KEY_READ, &hKey);
910 if (E_FILENOTFOUND != hr)
911 {
912 PathExitOnFailure(hr, "Failed to open system environment registry key.");
913
914 // Follow documented precedence rules for TMP/TEMP from ::GetTempPath.
915 // TODO: values will be expanded with the current environment variables instead of the system environment variables.
916 hr = RegReadString(hKey, L"TMP", &sczTemp);
917 if (E_FILENOTFOUND != hr)
918 {
919 PathExitOnFailure(hr, "Failed to get system TMP value.");
920
921 hr = PathBackslashTerminate(&sczTemp);
922 PathExitOnFailure(hr, "Failed to backslash terminate system TMP value.");
923
924 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczSystemTempPaths), *pcSystemTempPaths, 1, sizeof(LPWSTR), 3);
925 PathExitOnFailure(hr, "Failed to ensure array size for system TMP value.");
926
927 (*prgsczSystemTempPaths)[*pcSystemTempPaths] = sczTemp;
928 sczTemp = NULL;
929 *pcSystemTempPaths += 1;
930 }
931
932 hr = RegReadString(hKey, L"TEMP", &sczTemp);
933 if (E_FILENOTFOUND != hr)
934 {
935 PathExitOnFailure(hr, "Failed to get system TEMP value.");
936
937 hr = PathBackslashTerminate(&sczTemp);
938 PathExitOnFailure(hr, "Failed to backslash terminate system TEMP value.");
939
940 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczSystemTempPaths), *pcSystemTempPaths, 1, sizeof(LPWSTR), 2);
941 PathExitOnFailure(hr, "Failed to ensure array size for system TEMP value.");
942
943 (*prgsczSystemTempPaths)[*pcSystemTempPaths] = sczTemp;
944 sczTemp = NULL;
945 *pcSystemTempPaths += 1;
946 }
947 }
948
949 cch = ::GetSystemWindowsDirectoryW(wzTempPath, countof(wzTempPath));
950 if (!cch)
951 {
952 PathExitWithLastError(hr, "Failed to get Windows directory path.");
953 }
954 else if (cch >= countof(wzTempPath))
955 {
956 PathExitWithRootFailure(hr, E_INSUFFICIENT_BUFFER, "Windows directory path too long.");
957 }
958
959 hr = PathConcat(wzTempPath, L"TEMP\\", &sczTemp);
960 PathExitOnFailure(hr, "Failed to concat Temp directory on Windows directory path.");
961
962 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczSystemTempPaths), *pcSystemTempPaths, 1, sizeof(LPWSTR), 1);
963 PathExitOnFailure(hr, "Failed to ensure array size for Windows\\TEMP value.");
964
965 (*prgsczSystemTempPaths)[*pcSystemTempPaths] = sczTemp;
966 sczTemp = NULL;
967 *pcSystemTempPaths += 1;
968
969LExit:
970 ReleaseRegKey(hKey);
971 ReleaseStr(sczTemp);
972
973 return hr;
974}
975
976
977DAPI_(HRESULT) PathGetKnownFolder( 897DAPI_(HRESULT) PathGetKnownFolder(
978 __in int csidl, 898 __in int csidl,
979 __out LPWSTR* psczKnownFolder 899 __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:
102 return hr; 102 return hr;
103} 103}
104 104
105extern "C" HRESULT DAPI PolcReadUnexpandedString(
106 __in_z LPCWSTR wzPolicyPath,
107 __in_z LPCWSTR wzPolicyName,
108 __in_z_opt LPCWSTR wzDefault,
109 __inout BOOL* pfNeedsExpansion,
110 __deref_out_z LPWSTR* pscz
111 )
112{
113 HRESULT hr = S_OK;
114 HKEY hk = NULL;
115
116 hr = OpenPolicyKey(wzPolicyPath, &hk);
117 if (E_FILENOTFOUND == hr || E_PATHNOTFOUND == hr)
118 {
119 ExitFunction1(hr = S_FALSE);
120 }
121 PolcExitOnFailure(hr, "Failed to open policy key: %ls", wzPolicyPath);
122
123 hr = RegReadUnexpandedString(hk, wzPolicyName, pfNeedsExpansion, pscz);
124 if (E_FILENOTFOUND == hr || E_PATHNOTFOUND == hr)
125 {
126 ExitFunction1(hr = S_FALSE);
127 }
128 PolcExitOnFailure(hr, "Failed to open policy key: %ls, name: %ls", wzPolicyPath, wzPolicyName);
129
130LExit:
131 ReleaseRegKey(hk);
132
133 if (S_FALSE == hr || FAILED(hr))
134 {
135 if (NULL == wzDefault)
136 {
137 ReleaseNullStr(*pscz);
138 }
139 else
140 {
141 hr = StrAllocString(pscz, wzDefault, 0);
142 }
143 }
144
145 return hr;
146}
147
105 148
106// internal functions 149// internal functions
107 150
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 @@
9#define ProcExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_PROCUTIL, x, s, __VA_ARGS__) 9#define ProcExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_PROCUTIL, x, s, __VA_ARGS__)
10#define ProcExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_PROCUTIL, x, s, __VA_ARGS__) 10#define ProcExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_PROCUTIL, x, s, __VA_ARGS__)
11#define ProcExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_PROCUTIL, x, s, __VA_ARGS__) 11#define ProcExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_PROCUTIL, x, s, __VA_ARGS__)
12#define ProcExitWithRootFailure(x, e, s, ...) ExitWithRootFailureSource(DUTIL_SOURCE_PROCUTIL, x, e, s, __VA_ARGS__)
12#define ProcExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_PROCUTIL, x, s, __VA_ARGS__) 13#define ProcExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_PROCUTIL, x, s, __VA_ARGS__)
13#define ProcExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_PROCUTIL, p, x, e, s, __VA_ARGS__) 14#define ProcExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_PROCUTIL, p, x, e, s, __VA_ARGS__)
14#define ProcExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_PROCUTIL, p, x, s, __VA_ARGS__) 15#define ProcExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_PROCUTIL, p, x, s, __VA_ARGS__)
@@ -75,6 +76,73 @@ LExit:
75 return hr; 76 return hr;
76} 77}
77 78
79extern "C" HRESULT DAPI ProcSystem(
80 __in HANDLE hProcess,
81 __out BOOL* pfSystem
82 )
83{
84 HRESULT hr = S_OK;
85 TOKEN_USER* pTokenUser = NULL;
86
87 hr = ProcTokenUser(hProcess, &pTokenUser);
88 ProcExitOnFailure(hr, "Failed to get TokenUser from process token.");
89
90 *pfSystem = ::IsWellKnownSid(pTokenUser->User.Sid, WinLocalSystemSid);
91
92LExit:
93 ReleaseMem(pTokenUser);
94
95 return hr;
96}
97
98extern "C" HRESULT DAPI ProcTokenUser(
99 __in HANDLE hProcess,
100 __out TOKEN_USER** ppTokenUser
101 )
102{
103 HRESULT hr = S_OK;
104 DWORD er = ERROR_SUCCESS;
105 HANDLE hToken = NULL;
106 TOKEN_USER* pTokenUser = NULL;
107 DWORD cbToken = 0;
108
109 if (!::OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
110 {
111 ProcExitWithLastError(hr, "Failed to open process token.");
112 }
113
114 if (::GetTokenInformation(hToken, TokenUser, pTokenUser, 0, &cbToken))
115 {
116 er = ERROR_SUCCESS;
117 }
118 else
119 {
120 er = ::GetLastError();
121 }
122
123 if (er != ERROR_INSUFFICIENT_BUFFER)
124 {
125 ProcExitOnWin32Error(er, hr, "Failed to get user from process token size.");
126 }
127
128 pTokenUser = reinterpret_cast<TOKEN_USER*>(MemAlloc(cbToken, TRUE));
129 ProcExitOnNull(pTokenUser, hr, E_OUTOFMEMORY, "Failed to allocate token information.");
130
131 if (!::GetTokenInformation(hToken, TokenUser, pTokenUser, cbToken, &cbToken))
132 {
133 ProcExitWithLastError(hr, "Failed to get user from process token.");
134 }
135
136 *ppTokenUser = pTokenUser;
137 pTokenUser = NULL;
138
139LExit:
140 ReleaseMem(pTokenUser);
141 ReleaseHandle(hToken);
142
143 return hr;
144}
145
78extern "C" HRESULT DAPI ProcWow64( 146extern "C" HRESULT DAPI ProcWow64(
79 __in HANDLE hProcess, 147 __in HANDLE hProcess,
80 __out BOOL* pfWow64 148 __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 @@
40 40
41 <PropertyGroup> 41 <PropertyGroup>
42 <ProjectAdditionalIncludeDirectories>..\..\WixToolset.DUtil\inc</ProjectAdditionalIncludeDirectories> 42 <ProjectAdditionalIncludeDirectories>..\..\WixToolset.DUtil\inc</ProjectAdditionalIncludeDirectories>
43 <ProjectAdditionalLinkLibraries>rpcrt4.lib;Mpr.lib;Ws2_32.lib;shlwapi.lib;urlmon.lib;wininet.lib</ProjectAdditionalLinkLibraries> 43 <ProjectAdditionalLinkLibraries>rpcrt4.lib;Mpr.lib;Ws2_32.lib;shlwapi.lib;urlmon.lib;userenv.lib;wininet.lib</ProjectAdditionalLinkLibraries>
44 </PropertyGroup> 44 </PropertyGroup>
45 45
46 <ItemGroup> 46 <ItemGroup>
@@ -57,6 +57,7 @@
57 <ClCompile Include="MemUtilTest.cpp" /> 57 <ClCompile Include="MemUtilTest.cpp" />
58 <ClCompile Include="MonUtilTest.cpp" /> 58 <ClCompile Include="MonUtilTest.cpp" />
59 <ClCompile Include="PathUtilTest.cpp" /> 59 <ClCompile Include="PathUtilTest.cpp" />
60 <ClCompile Include="ProcUtilTest.cpp" />
60 <ClCompile Include="precomp.cpp"> 61 <ClCompile Include="precomp.cpp">
61 <PrecompiledHeader>Create</PrecompiledHeader> 62 <PrecompiledHeader>Create</PrecompiledHeader>
62 <!-- Warnings from referencing netstandard dlls --> 63 <!-- Warnings from referencing netstandard dlls -->
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 @@
54 <ClCompile Include="PathUtilTest.cpp"> 54 <ClCompile Include="PathUtilTest.cpp">
55 <Filter>Source Files</Filter> 55 <Filter>Source Files</Filter>
56 </ClCompile> 56 </ClCompile>
57 <ClCompile Include="ProcUtilTest.cpp">
58 <Filter>Source Files</Filter>
59 </ClCompile>
57 <ClCompile Include="precomp.cpp"> 60 <ClCompile Include="precomp.cpp">
58 <Filter>Source Files</Filter> 61 <Filter>Source Files</Filter>
59 </ClCompile> 62 </ClCompile>
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 @@
3#include "precomp.h" 3#include "precomp.h"
4 4
5using namespace System; 5using namespace System;
6using namespace System::Collections;
6using namespace Xunit; 7using namespace Xunit;
7using namespace WixBuildTools::TestSupport; 8using namespace WixBuildTools::TestSupport;
9using namespace WixBuildTools::TestSupport::XunitExtensions;
8 10
9namespace DutilTests 11namespace DutilTests
10{ 12{
@@ -46,5 +48,48 @@ namespace DutilTests
46 ReleaseStr(sczExpanded); 48 ReleaseStr(sczExpanded);
47 } 49 }
48 } 50 }
51
52 [SkippableFact]
53 void EnvExpandEnvironmentStringsForUserTest()
54 {
55 HRESULT hr = S_OK;
56 LPWSTR sczExpanded = NULL;
57 SIZE_T cchExpanded = 0;
58 String^ variableName = nullptr;
59 String^ variableValue = nullptr;
60
61 // Find a system environment variable that doesn't have variables in its value;
62 for each (DictionaryEntry^ entry in Environment::GetEnvironmentVariables(EnvironmentVariableTarget::Machine))
63 {
64 variableValue = (String^)entry->Value;
65 if (variableValue->Contains("%"))
66 {
67 continue;
68 }
69
70 variableName = (String^)entry->Key;
71 break;
72 }
73
74 if (nullptr == variableName)
75 {
76 WixAssert::Skip("No suitable system environment variables");
77 }
78
79 pin_ptr<const wchar_t> wzUnexpanded = PtrToStringChars("%" + variableName + "%_%USERNAME%");
80 String^ expandedValue = variableValue + "_SYSTEM";
81
82 try
83 {
84 hr = EnvExpandEnvironmentStringsForUser(NULL, wzUnexpanded, &sczExpanded, &cchExpanded);
85 NativeAssert::Succeeded(hr, "Failed to expand %ls.", wzUnexpanded);
86 WixAssert::StringEqual(expandedValue, gcnew String(sczExpanded), false);
87 NativeAssert::Equal<SIZE_T>(expandedValue->Length + 1, cchExpanded);
88 }
89 finally
90 {
91 ReleaseStr(sczExpanded);
92 }
93 }
49 }; 94 };
50} 95}
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 @@
1// 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.
2
3#include "precomp.h"
4
5using namespace System;
6using namespace System::Security::Principal;
7using namespace Xunit;
8using namespace WixBuildTools::TestSupport;
9
10namespace DutilTests
11{
12 public ref class ProcUtil
13 {
14 public:
15 [Fact]
16 void ProcTokenUserTest()
17 {
18 HRESULT hr = S_OK;
19 TOKEN_USER* pTokenUser = NULL;
20 LPWSTR sczSid = NULL;
21
22 try
23 {
24 hr = ProcTokenUser(::GetCurrentProcess(), &pTokenUser);
25 NativeAssert::Succeeded(hr, "Failed to get TokenUser for current process.");
26
27 if (!::ConvertSidToStringSidW(pTokenUser->User.Sid, &sczSid))
28 {
29 hr = HRESULT_FROM_WIN32(::GetLastError());
30 NativeAssert::Succeeded(hr, "Failed to get string SID from TokenUser SID.");
31 }
32
33 Assert::Equal<String^>(WindowsIdentity::GetCurrent()->User->Value, gcnew String(sczSid));
34 }
35 finally
36 {
37 ReleaseMem(pTokenUser);
38 ReleaseStr(sczSid);
39 }
40 }
41 };
42}
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 @@
5#include <windows.h> 5#include <windows.h>
6#include <strsafe.h> 6#include <strsafe.h>
7#include <ShlObj.h> 7#include <ShlObj.h>
8#include <sddl.h>
8 9
9// Include error.h before dutil.h 10// Include error.h before dutil.h
10#include <dutilsources.h> 11#include <dutilsources.h>
@@ -21,6 +22,7 @@
21#include <iniutil.h> 22#include <iniutil.h>
22#include <memutil.h> 23#include <memutil.h>
23#include <pathutil.h> 24#include <pathutil.h>
25#include <procutil.h>
24#include <strutil.h> 26#include <strutil.h>
25#include <monutil.h> 27#include <monutil.h>
26#include <regutil.h> 28#include <regutil.h>