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