2222
2323#include " xr_dependencies.h"
2424#include < string>
25+ #include < stdlib.h>
2526
2627// OpenXR paths and registry key locations
2728#define OPENXR_RELATIVE_PATH " openxr/"
@@ -57,6 +58,8 @@ namespace detail {
5758
5859static inline char * ImplGetEnv (const char * name) { return getenv (name); }
5960
61+ static inline int ImplSetEnv (const char * name, const char * value, int overwrite) { return setenv (name, value, overwrite); }
62+
6063static inline char * ImplGetSecureEnv (const char * name) {
6164#ifdef HAVE_SECURE_GETENV
6265 return secure_getenv (name);
@@ -93,6 +96,12 @@ static inline std::string PlatformUtilsGetSecureEnv(const char* name) {
9396
9497static inline bool PlatformUtilsGetEnvSet (const char * name) { return detail::ImplGetEnv (name) != nullptr ; }
9598
99+ static inline bool PlatformUtilsSetEnv (const char * name, const char * value) {
100+ const int shouldOverwrite = 1 ;
101+ int result = detail::ImplSetEnv (name, value, shouldOverwrite);
102+ return (result == 0 );
103+ }
104+
96105#elif defined(XR_OS_APPLE)
97106
98107static inline std::string PlatformUtilsGetEnv (const char * name) {
@@ -113,6 +122,12 @@ static inline std::string PlatformUtilsGetSecureEnv(const char* name) {
113122
114123static inline bool PlatformUtilsGetEnvSet (const char * name) { return detail::ImplGetEnv (name) != nullptr ; }
115124
125+ static inline bool PlatformUtilsSetEnv (const char * name, const char * value) {
126+ const int shouldOverwrite = 1 ;
127+ int result = detail::ImplSetEnv (name, value, shouldOverwrite);
128+ return (result == 0 );
129+ }
130+
116131// Prefix for the Apple global runtime JSON file name
117132static const std::string rt_dir_prefix = " /usr/local/share/openxr/" ;
118133static const std::string rt_filename = " /active_runtime.json" ;
@@ -181,7 +196,9 @@ inline std::string wide_to_utf8(const std::wstring& wideText) {
181196 return narrowText;
182197}
183198
199+ // Returns true if the current process has an integrity level > SECURITY_MANDATORY_MEDIUM_RID.
184200static inline bool IsHighIntegrityLevel () {
201+ // Execute this check once and save the value as a static bool.
185202 static bool isHighIntegrityLevel = ([] {
186203 HANDLE processToken;
187204 if (OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY | TOKEN_QUERY_SOURCE, &processToken)) {
@@ -191,9 +208,12 @@ static inline bool IsHighIntegrityLevel() {
191208 if (GetTokenInformation (processToken, TokenIntegrityLevel, mandatoryLabelBuffer, sizeof (mandatoryLabelBuffer),
192209 &bufferSize) != 0 ) {
193210 const auto mandatoryLabel = reinterpret_cast <const TOKEN_MANDATORY_LABEL*>(mandatoryLabelBuffer);
194- const DWORD subAuthorityCount = *GetSidSubAuthorityCount (mandatoryLabel->Label .Sid );
195- const DWORD integrityLevel = *GetSidSubAuthority (mandatoryLabel->Label .Sid , subAuthorityCount - 1 );
196- return integrityLevel > SECURITY_MANDATORY_MEDIUM_RID;
211+ if (mandatoryLabel->Label .Sid != 0 ) {
212+ const DWORD subAuthorityCount = *GetSidSubAuthorityCount (mandatoryLabel->Label .Sid );
213+ const DWORD integrityLevel = *GetSidSubAuthority (mandatoryLabel->Label .Sid , subAuthorityCount - 1 );
214+ CloseHandle (processToken);
215+ return integrityLevel > SECURITY_MANDATORY_MEDIUM_RID;
216+ }
197217 }
198218
199219 CloseHandle (processToken);
@@ -205,37 +225,45 @@ static inline bool IsHighIntegrityLevel() {
205225 return isHighIntegrityLevel;
206226}
207227
228+ // Returns true if the given environment variable exists.
229+ // The name is a case-sensitive UTF8 string.
208230static inline bool PlatformUtilsGetEnvSet (const char * name) {
209231 const std::wstring wname = utf8_to_wide (name);
210232 const DWORD valSize = ::GetEnvironmentVariableW (wname.c_str (), nullptr , 0 );
211- // GetEnvironmentVariable returns 0 when environment variable does not exist
233+ // GetEnvironmentVariable returns 0 when environment variable does not exist or there is an error.
212234 return 0 != valSize;
213235}
214236
237+ // Returns the environment variable value for the given name.
238+ // Returns an empty string if the environment variable doesn't exist or if it exists but is empty.
239+ // Use PlatformUtilsGetEnvSet to tell if it exists.
240+ // The name is a case-sensitive UTF8 string.
215241static inline std::string PlatformUtilsGetEnv (const char * name) {
216242 const std::wstring wname = utf8_to_wide (name);
217243 const DWORD valSize = ::GetEnvironmentVariableW (wname.c_str (), nullptr , 0 );
218- // GetEnvironmentVariable returns 0 when environment variable does not exist
244+ // GetEnvironmentVariable returns 0 when environment variable does not exist or there is an error.
219245 if (valSize == 0 ) {
220246 return {};
221247 }
222248
223249 // GetEnvironmentVariable returns size including null terminator for "query size" call.
224250 std::wstring wValue (valSize, 0 );
225- wchar_t * wValueData = const_cast < wchar_t *>( wValue. data ()); // mutable data() only exists in c++17
251+ wchar_t * wValueData = & wValue[ 0 ];
226252
227- // GetEnvironmentVariable returns string length, excluding null terminator for "get value" call.
228- const int length = ::GetEnvironmentVariableW (wname.c_str (), wValueData, (DWORD)wValue.size ());
229- if (length == 0 ) {
253+ // GetEnvironmentVariable returns string length, excluding null terminator for "get value"
254+ // call if there was enough capacity. Else it returns the required capacity (including null terminator).
255+ const DWORD length = ::GetEnvironmentVariableW (wname.c_str (), wValueData, (DWORD)wValue.size ());
256+ if ((length == 0 ) || (length >= wValue.size ())) { // If error or the variable increased length between calls...
230257 LogError (" GetEnvironmentVariable get value error: " + std::to_string (::GetLastError ()));
231258 return {};
232259 }
233260
234- wValue.resize (length); // Strip the null terminator.
261+ wValue.resize (length); // Strip the null terminator.
235262
236263 return wide_to_utf8 (wValue);
237264}
238265
266+ // Acts the same as PlatformUtilsGetEnv except returns an empty string if IsHighIntegrityLevel.
239267static inline std::string PlatformUtilsGetSecureEnv (const char * name) {
240268 // Do not allow high integrity processes to act on data that can be controlled by medium integrity processes.
241269 if (IsHighIntegrityLevel ()) {
@@ -246,23 +274,40 @@ static inline std::string PlatformUtilsGetSecureEnv(const char* name) {
246274 return PlatformUtilsGetEnv (name);
247275}
248276
249- #else // Not Linux or Windows
277+ // Sets an environment variable via UTF8 strings.
278+ // The name is case-sensitive.
279+ // Overwrites the variable if it already exists.
280+ // Returns true if it could be set.
281+ static inline bool PlatformUtilsSetEnv (const char * name, const char * value) {
282+ const std::wstring wname = utf8_to_wide (name);
283+ const std::wstring wvalue = utf8_to_wide (value);
284+ BOOL result = ::SetEnvironmentVariableW (wname.c_str (), wvalue.c_str ());
285+ return (result != 0 );
286+ }
250287
251- static inline std::string PlatformUtilsGetEnv (const char * /* name */ ) {
288+ #else // Not Linux, Apple, nor Windows
289+
290+ static inline bool PlatformUtilsGetEnvSet (const char * /* name */ ) {
291+ // Stub func
292+ return false ;
293+ }
294+
295+ static inline std::string PlatformUtilsGetEnv (const char * /* name */ ) {
252296 // Stub func
253297 return {};
254298}
255299
256- static inline char * PlatformUtilsGetSecureEnv (const char * /* name */ ) {
300+ static inline std::string PlatformUtilsGetSecureEnv (const char * /* name */ ) {
257301 // Stub func
258302 return {};
259303}
260304
261- static inline void PlatformUtilsFreeEnv ( char * /* val */ ) {
305+ static inline bool PlatformUtilsSetEnv ( const char * /* name */ , const char * /* value */ ) {
262306 // Stub func
307+ return false ;
263308}
264309
265- static inline bool PlatformGetGlobalRuntimeFileName (uint16_t /* major_version */ , std::string const & /* file_name */ ) {
310+ static inline bool PlatformGetGlobalRuntimeFileName (uint16_t /* major_version */ , std::string const & /* file_name */ ) {
266311 // Stub func
267312 return false ;
268313}
0 commit comments