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