Coverage Report

Created: 2023-09-25 06:56

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