ccb36d83664f5545f804ff33c810165f52020d36
[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 dwMaxValueNameLength++;
344 lpValueName = LocalAlloc(LPTR,
345 dwMaxValueNameLength * sizeof(WCHAR));
346 if (lpValueName == NULL)
347 {
348 RegCloseKey(hEnvKey);
349 return FALSE;
350 }
351
352 lpValueData = LocalAlloc(LPTR,
353 dwMaxValueDataLength);
354 if (lpValueData == NULL)
355 {
356 LocalFree(lpValueName);
357 RegCloseKey(hEnvKey);
358 return FALSE;
359 }
360
361 /* Enumerate values */
362 for (i = 0; i < dwValues; i++)
363 {
364 dwValueNameLength = dwMaxValueNameLength;
365 dwValueDataLength = dwMaxValueDataLength;
366 RegEnumValueW(hEnvKey,
367 i,
368 lpValueName,
369 &dwValueNameLength,
370 NULL,
371 &dwType,
372 (LPBYTE)lpValueData,
373 &dwValueDataLength);
374
375 if (!_wcsicmp (lpValueName, L"path"))
376 {
377 /* Append 'Path' environment variable */
378 AppendUserEnvironmentVariable(lpEnvironment,
379 lpValueName,
380 lpValueData);
381 }
382 else
383 {
384 /* Set environment variable */
385 SetUserEnvironmentVariable(lpEnvironment,
386 lpValueName,
387 lpValueData,
388 (dwType == REG_EXPAND_SZ));
389 }
390 }
391
392 LocalFree(lpValueData);
393 LocalFree(lpValueName);
394 RegCloseKey(hEnvKey);
395
396 return TRUE;
397 }
398
399
400 BOOL
401 WINAPI
402 CreateEnvironmentBlock(LPVOID *lpEnvironment,
403 HANDLE hToken,
404 BOOL bInherit)
405 {
406 WCHAR Buffer[MAX_PATH];
407 WCHAR szValue[1024];
408 DWORD Length;
409 DWORD dwType;
410 HKEY hKey;
411 HKEY hKeyUser;
412 LPWSTR lpUserName = NULL;
413 LPWSTR lpDomainName = NULL;
414 NTSTATUS Status;
415 LONG lError;
416
417 DPRINT("CreateEnvironmentBlock() called\n");
418
419 if (lpEnvironment == NULL)
420 {
421 SetLastError(ERROR_INVALID_PARAMETER);
422 return FALSE;
423 }
424
425 Status = RtlCreateEnvironment((BOOLEAN)bInherit,
426 (PWSTR*)lpEnvironment);
427 if (!NT_SUCCESS (Status))
428 {
429 DPRINT1("RtlCreateEnvironment() failed (Status %lx)\n", Status);
430 SetLastError(RtlNtStatusToDosError(Status));
431 return FALSE;
432 }
433
434 /* Set 'COMPUTERNAME' variable */
435 Length = MAX_PATH;
436 if (GetComputerNameW(Buffer,
437 &Length))
438 {
439 SetUserEnvironmentVariable(lpEnvironment,
440 L"COMPUTERNAME",
441 Buffer,
442 FALSE);
443 }
444
445 /* Set 'ALLUSERSPROFILE' variable */
446 Length = MAX_PATH;
447 if (GetAllUsersProfileDirectoryW(Buffer,
448 &Length))
449 {
450 SetUserEnvironmentVariable(lpEnvironment,
451 L"ALLUSERSPROFILE",
452 Buffer,
453 FALSE);
454 }
455
456 lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
457 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
458 0,
459 KEY_READ,
460 &hKey);
461 if (lError == ERROR_SUCCESS)
462 {
463 Length = 1024 * sizeof(WCHAR);
464 lError = RegQueryValueExW(hKey,
465 L"ProgramFilesDir",
466 NULL,
467 &dwType,
468 (LPBYTE)szValue,
469 &Length);
470 if (lError == ERROR_SUCCESS)
471 {
472 SetUserEnvironmentVariable(lpEnvironment,
473 L"ProgramFiles",
474 szValue,
475 FALSE);
476 }
477
478 Length = 1024 * sizeof(WCHAR);
479 lError = RegQueryValueExW(hKey,
480 L"CommonFilesDir",
481 NULL,
482 &dwType,
483 (LPBYTE)szValue,
484 &Length);
485 if (lError == ERROR_SUCCESS)
486 {
487 SetUserEnvironmentVariable(lpEnvironment,
488 L"CommonProgramFiles",
489 szValue,
490 FALSE);
491 }
492
493 RegCloseKey(hKey);
494 }
495
496 if (hToken == NULL)
497 return TRUE;
498
499 hKeyUser = GetCurrentUserKey(hToken);
500 if (hKeyUser == NULL)
501 {
502 DPRINT1("GetCurrentUserKey() failed\n");
503 RtlDestroyEnvironment(*lpEnvironment);
504 return FALSE;
505 }
506
507 /* Set 'USERPROFILE' variable */
508 Length = MAX_PATH;
509 if (GetUserProfileDirectoryW(hToken,
510 Buffer,
511 &Length))
512 {
513 SetUserEnvironmentVariable(lpEnvironment,
514 L"USERPROFILE",
515 Buffer,
516 FALSE);
517 }
518
519 if (GetUserAndDomainName(hToken,
520 &lpUserName,
521 &lpDomainName))
522 {
523 /* Set 'USERDOMAIN' variable */
524 SetUserEnvironmentVariable(lpEnvironment,
525 L"USERDOMAIN",
526 lpDomainName,
527 FALSE);
528
529 /* Set 'USERNAME' variable */
530 SetUserEnvironmentVariable(lpEnvironment,
531 L"USERNAME",
532 lpUserName,
533 FALSE);
534 }
535
536 /* Set user environment variables */
537 SetUserEnvironment(lpEnvironment,
538 hKeyUser,
539 L"Environment");
540
541 /* Set user volatile environment variables */
542 SetUserEnvironment(lpEnvironment,
543 hKeyUser,
544 L"Volatile Environment");
545
546 RegCloseKey(hKeyUser);
547
548 if (lpUserName != NULL)
549 LocalFree(lpUserName);
550
551 if (lpDomainName != NULL)
552 LocalFree(lpDomainName);
553
554 return TRUE;
555 }
556
557
558 BOOL
559 WINAPI
560 DestroyEnvironmentBlock(LPVOID lpEnvironment)
561 {
562 DPRINT("DestroyEnvironmentBlock() called\n");
563
564 if (lpEnvironment == NULL)
565 {
566 SetLastError(ERROR_INVALID_PARAMETER);
567 return FALSE;
568 }
569
570 RtlDestroyEnvironment(lpEnvironment);
571
572 return TRUE;
573 }
574
575
576 BOOL
577 WINAPI
578 ExpandEnvironmentStringsForUserW(IN HANDLE hToken,
579 IN LPCWSTR lpSrc,
580 OUT LPWSTR lpDest,
581 IN DWORD dwSize)
582 {
583 PVOID lpEnvironment;
584 BOOL Ret = FALSE;
585
586 if (lpSrc == NULL || lpDest == NULL || dwSize == 0)
587 {
588 SetLastError(ERROR_INVALID_PARAMETER);
589 return FALSE;
590 }
591
592 if (CreateEnvironmentBlock(&lpEnvironment,
593 hToken,
594 FALSE))
595 {
596 UNICODE_STRING SrcU, DestU;
597 NTSTATUS Status;
598
599 /* initialize the strings */
600 RtlInitUnicodeString(&SrcU,
601 lpSrc);
602 DestU.Length = 0;
603 DestU.MaximumLength = dwSize * sizeof(WCHAR);
604 DestU.Buffer = lpDest;
605
606 /* expand the strings */
607 Status = RtlExpandEnvironmentStrings_U((PWSTR)lpEnvironment,
608 &SrcU,
609 &DestU,
610 NULL);
611
612 DestroyEnvironmentBlock(lpEnvironment);
613
614 if (NT_SUCCESS(Status))
615 {
616 Ret = TRUE;
617 }
618 else
619 {
620 SetLastError(RtlNtStatusToDosError(Status));
621 }
622 }
623
624 return Ret;
625 }
626
627
628 BOOL
629 WINAPI
630 ExpandEnvironmentStringsForUserA(IN HANDLE hToken,
631 IN LPCSTR lpSrc,
632 OUT LPSTR lpDest,
633 IN DWORD dwSize)
634 {
635 DWORD dwSrcLen;
636 LPWSTR lpSrcW = NULL, lpDestW = NULL;
637 BOOL Ret = FALSE;
638
639 if (lpSrc == NULL || lpDest == NULL || dwSize == 0)
640 {
641 SetLastError(ERROR_INVALID_PARAMETER);
642 return FALSE;
643 }
644
645 dwSrcLen = strlen(lpSrc);
646 lpSrcW = (LPWSTR)GlobalAlloc(GMEM_FIXED,
647 (dwSrcLen + 1) * sizeof(WCHAR));
648 if (lpSrcW == NULL ||
649 MultiByteToWideChar(CP_ACP,
650 0,
651 lpSrc,
652 -1,
653 lpSrcW,
654 dwSrcLen + 1) == 0)
655 {
656 goto Cleanup;
657 }
658
659 lpDestW = (LPWSTR)GlobalAlloc(GMEM_FIXED,
660 dwSize * sizeof(WCHAR));
661 if (lpDestW == NULL)
662 {
663 goto Cleanup;
664 }
665
666 Ret = ExpandEnvironmentStringsForUserW(hToken,
667 lpSrcW,
668 lpDestW,
669 dwSize);
670 if (Ret)
671 {
672 if (WideCharToMultiByte(CP_ACP,
673 0,
674 lpDestW,
675 -1,
676 lpDest,
677 dwSize,
678 NULL,
679 NULL) == 0)
680 {
681 Ret = FALSE;
682 }
683 }
684
685 Cleanup:
686 if (lpSrcW != NULL)
687 {
688 GlobalFree((HGLOBAL)lpSrcW);
689 }
690
691 if (lpDestW != NULL)
692 {
693 GlobalFree((HGLOBAL)lpDestW);
694 }
695
696 return Ret;
697 }
698
699 /* EOF */