implemented some stubs needed by ClamWin
[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 <wine/debug.h>
15 #include <debug.h>
16
17 /*
18 * @implemented
19 */
20 BOOL STDCALL
21 AdjustTokenGroups (HANDLE TokenHandle,
22 BOOL ResetToDefault,
23 PTOKEN_GROUPS NewState,
24 DWORD BufferLength,
25 PTOKEN_GROUPS PreviousState,
26 PDWORD ReturnLength)
27 {
28 NTSTATUS Status;
29
30 Status = NtAdjustGroupsToken (TokenHandle,
31 ResetToDefault,
32 NewState,
33 BufferLength,
34 PreviousState,
35 (PULONG)ReturnLength);
36 if (!NT_SUCCESS (Status))
37 {
38 SetLastError (RtlNtStatusToDosError (Status));
39 return FALSE;
40 }
41
42 return TRUE;
43 }
44
45
46 /*
47 * @implemented
48 */
49 BOOL STDCALL
50 AdjustTokenPrivileges (HANDLE TokenHandle,
51 BOOL DisableAllPrivileges,
52 PTOKEN_PRIVILEGES NewState,
53 DWORD BufferLength,
54 PTOKEN_PRIVILEGES PreviousState,
55 PDWORD ReturnLength)
56 {
57 NTSTATUS Status;
58
59 Status = NtAdjustPrivilegesToken (TokenHandle,
60 DisableAllPrivileges,
61 NewState,
62 BufferLength,
63 PreviousState,
64 (PULONG)ReturnLength);
65 if (STATUS_NOT_ALL_ASSIGNED == Status)
66 {
67 SetLastError(ERROR_NOT_ALL_ASSIGNED);
68 return TRUE;
69 }
70 if (! NT_SUCCESS(Status))
71 {
72 SetLastError(RtlNtStatusToDosError(Status));
73 return FALSE;
74 }
75
76 SetLastError(ERROR_SUCCESS); /* AdjustTokenPrivileges is documented to do this */
77 return TRUE;
78 }
79
80
81 /*
82 * @implemented
83 */
84 BOOL STDCALL
85 GetTokenInformation (HANDLE TokenHandle,
86 TOKEN_INFORMATION_CLASS TokenInformationClass,
87 LPVOID TokenInformation,
88 DWORD TokenInformationLength,
89 PDWORD ReturnLength)
90 {
91 NTSTATUS Status;
92
93 Status = NtQueryInformationToken (TokenHandle,
94 TokenInformationClass,
95 TokenInformation,
96 TokenInformationLength,
97 (PULONG)ReturnLength);
98 if (!NT_SUCCESS (Status))
99 {
100 SetLastError (RtlNtStatusToDosError (Status));
101 return FALSE;
102 }
103
104 return TRUE;
105 }
106
107
108 /*
109 * @implemented
110 */
111 BOOL STDCALL
112 SetTokenInformation (HANDLE TokenHandle,
113 TOKEN_INFORMATION_CLASS TokenInformationClass,
114 LPVOID TokenInformation,
115 DWORD TokenInformationLength)
116 {
117 NTSTATUS Status;
118
119 Status = NtSetInformationToken (TokenHandle,
120 TokenInformationClass,
121 TokenInformation,
122 TokenInformationLength);
123 if (!NT_SUCCESS (Status))
124 {
125 SetLastError (RtlNtStatusToDosError (Status));
126 return FALSE;
127 }
128
129 return TRUE;
130 }
131
132
133 /*
134 * @implemented
135 */
136 BOOL STDCALL
137 AccessCheck (PSECURITY_DESCRIPTOR pSecurityDescriptor,
138 HANDLE ClientToken,
139 DWORD DesiredAccess,
140 PGENERIC_MAPPING GenericMapping,
141 PPRIVILEGE_SET PrivilegeSet,
142 LPDWORD PrivilegeSetLength,
143 LPDWORD GrantedAccess,
144 LPBOOL AccessStatus)
145 {
146 NTSTATUS Status;
147 NTSTATUS AccessStat;
148
149 Status = NtAccessCheck (pSecurityDescriptor,
150 ClientToken,
151 DesiredAccess,
152 GenericMapping,
153 PrivilegeSet,
154 (PULONG)PrivilegeSetLength,
155 (PACCESS_MASK)GrantedAccess,
156 &AccessStat);
157 if (!NT_SUCCESS (Status))
158 {
159 SetLastError (RtlNtStatusToDosError (Status));
160 return FALSE;
161 }
162
163 if (!NT_SUCCESS (AccessStat))
164 {
165 SetLastError (RtlNtStatusToDosError (Status));
166 *AccessStatus = FALSE;
167 return TRUE;
168 }
169
170 *AccessStatus = TRUE;
171
172 return TRUE;
173 }
174
175
176 /*
177 * @implemented
178 */
179 BOOL STDCALL
180 OpenProcessToken (HANDLE ProcessHandle,
181 DWORD DesiredAccess,
182 PHANDLE TokenHandle)
183 {
184 NTSTATUS Status;
185
186 Status = NtOpenProcessToken (ProcessHandle,
187 DesiredAccess,
188 TokenHandle);
189 if (!NT_SUCCESS (Status))
190 {
191 SetLastError (RtlNtStatusToDosError (Status));
192 return FALSE;
193 }
194
195 return TRUE;
196 }
197
198
199 /*
200 * @implemented
201 */
202 BOOL STDCALL
203 OpenThreadToken (HANDLE ThreadHandle,
204 DWORD DesiredAccess,
205 BOOL OpenAsSelf,
206 PHANDLE TokenHandle)
207 {
208 NTSTATUS Status;
209
210 Status = NtOpenThreadToken (ThreadHandle,
211 DesiredAccess,
212 OpenAsSelf,
213 TokenHandle);
214 if (!NT_SUCCESS(Status))
215 {
216 SetLastError (RtlNtStatusToDosError (Status));
217 return FALSE;
218 }
219
220 return TRUE;
221 }
222
223
224 /*
225 * @implemented
226 */
227 BOOL STDCALL
228 SetThreadToken (IN PHANDLE ThreadHandle OPTIONAL,
229 IN HANDLE TokenHandle)
230 {
231 NTSTATUS Status;
232 HANDLE hThread;
233
234 hThread = ((ThreadHandle != NULL) ? *ThreadHandle : NtCurrentThread());
235
236 Status = NtSetInformationThread (hThread,
237 ThreadImpersonationToken,
238 &TokenHandle,
239 sizeof(HANDLE));
240 if (!NT_SUCCESS(Status))
241 {
242 SetLastError (RtlNtStatusToDosError (Status));
243 return FALSE;
244 }
245
246 return TRUE;
247 }
248
249
250 /*
251 * @implemented
252 */
253 BOOL STDCALL
254 DuplicateTokenEx (IN HANDLE ExistingTokenHandle,
255 IN DWORD dwDesiredAccess,
256 IN LPSECURITY_ATTRIBUTES lpTokenAttributes OPTIONAL,
257 IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
258 IN TOKEN_TYPE TokenType,
259 OUT PHANDLE DuplicateTokenHandle)
260 {
261 OBJECT_ATTRIBUTES ObjectAttributes;
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 DuplicateTokenHandle);
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(IN HANDLE ExistingTokenHandle,
327 IN PSID SidToCheck,
328 OUT PBOOL IsMember)
329 {
330 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
331 ACCESS_MASK GrantedAccess;
332 struct
333 {
334 PRIVILEGE_SET PrivilegeSet;
335 LUID_AND_ATTRIBUTES Privileges[4];
336 } PrivBuffer;
337 ULONG PrivBufferSize = sizeof(PrivBuffer);
338 GENERIC_MAPPING GenericMapping =
339 {
340 STANDARD_RIGHTS_READ,
341 STANDARD_RIGHTS_WRITE,
342 STANDARD_RIGHTS_EXECUTE,
343 STANDARD_RIGHTS_ALL
344 };
345 PACL Dacl;
346 ULONG SidLen;
347 HANDLE hToken = NULL;
348 NTSTATUS Status, AccessStatus;
349
350 /* doesn't return gracefully if IsMember is NULL! */
351 *IsMember = FALSE;
352
353 SidLen = RtlLengthSid(SidToCheck);
354
355 if (ExistingTokenHandle == NULL)
356 {
357 Status = NtOpenThreadToken(NtCurrentThread(),
358 TOKEN_QUERY,
359 FALSE,
360 &hToken);
361
362 if (Status == STATUS_NO_TOKEN)
363 {
364 /* we're not impersonating, open the primary token */
365 Status = NtOpenProcessToken(NtCurrentProcess(),
366 TOKEN_QUERY | TOKEN_DUPLICATE,
367 &hToken);
368 if (NT_SUCCESS(Status))
369 {
370 HANDLE hNewToken = FALSE;
371 BOOL DupRet;
372
373 /* duplicate the primary token to create an impersonation token */
374 DupRet = DuplicateTokenEx(hToken,
375 TOKEN_QUERY | TOKEN_IMPERSONATE,
376 NULL,
377 SecurityImpersonation,
378 TokenImpersonation,
379 &hNewToken);
380
381 NtClose(hToken);
382
383 if (!DupRet)
384 {
385 DPRINT1("Failed to duplicate the primary token!\n");
386 return FALSE;
387 }
388
389 hToken = hNewToken;
390 }
391 }
392
393 if (!NT_SUCCESS(Status))
394 {
395 goto Cleanup;
396 }
397 }
398 else
399 {
400 hToken = ExistingTokenHandle;
401 }
402
403 /* create a security descriptor */
404 SecurityDescriptor = RtlAllocateHeap(RtlGetProcessHeap(),
405 0,
406 sizeof(SECURITY_DESCRIPTOR) +
407 sizeof(ACL) + SidLen +
408 sizeof(ACCESS_ALLOWED_ACE));
409 if (SecurityDescriptor == NULL)
410 {
411 Status = STATUS_INSUFFICIENT_RESOURCES;
412 goto Cleanup;
413 }
414
415 Status = RtlCreateSecurityDescriptor(SecurityDescriptor,
416 SECURITY_DESCRIPTOR_REVISION);
417 if (!NT_SUCCESS(Status))
418 {
419 goto Cleanup;
420 }
421
422 /* set the owner and group */
423 Status = RtlSetOwnerSecurityDescriptor(SecurityDescriptor,
424 SidToCheck,
425 FALSE);
426 if (!NT_SUCCESS(Status))
427 {
428 goto Cleanup;
429 }
430
431 Status = RtlSetGroupSecurityDescriptor(SecurityDescriptor,
432 SidToCheck,
433 FALSE);
434 if (!NT_SUCCESS(Status))
435 {
436 goto Cleanup;
437 }
438
439 /* create the DACL */
440 Dacl = (PACL)(SecurityDescriptor + 1);
441 Status = RtlCreateAcl(Dacl,
442 sizeof(ACL) + SidLen + sizeof(ACCESS_ALLOWED_ACE),
443 ACL_REVISION);
444 if (!NT_SUCCESS(Status))
445 {
446 goto Cleanup;
447 }
448
449 Status = RtlAddAccessAllowedAce(Dacl,
450 ACL_REVISION,
451 0x1,
452 SidToCheck);
453 if (!NT_SUCCESS(Status))
454 {
455 goto Cleanup;
456 }
457
458 /* assign the DACL to the security descriptor */
459 Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor,
460 TRUE,
461 Dacl,
462 FALSE);
463 if (!NT_SUCCESS(Status))
464 {
465 goto Cleanup;
466 }
467
468 /* it's time to perform the access check. Just use _some_ desired access right
469 (same as for the ACE) and see if we're getting it granted. This indicates
470 our SID is a member of the token. We however can't use a generic access
471 right as those aren't mapped and return an error (STATUS_GENERIC_NOT_MAPPED). */
472 Status = NtAccessCheck(SecurityDescriptor,
473 hToken,
474 0x1,
475 &GenericMapping,
476 &PrivBuffer.PrivilegeSet,
477 &PrivBufferSize,
478 &GrantedAccess,
479 &AccessStatus);
480
481 if (NT_SUCCESS(Status) && NT_SUCCESS(AccessStatus) && (GrantedAccess == 0x1))
482 {
483 *IsMember = TRUE;
484 }
485
486 Cleanup:
487 if (hToken != NULL && hToken != ExistingTokenHandle)
488 {
489 NtClose(hToken);
490 }
491
492 if (SecurityDescriptor != NULL)
493 {
494 RtlFreeHeap(RtlGetProcessHeap(),
495 0,
496 SecurityDescriptor);
497 }
498
499 if (!NT_SUCCESS(Status))
500 {
501 SetLastError(RtlNtStatusToDosError(Status));
502 return FALSE;
503 }
504
505 return TRUE;
506 }
507
508
509 /*
510 * @implemented
511 */
512 BOOL STDCALL
513 IsTokenRestricted(HANDLE TokenHandle)
514 {
515 ULONG RetLength;
516 PTOKEN_GROUPS lpGroups;
517 NTSTATUS Status;
518 BOOL Ret = FALSE;
519
520 /* determine the required buffer size and allocate enough memory to read the
521 list of restricted SIDs */
522
523 Status = NtQueryInformationToken(TokenHandle,
524 TokenRestrictedSids,
525 NULL,
526 0,
527 &RetLength);
528 if (Status != STATUS_BUFFER_TOO_SMALL)
529 {
530 SetLastError(RtlNtStatusToDosError(Status));
531 return FALSE;
532 }
533
534 AllocAndReadRestrictedSids:
535 lpGroups = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
536 0,
537 RetLength);
538 if (lpGroups == NULL)
539 {
540 SetLastError(ERROR_OUTOFMEMORY);
541 return FALSE;
542 }
543
544 /* actually read the list of the restricted SIDs */
545
546 Status = NtQueryInformationToken(TokenHandle,
547 TokenRestrictedSids,
548 lpGroups,
549 RetLength,
550 &RetLength);
551 if (NT_SUCCESS(Status))
552 {
553 Ret = (lpGroups->GroupCount != 0);
554 }
555 else if (Status == STATUS_BUFFER_TOO_SMALL)
556 {
557 /* looks like the token was modified in the meanwhile, let's just try again */
558
559 HeapFree(GetProcessHeap(),
560 0,
561 lpGroups);
562
563 goto AllocAndReadRestrictedSids;
564 }
565 else
566 {
567 SetLastError(RtlNtStatusToDosError(Status));
568 }
569
570 /* free allocated memory */
571
572 HeapFree(GetProcessHeap(),
573 0,
574 lpGroups);
575
576 return Ret;
577 }
578
579 BOOL STDCALL
580 CreateRestrictedToken(
581 HANDLE TokenHandle,
582 DWORD Flags,
583 DWORD DisableSidCount,
584 PSID_AND_ATTRIBUTES pSidAndAttributes,
585 DWORD DeletePrivilegeCount,
586 PLUID_AND_ATTRIBUTES pLUIDAndAttributes,
587 DWORD RestrictedSidCount,
588 PSID_AND_ATTRIBUTES pSIDAndAttributes,
589 PHANDLE NewTokenHandle
590 )
591 {
592 FIXME("unimplemented!\n", __FUNCTION__);
593 return FALSE;
594 }
595
596
597
598 /* EOF */