summaryrefslogtreecommitdiffstats
path: root/winpr/libwinpr/environment/environment.c
diff options
context:
space:
mode:
Diffstat (limited to 'winpr/libwinpr/environment/environment.c')
-rw-r--r--winpr/libwinpr/environment/environment.c708
1 files changed, 708 insertions, 0 deletions
diff --git a/winpr/libwinpr/environment/environment.c b/winpr/libwinpr/environment/environment.c
new file mode 100644
index 0000000..c6df6bd
--- /dev/null
+++ b/winpr/libwinpr/environment/environment.c
@@ -0,0 +1,708 @@
+/**
+ * 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/string.h>
+
+#include <winpr/environment.h>
+
+#ifndef _WIN32
+
+#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)
+{
+ char* cwd = NULL;
+ size_t length = 0;
+
+ cwd = getcwd(NULL, 0);
+
+ if (!cwd)
+ return 0;
+
+ length = strlen(cwd);
+
+ if ((nBufferLength == 0) && (lpBuffer == NULL))
+ {
+ free(cwd);
+
+ return (DWORD)length;
+ }
+ else
+ {
+ if (lpBuffer == NULL)
+ {
+ 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(DWORD nBufferLength, LPWSTR lpBuffer)
+{
+ return 0;
+}
+
+BOOL SetCurrentDirectoryA(LPCSTR lpPathName)
+{
+ return TRUE;
+}
+
+BOOL SetCurrentDirectoryW(LPCWSTR lpPathName)
+{
+ return TRUE;
+}
+
+DWORD SearchPathA(LPCSTR lpPath, LPCSTR lpFileName, LPCSTR lpExtension, DWORD nBufferLength,
+ LPSTR lpBuffer, LPSTR* lpFilePart)
+{
+ return 0;
+}
+
+DWORD SearchPathW(LPCWSTR lpPath, LPCWSTR lpFileName, LPCWSTR lpExtension, DWORD nBufferLength,
+ LPWSTR lpBuffer, LPWSTR* lpFilePart)
+{
+ return 0;
+}
+
+LPSTR GetCommandLineA(VOID)
+{
+ return NULL;
+}
+
+LPWSTR GetCommandLineW(VOID)
+{
+ return NULL;
+}
+
+BOOL NeedCurrentDirectoryForExePathA(LPCSTR ExeName)
+{
+ return TRUE;
+}
+
+BOOL NeedCurrentDirectoryForExePathW(LPCWSTR ExeName)
+{
+ return TRUE;
+}
+
+#endif
+
+#if !defined(_WIN32) || defined(_UWP)
+
+DWORD GetEnvironmentVariableA(LPCSTR lpName, LPSTR lpBuffer, DWORD nSize)
+{
+#if !defined(_UWP)
+ size_t length = 0;
+ char* env = NULL;
+
+ 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(LPCWSTR lpName, LPWSTR lpBuffer, DWORD nSize)
+{
+ SetLastError(ERROR_ENVVAR_NOT_FOUND);
+ return 0;
+}
+
+BOOL SetEnvironmentVariableA(LPCSTR lpName, LPCSTR lpValue)
+{
+#if !defined(_UWP)
+ if (!lpName)
+ return FALSE;
+
+ if (lpValue)
+ {
+ if (0 != setenv(lpName, lpValue, 1))
+ return FALSE;
+ }
+ else
+ {
+ if (0 != unsetenv(lpName))
+ return FALSE;
+ }
+
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+BOOL SetEnvironmentVariableW(LPCWSTR lpName, LPCWSTR lpValue)
+{
+ 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)
+ char* p = NULL;
+ size_t offset = 0;
+ size_t length = 0;
+ char** envp = NULL;
+ DWORD cchEnvironmentBlock = 0;
+ LPCH lpszEnvironmentBlock = NULL;
+
+ offset = 0;
+ envp = environ;
+
+ cchEnvironmentBlock = 128;
+ lpszEnvironmentBlock = (LPCH)calloc(cchEnvironmentBlock, sizeof(CHAR));
+ if (!lpszEnvironmentBlock)
+ return NULL;
+
+ while (*envp)
+ {
+ length = strlen(*envp);
+
+ while ((offset + length + 8) > cchEnvironmentBlock)
+ {
+ DWORD new_size = 0;
+ LPCH new_blk = NULL;
+
+ new_size = cchEnvironmentBlock * 2;
+ new_blk = (LPCH)realloc(lpszEnvironmentBlock, new_size * sizeof(CHAR));
+ if (!new_blk)
+ {
+ free(lpszEnvironmentBlock);
+ return NULL;
+ }
+
+ lpszEnvironmentBlock = new_blk;
+ cchEnvironmentBlock = new_size;
+ }
+
+ p = &(lpszEnvironmentBlock[offset]);
+
+ CopyMemory(p, *envp, length * sizeof(CHAR));
+ p[length] = '\0';
+
+ offset += (length + 1);
+ envp++;
+ }
+
+ lpszEnvironmentBlock[offset] = '\0';
+
+ return lpszEnvironmentBlock;
+#else
+ return NULL;
+#endif
+}
+
+LPWCH GetEnvironmentStringsW(VOID)
+{
+ return NULL;
+}
+
+BOOL SetEnvironmentStringsA(LPCH NewEnvironment)
+{
+ return TRUE;
+}
+
+BOOL SetEnvironmentStringsW(LPWCH NewEnvironment)
+{
+ return TRUE;
+}
+
+DWORD ExpandEnvironmentStringsA(LPCSTR lpSrc, LPSTR lpDst, DWORD nSize)
+{
+ return 0;
+}
+
+DWORD ExpandEnvironmentStringsW(LPCWSTR lpSrc, LPWSTR lpDst, DWORD nSize)
+{
+ return 0;
+}
+
+BOOL FreeEnvironmentStringsA(LPCH lpszEnvironmentBlock)
+{
+ free(lpszEnvironmentBlock);
+
+ return TRUE;
+}
+
+BOOL FreeEnvironmentStringsW(LPWCH lpszEnvironmentBlock)
+{
+ return TRUE;
+}
+
+#endif
+
+LPCH MergeEnvironmentStrings(PCSTR original, PCSTR merge)
+{
+ const char* cp = NULL;
+ char* p = NULL;
+ size_t offset = 0;
+ size_t length = 0;
+ const char* envp = NULL;
+ DWORD cchEnvironmentBlock = 0;
+ LPCH lpszEnvironmentBlock = NULL;
+ const char** mergeStrings = NULL;
+ size_t mergeStringLength = 0;
+ size_t mergeArraySize = 128;
+ size_t mergeLength = 0;
+ size_t foundMerge = 0;
+ char* foundEquals = NULL;
+
+ mergeStrings = (LPCSTR*)calloc(mergeArraySize, sizeof(char*));
+
+ if (!mergeStrings)
+ return NULL;
+
+ mergeStringLength = 0;
+
+ cp = merge;
+
+ while (*cp && *(cp + 1))
+ {
+ length = strlen(cp);
+
+ if (mergeStringLength == mergeArraySize)
+ {
+ const char** new_str = NULL;
+
+ mergeArraySize += 128;
+ new_str = (const char**)realloc((void*)mergeStrings, mergeArraySize * sizeof(char*));
+
+ if (!new_str)
+ {
+ free((void*)mergeStrings);
+ return NULL;
+ }
+ 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 NULL;
+ }
+
+ envp = original;
+
+ while ((original != NULL) && (*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 NULL;
+ }
+ 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;
+
+ if (strncmp(envp, mergeStrings[run], foundEquals - mergeStrings[run] + 1) == 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 NULL;
+ }
+ lpszEnvironmentBlock = tmp;
+ p = &(lpszEnvironmentBlock[old_offset]);
+ }
+
+ foundMerge = 1;
+ CopyMemory(p, mergeStrings[run], mergeLength);
+ mergeStrings[run] = NULL;
+ 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 NULL;
+ }
+
+ lpszEnvironmentBlock = tmp;
+ }
+
+ p = &(lpszEnvironmentBlock[offset]);
+
+ CopyMemory(p, mergeStrings[run], mergeLength);
+ mergeStrings[run] = NULL;
+ 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 = NULL;
+ char* foundEquals = NULL;
+ const char* penvb = envBlock;
+ size_t nLength = 0;
+ size_t fLength = 0;
+ size_t lpNameLength = 0;
+
+ if (!lpName || NULL == 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 = (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 = NULL;
+ char* newEB = NULL;
+
+ 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;
+
+ 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;
+
+ 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 = NULL;
+ SSIZE_T index = 0;
+ size_t count = 0;
+ size_t length = 0;
+ char** envp = NULL;
+
+ count = 0;
+ if (!lpszEnvironmentBlock)
+ return NULL;
+
+ 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 NULL;
+ envp[count] = NULL;
+
+ 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(envp);
+ return NULL;
+ }
+ 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 = NULL;
+ LPWSTR lpBufferW = NULL;
+ LPSTR lpBufferA = lpBuffer;
+
+ lpNameW = ConvertUtf8ToWCharAlloc(lpName, NULL);
+ if (!lpNameW)
+ goto cleanup;
+
+ if (!lpBuffer)
+ {
+ char lpBufferMaxA[WINPR_MAX_ENVIRONMENT_LENGTH] = { 0 };
+ WCHAR lpBufferMaxW[WINPR_MAX_ENVIRONMENT_LENGTH] = { 0 };
+ 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