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