diff --git a/dlls/userenv/tests/userenv.c b/dlls/userenv/tests/userenv.c index cd81232930c..b085d176332 100644 --- a/dlls/userenv/tests/userenv.c +++ b/dlls/userenv/tests/userenv.c @@ -35,10 +35,11 @@ #define expect_env(EXPECTED,GOT,VAR) ok((GOT)==(EXPECTED), "Expected %d, got %d for %s (%d)\n", (EXPECTED), (GOT), (VAR), j) #define expect_gle(EXPECTED) ok(GetLastError() == (EXPECTED), "Expected %d, got %d\n", (EXPECTED), GetLastError()) +static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL); + struct profile_item { const char * name; - const int todo[4]; }; /* Helper function for retrieving environment variables */ @@ -74,40 +75,48 @@ static BOOL get_env(const WCHAR * env, const char * var, char ** result) static void test_create_env(void) { - BOOL r; + BOOL r, is_wow64 = FALSE; HANDLE htok; WCHAR * env[4]; - char * st; + char * st, systemroot[100]; int i, j; static const struct profile_item common_vars[] = { - { "ComSpec", { 1, 1, 0, 0 } }, - { "COMPUTERNAME", { 1, 1, 1, 1 } }, - { "NUMBER_OF_PROCESSORS", { 1, 1, 0, 0 } }, - { "OS", { 1, 1, 0, 0 } }, - { "PROCESSOR_ARCHITECTURE", { 1, 1, 0, 0 } }, - { "PROCESSOR_IDENTIFIER", { 1, 1, 0, 0 } }, - { "PROCESSOR_LEVEL", { 1, 1, 0, 0 } }, - { "PROCESSOR_REVISION", { 1, 1, 0, 0 } }, - { "SystemDrive", { 1, 1, 0, 0 } }, - { "SystemRoot", { 1, 1, 0, 0 } }, - { "windir", { 1, 1, 0, 0 } } + { "ComSpec" }, + { "COMPUTERNAME" }, + { "NUMBER_OF_PROCESSORS" }, + { "OS" }, + { "PROCESSOR_ARCHITECTURE" }, + { "PROCESSOR_IDENTIFIER" }, + { "PROCESSOR_LEVEL" }, + { "PROCESSOR_REVISION" }, + { "SystemDrive" }, + { "SystemRoot" }, + { "windir" } }; static const struct profile_item common_post_nt4_vars[] = { - { "ALLUSERSPROFILE", { 1, 1, 0, 0 } }, - { "TEMP", { 1, 1, 0, 0 } }, - { "TMP", { 1, 1, 0, 0 } }, - { "CommonProgramFiles", { 1, 1, 0, 0 } }, - { "ProgramFiles", { 1, 1, 0, 0 } } + { "ALLUSERSPROFILE" }, + { "TEMP" }, + { "TMP" }, + { "CommonProgramFiles" }, + { "ProgramFiles" }, + { "PATH" }, + { "USERPROFILE" } }; - static const struct profile_item htok_vars[] = { - { "PATH", { 1, 1, 0, 0 } }, - { "USERPROFILE", { 1, 1, 0, 0 } } + static const struct profile_item common_win64_vars[] = { + { "ProgramW6432" }, + { "CommonProgramW6432" } }; r = SetEnvironmentVariableA("WINE_XYZZY", "ZZYZX"); expect(TRUE, r); + r = GetEnvironmentVariableA("SystemRoot", systemroot, sizeof(systemroot)); + ok(r != 0, "GetEnvironmentVariable failed (%d)\n", GetLastError()); + + r = SetEnvironmentVariableA("SystemRoot", "overwrite"); + expect(TRUE, r); + if (0) { /* Crashes on NT4 */ @@ -137,16 +146,23 @@ static void test_create_env(void) r = CreateEnvironmentBlock((LPVOID) &env[3], htok, TRUE); expect(TRUE, r); + r = SetEnvironmentVariableA("SystemRoot", systemroot); + expect(TRUE, r); + + for(i=0; i<4; i++) + { + r = get_env(env[i], "SystemRoot", &st); + ok(!strcmp(st, "SystemRoot=overwrite"), "%s\n", st); + expect(TRUE, r); + } + /* Test for common environment variables (NT4 and higher) */ for (i = 0; i < sizeof(common_vars)/sizeof(common_vars[0]); i++) { for (j = 0; j < 4; j++) { r = get_env(env[j], common_vars[i].name, &st); - if (common_vars[i].todo[j]) - todo_wine expect_env(TRUE, r, common_vars[i].name); - else - expect_env(TRUE, r, common_vars[i].name); + expect_env(TRUE, r, common_vars[i].name); if (r) HeapFree(GetProcessHeap(), 0, st); } } @@ -163,26 +179,24 @@ static void test_create_env(void) for (j = 0; j < 4; j++) { r = get_env(env[j], common_post_nt4_vars[i].name, &st); - if (common_post_nt4_vars[i].todo[j]) - todo_wine expect_env(TRUE, r, common_post_nt4_vars[i].name); - else - expect_env(TRUE, r, common_post_nt4_vars[i].name); + expect_env(TRUE, r, common_post_nt4_vars[i].name); if (r) HeapFree(GetProcessHeap(), 0, st); } } } - /* Test for environment variables with values that depends on htok */ - for (i = 0; i < sizeof(htok_vars)/sizeof(htok_vars[0]); i++) + if(pIsWow64Process) + pIsWow64Process(GetCurrentProcess(), &is_wow64); + if (sizeof(void*)==8 || is_wow64) { - for (j = 0; j < 4; j++) + for (i = 0; i < sizeof(common_win64_vars)/sizeof(common_win64_vars[0]); i++) { - r = get_env(env[j], htok_vars[i].name, &st); - if (htok_vars[i].todo[j]) - todo_wine expect_env(TRUE, r, htok_vars[i].name); - else - expect_env(TRUE, r, htok_vars[i].name); - if (r) HeapFree(GetProcessHeap(), 0, st); + for (j=0; j<4; j++) + { + r = get_env(env[j], common_win64_vars[i].name, &st); + ok(r || broken(!r)/* Vista,2k3,XP */, "Expected 1, got 0 for %s\n", common_win64_vars[i].name); + if (r) HeapFree(GetProcessHeap(), 0, st); + } } } @@ -388,6 +402,8 @@ static void test_get_user_profile_dir(void) START_TEST(userenv) { + pIsWow64Process = (void*)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process"); + test_create_env(); test_get_profiles_dir(); test_get_user_profile_dir(); diff --git a/dlls/userenv/userenv_main.c b/dlls/userenv/userenv_main.c index 3a021496888..89fedabadae 100644 --- a/dlls/userenv/userenv_main.c +++ b/dlls/userenv/userenv_main.c @@ -27,6 +27,7 @@ #include "winreg.h" #include "winternl.h" #include "winnls.h" +#include "sddl.h" #include "userenv.h" #include "wine/debug.h" @@ -51,20 +52,384 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) return TRUE; } +static BOOL get_reg_value(WCHAR *env, HKEY hkey, const WCHAR *name, WCHAR *val, DWORD size) +{ + DWORD type, res_size=0; + + if (RegQueryValueExW(hkey, name, 0, &type, NULL, &res_size) != ERROR_SUCCESS) + return FALSE; + + if (type == REG_SZ) + { + if (res_size > size) + return FALSE; + + return RegQueryValueExW(hkey, name, 0, NULL, (BYTE*)val, &size) == ERROR_SUCCESS; + } + else if (type == REG_EXPAND_SZ) + { + UNICODE_STRING us_buf, us_expanded; + WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, res_size); + if (!buf) + return FALSE; + + if (RegQueryValueExW(hkey, name, 0, NULL, (BYTE*)buf, &res_size) != ERROR_SUCCESS) + { + HeapFree(GetProcessHeap(), 0, buf); + return FALSE; + } + + RtlInitUnicodeString(&us_buf, buf); + us_expanded.Buffer = val; + us_expanded.MaximumLength = size; + if (RtlExpandEnvironmentStrings_U(env, &us_buf, &us_expanded, &size) != STATUS_SUCCESS) + { + HeapFree(GetProcessHeap(), 0, buf); + return FALSE; + } + + HeapFree(GetProcessHeap(), 0, buf); + return TRUE; + } + + return FALSE; +} + +static void set_registry_variables(WCHAR **env, HKEY hkey, DWORD type, BOOL set_path) +{ + static const WCHAR SystemRootW[] = {'S','y','s','t','e','m','R','o','o','t',0}; + static const WCHAR SystemDriveW[] = {'S','y','s','t','e','m','D','r','i','v','e',0}; + static const WCHAR PATHW[] = {'P','A','T','H'}; + + UNICODE_STRING us_name, us_value; + WCHAR name[1024], value[1024]; + DWORD ret, index, size; + + for (index = 0; ; index++) + { + size = sizeof(name)/sizeof(WCHAR); + ret = RegEnumValueW(hkey, index, name, &size, NULL, NULL, NULL, NULL); + if (ret != ERROR_SUCCESS) + break; + + if (!memicmpW(name, SystemRootW, sizeof(SystemRootW)/sizeof(WCHAR))) + continue; + if (!memicmpW(name, SystemDriveW, sizeof(SystemDriveW)/sizeof(WCHAR))) + continue; + + RtlInitUnicodeString(&us_name, name); + us_value.Buffer = value; + us_value.MaximumLength = sizeof(value); + if (!memicmpW(name, PATHW, sizeof(PATHW)/sizeof(WCHAR)) && + !RtlQueryEnvironmentVariable_U(*env, &us_name, &us_value)) + { + if (!set_path) + continue; + + size = strlenW(value)+1; + if (!get_reg_value(*env, hkey, name, value+size, + sizeof(value)-size*sizeof(WCHAR))) + continue; + + value[size] = ';'; + RtlInitUnicodeString(&us_value, value); + RtlSetEnvironmentVariable(env, &us_name, &us_value); + continue; + } + + if (!get_reg_value(*env, hkey, name, value, sizeof(value))) + continue; + + if(!value[0]) + continue; + + RtlInitUnicodeString(&us_value, value); + RtlSetEnvironmentVariable(env, &us_name, &us_value); + } +} + +static void set_wow64_environment(WCHAR **env) +{ + static const WCHAR versionW[] = {'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\', + 'W','i','n','d','o','w','s','\\', + 'C','u','r','r','e','n','t','V','e','r','s','i','o','n',0}; + static const WCHAR progdirW[] = {'P','r','o','g','r','a','m','F','i','l','e','s','D','i','r',0}; + static const WCHAR progdir86W[] = {'P','r','o','g','r','a','m','F','i','l','e','s','D','i','r',' ','(','x','8','6',')',0}; + static const WCHAR progfilesW[] = {'P','r','o','g','r','a','m','F','i','l','e','s',0}; + static const WCHAR progw6432W[] = {'P','r','o','g','r','a','m','W','6','4','3','2',0}; + static const WCHAR commondirW[] = {'C','o','m','m','o','n','F','i','l','e','s','D','i','r',0}; + static const WCHAR commondir86W[] = {'C','o','m','m','o','n','F','i','l','e','s','D','i','r',' ','(','x','8','6',')',0}; + static const WCHAR commonfilesW[] = {'C','o','m','m','o','n','P','r','o','g','r','a','m','F','i','l','e','s',0}; + static const WCHAR commonw6432W[] = {'C','o','m','m','o','n','P','r','o','g','r','a','m','W','6','4','3','2',0}; + + UNICODE_STRING nameW, valueW; + WCHAR buf[64]; + HKEY hkey; + BOOL is_win64 = (sizeof(void *) > sizeof(int)); + BOOL is_wow64; + + IsWow64Process( GetCurrentProcess(), &is_wow64 ); + + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, versionW, 0, + KEY_READ|KEY_WOW64_64KEY, &hkey)) + return; + + /* set the ProgramFiles variables */ + + if (get_reg_value(*env, hkey, progdirW, buf, sizeof(buf))) + { + if (is_win64 || is_wow64) + { + RtlInitUnicodeString(&nameW, progw6432W); + RtlInitUnicodeString(&valueW, buf); + RtlSetEnvironmentVariable(env, &nameW, &valueW); + } + if (is_win64 || !is_wow64) + { + RtlInitUnicodeString(&nameW, progfilesW); + RtlInitUnicodeString(&valueW, buf); + RtlSetEnvironmentVariable(env, &nameW, &valueW); + } + } + if (is_wow64 && get_reg_value(*env, hkey, progdir86W, buf, sizeof(buf))) + { + RtlInitUnicodeString(&nameW, progfilesW); + RtlInitUnicodeString(&valueW, buf); + RtlSetEnvironmentVariable(env, &nameW, &valueW); + } + + /* set the CommonProgramFiles variables */ + + if (get_reg_value(*env, hkey, commondirW, buf, sizeof(buf))) + { + if (is_win64 || is_wow64) + { + RtlInitUnicodeString(&nameW, commonw6432W); + RtlInitUnicodeString(&valueW, buf); + RtlSetEnvironmentVariable(env, &nameW, &valueW); + } + if (is_win64 || !is_wow64) + { + RtlInitUnicodeString(&nameW, commonfilesW); + RtlInitUnicodeString(&valueW, buf); + RtlSetEnvironmentVariable(env, &nameW, &valueW); + } + } + if (is_wow64 && get_reg_value(*env, hkey, commondir86W, buf, sizeof(buf))) + { + RtlInitUnicodeString(&nameW, commonfilesW); + RtlInitUnicodeString(&valueW, buf); + RtlSetEnvironmentVariable(env, &nameW, &valueW); + } + + RegCloseKey(hkey); +} + BOOL WINAPI CreateEnvironmentBlock( LPVOID* lpEnvironment, HANDLE hToken, BOOL bInherit ) { - NTSTATUS r; + static const WCHAR env_keyW[] = {'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'C','o','n','t','r','o','l','\\', + 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\', + 'E','n','v','i','r','o','n','m','e','n','t',0}; + static const WCHAR profile_keyW[] = {'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\', + 'W','i','n','d','o','w','s',' ','N','T','\\', + 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', + 'P','r','o','f','i','l','e','L','i','s','t',0}; + static const WCHAR envW[] = {'E','n','v','i','r','o','n','m','e','n','t',0}; + static const WCHAR volatile_envW[] = {'V','o','l','a','t','i','l','e',' ','E','n','v','i','r','o','n','m','e','n','t',0}; + static const WCHAR ProfilesDirectoryW[] = {'P','r','o','f','i','l','e','s','D','i','r','e','c','t','o','r','y',0}; + + static const WCHAR SystemRootW[] = {'S','y','s','t','e','m','R','o','o','t',0}; + static const WCHAR SystemDriveW[] = {'S','y','s','t','e','m','D','r','i','v','e',0}; + static const WCHAR AllUsersProfileW[] = {'A','l','l','U','s','e','r','s','P','r','o','f','i','l','e',0}; + static const WCHAR ALLUSERSPROFILEW[] = {'A','L','L','U','S','E','R','S','P','R','O','F','I','L','E',0}; + static const WCHAR USERNAMEW[] = {'U','S','E','R','N','A','M','E',0}; + static const WCHAR USERPROFILEW[] = {'U','S','E','R','P','R','O','F','I','L','E',0}; + static const WCHAR DefaultW[] = {'D','e','f','a','u','l','t',0}; + static const WCHAR COMPUTERNAMEW[] = {'C','O','M','P','U','T','E','R','N','A','M','E',0}; + + WCHAR *env, buf[UNICODE_STRING_MAX_CHARS], profiles_dir[MAX_PATH]; + UNICODE_STRING us_name, us_val; + DWORD len; + HKEY hkey, hsubkey; TRACE("%p %p %d\n", lpEnvironment, hToken, bInherit ); if (!lpEnvironment) return FALSE; - r = RtlCreateEnvironment(bInherit, (WCHAR **)lpEnvironment); - if (r == STATUS_SUCCESS) - return TRUE; - return FALSE; + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, env_keyW, 0, KEY_READ, &hkey) != ERROR_SUCCESS) + return FALSE; + + if (RtlCreateEnvironment(bInherit, &env) != STATUS_SUCCESS) + { + RegCloseKey(hkey); + return FALSE; + } + + if (!GetEnvironmentVariableW(SystemRootW, buf, UNICODE_STRING_MAX_CHARS)) + { + if (!get_reg_value(env, hkey, SystemRootW, buf, UNICODE_STRING_MAX_CHARS)) + { + buf[0] = 0; + WARN("SystemRoot variable not set\n"); + } + } + RtlInitUnicodeString(&us_name, SystemRootW); + RtlInitUnicodeString(&us_val, buf); + RtlSetEnvironmentVariable(&env, &us_name, &us_val); + + if (!GetEnvironmentVariableW(SystemDriveW, buf, UNICODE_STRING_MAX_CHARS)) + { + if (!get_reg_value(env, hkey, SystemRootW, buf, UNICODE_STRING_MAX_CHARS)) + { + buf[0] = 0; + WARN("SystemDrive variable not set\n"); + } + } + RtlInitUnicodeString(&us_name, SystemDriveW); + RtlInitUnicodeString(&us_val, buf); + RtlSetEnvironmentVariable(&env, &us_name, &us_val); + + set_registry_variables(&env, hkey, REG_SZ, !bInherit); + set_registry_variables(&env, hkey, REG_EXPAND_SZ, !bInherit); + + if (RegOpenKeyExW(hkey, envW, 0, KEY_READ, &hsubkey) == ERROR_SUCCESS) + { + set_registry_variables(&env, hsubkey, REG_SZ, !bInherit); + set_registry_variables(&env, hsubkey, REG_EXPAND_SZ, !bInherit); + RegCloseKey(hsubkey); + } + + if (RegOpenKeyExW(hkey, volatile_envW, 0, KEY_READ, &hsubkey) == ERROR_SUCCESS) + { + set_registry_variables(&env, hsubkey, REG_SZ, !bInherit); + set_registry_variables(&env, hsubkey, REG_EXPAND_SZ, !bInherit); + RegCloseKey(hsubkey); + } + RegCloseKey(hkey); + + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, profile_keyW, 0, KEY_READ, &hkey) == ERROR_SUCCESS) + { + if (get_reg_value(env, hkey, ProfilesDirectoryW, profiles_dir, MAX_PATH-sizeof(WCHAR))) + { + len = strlenW(profiles_dir); + if (profiles_dir[len-1] != '\\') + { + profiles_dir[len++] = '\\'; + profiles_dir[len] = '\0'; + } + + memcpy(buf, profiles_dir, len*sizeof(WCHAR)); + if (get_reg_value(env, hkey, AllUsersProfileW, buf+len, UNICODE_STRING_MAX_CHARS-len)) + { + RtlInitUnicodeString(&us_name, ALLUSERSPROFILEW); + RtlInitUnicodeString(&us_val, buf); + RtlSetEnvironmentVariable(&env, &us_name, &us_val); + } + } + else + { + profiles_dir[0] = 0; + } + + RegCloseKey(hkey); + } + + len = sizeof(buf)/sizeof(WCHAR); + if (GetComputerNameW(buf, &len)) + { + RtlInitUnicodeString(&us_name, COMPUTERNAMEW); + RtlInitUnicodeString(&us_val, buf); + RtlSetEnvironmentVariable(&env, &us_name, &us_val); + } + + set_wow64_environment(&env); + + if (!hToken) + { + if (profiles_dir[0]) + { + len = strlenW(profiles_dir); + if (len*sizeof(WCHAR)+sizeof(DefaultW) < sizeof(buf)) + { + memcpy(buf, profiles_dir, len*sizeof(WCHAR)); + memcpy(buf+len, DefaultW, sizeof(DefaultW)); + RtlInitUnicodeString(&us_name, USERPROFILEW); + RtlInitUnicodeString(&us_val, buf); + RtlSetEnvironmentVariable(&env, &us_name, &us_val); + } + } + + buf[0] = '.'; + memcpy(buf+1, DefaultW, sizeof(DefaultW)); + } + else + { + TOKEN_USER *token_user = NULL; + SID_NAME_USE use; + WCHAR *sidW; + DWORD size, tmp=0; + + if (GetTokenInformation(hToken, TokenUser, NULL, 0, &len) || + GetLastError()!=ERROR_INSUFFICIENT_BUFFER || + !(token_user = HeapAlloc(GetProcessHeap(), 0, len)) || + !GetTokenInformation(hToken, TokenUser, token_user, len, &len) || + !ConvertSidToStringSidW(token_user->User.Sid, &sidW)) + { + HeapFree(GetProcessHeap(), 0, token_user); + RtlDestroyEnvironment(env); + return FALSE; + } + + len = strlenW(profiles_dir); + memcpy(buf, profiles_dir, len*sizeof(WCHAR)); + + size = UNICODE_STRING_MAX_CHARS-len; + if (LookupAccountSidW(NULL, token_user->User.Sid, + buf+len, &size, NULL, &tmp, &use)) + { + RtlInitUnicodeString(&us_name, USERNAMEW); + RtlInitUnicodeString(&us_val, buf+len); + RtlSetEnvironmentVariable(&env, &us_name, &us_val); + + if (len) + { + RtlInitUnicodeString(&us_name, USERPROFILEW); + RtlInitUnicodeString(&us_val, buf); + RtlSetEnvironmentVariable(&env, &us_name, &us_val); + } + } + + HeapFree(GetProcessHeap(), 0, token_user); + strcpyW(buf, sidW); + LocalFree(sidW); + } + + if (RegOpenKeyExW(HKEY_USERS, buf, 0, KEY_READ, &hkey) == ERROR_SUCCESS) + { + if (RegOpenKeyExW(hkey, envW, 0, KEY_READ, &hsubkey) == ERROR_SUCCESS) + { + set_registry_variables(&env, hsubkey, REG_SZ, !bInherit); + set_registry_variables(&env, hsubkey, REG_EXPAND_SZ, !bInherit); + RegCloseKey(hsubkey); + } + + if (RegOpenKeyExW(hkey, volatile_envW, 0, KEY_READ, &hsubkey) == ERROR_SUCCESS) + { + set_registry_variables(&env, hsubkey, REG_SZ, !bInherit); + set_registry_variables(&env, hsubkey, REG_EXPAND_SZ, !bInherit); + RegCloseKey(hsubkey); + } + RegCloseKey(hkey); + } + + *lpEnvironment = env; + return TRUE; } BOOL WINAPI DestroyEnvironmentBlock(LPVOID lpEnvironment)