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 }
218