Copy w32api from trunk
[reactos.git] / reactos / lib / advapi32 / token / token.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/advapi32/token/token.c
5 * PURPOSE: Token functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * UPDATE HISTORY:
8 * Created 01/11/98
9 */
10
11 #include "advapi32.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
16 /*
17 * @implemented
18 */
19 BOOL STDCALL
20 AdjustTokenGroups (HANDLE TokenHandle,
21 BOOL ResetToDefault,
22 PTOKEN_GROUPS NewState,
23 DWORD BufferLength,
24 PTOKEN_GROUPS PreviousState,
25 PDWORD ReturnLength)
26 {
27 NTSTATUS Status;
28
29 Status = NtAdjustGroupsToken (TokenHandle,
30 ResetToDefault,
31 NewState,
32 BufferLength,
33 PreviousState,
34 (PULONG)ReturnLength);
35 if (!NT_SUCCESS (Status))
36 {
37 SetLastError (RtlNtStatusToDosError (Status));
38 return FALSE;
39 }
40
41 return TRUE;
42 }
43
44
45 /*
46 * @implemented
47 */
48 BOOL STDCALL
49 AdjustTokenPrivileges (HANDLE TokenHandle,
50 BOOL DisableAllPrivileges,
51 PTOKEN_PRIVILEGES NewState,
52 DWORD BufferLength,
53 PTOKEN_PRIVILEGES PreviousState,
54 PDWORD ReturnLength)
55 {
56 NTSTATUS Status;
57
58 Status = NtAdjustPrivilegesToken (TokenHandle,
59 DisableAllPrivileges,
60 NewState,
61 BufferLength,
62 PreviousState,
63 (PULONG)ReturnLength);
64 if (STATUS_NOT_ALL_ASSIGNED == Status)
65 {
66 SetLastError(ERROR_NOT_ALL_ASSIGNED);
67 return TRUE;
68 }
69 if (! NT_SUCCESS(Status))
70 {
71 SetLastError(RtlNtStatusToDosError(Status));
72 return FALSE;
73 }
74
75 SetLastError(ERROR_SUCCESS); /* AdjustTokenPrivileges is documented to do this */
76 return TRUE;
77 }
78
79
80 /*
81 * @implemented
82 */
83 BOOL STDCALL
84 GetTokenInformation (HANDLE TokenHandle,
85 TOKEN_INFORMATION_CLASS TokenInformationClass,
86 LPVOID TokenInformation,
87 DWORD TokenInformationLength,
88 PDWORD ReturnLength)
89 {
90 NTSTATUS Status;
91
92 Status = NtQueryInformationToken (TokenHandle,
93 TokenInformationClass,
94 TokenInformation,
95 TokenInformationLength,
96 (PULONG)ReturnLength);
97 if (!NT_SUCCESS (Status))
98 {
99 SetLastError (RtlNtStatusToDosError (Status));
100 return FALSE;
101 }
102
103 return TRUE;
104 }
105
106
107 /*
108 * @implemented
109 */
110 BOOL STDCALL
111 SetTokenInformation (HANDLE TokenHandle,
112 TOKEN_INFORMATION_CLASS TokenInformationClass,
113 LPVOID TokenInformation,
114 DWORD TokenInformationLength)
115 {
116 NTSTATUS Status;
117
118 Status = NtSetInformationToken (TokenHandle,
119 TokenInformationClass,
120 TokenInformation,
121 TokenInformationLength);
122 if (!NT_SUCCESS (Status))
123 {
124 SetLastError (RtlNtStatusToDosError (Status));
125 return FALSE;
126 }
127
128 return TRUE;
129 }
130
131
132 /*
133 * @implemented
134 */
135 BOOL STDCALL
136 AccessCheck (PSECURITY_DESCRIPTOR pSecurityDescriptor,
137 HANDLE ClientToken,
138 DWORD DesiredAccess,
139 PGENERIC_MAPPING GenericMapping,
140 PPRIVILEGE_SET PrivilegeSet,
141 LPDWORD PrivilegeSetLength,
142 LPDWORD GrantedAccess,
143 LPBOOL AccessStatus)
144 {
145 NTSTATUS Status;
146 NTSTATUS AccessStat;
147
148 Status = NtAccessCheck (pSecurityDescriptor,
149 ClientToken,
150 DesiredAccess,
151 GenericMapping,
152 PrivilegeSet,
153 (PULONG)PrivilegeSetLength,
154 (PACCESS_MASK)GrantedAccess,
155 &AccessStat);
156 if (!NT_SUCCESS (Status))
157 {
158 SetLastError (RtlNtStatusToDosError (Status));
159 return FALSE;
160 }
161
162 if (!NT_SUCCESS (AccessStat))
163 {
164 SetLastError (RtlNtStatusToDosError (Status));
165 *AccessStatus = FALSE;
166 return TRUE;
167 }
168
169 *AccessStatus = TRUE;
170
171 return TRUE;
172 }
173
174
175 /*
176 * @implemented
177 */
178 BOOL STDCALL
179 OpenProcessToken (HANDLE ProcessHandle,
180 DWORD DesiredAccess,
181 PHANDLE TokenHandle)
182 {
183 NTSTATUS Status;
184
185 Status = NtOpenProcessToken (ProcessHandle,
186 DesiredAccess,
187 TokenHandle);
188 if (!NT_SUCCESS (Status))
189 {
190 SetLastError (RtlNtStatusToDosError (Status));
191 return FALSE;
192 }
193
194 return TRUE;
195 }
196
197
198 /*
199 * @implemented
200 */
201 BOOL STDCALL
202 OpenThreadToken (HANDLE ThreadHandle,
203 DWORD DesiredAccess,
204 BOOL OpenAsSelf,
205 PHANDLE TokenHandle)
206 {
207 NTSTATUS Status;
208
209 Status = NtOpenThreadToken (ThreadHandle,
210 DesiredAccess,
211 OpenAsSelf,
212 TokenHandle);
213 if (!NT_SUCCESS(Status))
214 {
215 SetLastError (RtlNtStatusToDosError (Status));
216 return FALSE;
217 }
218
219 return TRUE;
220 }
221
222
223 /*
224 * @implemented
225 */
226 BOOL STDCALL
227 SetThreadToken (PHANDLE ThreadHandle,
228 HANDLE TokenHandle)
229 {
230 NTSTATUS Status;
231 HANDLE hThread;
232
233 hThread = NtCurrentThread();
234 if (ThreadHandle != NULL)
235 hThread = ThreadHandle;
236
237 Status = NtSetInformationThread (hThread,
238 ThreadImpersonationToken,
239 &TokenHandle,
240 sizeof(HANDLE));
241 if (!NT_SUCCESS(Status))
242 {
243 SetLastError (RtlNtStatusToDosError (Status));
244 return FALSE;
245 }
246
247 return TRUE;
248 }
249
250
251 /*
252 * @implemented
253 */
254 BOOL STDCALL
255 DuplicateTokenEx (HANDLE ExistingTokenHandle,
256 DWORD dwDesiredAccess,
257 LPSECURITY_ATTRIBUTES lpTokenAttributes,
258 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
259 TOKEN_TYPE TokenType,
260 PHANDLE DuplicateTokenHandle)
261 {
262 OBJECT_ATTRIBUTES ObjectAttributes;
263 HANDLE NewToken;
264 NTSTATUS Status;
265 SECURITY_QUALITY_OF_SERVICE Sqos;
266
267 Sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
268 Sqos.ImpersonationLevel = ImpersonationLevel;
269 Sqos.ContextTrackingMode = 0;
270 Sqos.EffectiveOnly = FALSE;
271
272 InitializeObjectAttributes(
273 &ObjectAttributes,
274 NULL,
275 lpTokenAttributes->bInheritHandle ? OBJ_INHERIT : 0,
276 NULL,
277 lpTokenAttributes->lpSecurityDescriptor
278 );
279
280 ObjectAttributes.SecurityQualityOfService = &Sqos;
281
282 Status = NtDuplicateToken (ExistingTokenHandle,
283 dwDesiredAccess,
284 &ObjectAttributes,
285 Sqos.EffectiveOnly, /* why both here _and_ in Sqos? */
286 TokenType,
287 &NewToken);
288 if (!NT_SUCCESS(Status))
289 {
290 SetLastError(RtlNtStatusToDosError(Status));
291 return FALSE;
292 }
293
294 return TRUE;
295 }
296
297
298 /*
299 * @implemented
300 */
301 BOOL STDCALL
302 DuplicateToken (HANDLE ExistingTokenHandle,
303 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
304 PHANDLE DuplicateTokenHandle)
305 {
306 return DuplicateTokenEx (ExistingTokenHandle,
307 TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY,
308 NULL,
309 ImpersonationLevel,
310 TokenImpersonation,
311 DuplicateTokenHandle);
312 }
313
314
315 /*
316 * @implemented
317 */
318 BOOL STDCALL
319 CheckTokenMembership (HANDLE ExistingTokenHandle,
320 PSID SidToCheck,
321 PBOOL IsMember)
322 {
323 HANDLE AccessToken;
324 BOOL ReleaseToken = FALSE;
325 BOOL Result = FALSE;
326 DWORD dwSize;
327 DWORD i;
328 PTOKEN_GROUPS lpGroups = NULL;
329 TOKEN_TYPE TokenInformation;
330
331 if (IsMember == NULL)
332 {
333 SetLastError(ERROR_INVALID_PARAMETER);
334 return FALSE;
335 }
336
337 if (ExistingTokenHandle == NULL)
338 {
339 /* Get impersonation token of the calling thread */
340 if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &ExistingTokenHandle))
341 return FALSE;
342
343 if (!DuplicateToken(ExistingTokenHandle, SecurityAnonymous, &AccessToken))
344 {
345 CloseHandle(ExistingTokenHandle);
346 goto ByeBye;
347 }
348 CloseHandle(ExistingTokenHandle);
349 ReleaseToken = TRUE;
350 }
351 else
352 {
353 if (!GetTokenInformation(ExistingTokenHandle, TokenType, &TokenInformation, sizeof(TokenInformation), &dwSize))
354 goto ByeBye;
355 if (TokenInformation != TokenImpersonation)
356 {
357 /* Duplicate token to have a impersonation token */
358 if (!DuplicateToken(ExistingTokenHandle, SecurityAnonymous, &AccessToken))
359 return FALSE;
360 ReleaseToken = TRUE;
361 }
362 else
363 AccessToken = ExistingTokenHandle;
364 }
365
366 *IsMember = FALSE;
367 /* Search in groups of the token */
368 if (!GetTokenInformation(AccessToken, TokenGroups, NULL, 0, &dwSize))
369 goto ByeBye;
370 lpGroups = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(), 0, dwSize);
371 if (!lpGroups)
372 goto ByeBye;
373 if (!GetTokenInformation(AccessToken, TokenGroups, lpGroups, dwSize, &dwSize))
374 goto ByeBye;
375 for (i = 0; i < lpGroups->GroupCount; i++)
376 {
377 if (EqualSid(SidToCheck, &lpGroups->Groups[i].Sid))
378 {
379 Result = TRUE;
380 *IsMember = TRUE;
381 goto ByeBye;
382 }
383 }
384 /* FIXME: Search in users of the token? */
385 DPRINT1("CheckTokenMembership() partially implemented!\n");
386 Result = TRUE;
387
388 ByeBye:
389 if (lpGroups != NULL)
390 HeapFree(GetProcessHeap(), 0, lpGroups);
391 if (ReleaseToken)
392 CloseHandle(AccessToken);
393
394 return Result;
395 }
396
397 /* EOF */