/* * ReactOS kernel * Copyright (C) 2004 ReactOS Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries * FILE: dll/win32/userenv/environment.c * PURPOSE: User environment functions * PROGRAMMER: Eric Kohl */ #include "precomp.h" #define NDEBUG #include static BOOL SetUserEnvironmentVariable(PWSTR* Environment, LPWSTR lpName, LPWSTR lpValue, BOOL bExpand) { NTSTATUS Status; UNICODE_STRING Name; UNICODE_STRING SrcValue, DstValue; ULONG Length; PVOID Buffer = NULL; WCHAR ShortName[MAX_PATH]; if (bExpand) { RtlInitUnicodeString(&SrcValue, lpValue); Length = 2 * MAX_PATH * sizeof(WCHAR); DstValue.Length = 0; DstValue.MaximumLength = Length; DstValue.Buffer = Buffer = LocalAlloc(LPTR, Length); if (DstValue.Buffer == NULL) { DPRINT1("LocalAlloc() failed\n"); return FALSE; } Status = RtlExpandEnvironmentStrings_U(*Environment, &SrcValue, &DstValue, &Length); if (!NT_SUCCESS(Status)) { DPRINT1("RtlExpandEnvironmentStrings_U() failed (Status %lx)\n", Status); DPRINT1("Length %lu\n", Length); if (Buffer) LocalFree(Buffer); return FALSE; } } else { RtlInitUnicodeString(&DstValue, lpValue); } if (!_wcsicmp(lpName, L"TEMP") || !_wcsicmp(lpName, L"TMP")) { if (GetShortPathNameW(DstValue.Buffer, ShortName, ARRAYSIZE(ShortName))) { RtlInitUnicodeString(&DstValue, ShortName); } else { DPRINT("GetShortPathNameW() failed for %S (Error %lu)\n", DstValue.Buffer, GetLastError()); } DPRINT("Buffer: %S\n", ShortName); } RtlInitUnicodeString(&Name, lpName); DPRINT("Value: %wZ\n", &DstValue); Status = RtlSetEnvironmentVariable(Environment, &Name, &DstValue); if (Buffer) LocalFree(Buffer); if (!NT_SUCCESS(Status)) { DPRINT1("RtlSetEnvironmentVariable() failed (Status %lx)\n", Status); return FALSE; } return TRUE; } static BOOL AppendUserEnvironmentVariable(PWSTR* Environment, LPWSTR lpName, LPWSTR lpValue) { NTSTATUS Status; UNICODE_STRING Name, Value; RtlInitUnicodeString(&Name, lpName); Value.Length = 0; Value.MaximumLength = 1024 * sizeof(WCHAR); Value.Buffer = LocalAlloc(LPTR, Value.MaximumLength); if (Value.Buffer == NULL) return FALSE; Value.Buffer[0] = UNICODE_NULL; Status = RtlQueryEnvironmentVariable_U(*Environment, &Name, &Value); if (NT_SUCCESS(Status)) RtlAppendUnicodeToString(&Value, L";"); RtlAppendUnicodeToString(&Value, lpValue); Status = RtlSetEnvironmentVariable(Environment, &Name, &Value); LocalFree(Value.Buffer); if (!NT_SUCCESS(Status)) { DPRINT1("RtlSetEnvironmentVariable() failed (Status %lx)\n", Status); return FALSE; } return TRUE; } static HKEY GetCurrentUserKey(HANDLE hToken) { LONG Error; UNICODE_STRING SidString; HKEY hKey; if (!GetUserSidStringFromToken(hToken, &SidString)) { DPRINT1("GetUserSidFromToken() failed\n"); return NULL; } Error = RegOpenKeyExW(HKEY_USERS, SidString.Buffer, 0, MAXIMUM_ALLOWED, &hKey); if (Error != ERROR_SUCCESS) { DPRINT1("RegOpenKeyExW() failed (Error %ld)\n", Error); RtlFreeUnicodeString(&SidString); SetLastError((DWORD)Error); return NULL; } RtlFreeUnicodeString(&SidString); return hKey; } static BOOL GetUserAndDomainName(IN HANDLE hToken, OUT LPWSTR *UserName, OUT LPWSTR *DomainName) { BOOL bRet = TRUE; PSID Sid = NULL; LPWSTR lpUserName = NULL; LPWSTR lpDomainName = NULL; DWORD cbUserName = 0; DWORD cbDomainName = 0; SID_NAME_USE SidNameUse; Sid = GetUserSid(hToken); if (Sid == NULL) { DPRINT1("GetUserSid() failed\n"); return FALSE; } if (!LookupAccountSidW(NULL, Sid, NULL, &cbUserName, NULL, &cbDomainName, &SidNameUse)) { if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { bRet = FALSE; goto done; } } lpUserName = LocalAlloc(LPTR, cbUserName * sizeof(WCHAR)); if (lpUserName == NULL) { bRet = FALSE; goto done; } lpDomainName = LocalAlloc(LPTR, cbDomainName * sizeof(WCHAR)); if (lpDomainName == NULL) { bRet = FALSE; goto done; } if (!LookupAccountSidW(NULL, Sid, lpUserName, &cbUserName, lpDomainName, &cbDomainName, &SidNameUse)) { bRet = FALSE; goto done; } *UserName = lpUserName; *DomainName = lpDomainName; done: if (bRet == FALSE) { if (lpUserName != NULL) LocalFree(lpUserName); if (lpDomainName != NULL) LocalFree(lpDomainName); } LocalFree(Sid); return bRet; } static BOOL SetUserEnvironment(PWSTR* Environment, HKEY hKey, LPWSTR lpSubKeyName) { LONG Error; HKEY hEnvKey; DWORD dwValues; DWORD dwMaxValueNameLength; DWORD dwMaxValueDataLength; DWORD dwValueNameLength; DWORD dwValueDataLength; DWORD dwType; DWORD i; LPWSTR lpValueName; LPWSTR lpValueData; Error = RegOpenKeyExW(hKey, lpSubKeyName, 0, KEY_QUERY_VALUE, &hEnvKey); if (Error != ERROR_SUCCESS) { DPRINT1("RegOpenKeyExW() failed (Error %ld)\n", Error); SetLastError((DWORD)Error); return FALSE; } Error = RegQueryInfoKey(hEnvKey, NULL, NULL, NULL, NULL, NULL, NULL, &dwValues, &dwMaxValueNameLength, &dwMaxValueDataLength, NULL, NULL); if (Error != ERROR_SUCCESS) { DPRINT1("RegQueryInforKey() failed (Error %ld)\n", Error); RegCloseKey(hEnvKey); SetLastError((DWORD)Error); return FALSE; } if (dwValues == 0) { RegCloseKey(hEnvKey); return TRUE; } /* Allocate buffers */ dwMaxValueNameLength++; lpValueName = LocalAlloc(LPTR, dwMaxValueNameLength * sizeof(WCHAR)); if (lpValueName == NULL) { RegCloseKey(hEnvKey); return FALSE; } lpValueData = LocalAlloc(LPTR, dwMaxValueDataLength); if (lpValueData == NULL) { LocalFree(lpValueName); RegCloseKey(hEnvKey); return FALSE; } /* Enumerate values */ for (i = 0; i < dwValues; i++) { dwValueNameLength = dwMaxValueNameLength; dwValueDataLength = dwMaxValueDataLength; Error = RegEnumValueW(hEnvKey, i, lpValueName, &dwValueNameLength, NULL, &dwType, (LPBYTE)lpValueData, &dwValueDataLength); if (Error == ERROR_SUCCESS) { if (!_wcsicmp(lpValueName, L"PATH")) { /* Append 'Path' environment variable */ AppendUserEnvironmentVariable(Environment, lpValueName, lpValueData); } else { /* Set environment variable */ SetUserEnvironmentVariable(Environment, lpValueName, lpValueData, (dwType == REG_EXPAND_SZ)); } } else { LocalFree(lpValueData); LocalFree(lpValueName); RegCloseKey(hEnvKey); return FALSE; } } LocalFree(lpValueData); LocalFree(lpValueName); RegCloseKey(hEnvKey); return TRUE; } static BOOL SetSystemEnvironment(PWSTR* Environment) { LONG Error; HKEY hEnvKey; DWORD dwValues; DWORD dwMaxValueNameLength; DWORD dwMaxValueDataLength; DWORD dwValueNameLength; DWORD dwValueDataLength; DWORD dwType; DWORD i; LPWSTR lpValueName; LPWSTR lpValueData; Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", 0, KEY_QUERY_VALUE, &hEnvKey); if (Error != ERROR_SUCCESS) { DPRINT1("RegOpenKeyExW() failed (Error %ld)\n", Error); return FALSE; } Error = RegQueryInfoKey(hEnvKey, NULL, NULL, NULL, NULL, NULL, NULL, &dwValues, &dwMaxValueNameLength, &dwMaxValueDataLength, NULL, NULL); if (Error != ERROR_SUCCESS) { DPRINT1("RegQueryInforKey() failed (Error %ld)\n", Error); RegCloseKey(hEnvKey); return FALSE; } if (dwValues == 0) { RegCloseKey(hEnvKey); return TRUE; } /* Allocate buffers */ dwMaxValueNameLength++; lpValueName = LocalAlloc(LPTR, dwMaxValueNameLength * sizeof(WCHAR)); if (lpValueName == NULL) { RegCloseKey(hEnvKey); return FALSE; } lpValueData = LocalAlloc(LPTR, dwMaxValueDataLength); if (lpValueData == NULL) { LocalFree(lpValueName); RegCloseKey(hEnvKey); return FALSE; } /* Enumerate values */ for (i = 0; i < dwValues; i++) { dwValueNameLength = dwMaxValueNameLength; dwValueDataLength = dwMaxValueDataLength; Error = RegEnumValueW(hEnvKey, i, lpValueName, &dwValueNameLength, NULL, &dwType, (LPBYTE)lpValueData, &dwValueDataLength); if (Error == ERROR_SUCCESS) { /* Set environment variable */ SetUserEnvironmentVariable(Environment, lpValueName, lpValueData, (dwType == REG_EXPAND_SZ)); } else { LocalFree(lpValueData); LocalFree(lpValueName); RegCloseKey(hEnvKey); return FALSE; } } LocalFree(lpValueData); LocalFree(lpValueName); RegCloseKey(hEnvKey); return TRUE; } BOOL WINAPI CreateEnvironmentBlock(OUT LPVOID *lpEnvironment, IN HANDLE hToken, IN BOOL bInherit) { NTSTATUS Status; LONG lError; PWSTR* Environment = (PWSTR*)lpEnvironment; DWORD Length; DWORD dwType; HKEY hKey; HKEY hKeyUser; LPWSTR lpUserName = NULL; LPWSTR lpDomainName = NULL; WCHAR Buffer[MAX_PATH]; WCHAR szValue[1024]; DPRINT("CreateEnvironmentBlock() called\n"); if (lpEnvironment == NULL) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } Status = RtlCreateEnvironment((BOOLEAN)bInherit, Environment); if (!NT_SUCCESS(Status)) { DPRINT1("RtlCreateEnvironment() failed (Status %lx)\n", Status); SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } /* Set 'SystemRoot' variable */ Length = ARRAYSIZE(Buffer); if (GetEnvironmentVariableW(L"SystemRoot", Buffer, Length)) { SetUserEnvironmentVariable(Environment, L"SystemRoot", Buffer, FALSE); } /* Set 'SystemDrive' variable */ if (GetEnvironmentVariableW(L"SystemDrive", Buffer, Length)) { SetUserEnvironmentVariable(Environment, L"SystemDrive", Buffer, FALSE); } /* Set variables from Session Manager */ if (!SetSystemEnvironment(Environment)) { RtlDestroyEnvironment(*Environment); return FALSE; } /* Set 'COMPUTERNAME' variable */ Length = ARRAYSIZE(Buffer); if (GetComputerNameW(Buffer, &Length)) { SetUserEnvironmentVariable(Environment, L"COMPUTERNAME", Buffer, FALSE); } /* Set 'ALLUSERSPROFILE' variable */ Length = ARRAYSIZE(Buffer); if (GetAllUsersProfileDirectoryW(Buffer, &Length)) { SetUserEnvironmentVariable(Environment, L"ALLUSERSPROFILE", Buffer, FALSE); } /* Set 'USERPROFILE' variable to the default users profile */ Length = ARRAYSIZE(Buffer); if (GetDefaultUserProfileDirectoryW(Buffer, &Length)) { SetUserEnvironmentVariable(Environment, L"USERPROFILE", Buffer, TRUE); } lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion", 0, KEY_READ, &hKey); if (lError == ERROR_SUCCESS) { Length = sizeof(szValue); lError = RegQueryValueExW(hKey, L"ProgramFilesDir", NULL, &dwType, (LPBYTE)szValue, &Length); if (lError == ERROR_SUCCESS) { SetUserEnvironmentVariable(Environment, L"ProgramFiles", szValue, FALSE); } Length = sizeof(szValue); lError = RegQueryValueExW(hKey, L"CommonFilesDir", NULL, &dwType, (LPBYTE)szValue, &Length); if (lError == ERROR_SUCCESS) { SetUserEnvironmentVariable(Environment, L"CommonProgramFiles", szValue, FALSE); } RegCloseKey(hKey); } /* * If no user token is specified, the system environment variables are set * and we stop here, otherwise continue setting the user-specific variables. */ if (hToken == NULL) return TRUE; hKeyUser = GetCurrentUserKey(hToken); if (hKeyUser == NULL) { DPRINT1("GetCurrentUserKey() failed\n"); RtlDestroyEnvironment(*Environment); return FALSE; } /* Set 'USERPROFILE' variable */ Length = ARRAYSIZE(Buffer); if (GetUserProfileDirectoryW(hToken, Buffer, &Length)) { DWORD MinLen = 2; SetUserEnvironmentVariable(Environment, L"USERPROFILE", Buffer, FALSE); // FIXME: Strangely enough the following two environment variables // are not set by userenv.dll in Windows... See r68284 / CORE-9875 // FIXME2: This is done by msgina.dll !! /* At least : */ if (Length > MinLen) { /* Set 'HOMEDRIVE' variable */ StringCchCopyNW(szValue, ARRAYSIZE(Buffer), Buffer, MinLen); SetUserEnvironmentVariable(Environment, L"HOMEDRIVE", szValue, FALSE); /* Set 'HOMEPATH' variable */ StringCchCopyNW(szValue, ARRAYSIZE(Buffer), Buffer + MinLen, Length - MinLen); SetUserEnvironmentVariable(Environment, L"HOMEPATH", szValue, FALSE); } } else { DPRINT1("GetUserProfileDirectoryW failed with error %lu\n", GetLastError()); } if (GetUserAndDomainName(hToken, &lpUserName, &lpDomainName)) { /* Set 'USERNAME' variable */ SetUserEnvironmentVariable(Environment, L"USERNAME", lpUserName, FALSE); /* Set 'USERDOMAIN' variable */ SetUserEnvironmentVariable(Environment, L"USERDOMAIN", lpDomainName, FALSE); if (lpUserName != NULL) LocalFree(lpUserName); if (lpDomainName != NULL) LocalFree(lpDomainName); } /* Set user environment variables */ SetUserEnvironment(Environment, hKeyUser, L"Environment"); /* Set user volatile environment variables */ SetUserEnvironment(Environment, hKeyUser, L"Volatile Environment"); RegCloseKey(hKeyUser); return TRUE; } BOOL WINAPI DestroyEnvironmentBlock(IN LPVOID lpEnvironment) { DPRINT("DestroyEnvironmentBlock() called\n"); if (lpEnvironment == NULL) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } RtlDestroyEnvironment(lpEnvironment); return TRUE; } BOOL WINAPI ExpandEnvironmentStringsForUserW(IN HANDLE hToken, IN LPCWSTR lpSrc, OUT LPWSTR lpDest, IN DWORD dwSize) { BOOL Ret = FALSE; PVOID lpEnvironment; if (lpSrc == NULL || lpDest == NULL || dwSize == 0) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (CreateEnvironmentBlock(&lpEnvironment, hToken, FALSE)) { UNICODE_STRING SrcU, DestU; NTSTATUS Status; /* Initialize the strings */ RtlInitUnicodeString(&SrcU, lpSrc); DestU.Length = 0; DestU.MaximumLength = dwSize * sizeof(WCHAR); DestU.Buffer = lpDest; /* Expand the strings */ Status = RtlExpandEnvironmentStrings_U((PWSTR)lpEnvironment, &SrcU, &DestU, NULL); DestroyEnvironmentBlock(lpEnvironment); if (NT_SUCCESS(Status)) { Ret = TRUE; } else { SetLastError(RtlNtStatusToDosError(Status)); } } return Ret; } BOOL WINAPI ExpandEnvironmentStringsForUserA(IN HANDLE hToken, IN LPCSTR lpSrc, OUT LPSTR lpDest, IN DWORD dwSize) { BOOL Ret = FALSE; DWORD dwSrcLen; LPWSTR lpSrcW = NULL, lpDestW = NULL; if (lpSrc == NULL || lpDest == NULL || dwSize == 0) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } dwSrcLen = strlen(lpSrc); lpSrcW = (LPWSTR)GlobalAlloc(GMEM_FIXED, (dwSrcLen + 1) * sizeof(WCHAR)); if (lpSrcW == NULL || MultiByteToWideChar(CP_ACP, 0, lpSrc, -1, lpSrcW, dwSrcLen + 1) == 0) { goto Cleanup; } lpDestW = (LPWSTR)GlobalAlloc(GMEM_FIXED, dwSize * sizeof(WCHAR)); if (lpDestW == NULL) goto Cleanup; Ret = ExpandEnvironmentStringsForUserW(hToken, lpSrcW, lpDestW, dwSize); if (Ret) { if (WideCharToMultiByte(CP_ACP, 0, lpDestW, -1, lpDest, dwSize, NULL, NULL) == 0) { Ret = FALSE; } } Cleanup: if (lpSrcW != NULL) GlobalFree((HGLOBAL)lpSrcW); if (lpDestW != NULL) GlobalFree((HGLOBAL)lpDestW); return Ret; } /* EOF */