[USERENV]
[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
33 static
34 BOOL
35 SetUserEnvironmentVariable(LPVOID *Environment,
36 LPWSTR lpName,
37 LPWSTR lpValue,
38 BOOL bExpand)
39 {
40 WCHAR ShortName[MAX_PATH];
41 UNICODE_STRING Name;
42 UNICODE_STRING SrcValue;
43 UNICODE_STRING DstValue;
44 ULONG Length;
45 NTSTATUS Status;
46 PVOID Buffer = NULL;
47
48 if (bExpand)
49 {
50 RtlInitUnicodeString(&SrcValue,
51 lpValue);
52
53 Length = 2 * MAX_PATH * sizeof(WCHAR);
54
55 DstValue.Length = 0;
56 DstValue.MaximumLength = Length;
57 DstValue.Buffer = Buffer = LocalAlloc(LPTR,
58 Length);
59 if (DstValue.Buffer == NULL)
60 {
61 DPRINT1("LocalAlloc() failed\n");
62 return FALSE;
63 }
64
65 Status = RtlExpandEnvironmentStrings_U((PWSTR)*Environment,
66 &SrcValue,
67 &DstValue,
68 &Length);
69 if (!NT_SUCCESS(Status))
70 {
71 DPRINT1("RtlExpandEnvironmentStrings_U() failed (Status %lx)\n", Status);
72 DPRINT1("Length %lu\n", Length);
73 if (Buffer)
74 LocalFree(Buffer);
75 return FALSE;
76 }
77 }
78 else
79 {
80 RtlInitUnicodeString(&DstValue,
81 lpValue);
82 }
83
84 if (!_wcsicmp(lpName, L"temp") || !_wcsicmp(lpName, L"tmp"))
85 {
86 if (!GetShortPathNameW(DstValue.Buffer, ShortName, MAX_PATH))
87 {
88 DPRINT1("GetShortPathNameW() failed for %S (Error %lu)\n", DstValue.Buffer, GetLastError());
89 if (Buffer)
90 LocalFree(Buffer);
91 return FALSE;
92 }
93
94 DPRINT("Buffer: %S\n", ShortName);
95 RtlInitUnicodeString(&DstValue,
96 ShortName);
97 }
98
99 RtlInitUnicodeString(&Name,
100 lpName);
101
102 DPRINT("Value: %wZ\n", &DstValue);
103
104 Status = RtlSetEnvironmentVariable((PWSTR*)Environment,
105 &Name,
106 &DstValue);
107
108 if (Buffer)
109 LocalFree(Buffer);
110
111 if (!NT_SUCCESS(Status))
112 {
113 DPRINT1("RtlSetEnvironmentVariable() failed (Status %lx)\n", Status);
114 return FALSE;
115 }
116
117 return TRUE;
118 }
119
120
121 static
122 BOOL
123 AppendUserEnvironmentVariable(LPVOID *Environment,
124 LPWSTR lpName,
125 LPWSTR lpValue)
126 {
127 UNICODE_STRING Name;
128 UNICODE_STRING Value;
129 NTSTATUS Status;
130
131 RtlInitUnicodeString(&Name,
132 lpName);
133
134 Value.Length = 0;
135 Value.MaximumLength = 1024 * sizeof(WCHAR);
136 Value.Buffer = LocalAlloc(LPTR,
137 1024 * sizeof(WCHAR));
138 if (Value.Buffer == NULL)
139 {
140 return FALSE;
141 }
142 Value.Buffer[0] = UNICODE_NULL;
143
144 Status = RtlQueryEnvironmentVariable_U((PWSTR)*Environment,
145 &Name,
146 &Value);
147 if (NT_SUCCESS(Status))
148 {
149 RtlAppendUnicodeToString(&Value,
150 L";");
151 }
152
153 RtlAppendUnicodeToString(&Value,
154 lpValue);
155
156 Status = RtlSetEnvironmentVariable((PWSTR*)Environment,
157 &Name,
158 &Value);
159 LocalFree(Value.Buffer);
160 if (!NT_SUCCESS(Status))
161 {
162 DPRINT1("RtlSetEnvironmentVariable() failed (Status %lx)\n", Status);
163 return FALSE;
164 }
165
166 return TRUE;
167 }
168
169
170 static
171 HKEY
172 GetCurrentUserKey(HANDLE hToken)
173 {
174 UNICODE_STRING SidString;
175 HKEY hKey;
176 LONG Error;
177
178 if (!GetUserSidStringFromToken(hToken,
179 &SidString))
180 {
181 DPRINT1("GetUserSidFromToken() failed\n");
182 return NULL;
183 }
184
185 Error = RegOpenKeyExW(HKEY_USERS,
186 SidString.Buffer,
187 0,
188 MAXIMUM_ALLOWED,
189 &hKey);
190 if (Error != ERROR_SUCCESS)
191 {
192 DPRINT1("RegOpenKeyExW() failed (Error %ld)\n", Error);
193 RtlFreeUnicodeString(&SidString);
194 SetLastError((DWORD)Error);
195 return NULL;
196 }
197
198 RtlFreeUnicodeString(&SidString);
199
200 return hKey;
201 }
202
203
204 static
205 BOOL
206 GetUserAndDomainName(IN HANDLE hToken,
207 OUT LPWSTR *UserName,
208 OUT LPWSTR *DomainName)
209 {
210 PSID Sid = NULL;
211 LPWSTR lpUserName = NULL;
212 LPWSTR lpDomainName = NULL;
213 DWORD cbUserName = 0;
214 DWORD cbDomainName = 0;
215 SID_NAME_USE SidNameUse;
216 BOOL bRet = TRUE;
217
218 if (!GetUserSidFromToken(hToken,
219 &Sid))
220 {
221 DPRINT1("GetUserSidFromToken() failed\n");
222 return FALSE;
223 }
224
225 if (!LookupAccountSidW(NULL,
226 Sid,
227 NULL,
228 &cbUserName,
229 NULL,
230 &cbDomainName,
231 &SidNameUse))
232 {
233 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
234 {
235 bRet = FALSE;
236 goto done;
237 }
238 }
239
240 lpUserName = LocalAlloc(LPTR,
241 cbUserName * sizeof(WCHAR));
242 if (lpUserName == NULL)
243 {
244 bRet = FALSE;
245 goto done;
246 }
247
248 lpDomainName = LocalAlloc(LPTR,
249 cbDomainName * sizeof(WCHAR));
250 if (lpDomainName == NULL)
251 {
252 bRet = FALSE;
253 goto done;
254 }
255
256 if (!LookupAccountSidW(NULL,
257 Sid,
258 lpUserName,
259 &cbUserName,
260 lpDomainName,
261 &cbDomainName,
262 &SidNameUse))
263 {
264 bRet = FALSE;
265 goto done;
266 }
267
268 *UserName = lpUserName;
269 *DomainName = lpDomainName;
270
271 done:
272 if (bRet == FALSE)
273 {
274 if (lpUserName != NULL)
275 LocalFree(lpUserName);
276
277 if (lpDomainName != NULL)
278 LocalFree(lpDomainName);
279 }
280
281 LocalFree(Sid);
282
283 return bRet;
284 }
285
286
287 static
288 BOOL
289 SetUserEnvironment(LPVOID *lpEnvironment,
290 HKEY hKey,
291 LPWSTR lpSubKeyName)
292 {
293 HKEY hEnvKey;
294 DWORD dwValues;
295 DWORD dwMaxValueNameLength;
296 DWORD dwMaxValueDataLength;
297 DWORD dwValueNameLength;
298 DWORD dwValueDataLength;
299 DWORD dwType;
300 DWORD i;
301 LPWSTR lpValueName;
302 LPWSTR lpValueData;
303 LONG Error;
304
305 Error = RegOpenKeyExW(hKey,
306 lpSubKeyName,
307 0,
308 KEY_QUERY_VALUE,
309 &hEnvKey);
310 if (Error != ERROR_SUCCESS)
311 {
312 DPRINT1("RegOpenKeyExW() failed (Error %ld)\n", Error);
313 SetLastError((DWORD)Error);
314 return FALSE;
315 }
316
317 Error = RegQueryInfoKey(hEnvKey,
318 NULL,
319 NULL,
320 NULL,
321 NULL,
322 NULL,
323 NULL,
324 &dwValues,
325 &dwMaxValueNameLength,
326 &dwMaxValueDataLength,
327 NULL,
328 NULL);
329 if (Error != ERROR_SUCCESS)
330 {
331 DPRINT1("RegQueryInforKey() failed (Error %ld)\n", Error);
332 RegCloseKey(hEnvKey);
333 SetLastError((DWORD)Error);
334 return FALSE;
335 }
336
337 if (dwValues == 0)
338 {
339 RegCloseKey(hEnvKey);
340 return TRUE;
341 }
342
343 /* Allocate buffers */
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 */