20c1b0f67210dad186b734eeb42a4c4fd9b026ff
[reactos.git] / reactos / dll / win32 / userenv / environment.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2004 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS system libraries
22 * FILE: dll/win32/userenv/environment.c
23 * PURPOSE: User environment functions
24 * PROGRAMMER: Eric Kohl
25 */
26
27 #include "precomp.h"
28
29 #define NDEBUG
30 #include <debug.h>
31
32 static
33 BOOL
34 SetUserEnvironmentVariable(LPVOID *Environment,
35 LPWSTR lpName,
36 LPWSTR lpValue,
37 BOOL bExpand)
38 {
39 WCHAR ShortName[MAX_PATH];
40 UNICODE_STRING Name;
41 UNICODE_STRING SrcValue;
42 UNICODE_STRING DstValue;
43 ULONG Length;
44 NTSTATUS Status;
45 PVOID Buffer = NULL;
46
47 if (bExpand)
48 {
49 RtlInitUnicodeString(&SrcValue,
50 lpValue);
51
52 Length = 2 * MAX_PATH * sizeof(WCHAR);
53
54 DstValue.Length = 0;
55 DstValue.MaximumLength = Length;
56 DstValue.Buffer = Buffer = LocalAlloc(LPTR,
57 Length);
58 if (DstValue.Buffer == NULL)
59 {
60 DPRINT1("LocalAlloc() failed\n");
61 return FALSE;
62 }
63
64 Status = RtlExpandEnvironmentStrings_U((PWSTR)*Environment,
65 &SrcValue,
66 &DstValue,
67 &Length);
68 if (!NT_SUCCESS(Status))
69 {
70 DPRINT1("RtlExpandEnvironmentStrings_U() failed (Status %lx)\n", Status);
71 DPRINT1("Length %lu\n", Length);
72 if (Buffer)
73 LocalFree(Buffer);
74 return FALSE;
75 }
76 }
77 else
78 {
79 RtlInitUnicodeString(&DstValue,
80 lpValue);
81 }
82
83 if (!_wcsicmp(lpName, L"temp") || !_wcsicmp(lpName, L"tmp"))
84 {
85 if (!GetShortPathNameW(DstValue.Buffer, ShortName, MAX_PATH))
86 {
87 DPRINT1("GetShortPathNameW() failed for %S (Error %lu)\n", DstValue.Buffer, GetLastError());
88 if (Buffer)
89 LocalFree(Buffer);
90 return FALSE;
91 }
92
93 DPRINT("Buffer: %S\n", ShortName);
94 RtlInitUnicodeString(&DstValue,
95 ShortName);
96 }
97
98 RtlInitUnicodeString(&Name,
99 lpName);
100
101 DPRINT("Value: %wZ\n", &DstValue);
102
103 Status = RtlSetEnvironmentVariable((PWSTR*)Environment,
104 &Name,
105 &DstValue);
106
107 if (Buffer)
108 LocalFree(Buffer);
109
110 if (!NT_SUCCESS(Status))
111 {
112 DPRINT1("RtlSetEnvironmentVariable() failed (Status %lx)\n", Status);
113 return FALSE;
114 }
115
116 return TRUE;
117 }
118
119
120 static
121 BOOL
122 AppendUserEnvironmentVariable(LPVOID *Environment,
123 LPWSTR lpName,
124 LPWSTR lpValue)
125 {
126 UNICODE_STRING Name;
127 UNICODE_STRING Value;
128 NTSTATUS Status;
129
130 RtlInitUnicodeString(&Name,
131 lpName);
132
133 Value.Length = 0;
134 Value.MaximumLength = 1024 * sizeof(WCHAR);
135 Value.Buffer = LocalAlloc(LPTR,
136 1024 * sizeof(WCHAR));
137 if (Value.Buffer == NULL)
138 {
139 return FALSE;
140 }
141 Value.Buffer[0] = UNICODE_NULL;
142
143 Status = RtlQueryEnvironmentVariable_U((PWSTR)*Environment,
144 &Name,
145 &Value);
146 if (NT_SUCCESS(Status))
147 {
148 RtlAppendUnicodeToString(&Value,
149 L";");
150 }
151
152 RtlAppendUnicodeToString(&Value,
153 lpValue);
154
155 Status = RtlSetEnvironmentVariable((PWSTR*)Environment,
156 &Name,
157 &Value);
158 LocalFree(Value.Buffer);
159 if (!NT_SUCCESS(Status))
160 {
161 DPRINT1("RtlSetEnvironmentVariable() failed (Status %lx)\n", Status);
162 return FALSE;
163 }
164
165 return TRUE;
166 }
167
168
169 static
170 HKEY
171 GetCurrentUserKey(HANDLE hToken)
172 {
173 UNICODE_STRING SidString;
174 HKEY hKey;
175 LONG Error;
176
177 if (!GetUserSidStringFromToken(hToken,
178 &SidString))
179 {
180 DPRINT1("GetUserSidFromToken() failed\n");
181 return NULL;
182 }
183
184 Error = RegOpenKeyExW(HKEY_USERS,
185 SidString.Buffer,
186 0,
187 MAXIMUM_ALLOWED,
188 &hKey);
189 if (Error != ERROR_SUCCESS)
190 {
191 DPRINT1("RegOpenKeyExW() failed (Error %ld)\n", Error);
192 RtlFreeUnicodeString(&SidString);
193 SetLastError((DWORD)Error);
194 return NULL;
195 }
196
197 RtlFreeUnicodeString(&SidString);
198
199 return hKey;
200 }
201
202
203 static
204 BOOL
205 GetUserAndDomainName(IN HANDLE hToken,
206 OUT LPWSTR *UserName,
207 OUT LPWSTR *DomainName)
208 {
209 PSID Sid = NULL;
210 LPWSTR lpUserName = NULL;
211 LPWSTR lpDomainName = NULL;
212 DWORD cbUserName = 0;
213 DWORD cbDomainName = 0;
214 SID_NAME_USE SidNameUse;
215 BOOL bRet = TRUE;
216
217 if (!GetUserSidFromToken(hToken,
218 &Sid))
219 {
220 DPRINT1("GetUserSidFromToken() failed\n");
221 return FALSE;
222 }
223
224 if (!LookupAccountSidW(NULL,
225 Sid,
226 NULL,
227 &cbUserName,
228 NULL,
229 &cbDomainName,
230 &SidNameUse))
231 {
232 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
233 {
234 bRet = FALSE;
235 goto done;
236 }
237 }
238
239 lpUserName = LocalAlloc(LPTR,
240 cbUserName * sizeof(WCHAR));
241 if (lpUserName == NULL)
242 {
243 bRet = FALSE;
244 goto done;
245 }
246
247 lpDomainName = LocalAlloc(LPTR,
248 cbDomainName * sizeof(WCHAR));
249 if (lpDomainName == NULL)
250 {
251 bRet = FALSE;
252 goto done;
253 }
254
255 if (!LookupAccountSidW(NULL,
256 Sid,
257 lpUserName,
258 &cbUserName,
259 lpDomainName,
260 &cbDomainName,
261 &SidNameUse))
262 {
263 bRet = FALSE;
264 goto done;
265 }
266
267 *UserName = lpUserName;
268 *DomainName = lpDomainName;
269
270 done:
271 if (bRet == FALSE)
272 {
273 if (lpUserName != NULL)
274 LocalFree(lpUserName);
275
276 if (lpDomainName != NULL)
277 LocalFree(lpDomainName);
278 }
279
280 LocalFree(Sid);
281
282 return bRet;
283 }
284
285
286 static
287 BOOL
288 SetUserEnvironment(LPVOID *lpEnvironment,
289 HKEY hKey,
290 LPWSTR lpSubKeyName)
291 {
292 HKEY hEnvKey;
293 DWORD dwValues;
294 DWORD dwMaxValueNameLength;
295 DWORD dwMaxValueDataLength;
296 DWORD dwValueNameLength;
297 DWORD dwValueDataLength;
298 DWORD dwType;
299 DWORD i;
300 LPWSTR lpValueName;
301 LPWSTR lpValueData;
302 LONG Error;
303
304 Error = RegOpenKeyExW(hKey,
305 lpSubKeyName,
306 0,
307 KEY_QUERY_VALUE,
308 &hEnvKey);
309 if (Error != ERROR_SUCCESS)
310 {
311 DPRINT1("RegOpenKeyExW() failed (Error %ld)\n", Error);
312 SetLastError((DWORD)Error);
313 return FALSE;
314 }
315
316 Error = RegQueryInfoKey(hEnvKey,
317 NULL,
318 NULL,
319 NULL,
320 NULL,
321 NULL,
322 NULL,
323 &dwValues,
324 &dwMaxValueNameLength,
325 &dwMaxValueDataLength,
326 NULL,
327 NULL);
328 if (Error != ERROR_SUCCESS)
329 {
330 DPRINT1("RegQueryInforKey() failed (Error %ld)\n", Error);
331 RegCloseKey(hEnvKey);
332 SetLastError((DWORD)Error);
333 return FALSE;
334 }
335
336 if (dwValues == 0)
337 {
338 RegCloseKey(hEnvKey);
339 return TRUE;
340 }
341
342 /* Allocate buffers */
343 lpValueName = LocalAlloc(LPTR,
344 dwMaxValueNameLength * sizeof(WCHAR));
345 if (lpValueName == NULL)
346 {
347 RegCloseKey(hEnvKey);
348 return FALSE;
349 }
350
351 lpValueData = LocalAlloc(LPTR,
352 dwMaxValueDataLength);
353 if (lpValueData == NULL)
354 {
355 LocalFree(lpValueName);
356 RegCloseKey(hEnvKey);
357 return FALSE;
358 }
359
360 /* Enumerate values */
361 for (i = 0; i < dwValues; i++)
362 {
363 dwValueNameLength = dwMaxValueNameLength;
364 dwValueDataLength = dwMaxValueDataLength;
365 RegEnumValueW(hEnvKey,
366 i,
367 lpValueName,
368 &dwValueNameLength,
369 NULL,
370 &dwType,
371 (LPBYTE)lpValueData,
372 &dwValueDataLength);
373
374 if (!_wcsicmp (lpValueName, L"path"))
375 {
376 /* Append 'Path' environment variable */
377 AppendUserEnvironmentVariable(lpEnvironment,
378 lpValueName,
379 lpValueData);
380 }
381 else
382 {
383 /* Set environment variable */
384 SetUserEnvironmentVariable(lpEnvironment,
385 lpValueName,
386 lpValueData,
387 (dwType == REG_EXPAND_SZ));
388 }
389 }
390
391 LocalFree(lpValueData);
392 LocalFree(lpValueName);
393 RegCloseKey(hEnvKey);
394
395 return TRUE;
396 }
397
398
399 BOOL
400 WINAPI
401 CreateEnvironmentBlock(LPVOID *lpEnvironment,
402 HANDLE hToken,
403 BOOL bInherit)
404 {
405 WCHAR Buffer[MAX_PATH];
406 WCHAR szValue[1024];
407 DWORD Length;
408 DWORD dwType;
409 HKEY hKey;
410 HKEY hKeyUser;
411 LPWSTR lpUserName = NULL;
412 LPWSTR lpDomainName = NULL;
413 NTSTATUS Status;
414 LONG lError;
415
416 DPRINT("CreateEnvironmentBlock() called\n");
417
418 if (lpEnvironment == NULL)
419 {
420 SetLastError(ERROR_INVALID_PARAMETER);
421 return FALSE;
422 }
423
424 Status = RtlCreateEnvironment((BOOLEAN)bInherit,
425 (PWSTR*)lpEnvironment);
426 if (!NT_SUCCESS (Status))
427 {
428 DPRINT1("RtlCreateEnvironment() failed (Status %lx)\n", Status);
429 SetLastError(RtlNtStatusToDosError(Status));
430 return FALSE;
431 }
432
433 /* Set 'COMPUTERNAME' variable */
434 Length = MAX_PATH;
435 if (GetComputerNameW(Buffer,
436 &Length))
437 {
438 SetUserEnvironmentVariable(lpEnvironment,
439 L"COMPUTERNAME",
440 Buffer,
441 FALSE);
442 }
443
444 /* Set 'ALLUSERSPROFILE' variable */
445 Length = MAX_PATH;
446 if (GetAllUsersProfileDirectoryW(Buffer,
447 &Length))
448 {
449 SetUserEnvironmentVariable(lpEnvironment,
450 L"ALLUSERSPROFILE",
451 Buffer,
452 FALSE);
453 }
454
455 lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
456 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
457 0,
458 KEY_READ,
459 &hKey);
460 if (lError == ERROR_SUCCESS)
461 {
462 Length = 1024 * sizeof(WCHAR);
463 lError = RegQueryValueExW(hKey,
464 L"ProgramFilesDir",
465 NULL,
466 &dwType,
467 (LPBYTE)szValue,
468 &Length);
469 if (lError == ERROR_SUCCESS)
470 {
471 SetUserEnvironmentVariable(lpEnvironment,
472 L"ProgramFiles",
473 szValue,
474 FALSE);
475 }
476
477 Length = 1024 * sizeof(WCHAR);
478 lError = RegQueryValueExW(hKey,
479 L"CommonFilesDir",
480 NULL,
481 &dwType,
482 (LPBYTE)szValue,
483 &Length);
484 if (lError == ERROR_SUCCESS)
485 {
486 SetUserEnvironmentVariable(lpEnvironment,
487 L"CommonProgramFiles",
488 szValue,
489 FALSE);
490 }
491
492 RegCloseKey(hKey);
493 }
494
495 if (hToken == NULL)
496 return TRUE;
497
498 hKeyUser = GetCurrentUserKey(hToken);
499 if (hKeyUser == NULL)
500 {
501 DPRINT1("GetCurrentUserKey() failed\n");
502 RtlDestroyEnvironment(*lpEnvironment);
503 return FALSE;
504 }
505
506 /* Set 'USERPROFILE' variable */
507 Length = MAX_PATH;
508 if (GetUserProfileDirectoryW(hToken,
509 Buffer,
510 &Length))
511 {
512 SetUserEnvironmentVariable(lpEnvironment,
513 L"USERPROFILE",
514 Buffer,
515 FALSE);
516 }
517
518 if (GetUserAndDomainName(hToken,
519 &lpUserName,
520 &lpDomainName))
521 {
522 /* Set 'USERDOMAIN' variable */
523 SetUserEnvironmentVariable(lpEnvironment,
524 L"USERDOMAIN",
525 lpDomainName,
526 FALSE);
527
528 /* Set 'USERNAME' variable */
529 SetUserEnvironmentVariable(lpEnvironment,
530 L"USERNAME",
531 lpUserName,
532 FALSE);
533 }
534
535 /* Set user environment variables */
536 SetUserEnvironment(lpEnvironment,
537 hKeyUser,
538 L"Environment");
539
540 /* Set user volatile environment variables */
541 SetUserEnvironment(lpEnvironment,
542 hKeyUser,
543 L"Volatile Environment");
544
545 RegCloseKey(hKeyUser);
546
547 if (lpUserName != NULL)
548 LocalFree(lpUserName);
549
550 if (lpDomainName != NULL)
551 LocalFree(lpDomainName);
552
553 return TRUE;
554 }
555
556
557 BOOL
558 WINAPI
559 DestroyEnvironmentBlock(LPVOID lpEnvironment)
560 {
561 DPRINT("DestroyEnvironmentBlock() called\n");
562
563 if (lpEnvironment == NULL)
564 {
565 SetLastError(ERROR_INVALID_PARAMETER);
566 return FALSE;
567 }
568
569 RtlDestroyEnvironment(lpEnvironment);
570
571 return TRUE;
572 }
573
574
575 BOOL
576 WINAPI
577 ExpandEnvironmentStringsForUserW(IN HANDLE hToken,
578 IN LPCWSTR lpSrc,
579 OUT LPWSTR lpDest,
580 IN DWORD dwSize)
581 {
582 PVOID lpEnvironment;
583 BOOL Ret = FALSE;
584
585 if (lpSrc == NULL || lpDest == NULL || dwSize == 0)
586 {
587 SetLastError(ERROR_INVALID_PARAMETER);
588 return FALSE;
589 }
590
591 if (CreateEnvironmentBlock(&lpEnvironment,
592 hToken,
593 FALSE))
594 {
595 UNICODE_STRING SrcU, DestU;
596 NTSTATUS Status;
597
598 /* initialize the strings */
599 RtlInitUnicodeString(&SrcU,
600 lpSrc);
601 DestU.Length = 0;
602 DestU.MaximumLength = dwSize * sizeof(WCHAR);
603 DestU.Buffer = lpDest;
604
605 /* expand the strings */
606 Status = RtlExpandEnvironmentStrings_U((PWSTR)lpEnvironment,
607 &SrcU,
608 &DestU,
609 NULL);
610
611 DestroyEnvironmentBlock(lpEnvironment);
612
613 if (NT_SUCCESS(Status))
614 {
615 Ret = TRUE;
616 }
617 else
618 {
619 SetLastError(RtlNtStatusToDosError(Status));
620 }
621 }
622
623 return Ret;
624 }
625
626
627 BOOL
628 WINAPI
629 ExpandEnvironmentStringsForUserA(IN HANDLE hToken,
630 IN LPCSTR lpSrc,
631 OUT LPSTR lpDest,
632 IN DWORD dwSize)
633 {
634 DWORD dwSrcLen;
635 LPWSTR lpSrcW = NULL, lpDestW = NULL;
636 BOOL Ret = FALSE;
637
638 if (lpSrc == NULL || lpDest == NULL || dwSize == 0)
639 {
640 SetLastError(ERROR_INVALID_PARAMETER);
641 return FALSE;
642 }
643
644 dwSrcLen = strlen(lpSrc);
645 lpSrcW = (LPWSTR)GlobalAlloc(GMEM_FIXED,
646 (dwSrcLen + 1) * sizeof(WCHAR));
647 if (lpSrcW == NULL ||
648 MultiByteToWideChar(CP_ACP,
649 0,
650 lpSrc,
651 -1,
652 lpSrcW,
653 dwSrcLen + 1) == 0)
654 {
655 goto Cleanup;
656 }
657
658 lpDestW = (LPWSTR)GlobalAlloc(GMEM_FIXED,
659 dwSize * sizeof(WCHAR));
660 if (lpDestW == NULL)
661 {
662 goto Cleanup;
663 }
664
665 Ret = ExpandEnvironmentStringsForUserW(hToken,
666 lpSrcW,
667 lpDestW,
668 dwSize);
669 if (Ret)
670 {
671 if (WideCharToMultiByte(CP_ACP,
672 0,
673 lpDestW,
674 -1,
675 lpDest,
676 dwSize,
677 NULL,
678 NULL) == 0)
679 {
680 Ret = FALSE;
681 }
682 }
683
684 Cleanup:
685 if (lpSrcW != NULL)
686 {
687 GlobalFree((HGLOBAL)lpSrcW);
688 }
689
690 if (lpDestW != NULL)
691 {
692 GlobalFree((HGLOBAL)lpDestW);
693 }
694
695 return Ret;
696 }
697
698 /* EOF */