FreeRDP
Loading...
Searching...
No Matches
environment.c
1
22#include <winpr/config.h>
23
24#include <winpr/crt.h>
25#include <winpr/platform.h>
26#include <winpr/error.h>
27#include <winpr/file.h>
28#include <winpr/string.h>
29#include <winpr/wlog.h>
30
31#include <winpr/environment.h>
32
33#include "../log.h"
34
35#define TAG WINPR_TAG("environment")
36
37#ifndef _WIN32
38
39#include <errno.h>
40
41#ifdef WINPR_HAVE_UNISTD_H
42#include <unistd.h>
43#endif
44
45#if defined(__IOS__)
46
47#elif defined(__MACOSX__)
48#include <crt_externs.h>
49#define environ (*_NSGetEnviron())
50#endif
51
52DWORD GetCurrentDirectoryA(DWORD nBufferLength, LPSTR lpBuffer)
53{
54 size_t length = 0;
55 char* cwd = nullptr;
56 char* ccwd = nullptr;
57
58 do
59 {
60 length += MAX_PATH;
61 char* tmp = realloc(cwd, length);
62 if (!tmp)
63 {
64 free(cwd);
65 return 0;
66 }
67 cwd = tmp;
68
69 ccwd = getcwd(cwd, length);
70 } while (!ccwd && (errno == ERANGE));
71
72 if (!ccwd)
73 {
74 free(cwd);
75 return 0;
76 }
77
78 length = strnlen(cwd, length);
79
80 if ((nBufferLength == 0) && (lpBuffer == nullptr))
81 {
82 free(cwd);
83 return (DWORD)length;
84 }
85 else
86 {
87 if (lpBuffer == nullptr)
88 {
89 free(cwd);
90 return 0;
91 }
92
93 if ((length + 1) > nBufferLength)
94 {
95 free(cwd);
96 return (DWORD)(length + 1);
97 }
98
99 memcpy(lpBuffer, cwd, length + 1);
100 free(cwd);
101 return (DWORD)length;
102 }
103}
104
105DWORD GetCurrentDirectoryW(WINPR_ATTR_UNUSED DWORD nBufferLength, WINPR_ATTR_UNUSED LPWSTR lpBuffer)
106{
107 WLog_ERR(TAG, "TODO: not implemented");
108 return 0;
109}
110
111BOOL SetCurrentDirectoryA(WINPR_ATTR_UNUSED LPCSTR lpPathName)
112{
113 WLog_ERR(TAG, "TODO: not implemented");
114 return TRUE;
115}
116
117BOOL SetCurrentDirectoryW(WINPR_ATTR_UNUSED LPCWSTR lpPathName)
118{
119 WLog_ERR(TAG, "TODO: not implemented");
120 return TRUE;
121}
122
123DWORD SearchPathA(WINPR_ATTR_UNUSED LPCSTR lpPath, WINPR_ATTR_UNUSED LPCSTR lpFileName,
124 WINPR_ATTR_UNUSED LPCSTR lpExtension, WINPR_ATTR_UNUSED DWORD nBufferLength,
125 WINPR_ATTR_UNUSED LPSTR lpBuffer, WINPR_ATTR_UNUSED LPSTR* lpFilePart)
126{
127 WLog_ERR(TAG, "TODO: not implemented");
128 return 0;
129}
130
131DWORD SearchPathW(WINPR_ATTR_UNUSED LPCWSTR lpPath, WINPR_ATTR_UNUSED LPCWSTR lpFileName,
132 WINPR_ATTR_UNUSED LPCWSTR lpExtension, WINPR_ATTR_UNUSED DWORD nBufferLength,
133 WINPR_ATTR_UNUSED LPWSTR lpBuffer, WINPR_ATTR_UNUSED LPWSTR* lpFilePart)
134{
135 WLog_ERR(TAG, "TODO: not implemented");
136 return 0;
137}
138
139LPSTR GetCommandLineA(VOID)
140{
141 WLog_ERR(TAG, "TODO: not implemented");
142 return nullptr;
143}
144
145LPWSTR GetCommandLineW(VOID)
146{
147 WLog_ERR(TAG, "TODO: not implemented");
148 return nullptr;
149}
150
151BOOL NeedCurrentDirectoryForExePathA(WINPR_ATTR_UNUSED LPCSTR ExeName)
152{
153 WLog_ERR(TAG, "TODO: not implemented");
154 return TRUE;
155}
156
157BOOL NeedCurrentDirectoryForExePathW(WINPR_ATTR_UNUSED LPCWSTR ExeName)
158{
159 WLog_ERR(TAG, "TODO: not implemented");
160 return TRUE;
161}
162
163#endif
164
165#if !defined(_WIN32) || defined(_UWP)
166
167DWORD GetEnvironmentVariableA(LPCSTR lpName, LPSTR lpBuffer, DWORD nSize)
168{
169#if !defined(_UWP)
170 size_t length = 0;
171
172 // NOLINTNEXTLINE(concurrency-mt-unsafe)
173 char* env = getenv(lpName);
174
175 if (!env)
176 {
177 SetLastError(ERROR_ENVVAR_NOT_FOUND);
178 return 0;
179 }
180
181 length = strlen(env);
182
183 if ((length + 1 > nSize) || (!lpBuffer))
184 return (DWORD)length + 1;
185
186 CopyMemory(lpBuffer, env, length);
187 lpBuffer[length] = '\0';
188
189 return (DWORD)length;
190#else
191 SetLastError(ERROR_ENVVAR_NOT_FOUND);
192 return 0;
193#endif
194}
195
196DWORD GetEnvironmentVariableW(WINPR_ATTR_UNUSED LPCWSTR lpName, WINPR_ATTR_UNUSED LPWSTR lpBuffer,
197 WINPR_ATTR_UNUSED DWORD nSize)
198{
199 WLog_ERR(TAG, "TODO: not implemented");
200 SetLastError(ERROR_ENVVAR_NOT_FOUND);
201 return 0;
202}
203
204BOOL SetEnvironmentVariableA(LPCSTR lpName, LPCSTR lpValue)
205{
206#if !defined(_UWP)
207 if (!lpName)
208 return FALSE;
209
210 if (lpValue)
211 {
212 // NOLINTNEXTLINE(concurrency-mt-unsafe)
213 if (0 != setenv(lpName, lpValue, 1))
214 return FALSE;
215 }
216 else
217 {
218 // NOLINTNEXTLINE(concurrency-mt-unsafe)
219 if (0 != unsetenv(lpName))
220 return FALSE;
221 }
222
223 return TRUE;
224#else
225 return FALSE;
226#endif
227}
228
229BOOL SetEnvironmentVariableW(WINPR_ATTR_UNUSED LPCWSTR lpName, WINPR_ATTR_UNUSED LPCWSTR lpValue)
230{
231 WLog_ERR(TAG, "TODO: not implemented");
232 return FALSE;
233}
234
251extern char** environ;
252
253WINPR_ATTR_MALLOC(FreeEnvironmentStringsA, 1)
254static LPCH GetEnvironmentStringsAN(size_t* pLen)
255{
256#if !defined(_UWP)
257 size_t offset = 0;
258 char** envp = environ;
259 const size_t blocksize = 128;
260 size_t cchEnvironmentBlock = blocksize;
261 LPCH lpszEnvironmentBlock = (LPCH)calloc(cchEnvironmentBlock, sizeof(CHAR));
262
263 if (pLen)
264 *pLen = 0;
265
266 if (!lpszEnvironmentBlock)
267 return nullptr;
268
269 while (*envp)
270 {
271 const size_t length = strlen(*envp);
272 const size_t required = offset + length + 8ull;
273 if (required > UINT32_MAX)
274 {
275 WLog_ERR(TAG, "Environment block too large: %" PRIuz, required);
276
277 free(lpszEnvironmentBlock);
278 return nullptr;
279 }
280
281 if (required > cchEnvironmentBlock)
282 {
283 size_t new_size = cchEnvironmentBlock;
284 do
285 {
286 new_size += blocksize;
287 } while (new_size <= required);
288 LPCH new_blk = (LPCH)realloc(lpszEnvironmentBlock, new_size * sizeof(CHAR));
289 if (!new_blk)
290 {
291 free(lpszEnvironmentBlock);
292 return nullptr;
293 }
294
295 const size_t diff = new_size - cchEnvironmentBlock;
296 const size_t old = cchEnvironmentBlock;
297 lpszEnvironmentBlock = new_blk;
298 cchEnvironmentBlock = new_size;
299
300 memset(&lpszEnvironmentBlock[old], 0, diff);
301 }
302
303 char* p = &(lpszEnvironmentBlock[offset]);
304
305 CopyMemory(p, *envp, length * sizeof(CHAR));
306 p[length] = '\0';
307
308 offset += (length + 1ull);
309 envp++;
310 }
311
312 lpszEnvironmentBlock[offset] = '\0';
313 if (pLen)
314 *pLen = cchEnvironmentBlock;
315
316 return lpszEnvironmentBlock;
317#else
318 if (pLen)
319 *pLen = 0;
320 return nullptr;
321#endif
322}
323
324LPCH GetEnvironmentStringsA(VOID)
325{
326 return GetEnvironmentStringsAN(nullptr);
327}
328
329LPWCH GetEnvironmentStringsW(VOID)
330{
331 size_t len = 0;
332 LPCH env = GetEnvironmentStringsAN(&len);
333 if (!env)
334 return nullptr;
335 LPWCH envW = ConvertMszUtf8NToWCharAlloc(env, len, nullptr);
336 FreeEnvironmentStringsA(env);
337 return envW;
338}
339
340BOOL SetEnvironmentStringsA(WINPR_ATTR_UNUSED LPCH NewEnvironment)
341{
342 WLog_ERR(TAG, "TODO: not implemented");
343 return TRUE;
344}
345
346BOOL SetEnvironmentStringsW(WINPR_ATTR_UNUSED LPWCH NewEnvironment)
347{
348 WLog_ERR(TAG, "TODO: not implemented");
349 return TRUE;
350}
351
352DWORD ExpandEnvironmentStringsA(WINPR_ATTR_UNUSED LPCSTR lpSrc, WINPR_ATTR_UNUSED LPSTR lpDst,
353 WINPR_ATTR_UNUSED DWORD nSize)
354{
355 WLog_ERR(TAG, "TODO: not implemented");
356 return 0;
357}
358
359DWORD ExpandEnvironmentStringsW(WINPR_ATTR_UNUSED LPCWSTR lpSrc, WINPR_ATTR_UNUSED LPWSTR lpDst,
360 WINPR_ATTR_UNUSED DWORD nSize)
361{
362 WLog_ERR(TAG, "TODO: not implemented");
363 return 0;
364}
365
366BOOL FreeEnvironmentStringsA(LPCH lpszEnvironmentBlock)
367{
368 free(lpszEnvironmentBlock);
369
370 return TRUE;
371}
372
373BOOL FreeEnvironmentStringsW(LPWCH lpszEnvironmentBlock)
374{
375 free(lpszEnvironmentBlock);
376
377 return TRUE;
378}
379
380#endif
381
382LPCH MergeEnvironmentStrings(PCSTR original, PCSTR merge)
383{
384 const char* cp = nullptr;
385 char* p = nullptr;
386 size_t offset = 0;
387 size_t length = 0;
388 const char* envp = nullptr;
389 DWORD cchEnvironmentBlock = 0;
390 LPCH lpszEnvironmentBlock = nullptr;
391 const char** mergeStrings = nullptr;
392 size_t mergeStringLength = 0;
393 size_t mergeArraySize = 128;
394 size_t mergeLength = 0;
395 size_t foundMerge = 0;
396 char* foundEquals = nullptr;
397
398 mergeStrings = (LPCSTR*)calloc(mergeArraySize, sizeof(char*));
399
400 if (!mergeStrings)
401 return nullptr;
402
403 mergeStringLength = 0;
404
405 cp = merge;
406
407 while (*cp && *(cp + 1))
408 {
409 length = strlen(cp);
410
411 if (mergeStringLength == mergeArraySize)
412 {
413 const char** new_str = nullptr;
414
415 mergeArraySize += 128;
416 new_str = (const char**)realloc((void*)mergeStrings, mergeArraySize * sizeof(char*));
417
418 if (!new_str)
419 {
420 free((void*)mergeStrings);
421 return nullptr;
422 }
423 mergeStrings = new_str;
424 }
425
426 mergeStrings[mergeStringLength] = cp;
427 cp += length + 1;
428 mergeStringLength++;
429 }
430
431 offset = 0;
432
433 cchEnvironmentBlock = 128;
434 lpszEnvironmentBlock = (LPCH)calloc(cchEnvironmentBlock, sizeof(CHAR));
435
436 if (!lpszEnvironmentBlock)
437 {
438 free((void*)mergeStrings);
439 return nullptr;
440 }
441
442 envp = original;
443
444 while ((original != nullptr) && (*envp && *(envp + 1)))
445 {
446 size_t old_offset = offset;
447 length = strlen(envp);
448
449 while ((offset + length + 8) > cchEnvironmentBlock)
450 {
451 cchEnvironmentBlock *= 2;
452 LPCH tmp = (LPCH)realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
453
454 if (!tmp)
455 {
456 free((void*)lpszEnvironmentBlock);
457 free((void*)mergeStrings);
458 return nullptr;
459 }
460 lpszEnvironmentBlock = tmp;
461 }
462
463 p = &(lpszEnvironmentBlock[offset]);
464
465 // check if this value is in the mergeStrings
466 foundMerge = 0;
467 for (size_t run = 0; run < mergeStringLength; run++)
468 {
469 if (!mergeStrings[run])
470 continue;
471
472 mergeLength = strlen(mergeStrings[run]);
473 foundEquals = strstr(mergeStrings[run], "=");
474
475 if (!foundEquals)
476 continue;
477
478 const intptr_t len = foundEquals - mergeStrings[run] + 1;
479 if (strncmp(envp, mergeStrings[run], WINPR_ASSERTING_INT_CAST(size_t, len)) == 0)
480 {
481 // found variable in merge list ... use this ....
482 if (*(foundEquals + 1) == '\0')
483 {
484 // check if the argument is set ... if not remove variable ...
485 foundMerge = 1;
486 }
487 else
488 {
489 while ((offset + mergeLength + 8) > cchEnvironmentBlock)
490 {
491 cchEnvironmentBlock *= 2;
492 LPCH tmp =
493 (LPCH)realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
494
495 if (!tmp)
496 {
497 free((void*)lpszEnvironmentBlock);
498 free((void*)mergeStrings);
499 return nullptr;
500 }
501 lpszEnvironmentBlock = tmp;
502 p = &(lpszEnvironmentBlock[old_offset]);
503 }
504
505 foundMerge = 1;
506 CopyMemory(p, mergeStrings[run], mergeLength);
507 mergeStrings[run] = nullptr;
508 p[mergeLength] = '\0';
509 offset += (mergeLength + 1);
510 }
511 }
512 }
513
514 if (foundMerge == 0)
515 {
516 CopyMemory(p, envp, length * sizeof(CHAR));
517 p[length] = '\0';
518 offset += (length + 1);
519 }
520
521 envp += (length + 1);
522 }
523
524 // now merge the not already merged env
525 for (size_t run = 0; run < mergeStringLength; run++)
526 {
527 if (!mergeStrings[run])
528 continue;
529
530 mergeLength = strlen(mergeStrings[run]);
531
532 while ((offset + mergeLength + 8) > cchEnvironmentBlock)
533 {
534 cchEnvironmentBlock *= 2;
535 LPCH tmp = (LPCH)realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
536
537 if (!tmp)
538 {
539 free((void*)lpszEnvironmentBlock);
540 free((void*)mergeStrings);
541 return nullptr;
542 }
543
544 lpszEnvironmentBlock = tmp;
545 }
546
547 p = &(lpszEnvironmentBlock[offset]);
548
549 CopyMemory(p, mergeStrings[run], mergeLength);
550 mergeStrings[run] = nullptr;
551 p[mergeLength] = '\0';
552 offset += (mergeLength + 1);
553 }
554
555 lpszEnvironmentBlock[offset] = '\0';
556
557 free((void*)mergeStrings);
558
559 return lpszEnvironmentBlock;
560}
561
562DWORD GetEnvironmentVariableEBA(LPCSTR envBlock, LPCSTR lpName, LPSTR lpBuffer, DWORD nSize)
563{
564 size_t vLength = 0;
565 char* env = nullptr;
566 char* foundEquals = nullptr;
567 const char* penvb = envBlock;
568 size_t nLength = 0;
569 size_t fLength = 0;
570 size_t lpNameLength = 0;
571
572 if (!lpName || nullptr == envBlock)
573 return 0;
574
575 lpNameLength = strlen(lpName);
576
577 if (lpNameLength < 1)
578 return 0;
579
580 while (*penvb && *(penvb + 1))
581 {
582 fLength = strlen(penvb);
583 foundEquals = strstr(penvb, "=");
584
585 if (!foundEquals)
586 {
587 /* if no = sign is found the envBlock is broken */
588 return 0;
589 }
590
591 nLength = WINPR_ASSERTING_INT_CAST(size_t, (foundEquals - penvb));
592
593 if (nLength != lpNameLength)
594 {
595 penvb += (fLength + 1);
596 continue;
597 }
598
599 if (strncmp(penvb, lpName, nLength) == 0)
600 {
601 env = foundEquals + 1;
602 break;
603 }
604
605 penvb += (fLength + 1);
606 }
607
608 if (!env)
609 return 0;
610
611 vLength = strlen(env);
612 if (vLength >= UINT32_MAX)
613 return 0;
614
615 if ((vLength + 1 > nSize) || (!lpBuffer))
616 return (DWORD)vLength + 1;
617
618 CopyMemory(lpBuffer, env, vLength + 1);
619
620 return (DWORD)vLength;
621}
622
623BOOL SetEnvironmentVariableEBA(LPSTR* envBlock, LPCSTR lpName, LPCSTR lpValue)
624{
625 size_t length = 0;
626 char* envstr = nullptr;
627 char* newEB = nullptr;
628
629 if (!lpName)
630 return FALSE;
631
632 if (lpValue)
633 {
634 length = (strlen(lpName) + strlen(lpValue) + 2); /* +2 because of = and \0 */
635 envstr = (char*)malloc(length + 1); /* +1 because of closing \0 */
636
637 if (!envstr)
638 return FALSE;
639
640 (void)sprintf_s(envstr, length, "%s=%s", lpName, lpValue);
641 }
642 else
643 {
644 length = strlen(lpName) + 2; /* +2 because of = and \0 */
645 envstr = (char*)malloc(length + 1); /* +1 because of closing \0 */
646
647 if (!envstr)
648 return FALSE;
649
650 (void)sprintf_s(envstr, length, "%s=", lpName);
651 }
652
653 envstr[length] = '\0';
654
655 newEB = MergeEnvironmentStrings((LPCSTR)*envBlock, envstr);
656
657 free(envstr);
658 free(*envBlock);
659
660 *envBlock = newEB;
661
662 return TRUE;
663}
664
665char** EnvironmentBlockToEnvpA(LPCH lpszEnvironmentBlock)
666{
667 char* p = nullptr;
668 SSIZE_T index = 0;
669 size_t count = 0;
670 size_t length = 0;
671 char** envp = nullptr;
672
673 count = 0;
674 if (!lpszEnvironmentBlock)
675 return nullptr;
676
677 p = (char*)lpszEnvironmentBlock;
678
679 while (p[0] && p[1])
680 {
681 length = strlen(p);
682 p += (length + 1);
683 count++;
684 }
685
686 index = 0;
687 p = (char*)lpszEnvironmentBlock;
688
689 envp = (char**)calloc(count + 1, sizeof(char*));
690 if (!envp)
691 return nullptr;
692 envp[count] = nullptr;
693
694 while (p[0] && p[1])
695 {
696 length = strlen(p);
697 envp[index] = _strdup(p);
698 if (!envp[index])
699 {
700 for (index -= 1; index >= 0; --index)
701 {
702 free(envp[index]);
703 }
704 free((void*)envp);
705 return nullptr;
706 }
707 p += (length + 1);
708 index++;
709 }
710
711 return envp;
712}
713
714#ifdef _WIN32
715
716// https://devblogs.microsoft.com/oldnewthing/20100203-00/?p=15083
717#define WINPR_MAX_ENVIRONMENT_LENGTH 2048
718
719DWORD GetEnvironmentVariableX(const char* lpName, char* lpBuffer, DWORD nSize)
720{
721 DWORD result = 0;
722 DWORD nSizeW = 0;
723 LPWSTR lpNameW = nullptr;
724 LPWSTR lpBufferW = nullptr;
725 LPSTR lpBufferA = lpBuffer;
726
727 lpNameW = ConvertUtf8ToWCharAlloc(lpName, nullptr);
728 if (!lpNameW)
729 goto cleanup;
730
731 if (!lpBuffer)
732 {
733 char lpBufferMaxA[WINPR_MAX_ENVIRONMENT_LENGTH] = WINPR_C_ARRAY_INIT;
734 WCHAR lpBufferMaxW[WINPR_MAX_ENVIRONMENT_LENGTH] = WINPR_C_ARRAY_INIT;
735 LPSTR lpTmpBuffer = lpBufferMaxA;
736
737 nSizeW = ARRAYSIZE(lpBufferMaxW);
738
739 result = GetEnvironmentVariableW(lpNameW, lpBufferMaxW, nSizeW);
740
741 SSIZE_T rc =
742 ConvertWCharNToUtf8(lpBufferMaxW, nSizeW, lpTmpBuffer, ARRAYSIZE(lpBufferMaxA));
743 if ((rc < 0) || (rc >= UINT32_MAX))
744 goto cleanup;
745
746 result = (DWORD)rc + 1;
747 }
748 else
749 {
750 nSizeW = nSize;
751 lpBufferW = calloc(nSizeW + 1, sizeof(WCHAR));
752
753 if (!lpBufferW)
754 goto cleanup;
755
756 result = GetEnvironmentVariableW(lpNameW, lpBufferW, nSizeW);
757
758 if (result == 0)
759 goto cleanup;
760
761 SSIZE_T rc = ConvertWCharNToUtf8(lpBufferW, nSizeW, lpBufferA, nSize);
762 if ((rc < 0) || (rc > UINT32_MAX))
763 goto cleanup;
764
765 result = (DWORD)rc;
766 }
767
768cleanup:
769 free(lpBufferW);
770 free(lpNameW);
771
772 return result;
773}
774
775#else
776
777DWORD GetEnvironmentVariableX(const char* lpName, char* lpBuffer, DWORD nSize)
778{
779 return GetEnvironmentVariableA(lpName, lpBuffer, nSize);
780}
781
782#endif