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  const intptr_t len = foundEquals - mergeStrings[run] + 1;
426  if (strncmp(envp, mergeStrings[run], WINPR_ASSERTING_INT_CAST(size_t, len)) == 0)
427  {
428  // found variable in merge list ... use this ....
429  if (*(foundEquals + 1) == '\0')
430  {
431  // check if the argument is set ... if not remove variable ...
432  foundMerge = 1;
433  }
434  else
435  {
436  while ((offset + mergeLength + 8) > cchEnvironmentBlock)
437  {
438  cchEnvironmentBlock *= 2;
439  LPCH tmp =
440  (LPCH)realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
441 
442  if (!tmp)
443  {
444  free((void*)lpszEnvironmentBlock);
445  free((void*)mergeStrings);
446  return NULL;
447  }
448  lpszEnvironmentBlock = tmp;
449  p = &(lpszEnvironmentBlock[old_offset]);
450  }
451 
452  foundMerge = 1;
453  CopyMemory(p, mergeStrings[run], mergeLength);
454  mergeStrings[run] = NULL;
455  p[mergeLength] = '\0';
456  offset += (mergeLength + 1);
457  }
458  }
459  }
460 
461  if (foundMerge == 0)
462  {
463  CopyMemory(p, envp, length * sizeof(CHAR));
464  p[length] = '\0';
465  offset += (length + 1);
466  }
467 
468  envp += (length + 1);
469  }
470 
471  // now merge the not already merged env
472  for (size_t run = 0; run < mergeStringLength; run++)
473  {
474  if (!mergeStrings[run])
475  continue;
476 
477  mergeLength = strlen(mergeStrings[run]);
478 
479  while ((offset + mergeLength + 8) > cchEnvironmentBlock)
480  {
481  cchEnvironmentBlock *= 2;
482  LPCH tmp = (LPCH)realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
483 
484  if (!tmp)
485  {
486  free((void*)lpszEnvironmentBlock);
487  free((void*)mergeStrings);
488  return NULL;
489  }
490 
491  lpszEnvironmentBlock = tmp;
492  }
493 
494  p = &(lpszEnvironmentBlock[offset]);
495 
496  CopyMemory(p, mergeStrings[run], mergeLength);
497  mergeStrings[run] = NULL;
498  p[mergeLength] = '\0';
499  offset += (mergeLength + 1);
500  }
501 
502  lpszEnvironmentBlock[offset] = '\0';
503 
504  free((void*)mergeStrings);
505 
506  return lpszEnvironmentBlock;
507 }
508 
509 DWORD GetEnvironmentVariableEBA(LPCSTR envBlock, LPCSTR lpName, LPSTR lpBuffer, DWORD nSize)
510 {
511  size_t vLength = 0;
512  char* env = NULL;
513  char* foundEquals = NULL;
514  const char* penvb = envBlock;
515  size_t nLength = 0;
516  size_t fLength = 0;
517  size_t lpNameLength = 0;
518 
519  if (!lpName || NULL == envBlock)
520  return 0;
521 
522  lpNameLength = strlen(lpName);
523 
524  if (lpNameLength < 1)
525  return 0;
526 
527  while (*penvb && *(penvb + 1))
528  {
529  fLength = strlen(penvb);
530  foundEquals = strstr(penvb, "=");
531 
532  if (!foundEquals)
533  {
534  /* if no = sign is found the envBlock is broken */
535  return 0;
536  }
537 
538  nLength = WINPR_ASSERTING_INT_CAST(size_t, (foundEquals - penvb));
539 
540  if (nLength != lpNameLength)
541  {
542  penvb += (fLength + 1);
543  continue;
544  }
545 
546  if (strncmp(penvb, lpName, nLength) == 0)
547  {
548  env = foundEquals + 1;
549  break;
550  }
551 
552  penvb += (fLength + 1);
553  }
554 
555  if (!env)
556  return 0;
557 
558  vLength = strlen(env);
559  if (vLength >= UINT32_MAX)
560  return 0;
561 
562  if ((vLength + 1 > nSize) || (!lpBuffer))
563  return (DWORD)vLength + 1;
564 
565  CopyMemory(lpBuffer, env, vLength + 1);
566 
567  return (DWORD)vLength;
568 }
569 
570 BOOL SetEnvironmentVariableEBA(LPSTR* envBlock, LPCSTR lpName, LPCSTR lpValue)
571 {
572  size_t length = 0;
573  char* envstr = NULL;
574  char* newEB = NULL;
575 
576  if (!lpName)
577  return FALSE;
578 
579  if (lpValue)
580  {
581  length = (strlen(lpName) + strlen(lpValue) + 2); /* +2 because of = and \0 */
582  envstr = (char*)malloc(length + 1); /* +1 because of closing \0 */
583 
584  if (!envstr)
585  return FALSE;
586 
587  (void)sprintf_s(envstr, length, "%s=%s", lpName, lpValue);
588  }
589  else
590  {
591  length = strlen(lpName) + 2; /* +2 because of = and \0 */
592  envstr = (char*)malloc(length + 1); /* +1 because of closing \0 */
593 
594  if (!envstr)
595  return FALSE;
596 
597  (void)sprintf_s(envstr, length, "%s=", lpName);
598  }
599 
600  envstr[length] = '\0';
601 
602  newEB = MergeEnvironmentStrings((LPCSTR)*envBlock, envstr);
603 
604  free(envstr);
605  free(*envBlock);
606 
607  *envBlock = newEB;
608 
609  return TRUE;
610 }
611 
612 char** EnvironmentBlockToEnvpA(LPCH lpszEnvironmentBlock)
613 {
614  char* p = NULL;
615  SSIZE_T index = 0;
616  size_t count = 0;
617  size_t length = 0;
618  char** envp = NULL;
619 
620  count = 0;
621  if (!lpszEnvironmentBlock)
622  return NULL;
623 
624  p = (char*)lpszEnvironmentBlock;
625 
626  while (p[0] && p[1])
627  {
628  length = strlen(p);
629  p += (length + 1);
630  count++;
631  }
632 
633  index = 0;
634  p = (char*)lpszEnvironmentBlock;
635 
636  envp = (char**)calloc(count + 1, sizeof(char*));
637  if (!envp)
638  return NULL;
639  envp[count] = NULL;
640 
641  while (p[0] && p[1])
642  {
643  length = strlen(p);
644  envp[index] = _strdup(p);
645  if (!envp[index])
646  {
647  for (index -= 1; index >= 0; --index)
648  {
649  free(envp[index]);
650  }
651  free((void*)envp);
652  return NULL;
653  }
654  p += (length + 1);
655  index++;
656  }
657 
658  return envp;
659 }
660 
661 #ifdef _WIN32
662 
663 // https://devblogs.microsoft.com/oldnewthing/20100203-00/?p=15083
664 #define WINPR_MAX_ENVIRONMENT_LENGTH 2048
665 
666 DWORD GetEnvironmentVariableX(const char* lpName, char* lpBuffer, DWORD nSize)
667 {
668  DWORD result = 0;
669  DWORD nSizeW = 0;
670  LPWSTR lpNameW = NULL;
671  LPWSTR lpBufferW = NULL;
672  LPSTR lpBufferA = lpBuffer;
673 
674  lpNameW = ConvertUtf8ToWCharAlloc(lpName, NULL);
675  if (!lpNameW)
676  goto cleanup;
677 
678  if (!lpBuffer)
679  {
680  char lpBufferMaxA[WINPR_MAX_ENVIRONMENT_LENGTH] = { 0 };
681  WCHAR lpBufferMaxW[WINPR_MAX_ENVIRONMENT_LENGTH] = { 0 };
682  LPSTR lpTmpBuffer = lpBufferMaxA;
683 
684  nSizeW = ARRAYSIZE(lpBufferMaxW);
685 
686  result = GetEnvironmentVariableW(lpNameW, lpBufferMaxW, nSizeW);
687 
688  SSIZE_T rc =
689  ConvertWCharNToUtf8(lpBufferMaxW, nSizeW, lpTmpBuffer, ARRAYSIZE(lpBufferMaxA));
690  if ((rc < 0) || (rc >= UINT32_MAX))
691  goto cleanup;
692 
693  result = (DWORD)rc + 1;
694  }
695  else
696  {
697  nSizeW = nSize;
698  lpBufferW = calloc(nSizeW + 1, sizeof(WCHAR));
699 
700  if (!lpBufferW)
701  goto cleanup;
702 
703  result = GetEnvironmentVariableW(lpNameW, lpBufferW, nSizeW);
704 
705  if (result == 0)
706  goto cleanup;
707 
708  SSIZE_T rc = ConvertWCharNToUtf8(lpBufferW, nSizeW, lpBufferA, nSize);
709  if ((rc < 0) || (rc > UINT32_MAX))
710  goto cleanup;
711 
712  result = (DWORD)rc;
713  }
714 
715 cleanup:
716  free(lpBufferW);
717  free(lpNameW);
718 
719  return result;
720 }
721 
722 #else
723 
724 DWORD GetEnvironmentVariableX(const char* lpName, char* lpBuffer, DWORD nSize)
725 {
726  return GetEnvironmentVariableA(lpName, lpBuffer, nSize);
727 }
728 
729 #endif