Milestone 5: deliver embedded RDP sessions and lifecycle hardening

This commit is contained in:
Keith Smith
2026-03-03 18:59:26 -07:00
parent 230a401386
commit 36006bd4aa
2941 changed files with 724359 additions and 77 deletions

View File

@@ -0,0 +1,22 @@
# WinPR: Windows Portable Runtime
# libwinpr-environment cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
winpr_module_add(environment.c)
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@@ -0,0 +1,9 @@
set(MINWIN_LAYER "1")
set(MINWIN_GROUP "core")
set(MINWIN_MAJOR_VERSION "2")
set(MINWIN_MINOR_VERSION "0")
set(MINWIN_SHORT_NAME "processenvironment")
set(MINWIN_LONG_NAME "Process Environment Functions")
set(MODULE_LIBRARY_NAME
"api-ms-win-${MINWIN_GROUP}-${MINWIN_SHORT_NAME}-l${MINWIN_LAYER}-${MINWIN_MAJOR_VERSION}-${MINWIN_MINOR_VERSION}"
)

View File

@@ -0,0 +1,760 @@
/**
* WinPR: Windows Portable Runtime
* Process Environment Functions
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2013 Thincast Technologies GmbH
* Copyright 2013 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/config.h>
#include <winpr/crt.h>
#include <winpr/platform.h>
#include <winpr/error.h>
#include <winpr/file.h>
#include <winpr/string.h>
#include <winpr/wlog.h>
#include <winpr/environment.h>
#include "../log.h"
#define TAG WINPR_TAG("environment")
#ifndef _WIN32
#include <errno.h>
#ifdef WINPR_HAVE_UNISTD_H
#include <unistd.h>
#endif
#if defined(__IOS__)
#elif defined(__MACOSX__)
#include <crt_externs.h>
#define environ (*_NSGetEnviron())
#endif
DWORD GetCurrentDirectoryA(DWORD nBufferLength, LPSTR lpBuffer)
{
size_t length = 0;
char* cwd = nullptr;
char* ccwd = nullptr;
do
{
length += MAX_PATH;
char* tmp = realloc(cwd, length);
if (!tmp)
{
free(cwd);
return 0;
}
cwd = tmp;
ccwd = getcwd(cwd, length);
} while (!ccwd && (errno == ERANGE));
if (!ccwd)
{
free(cwd);
return 0;
}
length = strnlen(cwd, length);
if ((nBufferLength == 0) && (lpBuffer == nullptr))
{
free(cwd);
return (DWORD)length;
}
else
{
if (lpBuffer == nullptr)
{
free(cwd);
return 0;
}
if ((length + 1) > nBufferLength)
{
free(cwd);
return (DWORD)(length + 1);
}
memcpy(lpBuffer, cwd, length + 1);
free(cwd);
return (DWORD)length;
}
}
DWORD GetCurrentDirectoryW(WINPR_ATTR_UNUSED DWORD nBufferLength, WINPR_ATTR_UNUSED LPWSTR lpBuffer)
{
WLog_ERR(TAG, "TODO: not implemented");
return 0;
}
BOOL SetCurrentDirectoryA(WINPR_ATTR_UNUSED LPCSTR lpPathName)
{
WLog_ERR(TAG, "TODO: not implemented");
return TRUE;
}
BOOL SetCurrentDirectoryW(WINPR_ATTR_UNUSED LPCWSTR lpPathName)
{
WLog_ERR(TAG, "TODO: not implemented");
return TRUE;
}
DWORD SearchPathA(WINPR_ATTR_UNUSED LPCSTR lpPath, WINPR_ATTR_UNUSED LPCSTR lpFileName,
WINPR_ATTR_UNUSED LPCSTR lpExtension, WINPR_ATTR_UNUSED DWORD nBufferLength,
WINPR_ATTR_UNUSED LPSTR lpBuffer, WINPR_ATTR_UNUSED LPSTR* lpFilePart)
{
WLog_ERR(TAG, "TODO: not implemented");
return 0;
}
DWORD SearchPathW(WINPR_ATTR_UNUSED LPCWSTR lpPath, WINPR_ATTR_UNUSED LPCWSTR lpFileName,
WINPR_ATTR_UNUSED LPCWSTR lpExtension, WINPR_ATTR_UNUSED DWORD nBufferLength,
WINPR_ATTR_UNUSED LPWSTR lpBuffer, WINPR_ATTR_UNUSED LPWSTR* lpFilePart)
{
WLog_ERR(TAG, "TODO: not implemented");
return 0;
}
LPSTR GetCommandLineA(VOID)
{
WLog_ERR(TAG, "TODO: not implemented");
return nullptr;
}
LPWSTR GetCommandLineW(VOID)
{
WLog_ERR(TAG, "TODO: not implemented");
return nullptr;
}
BOOL NeedCurrentDirectoryForExePathA(WINPR_ATTR_UNUSED LPCSTR ExeName)
{
WLog_ERR(TAG, "TODO: not implemented");
return TRUE;
}
BOOL NeedCurrentDirectoryForExePathW(WINPR_ATTR_UNUSED LPCWSTR ExeName)
{
WLog_ERR(TAG, "TODO: not implemented");
return TRUE;
}
#endif
#if !defined(_WIN32) || defined(_UWP)
DWORD GetEnvironmentVariableA(LPCSTR lpName, LPSTR lpBuffer, DWORD nSize)
{
#if !defined(_UWP)
size_t length = 0;
// NOLINTNEXTLINE(concurrency-mt-unsafe)
char* env = getenv(lpName);
if (!env)
{
SetLastError(ERROR_ENVVAR_NOT_FOUND);
return 0;
}
length = strlen(env);
if ((length + 1 > nSize) || (!lpBuffer))
return (DWORD)length + 1;
CopyMemory(lpBuffer, env, length);
lpBuffer[length] = '\0';
return (DWORD)length;
#else
SetLastError(ERROR_ENVVAR_NOT_FOUND);
return 0;
#endif
}
DWORD GetEnvironmentVariableW(WINPR_ATTR_UNUSED LPCWSTR lpName, WINPR_ATTR_UNUSED LPWSTR lpBuffer,
WINPR_ATTR_UNUSED DWORD nSize)
{
WLog_ERR(TAG, "TODO: not implemented");
SetLastError(ERROR_ENVVAR_NOT_FOUND);
return 0;
}
BOOL SetEnvironmentVariableA(LPCSTR lpName, LPCSTR lpValue)
{
#if !defined(_UWP)
if (!lpName)
return FALSE;
if (lpValue)
{
// NOLINTNEXTLINE(concurrency-mt-unsafe)
if (0 != setenv(lpName, lpValue, 1))
return FALSE;
}
else
{
// NOLINTNEXTLINE(concurrency-mt-unsafe)
if (0 != unsetenv(lpName))
return FALSE;
}
return TRUE;
#else
return FALSE;
#endif
}
BOOL SetEnvironmentVariableW(WINPR_ATTR_UNUSED LPCWSTR lpName, WINPR_ATTR_UNUSED LPCWSTR lpValue)
{
WLog_ERR(TAG, "TODO: not implemented");
return FALSE;
}
/**
* GetEnvironmentStrings function:
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms683187/
*
* The GetEnvironmentStrings function returns a pointer to a block of memory
* that contains the environment variables of the calling process (both the
* system and the user environment variables). Each environment block contains
* the environment variables in the following format:
*
* Var1=Value1\0
* Var2=Value2\0
* Var3=Value3\0
* ...
* VarN=ValueN\0\0
*/
extern char** environ;
LPCH GetEnvironmentStringsA(VOID)
{
#if !defined(_UWP)
size_t offset = 0;
char** envp = environ;
const size_t blocksize = 128;
size_t cchEnvironmentBlock = blocksize;
LPCH lpszEnvironmentBlock = (LPCH)calloc(cchEnvironmentBlock, sizeof(CHAR));
if (!lpszEnvironmentBlock)
return nullptr;
while (*envp)
{
const size_t length = strlen(*envp);
const size_t required = offset + length + 8ull;
if (required > UINT32_MAX)
{
WLog_ERR(TAG, "Environment block too large: %" PRIuz, required);
free(lpszEnvironmentBlock);
return nullptr;
}
if (required > cchEnvironmentBlock)
{
size_t new_size = cchEnvironmentBlock;
do
{
new_size += blocksize;
} while (new_size <= required);
LPCH new_blk = (LPCH)realloc(lpszEnvironmentBlock, new_size * sizeof(CHAR));
if (!new_blk)
{
free(lpszEnvironmentBlock);
return nullptr;
}
lpszEnvironmentBlock = new_blk;
cchEnvironmentBlock = new_size;
}
char* p = &(lpszEnvironmentBlock[offset]);
CopyMemory(p, *envp, length * sizeof(CHAR));
p[length] = '\0';
offset += (length + 1ull);
envp++;
}
lpszEnvironmentBlock[offset] = '\0';
return lpszEnvironmentBlock;
#else
return nullptr;
#endif
}
LPWCH GetEnvironmentStringsW(VOID)
{
WLog_ERR(TAG, "TODO: not implemented");
return nullptr;
}
BOOL SetEnvironmentStringsA(WINPR_ATTR_UNUSED LPCH NewEnvironment)
{
WLog_ERR(TAG, "TODO: not implemented");
return TRUE;
}
BOOL SetEnvironmentStringsW(WINPR_ATTR_UNUSED LPWCH NewEnvironment)
{
WLog_ERR(TAG, "TODO: not implemented");
return TRUE;
}
DWORD ExpandEnvironmentStringsA(WINPR_ATTR_UNUSED LPCSTR lpSrc, WINPR_ATTR_UNUSED LPSTR lpDst,
WINPR_ATTR_UNUSED DWORD nSize)
{
WLog_ERR(TAG, "TODO: not implemented");
return 0;
}
DWORD ExpandEnvironmentStringsW(WINPR_ATTR_UNUSED LPCWSTR lpSrc, WINPR_ATTR_UNUSED LPWSTR lpDst,
WINPR_ATTR_UNUSED DWORD nSize)
{
WLog_ERR(TAG, "TODO: not implemented");
return 0;
}
BOOL FreeEnvironmentStringsA(LPCH lpszEnvironmentBlock)
{
free(lpszEnvironmentBlock);
return TRUE;
}
BOOL FreeEnvironmentStringsW(LPWCH lpszEnvironmentBlock)
{
free(lpszEnvironmentBlock);
return TRUE;
}
#endif
LPCH MergeEnvironmentStrings(PCSTR original, PCSTR merge)
{
const char* cp = nullptr;
char* p = nullptr;
size_t offset = 0;
size_t length = 0;
const char* envp = nullptr;
DWORD cchEnvironmentBlock = 0;
LPCH lpszEnvironmentBlock = nullptr;
const char** mergeStrings = nullptr;
size_t mergeStringLength = 0;
size_t mergeArraySize = 128;
size_t mergeLength = 0;
size_t foundMerge = 0;
char* foundEquals = nullptr;
mergeStrings = (LPCSTR*)calloc(mergeArraySize, sizeof(char*));
if (!mergeStrings)
return nullptr;
mergeStringLength = 0;
cp = merge;
while (*cp && *(cp + 1))
{
length = strlen(cp);
if (mergeStringLength == mergeArraySize)
{
const char** new_str = nullptr;
mergeArraySize += 128;
new_str = (const char**)realloc((void*)mergeStrings, mergeArraySize * sizeof(char*));
if (!new_str)
{
free((void*)mergeStrings);
return nullptr;
}
mergeStrings = new_str;
}
mergeStrings[mergeStringLength] = cp;
cp += length + 1;
mergeStringLength++;
}
offset = 0;
cchEnvironmentBlock = 128;
lpszEnvironmentBlock = (LPCH)calloc(cchEnvironmentBlock, sizeof(CHAR));
if (!lpszEnvironmentBlock)
{
free((void*)mergeStrings);
return nullptr;
}
envp = original;
while ((original != nullptr) && (*envp && *(envp + 1)))
{
size_t old_offset = offset;
length = strlen(envp);
while ((offset + length + 8) > cchEnvironmentBlock)
{
cchEnvironmentBlock *= 2;
LPCH tmp = (LPCH)realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
if (!tmp)
{
free((void*)lpszEnvironmentBlock);
free((void*)mergeStrings);
return nullptr;
}
lpszEnvironmentBlock = tmp;
}
p = &(lpszEnvironmentBlock[offset]);
// check if this value is in the mergeStrings
foundMerge = 0;
for (size_t run = 0; run < mergeStringLength; run++)
{
if (!mergeStrings[run])
continue;
mergeLength = strlen(mergeStrings[run]);
foundEquals = strstr(mergeStrings[run], "=");
if (!foundEquals)
continue;
const intptr_t len = foundEquals - mergeStrings[run] + 1;
if (strncmp(envp, mergeStrings[run], WINPR_ASSERTING_INT_CAST(size_t, len)) == 0)
{
// found variable in merge list ... use this ....
if (*(foundEquals + 1) == '\0')
{
// check if the argument is set ... if not remove variable ...
foundMerge = 1;
}
else
{
while ((offset + mergeLength + 8) > cchEnvironmentBlock)
{
cchEnvironmentBlock *= 2;
LPCH tmp =
(LPCH)realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
if (!tmp)
{
free((void*)lpszEnvironmentBlock);
free((void*)mergeStrings);
return nullptr;
}
lpszEnvironmentBlock = tmp;
p = &(lpszEnvironmentBlock[old_offset]);
}
foundMerge = 1;
CopyMemory(p, mergeStrings[run], mergeLength);
mergeStrings[run] = nullptr;
p[mergeLength] = '\0';
offset += (mergeLength + 1);
}
}
}
if (foundMerge == 0)
{
CopyMemory(p, envp, length * sizeof(CHAR));
p[length] = '\0';
offset += (length + 1);
}
envp += (length + 1);
}
// now merge the not already merged env
for (size_t run = 0; run < mergeStringLength; run++)
{
if (!mergeStrings[run])
continue;
mergeLength = strlen(mergeStrings[run]);
while ((offset + mergeLength + 8) > cchEnvironmentBlock)
{
cchEnvironmentBlock *= 2;
LPCH tmp = (LPCH)realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
if (!tmp)
{
free((void*)lpszEnvironmentBlock);
free((void*)mergeStrings);
return nullptr;
}
lpszEnvironmentBlock = tmp;
}
p = &(lpszEnvironmentBlock[offset]);
CopyMemory(p, mergeStrings[run], mergeLength);
mergeStrings[run] = nullptr;
p[mergeLength] = '\0';
offset += (mergeLength + 1);
}
lpszEnvironmentBlock[offset] = '\0';
free((void*)mergeStrings);
return lpszEnvironmentBlock;
}
DWORD GetEnvironmentVariableEBA(LPCSTR envBlock, LPCSTR lpName, LPSTR lpBuffer, DWORD nSize)
{
size_t vLength = 0;
char* env = nullptr;
char* foundEquals = nullptr;
const char* penvb = envBlock;
size_t nLength = 0;
size_t fLength = 0;
size_t lpNameLength = 0;
if (!lpName || nullptr == envBlock)
return 0;
lpNameLength = strlen(lpName);
if (lpNameLength < 1)
return 0;
while (*penvb && *(penvb + 1))
{
fLength = strlen(penvb);
foundEquals = strstr(penvb, "=");
if (!foundEquals)
{
/* if no = sign is found the envBlock is broken */
return 0;
}
nLength = WINPR_ASSERTING_INT_CAST(size_t, (foundEquals - penvb));
if (nLength != lpNameLength)
{
penvb += (fLength + 1);
continue;
}
if (strncmp(penvb, lpName, nLength) == 0)
{
env = foundEquals + 1;
break;
}
penvb += (fLength + 1);
}
if (!env)
return 0;
vLength = strlen(env);
if (vLength >= UINT32_MAX)
return 0;
if ((vLength + 1 > nSize) || (!lpBuffer))
return (DWORD)vLength + 1;
CopyMemory(lpBuffer, env, vLength + 1);
return (DWORD)vLength;
}
BOOL SetEnvironmentVariableEBA(LPSTR* envBlock, LPCSTR lpName, LPCSTR lpValue)
{
size_t length = 0;
char* envstr = nullptr;
char* newEB = nullptr;
if (!lpName)
return FALSE;
if (lpValue)
{
length = (strlen(lpName) + strlen(lpValue) + 2); /* +2 because of = and \0 */
envstr = (char*)malloc(length + 1); /* +1 because of closing \0 */
if (!envstr)
return FALSE;
(void)sprintf_s(envstr, length, "%s=%s", lpName, lpValue);
}
else
{
length = strlen(lpName) + 2; /* +2 because of = and \0 */
envstr = (char*)malloc(length + 1); /* +1 because of closing \0 */
if (!envstr)
return FALSE;
(void)sprintf_s(envstr, length, "%s=", lpName);
}
envstr[length] = '\0';
newEB = MergeEnvironmentStrings((LPCSTR)*envBlock, envstr);
free(envstr);
free(*envBlock);
*envBlock = newEB;
return TRUE;
}
char** EnvironmentBlockToEnvpA(LPCH lpszEnvironmentBlock)
{
char* p = nullptr;
SSIZE_T index = 0;
size_t count = 0;
size_t length = 0;
char** envp = nullptr;
count = 0;
if (!lpszEnvironmentBlock)
return nullptr;
p = (char*)lpszEnvironmentBlock;
while (p[0] && p[1])
{
length = strlen(p);
p += (length + 1);
count++;
}
index = 0;
p = (char*)lpszEnvironmentBlock;
envp = (char**)calloc(count + 1, sizeof(char*));
if (!envp)
return nullptr;
envp[count] = nullptr;
while (p[0] && p[1])
{
length = strlen(p);
envp[index] = _strdup(p);
if (!envp[index])
{
for (index -= 1; index >= 0; --index)
{
free(envp[index]);
}
free((void*)envp);
return nullptr;
}
p += (length + 1);
index++;
}
return envp;
}
#ifdef _WIN32
// https://devblogs.microsoft.com/oldnewthing/20100203-00/?p=15083
#define WINPR_MAX_ENVIRONMENT_LENGTH 2048
DWORD GetEnvironmentVariableX(const char* lpName, char* lpBuffer, DWORD nSize)
{
DWORD result = 0;
DWORD nSizeW = 0;
LPWSTR lpNameW = nullptr;
LPWSTR lpBufferW = nullptr;
LPSTR lpBufferA = lpBuffer;
lpNameW = ConvertUtf8ToWCharAlloc(lpName, nullptr);
if (!lpNameW)
goto cleanup;
if (!lpBuffer)
{
char lpBufferMaxA[WINPR_MAX_ENVIRONMENT_LENGTH] = WINPR_C_ARRAY_INIT;
WCHAR lpBufferMaxW[WINPR_MAX_ENVIRONMENT_LENGTH] = WINPR_C_ARRAY_INIT;
LPSTR lpTmpBuffer = lpBufferMaxA;
nSizeW = ARRAYSIZE(lpBufferMaxW);
result = GetEnvironmentVariableW(lpNameW, lpBufferMaxW, nSizeW);
SSIZE_T rc =
ConvertWCharNToUtf8(lpBufferMaxW, nSizeW, lpTmpBuffer, ARRAYSIZE(lpBufferMaxA));
if ((rc < 0) || (rc >= UINT32_MAX))
goto cleanup;
result = (DWORD)rc + 1;
}
else
{
nSizeW = nSize;
lpBufferW = calloc(nSizeW + 1, sizeof(WCHAR));
if (!lpBufferW)
goto cleanup;
result = GetEnvironmentVariableW(lpNameW, lpBufferW, nSizeW);
if (result == 0)
goto cleanup;
SSIZE_T rc = ConvertWCharNToUtf8(lpBufferW, nSizeW, lpBufferA, nSize);
if ((rc < 0) || (rc > UINT32_MAX))
goto cleanup;
result = (DWORD)rc;
}
cleanup:
free(lpBufferW);
free(lpNameW);
return result;
}
#else
DWORD GetEnvironmentVariableX(const char* lpName, char* lpBuffer, DWORD nSize)
{
return GetEnvironmentVariableA(lpName, lpBuffer, nSize);
}
#endif

