userenv: Improved CreateEnvironmentBlock implementation.

This commit is contained in:
Piotr Caban 2011-11-15 12:55:36 +01:00 committed by Alexandre Julliard
parent 2429ef905c
commit f0d8c3383e
2 changed files with 425 additions and 44 deletions

View File

@ -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_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()) #define expect_gle(EXPECTED) ok(GetLastError() == (EXPECTED), "Expected %d, got %d\n", (EXPECTED), GetLastError())
static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
struct profile_item struct profile_item
{ {
const char * name; const char * name;
const int todo[4];
}; };
/* Helper function for retrieving environment variables */ /* 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) static void test_create_env(void)
{ {
BOOL r; BOOL r, is_wow64 = FALSE;
HANDLE htok; HANDLE htok;
WCHAR * env[4]; WCHAR * env[4];
char * st; char * st, systemroot[100];
int i, j; int i, j;
static const struct profile_item common_vars[] = { static const struct profile_item common_vars[] = {
{ "ComSpec", { 1, 1, 0, 0 } }, { "ComSpec" },
{ "COMPUTERNAME", { 1, 1, 1, 1 } }, { "COMPUTERNAME" },
{ "NUMBER_OF_PROCESSORS", { 1, 1, 0, 0 } }, { "NUMBER_OF_PROCESSORS" },
{ "OS", { 1, 1, 0, 0 } }, { "OS" },
{ "PROCESSOR_ARCHITECTURE", { 1, 1, 0, 0 } }, { "PROCESSOR_ARCHITECTURE" },
{ "PROCESSOR_IDENTIFIER", { 1, 1, 0, 0 } }, { "PROCESSOR_IDENTIFIER" },
{ "PROCESSOR_LEVEL", { 1, 1, 0, 0 } }, { "PROCESSOR_LEVEL" },
{ "PROCESSOR_REVISION", { 1, 1, 0, 0 } }, { "PROCESSOR_REVISION" },
{ "SystemDrive", { 1, 1, 0, 0 } }, { "SystemDrive" },
{ "SystemRoot", { 1, 1, 0, 0 } }, { "SystemRoot" },
{ "windir", { 1, 1, 0, 0 } } { "windir" }
}; };
static const struct profile_item common_post_nt4_vars[] = { static const struct profile_item common_post_nt4_vars[] = {
{ "ALLUSERSPROFILE", { 1, 1, 0, 0 } }, { "ALLUSERSPROFILE" },
{ "TEMP", { 1, 1, 0, 0 } }, { "TEMP" },
{ "TMP", { 1, 1, 0, 0 } }, { "TMP" },
{ "CommonProgramFiles", { 1, 1, 0, 0 } }, { "CommonProgramFiles" },
{ "ProgramFiles", { 1, 1, 0, 0 } } { "ProgramFiles" },
{ "PATH" },
{ "USERPROFILE" }
}; };
static const struct profile_item htok_vars[] = { static const struct profile_item common_win64_vars[] = {
{ "PATH", { 1, 1, 0, 0 } }, { "ProgramW6432" },
{ "USERPROFILE", { 1, 1, 0, 0 } } { "CommonProgramW6432" }
}; };
r = SetEnvironmentVariableA("WINE_XYZZY", "ZZYZX"); r = SetEnvironmentVariableA("WINE_XYZZY", "ZZYZX");
expect(TRUE, r); 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) if (0)
{ {
/* Crashes on NT4 */ /* Crashes on NT4 */
@ -137,16 +146,23 @@ static void test_create_env(void)
r = CreateEnvironmentBlock((LPVOID) &env[3], htok, TRUE); r = CreateEnvironmentBlock((LPVOID) &env[3], htok, TRUE);
expect(TRUE, r); 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) */ /* Test for common environment variables (NT4 and higher) */
for (i = 0; i < sizeof(common_vars)/sizeof(common_vars[0]); i++) for (i = 0; i < sizeof(common_vars)/sizeof(common_vars[0]); i++)
{ {
for (j = 0; j < 4; j++) for (j = 0; j < 4; j++)
{ {
r = get_env(env[j], common_vars[i].name, &st); r = get_env(env[j], common_vars[i].name, &st);
if (common_vars[i].todo[j]) expect_env(TRUE, r, common_vars[i].name);
todo_wine expect_env(TRUE, r, common_vars[i].name);
else
expect_env(TRUE, r, common_vars[i].name);
if (r) HeapFree(GetProcessHeap(), 0, st); if (r) HeapFree(GetProcessHeap(), 0, st);
} }
} }
@ -163,26 +179,24 @@ static void test_create_env(void)
for (j = 0; j < 4; j++) for (j = 0; j < 4; j++)
{ {
r = get_env(env[j], common_post_nt4_vars[i].name, &st); r = get_env(env[j], common_post_nt4_vars[i].name, &st);
if (common_post_nt4_vars[i].todo[j]) expect_env(TRUE, r, common_post_nt4_vars[i].name);
todo_wine expect_env(TRUE, r, common_post_nt4_vars[i].name);
else
expect_env(TRUE, r, common_post_nt4_vars[i].name);
if (r) HeapFree(GetProcessHeap(), 0, st); if (r) HeapFree(GetProcessHeap(), 0, st);
} }
} }
} }
/* Test for environment variables with values that depends on htok */ if(pIsWow64Process)
for (i = 0; i < sizeof(htok_vars)/sizeof(htok_vars[0]); i++) 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); for (j=0; j<4; j++)
if (htok_vars[i].todo[j]) {
todo_wine expect_env(TRUE, r, htok_vars[i].name); r = get_env(env[j], common_win64_vars[i].name, &st);
else ok(r || broken(!r)/* Vista,2k3,XP */, "Expected 1, got 0 for %s\n", common_win64_vars[i].name);
expect_env(TRUE, r, htok_vars[i].name); if (r) HeapFree(GetProcessHeap(), 0, st);
if (r) HeapFree(GetProcessHeap(), 0, st); }
} }
} }
@ -388,6 +402,8 @@ static void test_get_user_profile_dir(void)
START_TEST(userenv) START_TEST(userenv)
{ {
pIsWow64Process = (void*)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
test_create_env(); test_create_env();
test_get_profiles_dir(); test_get_profiles_dir();
test_get_user_profile_dir(); test_get_user_profile_dir();

View File

@ -27,6 +27,7 @@
#include "winreg.h" #include "winreg.h"
#include "winternl.h" #include "winternl.h"
#include "winnls.h" #include "winnls.h"
#include "sddl.h"
#include "userenv.h" #include "userenv.h"
#include "wine/debug.h" #include "wine/debug.h"
@ -51,20 +52,384 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
return TRUE; 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, BOOL WINAPI CreateEnvironmentBlock( LPVOID* lpEnvironment,
HANDLE hToken, BOOL bInherit ) 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 ); TRACE("%p %p %d\n", lpEnvironment, hToken, bInherit );
if (!lpEnvironment) if (!lpEnvironment)
return FALSE; return FALSE;
r = RtlCreateEnvironment(bInherit, (WCHAR **)lpEnvironment); if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, env_keyW, 0, KEY_READ, &hkey) != ERROR_SUCCESS)
if (r == STATUS_SUCCESS) return FALSE;
return TRUE;
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) BOOL WINAPI DestroyEnvironmentBlock(LPVOID lpEnvironment)