Coverage Report

Created: 2025-07-01 06:46

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