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
253LPCH GetEnvironmentStringsA(VOID)
254{
255#if !defined(_UWP)
256 size_t offset = 0;
257 char** envp = environ;
258 const size_t blocksize = 128;
259 size_t cchEnvironmentBlock = blocksize;
260 LPCH lpszEnvironmentBlock = (LPCH)calloc(cchEnvironmentBlock, sizeof(CHAR));
261
262 if (!lpszEnvironmentBlock)
263 return nullptr;
264
265 while (*envp)
266 {
267 const size_t length = strlen(*envp);
268 const size_t required = offset + length + 8ull;
269 if (required > UINT32_MAX)
270 {
271 WLog_ERR(TAG, "Environment block too large: %" PRIuz, required);
272
273 free(lpszEnvironmentBlock);
274 return nullptr;
275 }
276
277 if (required > cchEnvironmentBlock)
278 {
279 size_t new_size = cchEnvironmentBlock;
280 do
281 {
282 new_size += blocksize;
283 } while (new_size <= required);
284 LPCH new_blk = (LPCH)realloc(lpszEnvironmentBlock, new_size * sizeof(CHAR));
285 if (!new_blk)
286 {
287 free(lpszEnvironmentBlock);
288 return nullptr;
289 }
290
291 lpszEnvironmentBlock = new_blk;
292 cchEnvironmentBlock = new_size;
293 }
294
295 char* p = &(lpszEnvironmentBlock[offset]);
296
297 CopyMemory(p, *envp, length * sizeof(CHAR));
298 p[length] = '\0';
299
300 offset += (length + 1ull);
301 envp++;
302 }
303
304 lpszEnvironmentBlock[offset] = '\0';
305
306 return lpszEnvironmentBlock;
307#else
308 return nullptr;
309#endif
310}
311
312LPWCH GetEnvironmentStringsW(VOID)
313{
314 WLog_ERR(TAG, "TODO: not implemented");
315 return nullptr;
316}
317
318BOOL SetEnvironmentStringsA(WINPR_ATTR_UNUSED LPCH NewEnvironment)
319{
320 WLog_ERR(TAG, "TODO: not implemented");
321 return TRUE;
322}
323
324BOOL SetEnvironmentStringsW(WINPR_ATTR_UNUSED LPWCH NewEnvironment)
325{
326 WLog_ERR(TAG, "TODO: not implemented");
327 return TRUE;
328}
329
330DWORD ExpandEnvironmentStringsA(WINPR_ATTR_UNUSED LPCSTR lpSrc, WINPR_ATTR_UNUSED LPSTR lpDst,
331 WINPR_ATTR_UNUSED DWORD nSize)
332{
333 WLog_ERR(TAG, "TODO: not implemented");
334 return 0;
335}
336
337DWORD ExpandEnvironmentStringsW(WINPR_ATTR_UNUSED LPCWSTR lpSrc, WINPR_ATTR_UNUSED LPWSTR lpDst,
338 WINPR_ATTR_UNUSED DWORD nSize)
339{
340 WLog_ERR(TAG, "TODO: not implemented");
341 return 0;
342}
343
344BOOL FreeEnvironmentStringsA(LPCH lpszEnvironmentBlock)
345{
346 free(lpszEnvironmentBlock);
347
348 return TRUE;
349}
350
351BOOL FreeEnvironmentStringsW(LPWCH lpszEnvironmentBlock)
352{
353 free(lpszEnvironmentBlock);
354
355 return TRUE;
356}
357
358#endif
359
360LPCH MergeEnvironmentStrings(PCSTR original, PCSTR merge)
361{
362 const char* cp = nullptr;
363 char* p = nullptr;
364 size_t offset = 0;
365 size_t length = 0;
366 const char* envp = nullptr;
367 DWORD cchEnvironmentBlock = 0;
368 LPCH lpszEnvironmentBlock = nullptr;
369 const char** mergeStrings = nullptr;
370 size_t mergeStringLength = 0;
371 size_t mergeArraySize = 128;
372 size_t mergeLength = 0;
373 size_t foundMerge = 0;
374 char* foundEquals = nullptr;
375
376 mergeStrings = (LPCSTR*)calloc(mergeArraySize, sizeof(char*));
377
378 if (!mergeStrings)
379 return nullptr;
380
381 mergeStringLength = 0;
382
383 cp = merge;
384
385 while (*cp && *(cp + 1))
386 {
387 length = strlen(cp);
388
389 if (mergeStringLength == mergeArraySize)
390 {
391 const char** new_str = nullptr;
392
393 mergeArraySize += 128;
394 new_str = (const char**)realloc((void*)mergeStrings, mergeArraySize * sizeof(char*));
395
396 if (!new_str)
397 {
398 free((void*)mergeStrings);
399 return nullptr;
400 }
401 mergeStrings = new_str;
402 }
403
404 mergeStrings[mergeStringLength] = cp;
405 cp += length + 1;
406 mergeStringLength++;
407 }
408
409 offset = 0;
410
411 cchEnvironmentBlock = 128;
412 lpszEnvironmentBlock = (LPCH)calloc(cchEnvironmentBlock, sizeof(CHAR));
413
414 if (!lpszEnvironmentBlock)
415 {
416 free((void*)mergeStrings);
417 return nullptr;
418 }
419
420 envp = original;
421
422 while ((original != nullptr) && (*envp && *(envp + 1)))
423 {
424 size_t old_offset = offset;
425 length = strlen(envp);
426
427 while ((offset + length + 8) > cchEnvironmentBlock)
428 {
429 cchEnvironmentBlock *= 2;
430 LPCH tmp = (LPCH)realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
431
432 if (!tmp)
433 {
434 free((void*)lpszEnvironmentBlock);
435 free((void*)mergeStrings);
436 return nullptr;
437 }
438 lpszEnvironmentBlock = tmp;
439 }
440
441 p = &(lpszEnvironmentBlock[offset]);
442
443 // check if this value is in the mergeStrings
444 foundMerge = 0;
445 for (size_t run = 0; run < mergeStringLength; run++)
446 {
447 if (!mergeStrings[run])
448 continue;
449
450 mergeLength = strlen(mergeStrings[run]);
451 foundEquals = strstr(mergeStrings[run], "=");
452
453 if (!foundEquals)
454 continue;
455
456 const intptr_t len = foundEquals - mergeStrings[run] + 1;
457 if (strncmp(envp, mergeStrings[run], WINPR_ASSERTING_INT_CAST(size_t, len)) == 0)
458 {
459 // found variable in merge list ... use this ....
460 if (*(foundEquals + 1) == '\0')
461 {
462 // check if the argument is set ... if not remove variable ...
463 foundMerge = 1;
464 }
465 else
466 {
467 while ((offset + mergeLength + 8) > cchEnvironmentBlock)
468 {
469 cchEnvironmentBlock *= 2;
470 LPCH tmp =
471 (LPCH)realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
472
473 if (!tmp)
474 {
475 free((void*)lpszEnvironmentBlock);
476 free((void*)mergeStrings);
477 return nullptr;
478 }
479 lpszEnvironmentBlock = tmp;
480 p = &(lpszEnvironmentBlock[old_offset]);
481 }
482
483 foundMerge = 1;
484 CopyMemory(p, mergeStrings[run], mergeLength);
485 mergeStrings[run] = nullptr;
486 p[mergeLength] = '\0';
487 offset += (mergeLength + 1);
488 }
489 }
490 }
491
492 if (foundMerge == 0)
493 {
494 CopyMemory(p, envp, length * sizeof(CHAR));
495 p[length] = '\0';
496 offset += (length + 1);
497 }
498
499 envp += (length + 1);
500 }
501
502 // now merge the not already merged env
503 for (size_t run = 0; run < mergeStringLength; run++)
504 {
505 if (!mergeStrings[run])
506 continue;
507
508 mergeLength = strlen(mergeStrings[run]);
509
510 while ((offset + mergeLength + 8) > cchEnvironmentBlock)
511 {
512 cchEnvironmentBlock *= 2;
513 LPCH tmp = (LPCH)realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
514
515 if (!tmp)
516 {
517 free((void*)lpszEnvironmentBlock);
518 free((void*)mergeStrings);
519 return nullptr;
520 }
521
522 lpszEnvironmentBlock = tmp;
523 }
524
525 p = &(lpszEnvironmentBlock[offset]);
526
527 CopyMemory(p, mergeStrings[run], mergeLength);
528 mergeStrings[run] = nullptr;
529 p[mergeLength] = '\0';
530 offset += (mergeLength + 1);
531 }
532
533 lpszEnvironmentBlock[offset] = '\0';
534
535 free((void*)mergeStrings);
536
537 return lpszEnvironmentBlock;
538}
539
540DWORD GetEnvironmentVariableEBA(LPCSTR envBlock, LPCSTR lpName, LPSTR lpBuffer, DWORD nSize)
541{
542 size_t vLength = 0;
543 char* env = nullptr;
544 char* foundEquals = nullptr;
545 const char* penvb = envBlock;
546 size_t nLength = 0;
547 size_t fLength = 0;
548 size_t lpNameLength = 0;
549
550 if (!lpName || nullptr == envBlock)
551 return 0;
552
553 lpNameLength = strlen(lpName);
554
555 if (lpNameLength < 1)
556 return 0;
557
558 while (*penvb && *(penvb + 1))
559 {
560 fLength = strlen(penvb);
561 foundEquals = strstr(penvb, "=");
562
563 if (!foundEquals)
564 {
565 /* if no = sign is found the envBlock is broken */
566 return 0;
567 }
568
569 nLength = WINPR_ASSERTING_INT_CAST(size_t, (foundEquals - penvb));
570
571 if (nLength != lpNameLength)
572 {
573 penvb += (fLength + 1);
574 continue;
575 }
576
577 if (strncmp(penvb, lpName, nLength) == 0)
578 {
579 env = foundEquals + 1;
580 break;
581 }
582
583 penvb += (fLength + 1);
584 }
585
586 if (!env)
587 return 0;
588
589 vLength = strlen(env);
590 if (vLength >= UINT32_MAX)
591 return 0;
592
593 if ((vLength + 1 > nSize) || (!lpBuffer))
594 return (DWORD)vLength + 1;
595
596 CopyMemory(lpBuffer, env, vLength + 1);
597
598 return (DWORD)vLength;
599}
600
601BOOL SetEnvironmentVariableEBA(LPSTR* envBlock, LPCSTR lpName, LPCSTR lpValue)
602{
603 size_t length = 0;
604 char* envstr = nullptr;
605 char* newEB = nullptr;
606
607 if (!lpName)
608 return FALSE;
609
610 if (lpValue)
611 {
612 length = (strlen(lpName) + strlen(lpValue) + 2); /* +2 because of = and \0 */
613 envstr = (char*)malloc(length + 1); /* +1 because of closing \0 */
614
615 if (!envstr)
616 return FALSE;
617
618 (void)sprintf_s(envstr, length, "%s=%s", lpName, lpValue);
619 }
620 else
621 {
622 length = strlen(lpName) + 2; /* +2 because of = and \0 */
623 envstr = (char*)malloc(length + 1); /* +1 because of closing \0 */
624
625 if (!envstr)
626 return FALSE;
627
628 (void)sprintf_s(envstr, length, "%s=", lpName);
629 }
630
631 envstr[length] = '\0';
632
633 newEB = MergeEnvironmentStrings((LPCSTR)*envBlock, envstr);
634
635 free(envstr);
636 free(*envBlock);
637
638 *envBlock = newEB;
639
640 return TRUE;
641}
642
643char** EnvironmentBlockToEnvpA(LPCH lpszEnvironmentBlock)
644{
645 char* p = nullptr;
646 SSIZE_T index = 0;
647 size_t count = 0;
648 size_t length = 0;
649 char** envp = nullptr;
650
651 count = 0;
652 if (!lpszEnvironmentBlock)
653 return nullptr;
654
655 p = (char*)lpszEnvironmentBlock;
656
657 while (p[0] && p[1])
658 {
659 length = strlen(p);
660 p += (length + 1);
661 count++;
662 }
663
664 index = 0;
665 p = (char*)lpszEnvironmentBlock;
666
667 envp = (char**)calloc(count + 1, sizeof(char*));
668 if (!envp)
669 return nullptr;
670 envp[count] = nullptr;
671
672 while (p[0] && p[1])
673 {
674 length = strlen(p);
675 envp[index] = _strdup(p);
676 if (!envp[index])
677 {
678 for (index -= 1; index >= 0; --index)
679 {
680 free(envp[index]);
681 }
682 free((void*)envp);
683 return nullptr;
684 }
685 p += (length + 1);
686 index++;
687 }
688
689 return envp;
690}
691
692#ifdef _WIN32
693
694// https://devblogs.microsoft.com/oldnewthing/20100203-00/?p=15083
695#define WINPR_MAX_ENVIRONMENT_LENGTH 2048
696
697DWORD GetEnvironmentVariableX(const char* lpName, char* lpBuffer, DWORD nSize)
698{
699 DWORD result = 0;
700 DWORD nSizeW = 0;
701 LPWSTR lpNameW = nullptr;
702 LPWSTR lpBufferW = nullptr;
703 LPSTR lpBufferA = lpBuffer;
704
705 lpNameW = ConvertUtf8ToWCharAlloc(lpName, nullptr);
706 if (!lpNameW)
707 goto cleanup;
708
709 if (!lpBuffer)
710 {
711 char lpBufferMaxA[WINPR_MAX_ENVIRONMENT_LENGTH] = WINPR_C_ARRAY_INIT;
712 WCHAR lpBufferMaxW[WINPR_MAX_ENVIRONMENT_LENGTH] = WINPR_C_ARRAY_INIT;
713 LPSTR lpTmpBuffer = lpBufferMaxA;
714
715 nSizeW = ARRAYSIZE(lpBufferMaxW);
716
717 result = GetEnvironmentVariableW(lpNameW, lpBufferMaxW, nSizeW);
718
719 SSIZE_T rc =
720 ConvertWCharNToUtf8(lpBufferMaxW, nSizeW, lpTmpBuffer, ARRAYSIZE(lpBufferMaxA));
721 if ((rc < 0) || (rc >= UINT32_MAX))
722 goto cleanup;
723
724 result = (DWORD)rc + 1;
725 }
726 else
727 {
728 nSizeW = nSize;
729 lpBufferW = calloc(nSizeW + 1, sizeof(WCHAR));
730
731 if (!lpBufferW)
732 goto cleanup;
733
734 result = GetEnvironmentVariableW(lpNameW, lpBufferW, nSizeW);
735
736 if (result == 0)
737 goto cleanup;
738
739 SSIZE_T rc = ConvertWCharNToUtf8(lpBufferW, nSizeW, lpBufferA, nSize);
740 if ((rc < 0) || (rc > UINT32_MAX))
741 goto cleanup;
742
743 result = (DWORD)rc;
744 }
745
746cleanup:
747 free(lpBufferW);
748 free(lpNameW);
749
750 return result;
751}
752
753#else
754
755DWORD GetEnvironmentVariableX(const char* lpName, char* lpBuffer, DWORD nSize)
756{
757 return GetEnvironmentVariableA(lpName, lpBuffer, nSize);
758}
759
760#endif