Reintegrate header-work branch. Important changes include continued work on headers...
[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 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 /* Set user environment variables */
443 SetUserEnvironment(lpEnvironment,
444 hKeyUser,
445 L"Environment");
446
447 /* Set user volatile environment variables */
448 SetUserEnvironment(lpEnvironment,
449 hKeyUser,
450 L"Volatile Environment");
451
452 RegCloseKey(hKeyUser);
453
454 return TRUE;
455 }
456
457
458 BOOL WINAPI
459 DestroyEnvironmentBlock(LPVOID lpEnvironment)
460 {
461 DPRINT("DestroyEnvironmentBlock() called\n");
462
463 if (lpEnvironment == NULL)
464 {
465 SetLastError(ERROR_INVALID_PARAMETER);
466 return FALSE;
467 }
468
469 RtlDestroyEnvironment(lpEnvironment);
470
471 return TRUE;
472 }
473
474
475 BOOL WINAPI
476 ExpandEnvironmentStringsForUserW(IN HANDLE hToken,
477 IN LPCWSTR lpSrc,
478 OUT LPWSTR lpDest,
479 IN DWORD dwSize)
480 {
481 PVOID lpEnvironment;
482 BOOL Ret = FALSE;
483
484 if (lpSrc == NULL || lpDest == NULL || dwSize == 0)
485 {
486 SetLastError(ERROR_INVALID_PARAMETER);
487 return FALSE;
488 }
489
490 if (CreateEnvironmentBlock(&lpEnvironment,
491 hToken,
492 FALSE))
493 {
494 UNICODE_STRING SrcU, DestU;
495 NTSTATUS Status;
496
497 /* initialize the strings */
498 RtlInitUnicodeString(&SrcU,
499 lpSrc);
500 DestU.Length = 0;
501 DestU.MaximumLength = dwSize * sizeof(WCHAR);
502 DestU.Buffer = lpDest;
503
504 /* expand the strings */
505 Status = RtlExpandEnvironmentStrings_U((PWSTR)lpEnvironment,
506 &SrcU,
507 &DestU,
508 NULL);
509
510 DestroyEnvironmentBlock(lpEnvironment);
511
512 if (NT_SUCCESS(Status))
513 {
514 Ret = TRUE;
515 }
516 else
517 {
518 SetLastError(RtlNtStatusToDosError(Status));
519 }
520 }
521
522 return Ret;
523 }
524
525
526 BOOL WINAPI
527 ExpandEnvironmentStringsForUserA(IN HANDLE hToken,
528 IN LPCSTR lpSrc,
529 OUT LPSTR lpDest,
530 IN DWORD dwSize)
531 {
532 DWORD dwSrcLen;
533 LPWSTR lpSrcW = NULL, lpDestW = NULL;
534 BOOL Ret = FALSE;
535
536 if (lpSrc == NULL || lpDest == NULL || dwSize == 0)
537 {
538 SetLastError(ERROR_INVALID_PARAMETER);
539 return FALSE;
540 }
541
542 dwSrcLen = strlen(lpSrc);
543 lpSrcW = (LPWSTR)GlobalAlloc(GMEM_FIXED,
544 (dwSrcLen + 1) * sizeof(WCHAR));
545 if (lpSrcW == NULL ||
546 MultiByteToWideChar(CP_ACP,
547 0,
548 lpSrc,
549 -1,
550 lpSrcW,
551 dwSrcLen + 1) == 0)
552 {
553 goto Cleanup;
554 }
555
556 lpDestW = (LPWSTR)GlobalAlloc(GMEM_FIXED,
557 dwSize * sizeof(WCHAR));
558 if (lpDestW == NULL)
559 {
560 goto Cleanup;
561 }
562
563 Ret = ExpandEnvironmentStringsForUserW(hToken,
564 lpSrcW,
565 lpDestW,
566 dwSize);
567 if (Ret)
568 {
569 if (WideCharToMultiByte(CP_ACP,
570 0,
571 lpDestW,
572 -1,
573 lpDest,
574 dwSize,
575 NULL,
576 NULL) == 0)
577 {
578 Ret = FALSE;
579 }
580 }
581
582 Cleanup:
583 if (lpSrcW != NULL)
584 {
585 GlobalFree((HGLOBAL)lpSrcW);
586 }
587
588 if (lpDestW != NULL)
589 {
590 GlobalFree((HGLOBAL)lpDestW);
591 }
592
593 return Ret;
594 }
595
596 /* EOF */