Sync with trunk r47129
[reactos.git] / 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 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS system libraries
23 * FILE: lib/userenv/environment.c
24 * PURPOSE: User environment functions
25 * PROGRAMMER: Eric Kohl
26 */
27
28 #include <precomp.h>
29
30 #define NDEBUG
31 #include <debug.h>
32
33
34 static 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 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 HKEY
170 GetCurrentUserKey(HANDLE hToken)
171 {
172 UNICODE_STRING SidString;
173 HKEY hKey;
174 LONG Error;
175
176 if (!GetUserSidFromToken(hToken,
177 &SidString))
178 {
179 DPRINT1("GetUserSidFromToken() failed\n");
180 return NULL;
181 }
182
183 Error = RegOpenKeyExW(HKEY_USERS,
184 SidString.Buffer,
185 0,
186 MAXIMUM_ALLOWED,
187 &hKey);
188 if (Error != ERROR_SUCCESS)
189 {
190 DPRINT1("RegOpenKeyExW() failed (Error %ld)\n", Error);
191 RtlFreeUnicodeString(&SidString);
192 SetLastError((DWORD)Error);
193 return NULL;
194 }
195
196 RtlFreeUnicodeString(&SidString);
197
198 return hKey;
199 }
200
201
202 static BOOL
203 SetUserEnvironment(LPVOID *lpEnvironment,
204 HKEY hKey,
205 LPWSTR lpSubKeyName)
206 {
207 HKEY hEnvKey;
208 DWORD dwValues;
209 DWORD dwMaxValueNameLength;
210 DWORD dwMaxValueDataLength;
211 DWORD dwValueNameLength;
212 DWORD dwValueDataLength;
213 DWORD dwType;
214 DWORD i;
215 LPWSTR lpValueName;
216 LPWSTR lpValueData;
217 LONG Error;
218
219 Error = RegOpenKeyExW(hKey,
220 lpSubKeyName,
221 0,
222 KEY_QUERY_VALUE,
223 &hEnvKey);
224 if (Error != ERROR_SUCCESS)
225 {
226 DPRINT1("RegOpenKeyExW() failed (Error %ld)\n", Error);
227 SetLastError((DWORD)Error);
228 return FALSE;
229 }
230
231 Error = RegQueryInfoKey(hEnvKey,
232 NULL,
233 NULL,
234 NULL,
235 NULL,
236 NULL,
237 NULL,
238 &dwValues,
239 &dwMaxValueNameLength,
240 &dwMaxValueDataLength,
241 NULL,
242 NULL);
243 if (Error != ERROR_SUCCESS)
244 {
245 DPRINT1("RegQueryInforKey() failed (Error %ld)\n", Error);
246 RegCloseKey(hEnvKey);
247 SetLastError((DWORD)Error);
248 return FALSE;
249 }
250
251 if (dwValues == 0)
252 {
253 RegCloseKey(hEnvKey);
254 return TRUE;
255 }
256
257 /* Allocate buffers */
258 lpValueName = LocalAlloc(LPTR,
259 dwMaxValueNameLength * sizeof(WCHAR));
260 if (lpValueName == NULL)
261 {
262 RegCloseKey(hEnvKey);
263 return FALSE;
264 }
265
266 lpValueData = LocalAlloc(LPTR,
267 dwMaxValueDataLength);
268 if (lpValueData == NULL)
269 {
270 LocalFree(lpValueName);
271 RegCloseKey(hEnvKey);
272 return FALSE;
273 }
274
275 /* Enumerate values */
276 for (i = 0; i < dwValues; i++)
277 {
278 dwValueNameLength = dwMaxValueNameLength;
279 dwValueDataLength = dwMaxValueDataLength;
280 RegEnumValueW(hEnvKey,
281 i,
282 lpValueName,
283 &dwValueNameLength,
284 NULL,
285 &dwType,
286 (LPBYTE)lpValueData,
287 &dwValueDataLength);
288
289 if (!_wcsicmp (lpValueName, L"path"))
290 {
291 /* Append 'Path' environment variable */
292 AppendUserEnvironmentVariable(lpEnvironment,
293 lpValueName,
294 lpValueData);
295 }
296 else
297 {
298 /* Set environment variable */
299 SetUserEnvironmentVariable(lpEnvironment,
300 lpValueName,
301 lpValueData,
302 (dwType == REG_EXPAND_SZ));
303 }
304 }
305
306 LocalFree(lpValueData);
307 LocalFree(lpValueName);
308 RegCloseKey(hEnvKey);
309
310 return TRUE;
311 }
312
313
314 BOOL WINAPI
315 CreateEnvironmentBlock(LPVOID *lpEnvironment,
316 HANDLE hToken,
317 BOOL bInherit)
318 {
319 WCHAR Buffer[MAX_PATH];
320 WCHAR szValue[1024];
321 DWORD Length;
322 DWORD dwType;
323 HKEY hKey;
324 HKEY hKeyUser;
325 NTSTATUS Status;
326 LONG lError;
327
328 DPRINT("CreateEnvironmentBlock() called\n");
329
330 if (lpEnvironment == NULL)
331 {
332 SetLastError(ERROR_INVALID_PARAMETER);
333 return FALSE;
334 }
335
336 Status = RtlCreateEnvironment((BOOLEAN)bInherit,
337 (PWSTR*)lpEnvironment);
338 if (!NT_SUCCESS (Status))
339 {
340 DPRINT1("RtlCreateEnvironment() failed (Status %lx)\n", Status);
341 SetLastError(RtlNtStatusToDosError(Status));
342 return FALSE;
343 }
344
345 /* Set 'COMPUTERNAME' variable */
346 Length = MAX_PATH;
347 if (GetComputerNameW(Buffer,
348 &Length))
349 {
350 SetUserEnvironmentVariable(lpEnvironment,
351 L"COMPUTERNAME",
352 Buffer,
353 FALSE);
354 }
355
356 /* Set 'ALLUSERSPROFILE' variable */
357 Length = MAX_PATH;
358 if (GetAllUsersProfileDirectoryW(Buffer,
359 &Length))
360 {
361 SetUserEnvironmentVariable(lpEnvironment,
362 L"ALLUSERSPROFILE",
363 Buffer,
364 FALSE);
365 }
366
367 lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
368 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
369 0,
370 KEY_READ,
371 &hKey);
372 if (lError == ERROR_SUCCESS)
373 {
374 Length = 1024 * sizeof(WCHAR);
375 lError = RegQueryValueExW(hKey,
376 L"ProgramFilesDir",
377 NULL,
378 &dwType,
379 (LPBYTE)szValue,
380 &Length);
381 if (lError == ERROR_SUCCESS)
382 {
383 SetUserEnvironmentVariable(lpEnvironment,
384 L"ProgramFiles",
385 szValue,
386 FALSE);
387 }
388
389 Length = 1024 * sizeof(WCHAR);
390 lError = RegQueryValueExW(hKey,
391 L"CommonFilesDir",
392 NULL,
393 &dwType,
394 (LPBYTE)szValue,
395 &Length);
396 if (lError == ERROR_SUCCESS)
397 {
398 SetUserEnvironmentVariable(lpEnvironment,
399 L"CommonProgramFiles",
400 szValue,
401 FALSE);
402 }
403
404 RegCloseKey(hKey);
405 }
406
407 if (hToken == NULL)
408 return TRUE;
409
410 hKeyUser = GetCurrentUserKey(hToken);
411 if (hKeyUser == NULL)
412 {
413 DPRINT1("GetCurrentUserKey() failed\n");
414 RtlDestroyEnvironment(*lpEnvironment);
415 return FALSE;
416 }
417
418 /* Set 'USERPROFILE' variable */
419 Length = MAX_PATH;
420 if (GetUserProfileDirectoryW(hToken,
421 Buffer,
422 &Length))
423 {
424 SetUserEnvironmentVariable(lpEnvironment,
425 L"USERPROFILE",
426 Buffer,
427 FALSE);
428 }
429
430 /* FIXME: Set 'USERDOMAIN' variable */
431
432 Length = MAX_PATH;
433 if (GetUserNameW(Buffer,
434 &Length))
435 {
436 SetUserEnvironmentVariable(lpEnvironment,
437 L"USERNAME",
438 Buffer,
439 FALSE);
440 }
441
442
443
444 /* Set user environment variables */
445 SetUserEnvironment(lpEnvironment,
446 hKeyUser,
447 L"Environment");
448
449 RegCloseKey(hKeyUser);
450
451 return TRUE;
452 }
453
454
455 BOOL WINAPI
456 DestroyEnvironmentBlock(LPVOID lpEnvironment)
457 {
458 DPRINT("DestroyEnvironmentBlock() called\n");
459
460 if (lpEnvironment == NULL)
461 {
462 SetLastError(ERROR_INVALID_PARAMETER);
463 return FALSE;
464 }
465
466 RtlDestroyEnvironment(lpEnvironment);
467
468 return TRUE;
469 }
470
471
472 BOOL WINAPI
473 ExpandEnvironmentStringsForUserW(IN HANDLE hToken,
474 IN LPCWSTR lpSrc,
475 OUT LPWSTR lpDest,
476 IN DWORD dwSize)
477 {
478 PVOID lpEnvironment;
479 BOOL Ret = FALSE;
480
481 if (lpSrc == NULL || lpDest == NULL || dwSize == 0)
482 {
483 SetLastError(ERROR_INVALID_PARAMETER);
484 return FALSE;
485 }
486
487 if (CreateEnvironmentBlock(&lpEnvironment,
488 hToken,
489 FALSE))
490 {
491 UNICODE_STRING SrcU, DestU;
492 NTSTATUS Status;
493
494 /* initialize the strings */
495 RtlInitUnicodeString(&SrcU,
496 lpSrc);
497 DestU.Length = 0;
498 DestU.MaximumLength = dwSize * sizeof(WCHAR);
499 DestU.Buffer = lpDest;
500
501 /* expand the strings */
502 Status = RtlExpandEnvironmentStrings_U((PWSTR)lpEnvironment,
503 &SrcU,
504 &DestU,
505 NULL);
506
507 DestroyEnvironmentBlock(lpEnvironment);
508
509 if (NT_SUCCESS(Status))
510 {
511 Ret = TRUE;
512 }
513 else
514 {
515 SetLastError(RtlNtStatusToDosError(Status));
516 }
517 }
518
519 return Ret;
520 }
521
522
523 BOOL WINAPI
524 ExpandEnvironmentStringsForUserA(IN HANDLE hToken,
525 IN LPCSTR lpSrc,
526 OUT LPSTR lpDest,
527 IN DWORD dwSize)
528 {
529 DWORD dwSrcLen;
530 LPWSTR lpSrcW = NULL, lpDestW = NULL;
531 BOOL Ret = FALSE;
532
533 if (lpSrc == NULL || lpDest == NULL || dwSize == 0)
534 {
535 SetLastError(ERROR_INVALID_PARAMETER);
536 return FALSE;
537 }
538
539 dwSrcLen = strlen(lpSrc);
540 lpSrcW = (LPWSTR)GlobalAlloc(GMEM_FIXED,
541 (dwSrcLen + 1) * sizeof(WCHAR));
542 if (lpSrcW == NULL ||
543 MultiByteToWideChar(CP_ACP,
544 0,
545 lpSrc,
546 -1,
547 lpSrcW,
548 dwSrcLen + 1) == 0)
549 {
550 goto Cleanup;
551 }
552
553 lpDestW = (LPWSTR)GlobalAlloc(GMEM_FIXED,
554 dwSize * sizeof(WCHAR));
555 if (lpDestW == NULL)
556 {
557 goto Cleanup;
558 }
559
560 Ret = ExpandEnvironmentStringsForUserW(hToken,
561 lpSrcW,
562 lpDestW,
563 dwSize);
564 if (Ret)
565 {
566 if (WideCharToMultiByte(CP_ACP,
567 0,
568 lpDestW,
569 -1,
570 lpDest,
571 dwSize,
572 NULL,
573 NULL) == 0)
574 {
575 Ret = FALSE;
576 }
577 }
578
579 Cleanup:
580 if (lpSrcW != NULL)
581 {
582 GlobalFree((HGLOBAL)lpSrcW);
583 }
584
585 if (lpDestW != NULL)
586 {
587 GlobalFree((HGLOBAL)lpDestW);
588 }
589
590 return Ret;
591 }
592
593 /* EOF */