Coverage Report

Created: 2026-02-26 06:54

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 = NULL;
56
0
  char* ccwd = NULL;
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 == NULL))
81
0
  {
82
0
    free(cwd);
83
0
    return (DWORD)length;
84
0
  }
85
0
  else
86
0
  {
87
0
    if (lpBuffer == NULL)
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 NULL;
143
0
}
144
145
LPWSTR GetCommandLineW(VOID)
146
0
{
147
0
  WLog_ERR(TAG, "TODO: not implemented");
148
0
  return NULL;
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
303k
{
169
303k
#if !defined(_UWP)
170
303k
  size_t length = 0;
171
172
  // NOLINTNEXTLINE(concurrency-mt-unsafe)
173
303k
  char* env = getenv(lpName);
174
175
303k
  if (!env)
176
129k
  {
177
129k
    SetLastError(ERROR_ENVVAR_NOT_FOUND);
178
129k
    return 0;
179
129k
  }
180
181
173k
  length = strlen(env);
182
183
173k
  if ((length + 1 > nSize) || (!lpBuffer))
184
86.5k
    return (DWORD)length + 1;
185
186
86.5k
  CopyMemory(lpBuffer, env, length);
187
86.5k
  lpBuffer[length] = '\0';
188
189
86.5k
  return (DWORD)length;
190
#else
191
  SetLastError(ERROR_ENVVAR_NOT_FOUND);
192
  return 0;
193
#endif
194
173k
}
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
LPCH GetEnvironmentStringsA(VOID)
254
0
{
255
0
#if !defined(_UWP)
256
0
  size_t offset = 0;
257
0
  char** envp = environ;
258
0
  const size_t blocksize = 128;
259
0
  size_t cchEnvironmentBlock = blocksize;
260
0
  LPCH lpszEnvironmentBlock = (LPCH)calloc(cchEnvironmentBlock, sizeof(CHAR));
261
262
0
  if (!lpszEnvironmentBlock)
263
0
    return NULL;
264
265
0
  while (*envp)
266
0
  {
267
0
    const size_t length = strlen(*envp);
268
0
    const size_t required = offset + length + 8ull;
269
0
    if (required > UINT32_MAX)
270
0
    {
271
0
      WLog_ERR(TAG, "Environment block too large: %" PRIuz, required);
272
273
0
      free(lpszEnvironmentBlock);
274
0
      return NULL;
275
0
    }
276
277
0
    if (required > cchEnvironmentBlock)
278
0
    {
279
0
      size_t new_size = cchEnvironmentBlock;
280
0
      do
281
0
      {
282
0
        new_size += blocksize;
283
0
      } while (new_size <= required);
284
0
      LPCH new_blk = (LPCH)realloc(lpszEnvironmentBlock, new_size * sizeof(CHAR));
285
0
      if (!new_blk)
286
0
      {
287
0
        free(lpszEnvironmentBlock);
288
0
        return NULL;
289
0
      }
290
291
0
      lpszEnvironmentBlock = new_blk;
292
0
      cchEnvironmentBlock = new_size;
293
0
    }
294
295
0
    char* p = &(lpszEnvironmentBlock[offset]);
296
297
0
    CopyMemory(p, *envp, length * sizeof(CHAR));
298
0
    p[length] = '\0';
299
300
0
    offset += (length + 1ull);
301
0
    envp++;
302
0
  }
303
304
0
  lpszEnvironmentBlock[offset] = '\0';
305
306
0
  return lpszEnvironmentBlock;
307
#else
308
  return NULL;
309
#endif
310
0
}
311
312
LPWCH GetEnvironmentStringsW(VOID)
313
0
{
314
0
  WLog_ERR(TAG, "TODO: not implemented");
315
0
  return NULL;
316
0
}
317
318
BOOL SetEnvironmentStringsA(WINPR_ATTR_UNUSED LPCH NewEnvironment)
319
0
{
320
0
  WLog_ERR(TAG, "TODO: not implemented");
321
0
  return TRUE;
322
0
}
323
324
BOOL SetEnvironmentStringsW(WINPR_ATTR_UNUSED LPWCH NewEnvironment)
325
0
{
326
0
  WLog_ERR(TAG, "TODO: not implemented");
327
0
  return TRUE;
328
0
}
329
330
DWORD ExpandEnvironmentStringsA(WINPR_ATTR_UNUSED LPCSTR lpSrc, WINPR_ATTR_UNUSED LPSTR lpDst,
331
                                WINPR_ATTR_UNUSED DWORD nSize)
332
0
{
333
0
  WLog_ERR(TAG, "TODO: not implemented");
334
0
  return 0;
335
0
}
336
337
DWORD ExpandEnvironmentStringsW(WINPR_ATTR_UNUSED LPCWSTR lpSrc, WINPR_ATTR_UNUSED LPWSTR lpDst,
338
                                WINPR_ATTR_UNUSED DWORD nSize)
339
0
{
340
0
  WLog_ERR(TAG, "TODO: not implemented");
341
0
  return 0;
342
0
}
343
344
BOOL FreeEnvironmentStringsA(LPCH lpszEnvironmentBlock)
345
0
{
346
0
  free(lpszEnvironmentBlock);
347
348
0
  return TRUE;
349
0
}
350
351
BOOL FreeEnvironmentStringsW(LPWCH lpszEnvironmentBlock)
352
0
{
353
0
  free(lpszEnvironmentBlock);
354
355
0
  return TRUE;
356
0
}
357
358
#endif
359
360
LPCH MergeEnvironmentStrings(PCSTR original, PCSTR merge)
361
0
{
362
0
  const char* cp = NULL;
363
0
  char* p = NULL;
364
0
  size_t offset = 0;
365
0
  size_t length = 0;
366
0
  const char* envp = NULL;
367
0
  DWORD cchEnvironmentBlock = 0;
368
0
  LPCH lpszEnvironmentBlock = NULL;
369
0
  const char** mergeStrings = NULL;
370
0
  size_t mergeStringLength = 0;
371
0
  size_t mergeArraySize = 128;
372
0
  size_t mergeLength = 0;
373
0
  size_t foundMerge = 0;
374
0
  char* foundEquals = NULL;
375
376
0
  mergeStrings = (LPCSTR*)calloc(mergeArraySize, sizeof(char*));
377
378
0
  if (!mergeStrings)
379
0
    return NULL;
380
381
0
  mergeStringLength = 0;
382
383
0
  cp = merge;
384
385
0
  while (*cp && *(cp + 1))
386
0
  {
387
0
    length = strlen(cp);
388
389
0
    if (mergeStringLength == mergeArraySize)
390
0
    {
391
0
      const char** new_str = NULL;
392
393
0
      mergeArraySize += 128;
394
0
      new_str = (const char**)realloc((void*)mergeStrings, mergeArraySize * sizeof(char*));
395
396
0
      if (!new_str)
397
0
      {
398
0
        free((void*)mergeStrings);
399
0
        return NULL;
400
0
      }
401
0
      mergeStrings = new_str;
402
0
    }
403
404
0
    mergeStrings[mergeStringLength] = cp;
405
0
    cp += length + 1;
406
0
    mergeStringLength++;
407
0
  }
408
409
0
  offset = 0;
410
411
0
  cchEnvironmentBlock = 128;
412
0
  lpszEnvironmentBlock = (LPCH)calloc(cchEnvironmentBlock, sizeof(CHAR));
413
414
0
  if (!lpszEnvironmentBlock)
415
0
  {
416
0
    free((void*)mergeStrings);
417
0
    return NULL;
418
0
  }
419
420
0
  envp = original;
421
422
0
  while ((original != NULL) && (*envp && *(envp + 1)))
423
0
  {
424
0
    size_t old_offset = offset;
425
0
    length = strlen(envp);
426
427
0
    while ((offset + length + 8) > cchEnvironmentBlock)
428
0
    {
429
0
      cchEnvironmentBlock *= 2;
430
0
      LPCH tmp = (LPCH)realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
431
432
0
      if (!tmp)
433
0
      {
434
0
        free((void*)lpszEnvironmentBlock);
435
0
        free((void*)mergeStrings);
436
0
        return NULL;
437
0
      }
438
0
      lpszEnvironmentBlock = tmp;
439
0
    }
440
441
0
    p = &(lpszEnvironmentBlock[offset]);
442
443
    // check if this value is in the mergeStrings
444
0
    foundMerge = 0;
445
0
    for (size_t run = 0; run < mergeStringLength; run++)
446
0
    {
447
0
      if (!mergeStrings[run])
448
0
        continue;
449
450
0
      mergeLength = strlen(mergeStrings[run]);
451
0
      foundEquals = strstr(mergeStrings[run], "=");
452
453
0
      if (!foundEquals)
454
0
        continue;
455
456
0
      const intptr_t len = foundEquals - mergeStrings[run] + 1;
457
0
      if (strncmp(envp, mergeStrings[run], WINPR_ASSERTING_INT_CAST(size_t, len)) == 0)
458
0
      {
459
        // found variable in merge list ... use this ....
460
0
        if (*(foundEquals + 1) == '\0')
461
0
        {
462
          // check if the argument is set ... if not remove variable ...
463
0
          foundMerge = 1;
464
0
        }
465
0
        else
466
0
        {
467
0
          while ((offset + mergeLength + 8) > cchEnvironmentBlock)
468
0
          {
469
0
            cchEnvironmentBlock *= 2;
470
0
            LPCH tmp =
471
0
                (LPCH)realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
472
473
0
            if (!tmp)
474
0
            {
475
0
              free((void*)lpszEnvironmentBlock);
476
0
              free((void*)mergeStrings);
477
0
              return NULL;
478
0
            }
479
0
            lpszEnvironmentBlock = tmp;
480
0
            p = &(lpszEnvironmentBlock[old_offset]);
481
0
          }
482
483
0
          foundMerge = 1;
484
0
          CopyMemory(p, mergeStrings[run], mergeLength);
485
0
          mergeStrings[run] = NULL;
486
0
          p[mergeLength] = '\0';
487
0
          offset += (mergeLength + 1);
488
0
        }
489
0
      }
490
0
    }
491
492
0
    if (foundMerge == 0)
493
0
    {
494
0
      CopyMemory(p, envp, length * sizeof(CHAR));
495
0
      p[length] = '\0';
496
0
      offset += (length + 1);
497
0
    }
498
499
0
    envp += (length + 1);
500
0
  }
501
502
  // now merge the not already merged env
503
0
  for (size_t run = 0; run < mergeStringLength; run++)
504
0
  {
505
0
    if (!mergeStrings[run])
506
0
      continue;
507
508
0
    mergeLength = strlen(mergeStrings[run]);
509
510
0
    while ((offset + mergeLength + 8) > cchEnvironmentBlock)
511
0
    {
512
0
      cchEnvironmentBlock *= 2;
513
0
      LPCH tmp = (LPCH)realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
514
515
0
      if (!tmp)
516
0
      {
517
0
        free((void*)lpszEnvironmentBlock);
518
0
        free((void*)mergeStrings);
519
0
        return NULL;
520
0
      }
521
522
0
      lpszEnvironmentBlock = tmp;
523
0
    }
524
525
0
    p = &(lpszEnvironmentBlock[offset]);
526
527
0
    CopyMemory(p, mergeStrings[run], mergeLength);
528
0
    mergeStrings[run] = NULL;
529
0
    p[mergeLength] = '\0';
530
0
    offset += (mergeLength + 1);
531
0
  }
532
533
0
  lpszEnvironmentBlock[offset] = '\0';
534
535
0
  free((void*)mergeStrings);
536
537
0
  return lpszEnvironmentBlock;
538
0
}
539
540
DWORD GetEnvironmentVariableEBA(LPCSTR envBlock, LPCSTR lpName, LPSTR lpBuffer, DWORD nSize)
541
0
{
542
0
  size_t vLength = 0;
543
0
  char* env = NULL;
544
0
  char* foundEquals = NULL;
545
0
  const char* penvb = envBlock;
546
0
  size_t nLength = 0;
547
0
  size_t fLength = 0;
548
0
  size_t lpNameLength = 0;
549
550
0
  if (!lpName || NULL == envBlock)
551
0
    return 0;
552
553
0
  lpNameLength = strlen(lpName);
554
555
0
  if (lpNameLength < 1)
556
0
    return 0;
557
558
0
  while (*penvb && *(penvb + 1))
559
0
  {
560
0
    fLength = strlen(penvb);
561
0
    foundEquals = strstr(penvb, "=");
562
563
0
    if (!foundEquals)
564
0
    {
565
      /* if no = sign is found the envBlock is broken */
566
0
      return 0;
567
0
    }
568
569
0
    nLength = WINPR_ASSERTING_INT_CAST(size_t, (foundEquals - penvb));
570
571
0
    if (nLength != lpNameLength)
572
0
    {
573
0
      penvb += (fLength + 1);
574
0
      continue;
575
0
    }
576
577
0
    if (strncmp(penvb, lpName, nLength) == 0)
578
0
    {
579
0
      env = foundEquals + 1;
580
0
      break;
581
0
    }
582
583
0
    penvb += (fLength + 1);
584
0
  }
585
586
0
  if (!env)
587
0
    return 0;
588
589
0
  vLength = strlen(env);
590
0
  if (vLength >= UINT32_MAX)
591
0
    return 0;
592
593
0
  if ((vLength + 1 > nSize) || (!lpBuffer))
594
0
    return (DWORD)vLength + 1;
595
596
0
  CopyMemory(lpBuffer, env, vLength + 1);
597
598
0
  return (DWORD)vLength;
599
0
}
600
601
BOOL SetEnvironmentVariableEBA(LPSTR* envBlock, LPCSTR lpName, LPCSTR lpValue)
602
0
{
603
0
  size_t length = 0;
604
0
  char* envstr = NULL;
605
0
  char* newEB = NULL;
606
607
0
  if (!lpName)
608
0
    return FALSE;
609
610
0
  if (lpValue)
611
0
  {
612
0
    length = (strlen(lpName) + strlen(lpValue) + 2); /* +2 because of = and \0 */
613
0
    envstr = (char*)malloc(length + 1);              /* +1 because of closing \0 */
614
615
0
    if (!envstr)
616
0
      return FALSE;
617
618
0
    (void)sprintf_s(envstr, length, "%s=%s", lpName, lpValue);
619
0
  }
620
0
  else
621
0
  {
622
0
    length = strlen(lpName) + 2;        /* +2 because of = and \0 */
623
0
    envstr = (char*)malloc(length + 1); /* +1 because of closing \0 */
624
625
0
    if (!envstr)
626
0
      return FALSE;
627
628
0
    (void)sprintf_s(envstr, length, "%s=", lpName);
629
0
  }
630
631
0
  envstr[length] = '\0';
632
633
0
  newEB = MergeEnvironmentStrings((LPCSTR)*envBlock, envstr);
634
635
0
  free(envstr);
636
0
  free(*envBlock);
637
638
0
  *envBlock = newEB;
639
640
0
  return TRUE;
641
0
}
642
643
char** EnvironmentBlockToEnvpA(LPCH lpszEnvironmentBlock)
644
0
{
645
0
  char* p = NULL;
646
0
  SSIZE_T index = 0;
647
0
  size_t count = 0;
648
0
  size_t length = 0;
649
0
  char** envp = NULL;
650
651
0
  count = 0;
652
0
  if (!lpszEnvironmentBlock)
653
0
    return NULL;
654
655
0
  p = (char*)lpszEnvironmentBlock;
656
657
0
  while (p[0] && p[1])
658
0
  {
659
0
    length = strlen(p);
660
0
    p += (length + 1);
661
0
    count++;
662
0
  }
663
664
0
  index = 0;
665
0
  p = (char*)lpszEnvironmentBlock;
666
667
0
  envp = (char**)calloc(count + 1, sizeof(char*));
668
0
  if (!envp)
669
0
    return NULL;
670
0
  envp[count] = NULL;
671
672
0
  while (p[0] && p[1])
673
0
  {
674
0
    length = strlen(p);
675
0
    envp[index] = _strdup(p);
676
0
    if (!envp[index])
677
0
    {
678
0
      for (index -= 1; index >= 0; --index)
679
0
      {
680
0
        free(envp[index]);
681
0
      }
682
0
      free((void*)envp);
683
0
      return NULL;
684
0
    }
685
0
    p += (length + 1);
686
0
    index++;
687
0
  }
688
689
0
  return envp;
690
0
}
691
692
#ifdef _WIN32
693
694
// https://devblogs.microsoft.com/oldnewthing/20100203-00/?p=15083
695
#define WINPR_MAX_ENVIRONMENT_LENGTH 2048
696
697
DWORD GetEnvironmentVariableX(const char* lpName, char* lpBuffer, DWORD nSize)
698
{
699
  DWORD result = 0;
700
  DWORD nSizeW = 0;
701
  LPWSTR lpNameW = NULL;
702
  LPWSTR lpBufferW = NULL;
703
  LPSTR lpBufferA = lpBuffer;
704
705
  lpNameW = ConvertUtf8ToWCharAlloc(lpName, NULL);
706
  if (!lpNameW)
707
    goto cleanup;
708
709
  if (!lpBuffer)
710
  {
711
    char lpBufferMaxA[WINPR_MAX_ENVIRONMENT_LENGTH] = WINPR_C_ARRAY_INIT;
712
    WCHAR lpBufferMaxW[WINPR_MAX_ENVIRONMENT_LENGTH] = WINPR_C_ARRAY_INIT;
713
    LPSTR lpTmpBuffer = lpBufferMaxA;
714
715
    nSizeW = ARRAYSIZE(lpBufferMaxW);
716
717
    result = GetEnvironmentVariableW(lpNameW, lpBufferMaxW, nSizeW);
718
719
    SSIZE_T rc =
720
        ConvertWCharNToUtf8(lpBufferMaxW, nSizeW, lpTmpBuffer, ARRAYSIZE(lpBufferMaxA));
721
    if ((rc < 0) || (rc >= UINT32_MAX))
722
      goto cleanup;
723
724
    result = (DWORD)rc + 1;
725
  }
726
  else
727
  {
728
    nSizeW = nSize;
729
    lpBufferW = calloc(nSizeW + 1, sizeof(WCHAR));
730
731
    if (!lpBufferW)
732
      goto cleanup;
733
734
    result = GetEnvironmentVariableW(lpNameW, lpBufferW, nSizeW);
735
736
    if (result == 0)
737
      goto cleanup;
738
739
    SSIZE_T rc = ConvertWCharNToUtf8(lpBufferW, nSizeW, lpBufferA, nSize);
740
    if ((rc < 0) || (rc > UINT32_MAX))
741
      goto cleanup;
742
743
    result = (DWORD)rc;
744
  }
745
746
cleanup:
747
  free(lpBufferW);
748
  free(lpNameW);
749
750
  return result;
751
}
752
753
#else
754
755
DWORD GetEnvironmentVariableX(const char* lpName, char* lpBuffer, DWORD nSize)
756
216k
{
757
216k
  return GetEnvironmentVariableA(lpName, lpBuffer, nSize);
758
216k
}
759
760
#endif