View File

@@ -0,0 +1,25 @@
set(MODULE_NAME "TestEnvironment")
set(MODULE_PREFIX "TEST_ENVIRONMENT")
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS TestEnvironmentGetEnvironmentStrings.c TestEnvironmentSetEnvironmentVariable.c
TestEnvironmentMergeEnvironmentStrings.c TestEnvironmentGetSetEB.c
)
create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} ${${MODULE_PREFIX}_TESTS})
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
target_link_libraries(${MODULE_NAME} winpr)
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
foreach(test ${${MODULE_PREFIX}_TESTS})
get_filename_component(TestName ${test} NAME_WE)
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
endforeach()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")

View File

@@ -0,0 +1,41 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/tchar.h>
#include <winpr/environment.h>
int TestEnvironmentGetEnvironmentStrings(int argc, char* argv[])
{
int r = -1;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
LPTCH lpszEnvironmentBlock = GetEnvironmentStrings();
if (!lpszEnvironmentBlock)
goto fail;
TCHAR* p = lpszEnvironmentBlock;
while (p[0] && p[1])
{
const size_t max = _tcslen(p);
const int rc = _sntprintf(nullptr, 0, _T("%s\n"), p);
if (rc < 1)
{
_tprintf(_T("test failed: return %d\n"), rc);
goto fail;
}
if (max != (size_t)(rc - 1))
{
_tprintf(_T("test failed: length %") _T(PRIuz) _T(" != %d [%s]\n"), max, rc - 1, p);
goto fail;
}
p += (max + 1);
}
r = 0;
fail:
FreeEnvironmentStrings(lpszEnvironmentBlock);
return r;
}

