Author: hbelusca Date: Thu Dec 15 18:44:47 2016 New Revision: 73458
URL: http://svn.reactos.org/svn/reactos?rev=73458&view=rev Log: [APITESTS]: Add a test for userenv.dll API Load/UnloadUserProfile. CORE-12541
Added: trunk/rostests/apitests/userenv/ trunk/rostests/apitests/userenv/CMakeLists.txt (with props) trunk/rostests/apitests/userenv/LoadUserProfile.c (with props) trunk/rostests/apitests/userenv/testlist.c (with props) Modified: trunk/rostests/apitests/CMakeLists.txt
Modified: trunk/rostests/apitests/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/CMakeLists.txt?re... ============================================================================== --- trunk/rostests/apitests/CMakeLists.txt [iso-8859-1] (original) +++ trunk/rostests/apitests/CMakeLists.txt [iso-8859-1] Thu Dec 15 18:44:47 2016 @@ -30,6 +30,7 @@ add_subdirectory(psapi) add_subdirectory(user32) add_subdirectory(user32_dynamic) +add_subdirectory(userenv) if(NOT ARCH STREQUAL "amd64" AND NOT CMAKE_BUILD_TYPE STREQUAL "Release") add_subdirectory(win32kdll) add_subdirectory(win32nt)
Added: trunk/rostests/apitests/userenv/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/userenv/CMakeList... ============================================================================== --- trunk/rostests/apitests/userenv/CMakeLists.txt (added) +++ trunk/rostests/apitests/userenv/CMakeLists.txt [iso-8859-1] Thu Dec 15 18:44:47 2016 @@ -0,0 +1,10 @@ + +list(APPEND SOURCE + LoadUserProfile.c + testlist.c) + +add_executable(userenv_apitest ${SOURCE}) +target_link_libraries(userenv_apitest wine ${PSEH_LIB}) +set_module_type(userenv_apitest win32cui) +add_importlibs(userenv_apitest userenv advapi32 msvcrt kernel32) +add_cd_file(TARGET userenv_apitest DESTINATION reactos/bin FOR all)
Propchange: trunk/rostests/apitests/userenv/CMakeLists.txt ------------------------------------------------------------------------------ svn:eol-style = native
Added: trunk/rostests/apitests/userenv/LoadUserProfile.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/userenv/LoadUserP... ============================================================================== --- trunk/rostests/apitests/userenv/LoadUserProfile.c (added) +++ trunk/rostests/apitests/userenv/LoadUserProfile.c [iso-8859-1] Thu Dec 15 18:44:47 2016 @@ -0,0 +1,217 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory + * PURPOSE: Tests for Load/UnloadUserProfile + * PROGRAMMERS: Hermes Belusca-Maito + */ + +#include <apitest.h> +// #include <windef.h> +// #include <winbase.h> +#include <sddl.h> +#include <userenv.h> +#include <strsafe.h> + +#undef SE_RESTORE_NAME +#undef SE_BACKUP_NAME +#define SE_RESTORE_NAME L"SeRestorePrivilege" +#define SE_BACKUP_NAME L"SeBackupPrivilege" + +/* + * Taken from dll/win32/shell32/dialogs/dialogs.cpp ; + * See also base/applications/shutdown/shutdown.c . + */ +static BOOL +EnablePrivilege(LPCWSTR lpszPrivilegeName, BOOL bEnablePrivilege) +{ + BOOL Success; + HANDLE hToken; + TOKEN_PRIVILEGES tp; + + Success = OpenProcessToken(GetCurrentProcess(), + TOKEN_ADJUST_PRIVILEGES, + &hToken); + if (!Success) return Success; + + Success = LookupPrivilegeValueW(NULL, + lpszPrivilegeName, + &tp.Privileges[0].Luid); + if (!Success) goto Quit; + + tp.PrivilegeCount = 1; + tp.Privileges[0].Attributes = (bEnablePrivilege ? SE_PRIVILEGE_ENABLED : 0); + + Success = AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL); + +Quit: + CloseHandle(hToken); + return Success; +} + +/* + * Taken from dll/win32/userenv/sid.c . + * We cannot directly use the USERENV.DLL export, because: 1) it is exported + * by ordinal (#142), and: 2) it is simply not exported at all in Vista+ + * (and ordinal #142 is assigned there to LoadUserProfileA). + */ +PSID +WINAPI +GetUserSid(IN HANDLE hToken) +{ + BOOL Success; + PSID pSid; + ULONG Length; + PTOKEN_USER UserBuffer; + PTOKEN_USER TempBuffer; + + Length = 256; + UserBuffer = LocalAlloc(LPTR, Length); + if (UserBuffer == NULL) + return NULL; + + Success = GetTokenInformation(hToken, + TokenUser, + (PVOID)UserBuffer, + Length, + &Length); + if (!Success && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) + { + TempBuffer = LocalReAlloc(UserBuffer, Length, LMEM_MOVEABLE); + if (TempBuffer == NULL) + { + LocalFree(UserBuffer); + return NULL; + } + + UserBuffer = TempBuffer; + Success = GetTokenInformation(hToken, + TokenUser, + (PVOID)UserBuffer, + Length, + &Length); + } + + if (!Success) + { + LocalFree(UserBuffer); + return NULL; + } + + Length = GetLengthSid(UserBuffer->User.Sid); + + pSid = LocalAlloc(LPTR, Length); + if (pSid == NULL) + { + LocalFree(UserBuffer); + return NULL; + } + + Success = CopySid(Length, pSid, UserBuffer->User.Sid); + + LocalFree(UserBuffer); + + if (!Success) + { + LocalFree(pSid); + return NULL; + } + + return pSid; +} + +START_TEST(LoadUserProfile) +{ + BOOL Success; + HANDLE hToken = NULL; + PSID pUserSid = NULL; + USHORT i; + PROFILEINFOW ProfileInfo[2] = { {0}, {0} }; + + Success = OpenThreadToken(GetCurrentThread(), + TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, + TRUE, + &hToken); + if (!Success && (GetLastError() == ERROR_NO_TOKEN)) + { + trace("OpenThreadToken failed with error %lu, falling back to OpenProcessToken\n", GetLastError()); + Success = OpenProcessToken(GetCurrentProcess(), + TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, + &hToken); + } + if (!Success || (hToken == NULL)) + { + skip("Open[Thread|Process]Token failed with error %lu\n", GetLastError()); + return; + } + + pUserSid = GetUserSid(hToken); + ok(pUserSid != NULL, "GetUserSid failed with error %lu\n", GetLastError()); + if (pUserSid) + { + LPWSTR pSidStr = NULL; + Success = ConvertSidToStringSidW(pUserSid, &pSidStr); + ok(Success, "ConvertSidToStringSidW failed with error %lu\n", GetLastError()); + if (Success) + { + trace("User SID is '%ls'\n", pSidStr); + LocalFree(pSidStr); + } + LocalFree(pUserSid); + pUserSid = NULL; + } + else + { + trace("No SID available!\n"); + } + + /* Check whether ProfileInfo.lpUserName is really needed */ + ZeroMemory(&ProfileInfo[0], sizeof(ProfileInfo[0])); + ProfileInfo[0].dwSize = sizeof(ProfileInfo[0]); + ProfileInfo[0].dwFlags = PI_NOUI; + ProfileInfo[0].lpUserName = NULL; + Success = LoadUserProfileW(hToken, &ProfileInfo[0]); + ok(!Success, "LoadUserProfile succeeded with error %lu, expected failing\n", GetLastError()); + ok(ProfileInfo[0].hProfile == NULL, "ProfileInfo[0].hProfile != NULL, expected NULL\n"); + /* Unload the user profile if we erroneously succeeded, just in case... */ + if (Success) + { + trace("LoadUserProfileW(ProfileInfo[0]) unexpectedly succeeded, unload the user profile just in case...\n"); + UnloadUserProfile(hToken, ProfileInfo[0].hProfile); + } + + /* TODO: Check which privileges we do need */ + + /* Enable both the SE_RESTORE_NAME and SE_BACKUP_NAME privileges */ + Success = EnablePrivilege(SE_RESTORE_NAME, TRUE); + ok(Success, "EnablePrivilege(SE_RESTORE_NAME) failed with error %lu\n", GetLastError()); + Success = EnablePrivilege(SE_BACKUP_NAME, TRUE); + ok(Success, "EnablePrivilege(SE_BACKUP_NAME) failed with error %lu\n", GetLastError()); + + /* Check whether we can load multiple times the same user profile */ + for (i = 0; i < ARRAYSIZE(ProfileInfo); ++i) + { + ZeroMemory(&ProfileInfo[i], sizeof(ProfileInfo[i])); + ProfileInfo[i].dwSize = sizeof(ProfileInfo[i]); + ProfileInfo[i].dwFlags = PI_NOUI; + ProfileInfo[i].lpUserName = L"toto"; // Dummy name; normally this should be the user name... + Success = LoadUserProfileW(hToken, &ProfileInfo[i]); + ok(Success, "LoadUserProfileW(ProfileInfo[%d]) failed with error %lu\n", i, GetLastError()); + ok(ProfileInfo[i].hProfile != NULL, "ProfileInfo[%d].hProfile == NULL\n", i); + trace("ProfileInfo[%d].hProfile = 0x%p\n", i, ProfileInfo[i].hProfile); + } + + i = ARRAYSIZE(ProfileInfo); + while (i-- > 0) + { + trace("UnloadUserProfile(ProfileInfo[%d].hProfile)\n", i); + Success = UnloadUserProfile(hToken, ProfileInfo[i].hProfile); + ok(Success, "UnloadUserProfile(ProfileInfo[%d].hProfile) failed with error %lu\n", i, GetLastError()); + } + + /* Disable the privileges */ + EnablePrivilege(SE_BACKUP_NAME, FALSE); + EnablePrivilege(SE_RESTORE_NAME, FALSE); + + /* Final cleanup */ + CloseHandle(hToken); +}
Propchange: trunk/rostests/apitests/userenv/LoadUserProfile.c ------------------------------------------------------------------------------ svn:eol-style = native
Added: trunk/rostests/apitests/userenv/testlist.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/userenv/testlist.... ============================================================================== --- trunk/rostests/apitests/userenv/testlist.c (added) +++ trunk/rostests/apitests/userenv/testlist.c [iso-8859-1] Thu Dec 15 18:44:47 2016 @@ -0,0 +1,12 @@ +#define __ROS_LONG64__ + +#define STANDALONE +#include <apitest.h> + +extern void func_LoadUserProfile(void); + +const struct test winetest_testlist[] = +{ + { "LoadUserProfile", func_LoadUserProfile }, + { 0, 0 } +};
Propchange: trunk/rostests/apitests/userenv/testlist.c ------------------------------------------------------------------------------ svn:eol-style = native