[APITESTS]: Add a test for userenv.dll API Load/UnloadUserProfile.
[reactos.git] / rostests / apitests / userenv / LoadUserProfile.c
1 /*
2 * PROJECT: ReactOS api tests
3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
4 * PURPOSE: Tests for Load/UnloadUserProfile
5 * PROGRAMMERS: Hermes Belusca-Maito
6 */
7
8 #include <apitest.h>
9 // #include <windef.h>
10 // #include <winbase.h>
11 #include <sddl.h>
12 #include <userenv.h>
13 #include <strsafe.h>
14
15 #undef SE_RESTORE_NAME
16 #undef SE_BACKUP_NAME
17 #define SE_RESTORE_NAME L"SeRestorePrivilege"
18 #define SE_BACKUP_NAME L"SeBackupPrivilege"
19
20 /*
21 * Taken from dll/win32/shell32/dialogs/dialogs.cpp ;
22 * See also base/applications/shutdown/shutdown.c .
23 */
24 static BOOL
25 EnablePrivilege(LPCWSTR lpszPrivilegeName, BOOL bEnablePrivilege)
26 {
27 BOOL Success;
28 HANDLE hToken;
29 TOKEN_PRIVILEGES tp;
30
31 Success = OpenProcessToken(GetCurrentProcess(),
32 TOKEN_ADJUST_PRIVILEGES,
33 &hToken);
34 if (!Success) return Success;
35
36 Success = LookupPrivilegeValueW(NULL,
37 lpszPrivilegeName,
38 &tp.Privileges[0].Luid);
39 if (!Success) goto Quit;
40
41 tp.PrivilegeCount = 1;
42 tp.Privileges[0].Attributes = (bEnablePrivilege ? SE_PRIVILEGE_ENABLED : 0);
43
44 Success = AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
45
46 Quit:
47 CloseHandle(hToken);
48 return Success;
49 }
50
51 /*
52 * Taken from dll/win32/userenv/sid.c .
53 * We cannot directly use the USERENV.DLL export, because: 1) it is exported
54 * by ordinal (#142), and: 2) it is simply not exported at all in Vista+
55 * (and ordinal #142 is assigned there to LoadUserProfileA).
56 */
57 PSID
58 WINAPI
59 GetUserSid(IN HANDLE hToken)
60 {
61 BOOL Success;
62 PSID pSid;
63 ULONG Length;
64 PTOKEN_USER UserBuffer;
65 PTOKEN_USER TempBuffer;
66
67 Length = 256;
68 UserBuffer = LocalAlloc(LPTR, Length);
69 if (UserBuffer == NULL)
70 return NULL;
71
72 Success = GetTokenInformation(hToken,
73 TokenUser,
74 (PVOID)UserBuffer,
75 Length,
76 &Length);
77 if (!Success && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
78 {
79 TempBuffer = LocalReAlloc(UserBuffer, Length, LMEM_MOVEABLE);
80 if (TempBuffer == NULL)
81 {
82 LocalFree(UserBuffer);
83 return NULL;
84 }
85
86 UserBuffer = TempBuffer;
87 Success = GetTokenInformation(hToken,
88 TokenUser,
89 (PVOID)UserBuffer,
90 Length,
91 &Length);
92 }
93
94 if (!Success)
95 {
96 LocalFree(UserBuffer);
97 return NULL;
98 }
99
100 Length = GetLengthSid(UserBuffer->User.Sid);
101
102 pSid = LocalAlloc(LPTR, Length);
103 if (pSid == NULL)
104 {
105 LocalFree(UserBuffer);
106 return NULL;
107 }
108
109 Success = CopySid(Length, pSid, UserBuffer->User.Sid);
110
111 LocalFree(UserBuffer);
112
113 if (!Success)
114 {
115 LocalFree(pSid);
116 return NULL;
117 }
118
119 return pSid;
120 }
121
122 START_TEST(LoadUserProfile)
123 {
124 BOOL Success;
125 HANDLE hToken = NULL;
126 PSID pUserSid = NULL;
127 USHORT i;
128 PROFILEINFOW ProfileInfo[2] = { {0}, {0} };
129
130 Success = OpenThreadToken(GetCurrentThread(),
131 TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
132 TRUE,
133 &hToken);
134 if (!Success && (GetLastError() == ERROR_NO_TOKEN))
135 {
136 trace("OpenThreadToken failed with error %lu, falling back to OpenProcessToken\n", GetLastError());
137 Success = OpenProcessToken(GetCurrentProcess(),
138 TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
139 &hToken);
140 }
141 if (!Success || (hToken == NULL))
142 {
143 skip("Open[Thread|Process]Token failed with error %lu\n", GetLastError());
144 return;
145 }
146
147 pUserSid = GetUserSid(hToken);
148 ok(pUserSid != NULL, "GetUserSid failed with error %lu\n", GetLastError());
149 if (pUserSid)
150 {
151 LPWSTR pSidStr = NULL;
152 Success = ConvertSidToStringSidW(pUserSid, &pSidStr);
153 ok(Success, "ConvertSidToStringSidW failed with error %lu\n", GetLastError());
154 if (Success)
155 {
156 trace("User SID is '%ls'\n", pSidStr);
157 LocalFree(pSidStr);
158 }
159 LocalFree(pUserSid);
160 pUserSid = NULL;
161 }
162 else
163 {
164 trace("No SID available!\n");
165 }
166
167 /* Check whether ProfileInfo.lpUserName is really needed */
168 ZeroMemory(&ProfileInfo[0], sizeof(ProfileInfo[0]));
169 ProfileInfo[0].dwSize = sizeof(ProfileInfo[0]);
170 ProfileInfo[0].dwFlags = PI_NOUI;
171 ProfileInfo[0].lpUserName = NULL;
172 Success = LoadUserProfileW(hToken, &ProfileInfo[0]);
173 ok(!Success, "LoadUserProfile succeeded with error %lu, expected failing\n", GetLastError());
174 ok(ProfileInfo[0].hProfile == NULL, "ProfileInfo[0].hProfile != NULL, expected NULL\n");
175 /* Unload the user profile if we erroneously succeeded, just in case... */
176 if (Success)
177 {
178 trace("LoadUserProfileW(ProfileInfo[0]) unexpectedly succeeded, unload the user profile just in case...\n");
179 UnloadUserProfile(hToken, ProfileInfo[0].hProfile);
180 }
181
182 /* TODO: Check which privileges we do need */
183
184 /* Enable both the SE_RESTORE_NAME and SE_BACKUP_NAME privileges */
185 Success = EnablePrivilege(SE_RESTORE_NAME, TRUE);
186 ok(Success, "EnablePrivilege(SE_RESTORE_NAME) failed with error %lu\n", GetLastError());
187 Success = EnablePrivilege(SE_BACKUP_NAME, TRUE);
188 ok(Success, "EnablePrivilege(SE_BACKUP_NAME) failed with error %lu\n", GetLastError());
189
190 /* Check whether we can load multiple times the same user profile */
191 for (i = 0; i < ARRAYSIZE(ProfileInfo); ++i)
192 {
193 ZeroMemory(&ProfileInfo[i], sizeof(ProfileInfo[i]));
194 ProfileInfo[i].dwSize = sizeof(ProfileInfo[i]);
195 ProfileInfo[i].dwFlags = PI_NOUI;
196 ProfileInfo[i].lpUserName = L"toto"; // Dummy name; normally this should be the user name...
197 Success = LoadUserProfileW(hToken, &ProfileInfo[i]);
198 ok(Success, "LoadUserProfileW(ProfileInfo[%d]) failed with error %lu\n", i, GetLastError());
199 ok(ProfileInfo[i].hProfile != NULL, "ProfileInfo[%d].hProfile == NULL\n", i);
200 trace("ProfileInfo[%d].hProfile = 0x%p\n", i, ProfileInfo[i].hProfile);
201 }
202
203 i = ARRAYSIZE(ProfileInfo);
204 while (i-- > 0)
205 {
206 trace("UnloadUserProfile(ProfileInfo[%d].hProfile)\n", i);
207 Success = UnloadUserProfile(hToken, ProfileInfo[i].hProfile);
208 ok(Success, "UnloadUserProfile(ProfileInfo[%d].hProfile) failed with error %lu\n", i, GetLastError());
209 }
210
211 /* Disable the privileges */
212 EnablePrivilege(SE_BACKUP_NAME, FALSE);
213 EnablePrivilege(SE_RESTORE_NAME, FALSE);
214
215 /* Final cleanup */
216 CloseHandle(hToken);
217 }