View File

@@ -0,0 +1,138 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/tchar.h>
#include <winpr/environment.h>
int TestEnvironmentGetSetEB(int argc, char* argv[])
{
int rc = 0;
#ifndef _WIN32
char test[1024];
TCHAR* p = nullptr;
DWORD length = 0;
LPTCH lpszEnvironmentBlock = "SHELL=123\0test=1\0test1=2\0DISPLAY=WINPR_TEST_VALUE\0\0";
LPTCH lpszEnvironmentBlockNew = nullptr;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
rc = -1;
/* Get length of an variable */
length = GetEnvironmentVariableEBA(lpszEnvironmentBlock, "DISPLAY", nullptr, 0);
if (0 == length)
return -1;
/* Get the variable itself */
p = (LPSTR)malloc(length);
if (!p)
goto fail;
if (GetEnvironmentVariableEBA(lpszEnvironmentBlock, "DISPLAY", p, length) != length - 1)
goto fail;
printf("GetEnvironmentVariableA(WINPR_TEST_VARIABLE) = %s\n", p);
if (strcmp(p, "WINPR_TEST_VALUE") != 0)
goto fail;
/* Get length of an non-existing variable */
length = GetEnvironmentVariableEBA(lpszEnvironmentBlock, "BLA", nullptr, 0);
if (0 != length)
{
printf("Unset variable returned\n");
goto fail;
}
/* Get length of an similar called variables */
length = GetEnvironmentVariableEBA(lpszEnvironmentBlock, "XDISPLAY", nullptr, 0);
if (0 != length)
{
printf("Similar named variable returned (XDISPLAY, length %d)\n", length);
goto fail;
}
length = GetEnvironmentVariableEBA(lpszEnvironmentBlock, "DISPLAYX", nullptr, 0);
if (0 != length)
{
printf("Similar named variable returned (DISPLAYX, length %d)\n", length);
goto fail;
}
length = GetEnvironmentVariableEBA(lpszEnvironmentBlock, "DISPLA", nullptr, 0);
if (0 != length)
{
printf("Similar named variable returned (DISPLA, length %d)\n", length);
goto fail;
}
length = GetEnvironmentVariableEBA(lpszEnvironmentBlock, "ISPLAY", nullptr, 0);
if (0 != length)
{
printf("Similar named variable returned (ISPLAY, length %d)\n", length);
goto fail;
}
/* Set variable in empty environment block */
if (SetEnvironmentVariableEBA(&lpszEnvironmentBlockNew, "test", "5"))
{
if (GetEnvironmentVariableEBA(lpszEnvironmentBlockNew, "test", test, 1023))
{
if (strcmp(test, "5") != 0)
goto fail;
}
else
goto fail;
}
/* Clear variable */
if (SetEnvironmentVariableEBA(&lpszEnvironmentBlockNew, "test", nullptr))
{
if (GetEnvironmentVariableEBA(lpszEnvironmentBlockNew, "test", test, 1023))
goto fail;
else
{
// not found .. this is expected
}
}
free(lpszEnvironmentBlockNew);
lpszEnvironmentBlockNew = (LPTCH)calloc(1024, sizeof(TCHAR));
if (!lpszEnvironmentBlockNew)
goto fail;
memcpy(lpszEnvironmentBlockNew, lpszEnvironmentBlock, length);
/* Set variable in empty environment block */
if (SetEnvironmentVariableEBA(&lpszEnvironmentBlockNew, "test", "5"))
{
if (0 != GetEnvironmentVariableEBA(lpszEnvironmentBlockNew, "testr", test, 1023))
{
printf("GetEnvironmentVariableEBA returned unset variable\n");
goto fail;
}
if (GetEnvironmentVariableEBA(lpszEnvironmentBlockNew, "test", test, 1023))
{
if (strcmp(test, "5") != 0)
goto fail;
}
else
goto fail;
}
rc = 0;
fail:
free(p);
free(lpszEnvironmentBlockNew);
#endif
return rc;
}

