Coverage Report

Created: 2024-05-20 06:11

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