Coverage Report

Created: 2026-05-11 06:55

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