5cb88a90572e248ab64e2918739e28d0a33cc752
[reactos.git] / reactos / dll / win32 / 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 #include <ndk/setypes.h>
14
15 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
16
17 /*
18 * @implemented
19 */
20 BOOL WINAPI
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 WINAPI
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
71 if (!NT_SUCCESS(Status))
72 {
73 SetLastError(RtlNtStatusToDosError(Status));
74 return FALSE;
75 }
76
77 /* AdjustTokenPrivileges is documented to do this */
78 SetLastError(ERROR_SUCCESS);
79
80 return TRUE;
81 }
82
83
84 /*
85 * @implemented
86 */
87 BOOL WINAPI
88 GetTokenInformation(HANDLE TokenHandle,
89 TOKEN_INFORMATION_CLASS TokenInformationClass,
90 LPVOID TokenInformation,
91 DWORD TokenInformationLength,
92 PDWORD ReturnLength)
93 {
94 NTSTATUS Status;
95
96 Status = NtQueryInformationToken(TokenHandle,
97 TokenInformationClass,
98 TokenInformation,
99 TokenInformationLength,
100 (PULONG)ReturnLength);
101 if (!NT_SUCCESS(Status))
102 {
103 SetLastError(RtlNtStatusToDosError(Status));
104 return FALSE;
105 }
106
107 return TRUE;
108 }
109
110
111 /*
112 * @implemented
113 */
114 BOOL WINAPI
115 SetTokenInformation(HANDLE TokenHandle,
116 TOKEN_INFORMATION_CLASS TokenInformationClass,
117 LPVOID TokenInformation,
118 DWORD TokenInformationLength)
119 {
120 NTSTATUS Status;
121
122 Status = NtSetInformationToken(TokenHandle,
123 TokenInformationClass,
124 TokenInformation,
125 TokenInformationLength);
126 if (!NT_SUCCESS(Status))
127 {
128 SetLastError(RtlNtStatusToDosError(Status));
129 return FALSE;
130 }
131
132 return TRUE;
133 }
134
135
136 /*
137 * @implemented
138 */
139 BOOL
140 WINAPI
141 AccessCheck(IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
142 IN HANDLE ClientToken,
143 IN DWORD DesiredAccess,
144 IN PGENERIC_MAPPING GenericMapping,
145 OUT PPRIVILEGE_SET PrivilegeSet OPTIONAL,
146 IN OUT LPDWORD PrivilegeSetLength,
147 OUT LPDWORD GrantedAccess,
148 OUT LPBOOL AccessStatus)
149 {
150 NTSTATUS Status;
151 NTSTATUS NtAccessStatus;
152
153 /* Do the access check */
154 Status = NtAccessCheck(pSecurityDescriptor,
155 ClientToken,
156 DesiredAccess,
157 GenericMapping,
158 PrivilegeSet,
159 (PULONG)PrivilegeSetLength,
160 (PACCESS_MASK)GrantedAccess,
161 &NtAccessStatus);
162
163 /* See if the access check operation succeeded */
164 if (!NT_SUCCESS(Status))
165 {
166 /* Check failed */
167 SetLastError(RtlNtStatusToDosError(Status));
168 return FALSE;
169 }
170
171 /* Now check the access status */
172 if (!NT_SUCCESS(NtAccessStatus))
173 {
174 /* Access denied */
175 SetLastError(RtlNtStatusToDosError(NtAccessStatus));
176 *AccessStatus = FALSE;
177 }
178 else
179 {
180 /* Access granted */
181 *AccessStatus = TRUE;
182 }
183
184 /* Check succeeded */
185 return TRUE;
186 }
187
188 /*
189 * @unimplemented
190 */
191 BOOL WINAPI AccessCheckByType(
192 PSECURITY_DESCRIPTOR pSecurityDescriptor,
193 PSID PrincipalSelfSid,
194 HANDLE ClientToken,
195 DWORD DesiredAccess,
196 POBJECT_TYPE_LIST ObjectTypeList,
197 DWORD ObjectTypeListLength,
198 PGENERIC_MAPPING GenericMapping,
199 PPRIVILEGE_SET PrivilegeSet,
200 LPDWORD PrivilegeSetLength,
201 LPDWORD GrantedAccess,
202 LPBOOL AccessStatus)
203 {
204 FIXME("stub\n");
205
206 *AccessStatus = TRUE;
207
208 return !*AccessStatus;
209 }
210
211 /*
212 * @implemented
213 */
214 BOOL WINAPI
215 OpenProcessToken(HANDLE ProcessHandle,
216 DWORD DesiredAccess,
217 PHANDLE TokenHandle)
218 {
219 NTSTATUS Status;
220
221 TRACE("%p, %x, %p.\n", ProcessHandle, DesiredAccess, TokenHandle);
222
223 Status = NtOpenProcessToken(ProcessHandle,
224 DesiredAccess,
225 TokenHandle);
226 if (!NT_SUCCESS(Status))
227 {
228 ERR("NtOpenProcessToken failed! Status %08x.\n", Status);
229 SetLastError(RtlNtStatusToDosError(Status));
230 return FALSE;
231 }
232
233 TRACE("Returning token %p.\n", *TokenHandle);
234
235 return TRUE;
236 }
237
238
239 /*
240 * @implemented
241 */
242 BOOL WINAPI
243 OpenThreadToken(HANDLE ThreadHandle,
244 DWORD DesiredAccess,
245 BOOL OpenAsSelf,
246 PHANDLE TokenHandle)
247 {
248 NTSTATUS Status;
249
250 Status = NtOpenThreadToken(ThreadHandle,
251 DesiredAccess,
252 OpenAsSelf,
253 TokenHandle);
254 if (!NT_SUCCESS(Status))
255 {
256 SetLastError(RtlNtStatusToDosError(Status));
257 return FALSE;
258 }
259
260 return TRUE;
261 }
262
263
264 /*
265 * @implemented
266 */
267 BOOL WINAPI
268 SetThreadToken(IN PHANDLE ThreadHandle OPTIONAL,
269 IN HANDLE TokenHandle)
270 {
271 NTSTATUS Status;
272 HANDLE hThread;
273
274 hThread = (ThreadHandle != NULL) ? *ThreadHandle : NtCurrentThread();
275
276 Status = NtSetInformationThread(hThread,
277 ThreadImpersonationToken,
278 &TokenHandle,
279 sizeof(HANDLE));
280 if (!NT_SUCCESS(Status))
281 {
282 SetLastError(RtlNtStatusToDosError(Status));
283 return FALSE;
284 }
285
286 return TRUE;
287 }
288
289
290 /*
291 * @implemented
292 */
293 BOOL WINAPI
294 DuplicateTokenEx(IN HANDLE ExistingTokenHandle,
295 IN DWORD dwDesiredAccess,
296 IN LPSECURITY_ATTRIBUTES lpTokenAttributes OPTIONAL,
297 IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
298 IN TOKEN_TYPE TokenType,
299 OUT PHANDLE DuplicateTokenHandle)
300 {
301 OBJECT_ATTRIBUTES ObjectAttributes;
302 NTSTATUS Status;
303 SECURITY_QUALITY_OF_SERVICE Sqos;
304
305 TRACE("%p 0x%08x 0x%08x 0x%08x %p\n", ExistingTokenHandle, dwDesiredAccess,
306 ImpersonationLevel, TokenType, DuplicateTokenHandle);
307
308 Sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
309 Sqos.ImpersonationLevel = ImpersonationLevel;
310 Sqos.ContextTrackingMode = 0;
311 Sqos.EffectiveOnly = FALSE;
312
313 if (lpTokenAttributes != NULL)
314 {
315 InitializeObjectAttributes(&ObjectAttributes,
316 NULL,
317 lpTokenAttributes->bInheritHandle ? OBJ_INHERIT : 0,
318 NULL,
319 lpTokenAttributes->lpSecurityDescriptor);
320 }
321 else
322 {
323 InitializeObjectAttributes(&ObjectAttributes,
324 NULL,
325 0,
326 NULL,
327 NULL);
328 }
329
330 ObjectAttributes.SecurityQualityOfService = &Sqos;
331
332 Status = NtDuplicateToken(ExistingTokenHandle,
333 dwDesiredAccess,
334 &ObjectAttributes,
335 FALSE,
336 TokenType,
337 DuplicateTokenHandle);
338 if (!NT_SUCCESS(Status))
339 {
340 ERR("NtDuplicateToken failed: Status %08x\n", Status);
341 SetLastError(RtlNtStatusToDosError(Status));
342 return FALSE;
343 }
344
345 TRACE("Returning token %p.\n", *DuplicateTokenHandle);
346
347 return TRUE;
348 }
349
350
351 /*
352 * @implemented
353 */
354 BOOL WINAPI
355 DuplicateToken(IN HANDLE ExistingTokenHandle,
356 IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
357 OUT PHANDLE DuplicateTokenHandle)
358 {
359 return DuplicateTokenEx(ExistingTokenHandle,
360 TOKEN_IMPERSONATE | TOKEN_QUERY,
361 NULL,
362 ImpersonationLevel,
363 TokenImpersonation,
364 DuplicateTokenHandle);
365 }
366
367
368 /*
369 * @implemented
370 */
371 BOOL WINAPI
372 CheckTokenMembership(IN HANDLE ExistingTokenHandle,
373 IN PSID SidToCheck,
374 OUT PBOOL IsMember)
375 {
376 PISECURITY_DESCRIPTOR SecurityDescriptor = NULL;
377 ACCESS_MASK GrantedAccess;
378 struct
379 {
380 PRIVILEGE_SET PrivilegeSet;
381 LUID_AND_ATTRIBUTES Privileges[4];
382 } PrivBuffer;
383 ULONG PrivBufferSize = sizeof(PrivBuffer);
384 GENERIC_MAPPING GenericMapping =
385 {
386 STANDARD_RIGHTS_READ,
387 STANDARD_RIGHTS_WRITE,
388 STANDARD_RIGHTS_EXECUTE,
389 STANDARD_RIGHTS_ALL
390 };
391 PACL Dacl;
392 ULONG SidLen;
393 HANDLE hToken = NULL;
394 NTSTATUS Status, AccessStatus;
395
396 /* doesn't return gracefully if IsMember is NULL! */
397 *IsMember = FALSE;
398
399 SidLen = RtlLengthSid(SidToCheck);
400
401 if (ExistingTokenHandle == NULL)
402 {
403 Status = NtOpenThreadToken(NtCurrentThread(),
404 TOKEN_QUERY,
405 FALSE,
406 &hToken);
407
408 if (Status == STATUS_NO_TOKEN)
409 {
410 /* we're not impersonating, open the primary token */
411 Status = NtOpenProcessToken(NtCurrentProcess(),
412 TOKEN_QUERY | TOKEN_DUPLICATE,
413 &hToken);
414 if (NT_SUCCESS(Status))
415 {
416 HANDLE hNewToken = FALSE;
417 BOOL DupRet;
418
419 /* duplicate the primary token to create an impersonation token */
420 DupRet = DuplicateTokenEx(hToken,
421 TOKEN_QUERY | TOKEN_IMPERSONATE,
422 NULL,
423 SecurityImpersonation,
424 TokenImpersonation,
425 &hNewToken);
426
427 NtClose(hToken);
428
429 if (!DupRet)
430 {
431 WARN("Failed to duplicate the primary token!\n");
432 return FALSE;
433 }
434
435 hToken = hNewToken;
436 }
437 }
438
439 if (!NT_SUCCESS(Status))
440 {
441 goto Cleanup;
442 }
443 }
444 else
445 {
446 hToken = ExistingTokenHandle;
447 }
448
449 /* create a security descriptor */
450 SecurityDescriptor = RtlAllocateHeap(RtlGetProcessHeap(),
451 0,
452 sizeof(SECURITY_DESCRIPTOR) +
453 sizeof(ACL) + SidLen +
454 sizeof(ACCESS_ALLOWED_ACE));
455 if (SecurityDescriptor == NULL)
456 {
457 Status = STATUS_INSUFFICIENT_RESOURCES;
458 goto Cleanup;
459 }
460
461 Status = RtlCreateSecurityDescriptor(SecurityDescriptor,
462 SECURITY_DESCRIPTOR_REVISION);
463 if (!NT_SUCCESS(Status))
464 {
465 goto Cleanup;
466 }
467
468 /* set the owner and group */
469 Status = RtlSetOwnerSecurityDescriptor(SecurityDescriptor,
470 SidToCheck,
471 FALSE);
472 if (!NT_SUCCESS(Status))
473 {
474 goto Cleanup;
475 }
476
477 Status = RtlSetGroupSecurityDescriptor(SecurityDescriptor,
478 SidToCheck,
479 FALSE);
480 if (!NT_SUCCESS(Status))
481 {
482 goto Cleanup;
483 }
484
485 /* create the DACL */
486 Dacl = (PACL)(SecurityDescriptor + 1);
487 Status = RtlCreateAcl(Dacl,
488 sizeof(ACL) + SidLen + sizeof(ACCESS_ALLOWED_ACE),
489 ACL_REVISION);
490 if (!NT_SUCCESS(Status))
491 {
492 goto Cleanup;
493 }
494
495 Status = RtlAddAccessAllowedAce(Dacl,
496 ACL_REVISION,
497 0x1,
498 SidToCheck);
499 if (!NT_SUCCESS(Status))
500 {
501 goto Cleanup;
502 }
503
504 /* assign the DACL to the security descriptor */
505 Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor,
506 TRUE,
507 Dacl,
508 FALSE);
509 if (!NT_SUCCESS(Status))
510 {
511 goto Cleanup;
512 }
513
514 /* it's time to perform the access check. Just use _some_ desired access right
515 (same as for the ACE) and see if we're getting it granted. This indicates
516 our SID is a member of the token. We however can't use a generic access
517 right as those aren't mapped and return an error (STATUS_GENERIC_NOT_MAPPED). */
518 Status = NtAccessCheck(SecurityDescriptor,
519 hToken,
520 0x1,
521 &GenericMapping,
522 &PrivBuffer.PrivilegeSet,
523 &PrivBufferSize,
524 &GrantedAccess,
525 &AccessStatus);
526 if (NT_SUCCESS(Status) && NT_SUCCESS(AccessStatus) && (GrantedAccess == 0x1))
527 {
528 *IsMember = TRUE;
529 }
530
531 Cleanup:
532 if (hToken != NULL && hToken != ExistingTokenHandle)
533 {
534 NtClose(hToken);
535 }
536
537 if (SecurityDescriptor != NULL)
538 {
539 RtlFreeHeap(RtlGetProcessHeap(),
540 0,
541 SecurityDescriptor);
542 }
543
544 if (!NT_SUCCESS(Status))
545 {
546 SetLastError(RtlNtStatusToDosError(Status));
547 return FALSE;
548 }
549
550 return TRUE;
551 }
552
553
554 /*
555 * @implemented
556 */
557 BOOL WINAPI
558 IsTokenRestricted(HANDLE TokenHandle)
559 {
560 ULONG RetLength;
561 PTOKEN_GROUPS lpGroups;
562 NTSTATUS Status;
563 BOOL Ret = FALSE;
564
565 /* determine the required buffer size and allocate enough memory to read the
566 list of restricted SIDs */
567 Status = NtQueryInformationToken(TokenHandle,
568 TokenRestrictedSids,
569 NULL,
570 0,
571 &RetLength);
572 if (Status != STATUS_BUFFER_TOO_SMALL)
573 {
574 SetLastError(RtlNtStatusToDosError(Status));
575 return FALSE;
576 }
577
578 AllocAndReadRestrictedSids:
579 lpGroups = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
580 0,
581 RetLength);
582 if (lpGroups == NULL)
583 {
584 SetLastError(ERROR_OUTOFMEMORY);
585 return FALSE;
586 }
587
588 /* actually read the list of the restricted SIDs */
589 Status = NtQueryInformationToken(TokenHandle,
590 TokenRestrictedSids,
591 lpGroups,
592 RetLength,
593 &RetLength);
594 if (NT_SUCCESS(Status))
595 {
596 Ret = (lpGroups->GroupCount != 0);
597 }
598 else if (Status == STATUS_BUFFER_TOO_SMALL)
599 {
600 /* looks like the token was modified in the meanwhile, let's just try again */
601 HeapFree(GetProcessHeap(),
602 0,
603 lpGroups);
604
605 goto AllocAndReadRestrictedSids;
606 }
607 else
608 {
609 SetLastError(RtlNtStatusToDosError(Status));
610 }
611
612 /* free allocated memory */
613 HeapFree(GetProcessHeap(),
614 0,
615 lpGroups);
616
617 return Ret;
618 }
619
620
621 BOOL WINAPI
622 CreateRestrictedToken(HANDLE TokenHandle,
623 DWORD Flags,
624 DWORD DisableSidCount,
625 PSID_AND_ATTRIBUTES pSidAndAttributes,
626 DWORD DeletePrivilegeCount,
627 PLUID_AND_ATTRIBUTES pLUIDAndAttributes,
628 DWORD RestrictedSidCount,
629 PSID_AND_ATTRIBUTES pSIDAndAttributes,
630 PHANDLE NewTokenHandle)
631 {
632 UNIMPLEMENTED;
633 return FALSE;
634 }
635
636
637 /*
638 * @unimplemented
639 */
640 PSID
641 WINAPI
642 GetSiteSidFromToken(IN HANDLE TokenHandle)
643 {
644 PTOKEN_GROUPS RestrictedSids;
645 ULONG RetLen;
646 UINT i;
647 NTSTATUS Status;
648 PSID PSiteSid = NULL;
649 SID_IDENTIFIER_AUTHORITY InternetSiteAuthority = {SECURITY_INTERNETSITE_AUTHORITY};
650
651 Status = NtQueryInformationToken(TokenHandle,
652 TokenRestrictedSids,
653 NULL,
654 0,
655 &RetLen);
656 if (Status != STATUS_BUFFER_TOO_SMALL)
657 {
658 SetLastError(RtlNtStatusToDosError(Status));
659 return NULL;
660 }
661
662 RestrictedSids = (PTOKEN_GROUPS)RtlAllocateHeap(RtlGetProcessHeap(),
663 0,
664 RetLen);
665 if (RestrictedSids == NULL)
666 {
667 SetLastError(ERROR_OUTOFMEMORY);
668 return NULL;
669 }
670
671 Status = NtQueryInformationToken(TokenHandle,
672 TokenRestrictedSids,
673 RestrictedSids,
674 RetLen,
675 &RetLen);
676 if (NT_SUCCESS(Status))
677 {
678 for (i = 0; i < RestrictedSids->GroupCount; i++)
679 {
680 SID* RSSid = RestrictedSids->Groups[i].Sid;
681
682 if (RtlCompareMemory(&(RSSid->IdentifierAuthority),
683 &InternetSiteAuthority,
684 sizeof(SID_IDENTIFIER_AUTHORITY)) ==
685 sizeof(SID_IDENTIFIER_AUTHORITY))
686 {
687 PSiteSid = RtlAllocateHeap(RtlGetProcessHeap(),
688 0,
689 RtlLengthSid((RestrictedSids->
690 Groups[i]).Sid));
691 if (PSiteSid == NULL)
692 {
693 SetLastError(ERROR_OUTOFMEMORY);
694 }
695 else
696 {
697 RtlCopySid(RtlLengthSid(RestrictedSids->Groups[i].Sid),
698 PSiteSid,
699 RestrictedSids->Groups[i].Sid);
700 }
701
702 break;
703 }
704 }
705 }
706 else
707 {
708 SetLastError(RtlNtStatusToDosError(Status));
709 }
710
711 RtlFreeHeap(RtlGetProcessHeap(), 0, RestrictedSids);
712 return PSiteSid;
713 }
714
715
716 BOOL
717 WINAPI
718 CreateProcessWithTokenW(IN HANDLE hToken,
719 IN DWORD dwLogonFlags,
720 IN LPCWSTR lpApplicationName OPTIONAL,
721 IN OUT LPWSTR lpCommandLine OPTIONAL,
722 IN DWORD dwCreationFlags,
723 IN LPVOID lpEnvironment OPTIONAL,
724 IN LPCWSTR lpCurrentDirectory OPTIONAL,
725 IN LPSTARTUPINFOW lpStartupInfo,
726 OUT LPPROCESS_INFORMATION lpProcessInfo)
727 {
728 UNIMPLEMENTED;
729 return FALSE;
730 }