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