View File

@@ -0,0 +1,34 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/tchar.h>
#include <winpr/environment.h>
int TestEnvironmentMergeEnvironmentStrings(int argc, char* argv[])
{
#ifndef _WIN32
TCHAR* p = nullptr;
size_t length = 0;
LPTCH lpszEnvironmentBlock = nullptr;
LPTCH lpsz2Merge = "SHELL=123\0test=1\0test1=2\0DISPLAY=:77\0\0";
LPTCH lpszMergedEnvironmentBlock = nullptr;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
lpszEnvironmentBlock = GetEnvironmentStrings();
lpszMergedEnvironmentBlock = MergeEnvironmentStrings(lpszEnvironmentBlock, lpsz2Merge);
p = (TCHAR*)lpszMergedEnvironmentBlock;
while (p[0] && p[1])
{
printf("%s\n", p);
length = strlen(p);
p += (length + 1);
}
FreeEnvironmentStrings(lpszMergedEnvironmentBlock);
FreeEnvironmentStrings(lpszEnvironmentBlock);
#endif
return 0;
}

View File

@@ -0,0 +1,72 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/tchar.h>
#include <winpr/environment.h>
#include <winpr/error.h>
#define TEST_NAME "WINPR_TEST_VARIABLE"
#define TEST_VALUE "WINPR_TEST_VALUE"
int TestEnvironmentSetEnvironmentVariable(int argc, char* argv[])
{
int rc = -1;
DWORD nSize = 0;
LPSTR lpBuffer = nullptr;
DWORD error = 0;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
SetEnvironmentVariableA(TEST_NAME, TEST_VALUE);
nSize = GetEnvironmentVariableA(TEST_NAME, nullptr, 0);
/* check if value returned is len + 1 ) */
if (nSize != strnlen(TEST_VALUE, sizeof(TEST_VALUE)) + 1)
{
printf("GetEnvironmentVariableA not found error\n");
return -1;
}
lpBuffer = (LPSTR)malloc(nSize);
if (!lpBuffer)
return -1;
nSize = GetEnvironmentVariableA(TEST_NAME, lpBuffer, nSize);
if (nSize != strnlen(TEST_VALUE, sizeof(TEST_VALUE)))
{
printf("GetEnvironmentVariableA wrong size returned\n");
goto fail;
}
if (strcmp(lpBuffer, TEST_VALUE) != 0)
{
printf("GetEnvironmentVariableA returned value doesn't match\n");
goto fail;
}
nSize = GetEnvironmentVariableA("__xx__notset_", lpBuffer, nSize);
error = GetLastError();
if (0 != nSize || ERROR_ENVVAR_NOT_FOUND != error)
{
printf("GetEnvironmentVariableA not found error\n");
goto fail;
}
/* clear variable */
SetEnvironmentVariableA(TEST_NAME, nullptr);
nSize = GetEnvironmentVariableA(TEST_VALUE, nullptr, 0);
if (0 != nSize)
{
printf("SetEnvironmentVariableA failed to clear variable\n");
goto fail;
}
rc = 0;
fail:
free(lpBuffer);
return rc;
}