fixed some warnings when compiling with -O3
[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 (IN PHANDLE ThreadHandle OPTIONAL,
228 IN HANDLE TokenHandle)
229 {
230 NTSTATUS Status;
231 HANDLE hThread;
232
233 hThread = ((ThreadHandle != NULL) ? *ThreadHandle : NtCurrentThread());
234
235 Status = NtSetInformationThread (hThread,
236 ThreadImpersonationToken,
237 &TokenHandle,
238 sizeof(HANDLE));
239 if (!NT_SUCCESS(Status))
240 {
241 SetLastError (RtlNtStatusToDosError (Status));
242 return FALSE;
243 }
244
245 return TRUE;
246 }
247
248
249 /*
250 * @implemented
251 */
252 BOOL STDCALL
253 DuplicateTokenEx (IN HANDLE ExistingTokenHandle,
254 IN DWORD dwDesiredAccess,
255 IN LPSECURITY_ATTRIBUTES lpTokenAttributes OPTIONAL,
256 IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
257 IN TOKEN_TYPE TokenType,
258 OUT PHANDLE DuplicateTokenHandle)
259 {
260 OBJECT_ATTRIBUTES ObjectAttributes;
261 HANDLE NewToken;
262 NTSTATUS Status;
263 SECURITY_QUALITY_OF_SERVICE Sqos;
264
265 Sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
266 Sqos.ImpersonationLevel = ImpersonationLevel;
267 Sqos.ContextTrackingMode = 0;
268 Sqos.EffectiveOnly = FALSE;
269
270 if (lpTokenAttributes != NULL)
271 {
272 InitializeObjectAttributes(&ObjectAttributes,
273 NULL,
274 lpTokenAttributes->bInheritHandle ? OBJ_INHERIT : 0,
275 NULL,
276 lpTokenAttributes->lpSecurityDescriptor);
277 }
278 else
279 {
280 InitializeObjectAttributes(&ObjectAttributes,
281 NULL,
282 0,
283 NULL,
284 NULL);
285 }
286
287 ObjectAttributes.SecurityQualityOfService = &Sqos;
288
289 Status = NtDuplicateToken (ExistingTokenHandle,
290 dwDesiredAccess,
291 &ObjectAttributes,
292 FALSE,
293 TokenType,
294 &NewToken);
295 if (!NT_SUCCESS(Status))
296 {
297 SetLastError(RtlNtStatusToDosError(Status));
298 return FALSE;
299 }
300
301 return TRUE;
302 }
303
304
305 /*
306 * @implemented
307 */
308 BOOL STDCALL
309 DuplicateToken (IN HANDLE ExistingTokenHandle,
310 IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
311 OUT PHANDLE DuplicateTokenHandle)
312 {
313 return DuplicateTokenEx (ExistingTokenHandle,
314 TOKEN_IMPERSONATE | TOKEN_QUERY,
315 NULL,
316 ImpersonationLevel,
317 TokenImpersonation,
318 DuplicateTokenHandle);
319 }
320
321
322 /*
323 * @implemented
324 */
325 BOOL STDCALL
326 CheckTokenMembership (HANDLE ExistingTokenHandle,
327 PSID SidToCheck,
328 PBOOL IsMember)
329 {
330 HANDLE AccessToken = NULL;
331 BOOL Result = FALSE;
332 DWORD dwSize;
333 DWORD i;
334 PTOKEN_GROUPS lpGroups = NULL;
335 TOKEN_TYPE TokenInformation;
336
337 if (IsMember == NULL)
338 {
339 SetLastError(ERROR_INVALID_PARAMETER);
340 return FALSE;
341 }
342
343 if (ExistingTokenHandle == NULL)
344 {
345 /* Get impersonation token of the calling thread */
346 if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &ExistingTokenHandle))
347 return FALSE;
348
349 if (!DuplicateToken(ExistingTokenHandle, SecurityAnonymous, &AccessToken))
350 {
351 CloseHandle(ExistingTokenHandle);
352 goto ByeBye;
353 }
354 CloseHandle(ExistingTokenHandle);
355 }
356 else
357 {
358 if (!GetTokenInformation(ExistingTokenHandle, TokenType, &TokenInformation, sizeof(TokenInformation), &dwSize))
359 goto ByeBye;
360 if (TokenInformation != TokenImpersonation)
361 {
362 /* Duplicate token to have a impersonation token */
363 if (!DuplicateToken(ExistingTokenHandle, SecurityAnonymous, &AccessToken))
364 return FALSE;
365 }
366 else
367 AccessToken = ExistingTokenHandle;
368 }
369
370 *IsMember = FALSE;
371 /* Search in groups of the token */
372 if (!GetTokenInformation(AccessToken, TokenGroups, NULL, 0, &dwSize))
373 goto ByeBye;
374 lpGroups = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(), 0, dwSize);
375 if (!lpGroups)
376 goto ByeBye;
377 if (!GetTokenInformation(AccessToken, TokenGroups, lpGroups, dwSize, &dwSize))
378 goto ByeBye;
379 for (i = 0; i < lpGroups->GroupCount; i++)
380 {
381 if (EqualSid(SidToCheck, &lpGroups->Groups[i].Sid))
382 {
383 Result = TRUE;
384 *IsMember = TRUE;
385 goto ByeBye;
386 }
387 }
388 /* FIXME: Search in users of the token? */
389 DPRINT1("CheckTokenMembership() partially implemented!\n");
390 Result = TRUE;
391
392 ByeBye:
393 if (lpGroups != NULL)
394 HeapFree(GetProcessHeap(), 0, lpGroups);
395 if (AccessToken != NULL && AccessToken != ExistingTokenHandle)
396 CloseHandle(AccessToken);
397
398 return Result;
399 }
400
401
402 /*
403 * @implemented
404 */
405 BOOL STDCALL
406 IsTokenRestricted(HANDLE TokenHandle)
407 {
408 ULONG RetLength;
409 PTOKEN_GROUPS lpGroups;
410 NTSTATUS Status;
411 BOOL Ret = FALSE;
412
413 /* determine the required buffer size and allocate enough memory to read the
414 list of restricted SIDs */
415
416 Status = NtQueryInformationToken(TokenHandle,
417 TokenRestrictedSids,
418 NULL,
419 0,
420 &RetLength);
421 if (Status != STATUS_BUFFER_TOO_SMALL)
422 {
423 SetLastError(RtlNtStatusToDosError(Status));
424 return FALSE;
425 }
426
427 AllocAndReadRestrictedSids:
428 lpGroups = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
429 0,
430 RetLength);
431 if (lpGroups == NULL)
432 {
433 SetLastError(ERROR_OUTOFMEMORY);
434 return FALSE;
435 }
436
437 /* actually read the list of the restricted SIDs */
438
439 Status = NtQueryInformationToken(TokenHandle,
440 TokenRestrictedSids,
441 lpGroups,
442 RetLength,
443 &RetLength);
444 if (NT_SUCCESS(Status))
445 {
446 Ret = (lpGroups->GroupCount != 0);
447 }
448 else if (Status == STATUS_BUFFER_TOO_SMALL)
449 {
450 /* looks like the token was modified in the meanwhile, let's just try again */
451
452 HeapFree(GetProcessHeap(),
453 0,
454 lpGroups);
455
456 goto AllocAndReadRestrictedSids;
457 }
458 else
459 {
460 SetLastError(RtlNtStatusToDosError(Status));
461 }
462
463 /* free allocated memory */
464
465 HeapFree(GetProcessHeap(),
466 0,
467 lpGroups);
468
469 return Ret;
470 }
471
472 /* EOF */