75ab43d21e6c26e92d0267307ddd186a886b207b
[reactos.git] / ntoskrnl / se / token.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/se/token.c
5 * PURPOSE: Security manager
6 *
7 * PROGRAMMERS: David Welch <welch@cwcom.net>
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 #if defined (ALLOC_PRAGMA)
17 #pragma alloc_text(INIT, SepInitializeTokenImplementation)
18 #endif
19
20 #include <ntlsa.h>
21
22 typedef struct _TOKEN_AUDIT_POLICY_INFORMATION
23 {
24 ULONG PolicyCount;
25 struct
26 {
27 ULONG Category;
28 UCHAR Value;
29 } Policies[1];
30 } TOKEN_AUDIT_POLICY_INFORMATION, *PTOKEN_AUDIT_POLICY_INFORMATION;
31
32 /* GLOBALS ********************************************************************/
33
34 POBJECT_TYPE SeTokenObjectType = NULL;
35 ERESOURCE SepTokenLock;
36
37 TOKEN_SOURCE SeSystemTokenSource = {"*SYSTEM*", {0}};
38 LUID SeSystemAuthenticationId = SYSTEM_LUID;
39 LUID SeAnonymousAuthenticationId = ANONYMOUS_LOGON_LUID;
40
41 static GENERIC_MAPPING SepTokenMapping = {
42 TOKEN_READ,
43 TOKEN_WRITE,
44 TOKEN_EXECUTE,
45 TOKEN_ALL_ACCESS
46 };
47
48 static const INFORMATION_CLASS_INFO SeTokenInformationClass[] = {
49
50 /* Class 0 not used, blame MS! */
51 ICI_SQ_SAME( 0, 0, 0),
52
53 /* TokenUser */
54 ICI_SQ_SAME( sizeof(TOKEN_USER), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ),
55 /* TokenGroups */
56 ICI_SQ_SAME( sizeof(TOKEN_GROUPS), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ),
57 /* TokenPrivileges */
58 ICI_SQ_SAME( sizeof(TOKEN_PRIVILEGES), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ),
59 /* TokenOwner */
60 ICI_SQ_SAME( sizeof(TOKEN_OWNER), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET | ICIF_SET_SIZE_VARIABLE ),
61 /* TokenPrimaryGroup */
62 ICI_SQ_SAME( sizeof(TOKEN_PRIMARY_GROUP), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET | ICIF_SET_SIZE_VARIABLE ),
63 /* TokenDefaultDacl */
64 ICI_SQ_SAME( sizeof(TOKEN_DEFAULT_DACL), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET | ICIF_SET_SIZE_VARIABLE ),
65 /* TokenSource */
66 ICI_SQ_SAME( sizeof(TOKEN_SOURCE), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ),
67 /* TokenType */
68 ICI_SQ_SAME( sizeof(TOKEN_TYPE), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
69 /* TokenImpersonationLevel */
70 ICI_SQ_SAME( sizeof(SECURITY_IMPERSONATION_LEVEL), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
71 /* TokenStatistics */
72 ICI_SQ_SAME( sizeof(TOKEN_STATISTICS), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ),
73 /* TokenRestrictedSids */
74 ICI_SQ_SAME( sizeof(TOKEN_GROUPS), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
75 /* TokenSessionId */
76 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY | ICIF_SET ),
77 /* TokenGroupsAndPrivileges */
78 ICI_SQ_SAME( sizeof(TOKEN_GROUPS_AND_PRIVILEGES), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
79 /* TokenSessionReference */
80 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_SET | ICIF_QUERY_SIZE_VARIABLE ),
81 /* TokenSandBoxInert */
82 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
83 /* TokenAuditPolicy */
84 ICI_SQ_SAME( /* FIXME */0, sizeof(ULONG), ICIF_QUERY | ICIF_SET | ICIF_QUERY_SIZE_VARIABLE ),
85 /* TokenOrigin */
86 ICI_SQ_SAME( sizeof(TOKEN_ORIGIN), sizeof(ULONG), ICIF_QUERY | ICIF_SET | ICIF_QUERY_SIZE_VARIABLE ),
87 };
88
89 /* FUNCTIONS *****************************************************************/
90
91 static NTSTATUS
92 SepCompareTokens(IN PTOKEN FirstToken,
93 IN PTOKEN SecondToken,
94 OUT PBOOLEAN Equal)
95 {
96 BOOLEAN Restricted, IsEqual = FALSE;
97
98 ASSERT(FirstToken != SecondToken);
99
100 /* FIXME: Check if every SID that is present in either token is also present in the other one */
101
102 Restricted = SeTokenIsRestricted(FirstToken);
103 if (Restricted == SeTokenIsRestricted(SecondToken))
104 {
105 if (Restricted)
106 {
107 /* FIXME: Check if every SID that is restricted in either token is also restricted in the other one */
108 }
109
110 /* FIXME: Check if every privilege that is present in either token is also present in the other one */
111 DPRINT1("FIXME: Pretending tokens are equal!\n");
112 IsEqual = TRUE;
113 }
114
115 *Equal = IsEqual;
116 return STATUS_SUCCESS;
117 }
118
119 static
120 VOID
121 SepUpdateSinglePrivilegeFlagToken(
122 _Inout_ PTOKEN Token,
123 _In_ ULONG Index)
124 {
125 ULONG TokenFlag;
126 ASSERT(Index < Token->PrivilegeCount);
127
128 /* The high part of all values we are interested in is 0 */
129 if (Token->Privileges[Index].Luid.HighPart != 0)
130 {
131 return;
132 }
133
134 /* Check for certain privileges to update flags */
135 if (Token->Privileges[Index].Luid.LowPart == SE_CHANGE_NOTIFY_PRIVILEGE)
136 {
137 TokenFlag = TOKEN_HAS_TRAVERSE_PRIVILEGE;
138 }
139 else if (Token->Privileges[Index].Luid.LowPart == SE_BACKUP_PRIVILEGE)
140 {
141 TokenFlag = TOKEN_HAS_BACKUP_PRIVILEGE;
142 }
143 else if (Token->Privileges[Index].Luid.LowPart == SE_RESTORE_PRIVILEGE)
144 {
145 TokenFlag = TOKEN_HAS_RESTORE_PRIVILEGE;
146 }
147 else if (Token->Privileges[Index].Luid.LowPart == SE_IMPERSONATE_PRIVILEGE)
148 {
149 TokenFlag = TOKEN_HAS_IMPERSONATE_PRIVILEGE;
150 }
151 else
152 {
153 /* Nothing to do */
154 return;
155 }
156
157 /* Check if the specified privilege is enabled */
158 if (Token->Privileges[Index].Attributes & SE_PRIVILEGE_ENABLED)
159 {
160 /* It is enabled, so set the flag */
161 Token->TokenFlags |= TokenFlag;
162 }
163 else
164 {
165 /* Is is disabled, so remove the flag */
166 Token->TokenFlags &= ~TokenFlag;
167 }
168 }
169
170 static
171 VOID
172 SepUpdatePrivilegeFlagsToken(
173 _Inout_ PTOKEN Token)
174 {
175 ULONG i;
176
177 /* Loop all privileges */
178 for (i = 0; i < Token->PrivilegeCount; i++)
179 {
180 /* Updates the flags dor this privilege */
181 SepUpdateSinglePrivilegeFlagToken(Token, i);
182 }
183 }
184
185 static
186 VOID
187 SepRemovePrivilegeToken(
188 _Inout_ PTOKEN Token,
189 _In_ ULONG Index)
190 {
191 ULONG MoveCount;
192 ASSERT(Index < Token->PrivilegeCount);
193
194 /* Calculate the number of trailing privileges */
195 MoveCount = Token->PrivilegeCount - Index - 1;
196 if (MoveCount != 0)
197 {
198 /* Move them one location ahead */
199 RtlMoveMemory(&Token->Privileges[Index],
200 &Token->Privileges[Index + 1],
201 MoveCount * sizeof(LUID_AND_ATTRIBUTES));
202 }
203
204 /* Update privilege count */
205 Token->PrivilegeCount--;
206 }
207
208 VOID
209 NTAPI
210 SepFreeProxyData(PVOID ProxyData)
211 {
212 UNIMPLEMENTED;
213 }
214
215 NTSTATUS
216 NTAPI
217 SepCopyProxyData(PVOID* Dest,
218 PVOID Src)
219 {
220 UNIMPLEMENTED;
221 return STATUS_NOT_IMPLEMENTED;
222 }
223
224 NTSTATUS
225 NTAPI
226 SeExchangePrimaryToken(PEPROCESS Process,
227 PACCESS_TOKEN NewTokenP,
228 PACCESS_TOKEN* OldTokenP)
229 {
230 PTOKEN OldToken;
231 PTOKEN NewToken = (PTOKEN)NewTokenP;
232
233 PAGED_CODE();
234
235 if (NewToken->TokenType != TokenPrimary) return STATUS_BAD_TOKEN_TYPE;
236 if (NewToken->TokenInUse)
237 {
238 BOOLEAN IsEqual;
239 NTSTATUS Status;
240
241 /* Maybe we're trying to set the same token */
242 OldToken = PsReferencePrimaryToken(Process);
243 if (OldToken == NewToken)
244 {
245 /* So it's a nop. */
246 *OldTokenP = OldToken;
247 return STATUS_SUCCESS;
248 }
249
250 Status = SepCompareTokens(OldToken, NewToken, &IsEqual);
251 if (!NT_SUCCESS(Status))
252 {
253 *OldTokenP = NULL;
254 PsDereferencePrimaryToken(OldToken);
255 return Status;
256 }
257
258 if (!IsEqual)
259 {
260 *OldTokenP = NULL;
261 PsDereferencePrimaryToken(OldToken);
262 return STATUS_TOKEN_ALREADY_IN_USE;
263 }
264 /* Silently return STATUS_SUCCESS but do not set the new token,
265 * as it's already in use elsewhere. */
266 *OldTokenP = OldToken;
267 return STATUS_SUCCESS;
268 }
269
270 /* Mark new token in use */
271 NewToken->TokenInUse = TRUE;
272
273 /* Reference the New Token */
274 ObReferenceObject(NewToken);
275
276 /* Replace the old with the new */
277 OldToken = ObFastReplaceObject(&Process->Token, NewToken);
278
279 /* Mark the Old Token as free */
280 OldToken->TokenInUse = FALSE;
281
282 *OldTokenP = (PACCESS_TOKEN)OldToken;
283 return STATUS_SUCCESS;
284 }
285
286 VOID
287 NTAPI
288 SeDeassignPrimaryToken(PEPROCESS Process)
289 {
290 PTOKEN OldToken;
291
292 /* Remove the Token */
293 OldToken = ObFastReplaceObject(&Process->Token, NULL);
294
295 /* Mark the Old Token as free */
296 OldToken->TokenInUse = FALSE;
297
298 /* Dereference the Token */
299 ObDereferenceObject(OldToken);
300 }
301
302 static ULONG
303 RtlLengthSidAndAttributes(ULONG Count,
304 PSID_AND_ATTRIBUTES Src)
305 {
306 ULONG i;
307 ULONG uLength;
308
309 PAGED_CODE();
310
311 uLength = Count * sizeof(SID_AND_ATTRIBUTES);
312 for (i = 0; i < Count; i++)
313 uLength += RtlLengthSid(Src[i].Sid);
314
315 return uLength;
316 }
317
318
319 NTSTATUS
320 NTAPI
321 SepFindPrimaryGroupAndDefaultOwner(PTOKEN Token,
322 PSID PrimaryGroup,
323 PSID DefaultOwner)
324 {
325 ULONG i;
326
327 Token->PrimaryGroup = NULL;
328
329 if (DefaultOwner)
330 {
331 Token->DefaultOwnerIndex = Token->UserAndGroupCount;
332 }
333
334 /* Validate and set the primary group and user pointers */
335 for (i = 0; i < Token->UserAndGroupCount; i++)
336 {
337 if (DefaultOwner &&
338 RtlEqualSid(Token->UserAndGroups[i].Sid, DefaultOwner))
339 {
340 Token->DefaultOwnerIndex = i;
341 }
342
343 if (RtlEqualSid(Token->UserAndGroups[i].Sid, PrimaryGroup))
344 {
345 Token->PrimaryGroup = Token->UserAndGroups[i].Sid;
346 }
347 }
348
349 if (Token->DefaultOwnerIndex == Token->UserAndGroupCount)
350 {
351 return STATUS_INVALID_OWNER;
352 }
353
354 if (Token->PrimaryGroup == NULL)
355 {
356 return STATUS_INVALID_PRIMARY_GROUP;
357 }
358
359 return STATUS_SUCCESS;
360 }
361
362
363 NTSTATUS
364 NTAPI
365 SepDuplicateToken(
366 _In_ PTOKEN Token,
367 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
368 _In_ BOOLEAN EffectiveOnly,
369 _In_ TOKEN_TYPE TokenType,
370 _In_ SECURITY_IMPERSONATION_LEVEL Level,
371 _In_ KPROCESSOR_MODE PreviousMode,
372 _Out_ PTOKEN* NewAccessToken)
373 {
374 ULONG uLength;
375 ULONG i;
376 PVOID EndMem;
377 PTOKEN AccessToken;
378 NTSTATUS Status;
379
380 PAGED_CODE();
381
382 Status = ObCreateObject(PreviousMode,
383 SeTokenObjectType,
384 ObjectAttributes,
385 PreviousMode,
386 NULL,
387 sizeof(TOKEN),
388 0,
389 0,
390 (PVOID*)&AccessToken);
391 if (!NT_SUCCESS(Status))
392 {
393 DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status);
394 return Status;
395 }
396
397 /* Zero out the buffer */
398 RtlZeroMemory(AccessToken, sizeof(TOKEN));
399
400 ExAllocateLocallyUniqueId(&AccessToken->TokenId);
401
402 AccessToken->TokenLock = &SepTokenLock;
403
404 /* Copy and reference the logon session */
405 RtlCopyLuid(&AccessToken->AuthenticationId, &Token->AuthenticationId);
406 SepRmReferenceLogonSession(&AccessToken->AuthenticationId);
407
408 AccessToken->TokenType = TokenType;
409 AccessToken->ImpersonationLevel = Level;
410 RtlCopyLuid(&AccessToken->ModifiedId, &Token->ModifiedId);
411
412 AccessToken->TokenSource.SourceIdentifier.LowPart = Token->TokenSource.SourceIdentifier.LowPart;
413 AccessToken->TokenSource.SourceIdentifier.HighPart = Token->TokenSource.SourceIdentifier.HighPart;
414 memcpy(AccessToken->TokenSource.SourceName,
415 Token->TokenSource.SourceName,
416 sizeof(Token->TokenSource.SourceName));
417 AccessToken->ExpirationTime.QuadPart = Token->ExpirationTime.QuadPart;
418 AccessToken->UserAndGroupCount = Token->UserAndGroupCount;
419 AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex;
420
421 uLength = sizeof(SID_AND_ATTRIBUTES) * AccessToken->UserAndGroupCount;
422 for (i = 0; i < Token->UserAndGroupCount; i++)
423 uLength += RtlLengthSid(Token->UserAndGroups[i].Sid);
424
425 AccessToken->UserAndGroups = ExAllocatePoolWithTag(PagedPool,
426 uLength,
427 TAG_TOKEN_USERS);
428 if (AccessToken->UserAndGroups == NULL)
429 {
430 Status = STATUS_INSUFFICIENT_RESOURCES;
431 goto done;
432 }
433
434 EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
435
436 Status = RtlCopySidAndAttributesArray(AccessToken->UserAndGroupCount,
437 Token->UserAndGroups,
438 uLength,
439 AccessToken->UserAndGroups,
440 EndMem,
441 &EndMem,
442 &uLength);
443 if (!NT_SUCCESS(Status))
444 goto done;
445
446 Status = SepFindPrimaryGroupAndDefaultOwner(AccessToken,
447 Token->PrimaryGroup,
448 0);
449 if (!NT_SUCCESS(Status))
450 goto done;
451
452 AccessToken->PrivilegeCount = Token->PrivilegeCount;
453
454 uLength = AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
455 AccessToken->Privileges = ExAllocatePoolWithTag(PagedPool,
456 uLength,
457 TAG_TOKEN_PRIVILAGES);
458 if (AccessToken->Privileges == NULL)
459 {
460 Status = STATUS_INSUFFICIENT_RESOURCES;
461 goto done;
462 }
463
464 for (i = 0; i < AccessToken->PrivilegeCount; i++)
465 {
466 RtlCopyLuid(&AccessToken->Privileges[i].Luid,
467 &Token->Privileges[i].Luid);
468 AccessToken->Privileges[i].Attributes =
469 Token->Privileges[i].Attributes;
470 }
471
472 if (Token->DefaultDacl)
473 {
474 AccessToken->DefaultDacl = ExAllocatePoolWithTag(PagedPool,
475 Token->DefaultDacl->AclSize,
476 TAG_TOKEN_ACL);
477 if (AccessToken->DefaultDacl == NULL)
478 {
479 Status = STATUS_INSUFFICIENT_RESOURCES;
480 goto done;
481 }
482
483 memcpy(AccessToken->DefaultDacl,
484 Token->DefaultDacl,
485 Token->DefaultDacl->AclSize);
486 }
487
488 *NewAccessToken = AccessToken;
489
490 done:
491 if (!NT_SUCCESS(Status))
492 {
493 /* Dereference the token, the delete procedure will clean up */
494 ObDereferenceObject(AccessToken);
495 }
496
497 return Status;
498 }
499
500 NTSTATUS
501 NTAPI
502 SeSubProcessToken(IN PTOKEN ParentToken,
503 OUT PTOKEN *Token,
504 IN BOOLEAN InUse,
505 IN ULONG SessionId)
506 {
507 PTOKEN NewToken;
508 OBJECT_ATTRIBUTES ObjectAttributes;
509 NTSTATUS Status;
510
511 /* Initialize the attributes and duplicate it */
512 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
513 Status = SepDuplicateToken(ParentToken,
514 &ObjectAttributes,
515 FALSE,
516 TokenPrimary,
517 ParentToken->ImpersonationLevel,
518 KernelMode,
519 &NewToken);
520 if (NT_SUCCESS(Status))
521 {
522 /* Insert it */
523 Status = ObInsertObject(NewToken,
524 NULL,
525 0,
526 0,
527 NULL,
528 NULL);
529 if (NT_SUCCESS(Status))
530 {
531 /* Set the session ID */
532 NewToken->SessionId = SessionId;
533 NewToken->TokenInUse = InUse;
534
535 /* Return the token */
536 *Token = NewToken;
537 }
538 }
539
540 /* Return status */
541 return Status;
542 }
543
544 NTSTATUS
545 NTAPI
546 SeIsTokenChild(IN PTOKEN Token,
547 OUT PBOOLEAN IsChild)
548 {
549 PTOKEN ProcessToken;
550 LUID ProcessLuid, CallerLuid;
551
552 /* Assume failure */
553 *IsChild = FALSE;
554
555 /* Reference the process token */
556 ProcessToken = PsReferencePrimaryToken(PsGetCurrentProcess());
557
558 /* Get the ID */
559 ProcessLuid = ProcessToken->AuthenticationId;
560
561 /* Dereference the token */
562 ObFastDereferenceObject(&PsGetCurrentProcess()->Token, ProcessToken);
563
564 /* Get our LUID */
565 CallerLuid = Token->AuthenticationId;
566
567 /* Compare the LUIDs */
568 if (RtlEqualLuid(&CallerLuid, &ProcessLuid)) *IsChild = TRUE;
569
570 /* Return success */
571 return STATUS_SUCCESS;
572 }
573
574 NTSTATUS
575 NTAPI
576 SeCopyClientToken(IN PACCESS_TOKEN Token,
577 IN SECURITY_IMPERSONATION_LEVEL Level,
578 IN KPROCESSOR_MODE PreviousMode,
579 OUT PACCESS_TOKEN* NewToken)
580 {
581 NTSTATUS Status;
582 OBJECT_ATTRIBUTES ObjectAttributes;
583
584 PAGED_CODE();
585
586 InitializeObjectAttributes(&ObjectAttributes,
587 NULL,
588 0,
589 NULL,
590 NULL);
591
592 Status = SepDuplicateToken(Token,
593 &ObjectAttributes,
594 FALSE,
595 TokenImpersonation,
596 Level,
597 PreviousMode,
598 (PTOKEN*)NewToken);
599
600 return Status;
601 }
602
603 VOID
604 NTAPI
605 SepDeleteToken(PVOID ObjectBody)
606 {
607 PTOKEN AccessToken = (PTOKEN)ObjectBody;
608
609 DPRINT("SepDeleteToken()\n");
610
611 /* Dereference the logon session */
612 SepRmDereferenceLogonSession(&AccessToken->AuthenticationId);
613
614 if (AccessToken->UserAndGroups)
615 ExFreePoolWithTag(AccessToken->UserAndGroups, TAG_TOKEN_USERS);
616
617 if (AccessToken->Privileges)
618 ExFreePoolWithTag(AccessToken->Privileges, TAG_TOKEN_PRIVILAGES);
619
620 if (AccessToken->DefaultDacl)
621 ExFreePoolWithTag(AccessToken->DefaultDacl, TAG_TOKEN_ACL);
622 }
623
624
625 VOID
626 INIT_FUNCTION
627 NTAPI
628 SepInitializeTokenImplementation(VOID)
629 {
630 UNICODE_STRING Name;
631 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
632
633 ExInitializeResource(&SepTokenLock);
634
635 DPRINT("Creating Token Object Type\n");
636
637 /* Initialize the Token type */
638 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
639 RtlInitUnicodeString(&Name, L"Token");
640 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
641 ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
642 ObjectTypeInitializer.SecurityRequired = TRUE;
643 ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(TOKEN);
644 ObjectTypeInitializer.GenericMapping = SepTokenMapping;
645 ObjectTypeInitializer.PoolType = PagedPool;
646 ObjectTypeInitializer.ValidAccessMask = TOKEN_ALL_ACCESS;
647 ObjectTypeInitializer.UseDefaultObject = TRUE;
648 ObjectTypeInitializer.DeleteProcedure = SepDeleteToken;
649 ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &SeTokenObjectType);
650 }
651
652 VOID
653 NTAPI
654 SeAssignPrimaryToken(IN PEPROCESS Process,
655 IN PTOKEN Token)
656 {
657 PAGED_CODE();
658
659 /* Sanity checks */
660 ASSERT(Token->TokenType == TokenPrimary);
661 ASSERT(!Token->TokenInUse);
662
663 /* Clean any previous token */
664 if (Process->Token.Object) SeDeassignPrimaryToken(Process);
665
666 /* Set the new token */
667 ObReferenceObject(Token);
668 Token->TokenInUse = TRUE;
669 ObInitializeFastReference(&Process->Token, Token);
670 }
671
672 NTSTATUS
673 NTAPI
674 SepCreateToken(
675 _Out_ PHANDLE TokenHandle,
676 _In_ KPROCESSOR_MODE PreviousMode,
677 _In_ ACCESS_MASK DesiredAccess,
678 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
679 _In_ TOKEN_TYPE TokenType,
680 _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
681 _In_ PLUID AuthenticationId,
682 _In_ PLARGE_INTEGER ExpirationTime,
683 _In_ PSID_AND_ATTRIBUTES User,
684 _In_ ULONG GroupCount,
685 _In_ PSID_AND_ATTRIBUTES Groups,
686 _In_ ULONG GroupsLength,
687 _In_ ULONG PrivilegeCount,
688 _In_ PLUID_AND_ATTRIBUTES Privileges,
689 _In_opt_ PSID Owner,
690 _In_ PSID PrimaryGroup,
691 _In_opt_ PACL DefaultDacl,
692 _In_ PTOKEN_SOURCE TokenSource,
693 _In_ BOOLEAN SystemToken)
694 {
695 PTOKEN AccessToken;
696 LUID TokenId;
697 LUID ModifiedId;
698 PVOID EndMem;
699 ULONG uLength;
700 ULONG i;
701 NTSTATUS Status;
702 ULONG TokenFlags = 0;
703
704 PAGED_CODE();
705
706 /* Loop all groups */
707 for (i = 0; i < GroupCount; i++)
708 {
709 /* Check for mandatory groups */
710 if (Groups[i].Attributes & SE_GROUP_MANDATORY)
711 {
712 /* Force them to be enabled */
713 Groups[i].Attributes |= (SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT);
714 }
715
716 /* Check of the group is an admin group */
717 if (RtlEqualSid(SeAliasAdminsSid, Groups[i].Sid))
718 {
719 /* Remember this so we can optimize queries later */
720 TokenFlags |= TOKEN_HAS_ADMIN_GROUP;
721 }
722 }
723
724 ExAllocateLocallyUniqueId(&TokenId);
725 ExAllocateLocallyUniqueId(&ModifiedId);
726
727 Status = ObCreateObject(PreviousMode,
728 SeTokenObjectType,
729 ObjectAttributes,
730 PreviousMode,
731 NULL,
732 sizeof(TOKEN),
733 0,
734 0,
735 (PVOID*)&AccessToken);
736 if (!NT_SUCCESS(Status))
737 {
738 DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status);
739 return Status;
740 }
741
742 /* Zero out the buffer */
743 RtlZeroMemory(AccessToken, sizeof(TOKEN));
744
745 AccessToken->TokenLock = &SepTokenLock;
746
747 RtlCopyLuid(&AccessToken->TokenSource.SourceIdentifier,
748 &TokenSource->SourceIdentifier);
749 memcpy(AccessToken->TokenSource.SourceName,
750 TokenSource->SourceName,
751 sizeof(TokenSource->SourceName));
752
753 /* Copy and reference the logon session */
754 RtlCopyLuid(&AccessToken->AuthenticationId, AuthenticationId);
755 SepRmReferenceLogonSession(&AccessToken->AuthenticationId);
756
757 RtlCopyLuid(&AccessToken->TokenId, &TokenId);
758 AccessToken->ExpirationTime = *ExpirationTime;
759 RtlCopyLuid(&AccessToken->ModifiedId, &ModifiedId);
760
761 AccessToken->UserAndGroupCount = GroupCount + 1;
762 AccessToken->PrivilegeCount = PrivilegeCount;
763
764 AccessToken->TokenFlags = TokenFlags;
765 AccessToken->TokenType = TokenType;
766 AccessToken->ImpersonationLevel = ImpersonationLevel;
767
768 /*
769 * Normally we would just point these members into the variable information
770 * area; however, our ObCreateObject() call can't allocate a variable information
771 * area, so we allocate them seperately and provide a destroy function.
772 */
773
774 uLength = sizeof(SID_AND_ATTRIBUTES) * AccessToken->UserAndGroupCount;
775 uLength += RtlLengthSid(User->Sid);
776 for (i = 0; i < GroupCount; i++)
777 uLength += RtlLengthSid(Groups[i].Sid);
778
779 // FIXME: should use the object itself
780 AccessToken->UserAndGroups = ExAllocatePoolWithTag(PagedPool,
781 uLength,
782 TAG_TOKEN_USERS);
783 if (AccessToken->UserAndGroups == NULL)
784 {
785 Status = STATUS_INSUFFICIENT_RESOURCES;
786 goto done;
787 }
788
789 EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
790
791 Status = RtlCopySidAndAttributesArray(1,
792 User,
793 uLength,
794 AccessToken->UserAndGroups,
795 EndMem,
796 &EndMem,
797 &uLength);
798 if (!NT_SUCCESS(Status))
799 goto done;
800
801 Status = RtlCopySidAndAttributesArray(GroupCount,
802 Groups,
803 uLength,
804 &AccessToken->UserAndGroups[1],
805 EndMem,
806 &EndMem,
807 &uLength);
808 if (!NT_SUCCESS(Status))
809 goto done;
810
811 Status = SepFindPrimaryGroupAndDefaultOwner(AccessToken,
812 PrimaryGroup,
813 Owner);
814 if (!NT_SUCCESS(Status))
815 goto done;
816
817 // FIXME: should use the object itself
818 uLength = PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
819 if (uLength == 0) uLength = sizeof(PVOID);
820 AccessToken->Privileges = ExAllocatePoolWithTag(PagedPool,
821 uLength,
822 TAG_TOKEN_PRIVILAGES);
823 if (AccessToken->Privileges == NULL)
824 {
825 Status = STATUS_INSUFFICIENT_RESOURCES;
826 goto done;
827 }
828
829 if (PreviousMode != KernelMode)
830 {
831 _SEH2_TRY
832 {
833 RtlCopyMemory(AccessToken->Privileges,
834 Privileges,
835 PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
836 }
837 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
838 {
839 Status = _SEH2_GetExceptionCode();
840 }
841 _SEH2_END;
842 }
843 else
844 {
845 RtlCopyMemory(AccessToken->Privileges,
846 Privileges,
847 PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
848 }
849
850 if (!NT_SUCCESS(Status))
851 goto done;
852
853 /* Update privilege flags */
854 SepUpdatePrivilegeFlagsToken(AccessToken);
855
856 if (DefaultDacl != NULL)
857 {
858 // FIXME: should use the object itself
859 AccessToken->DefaultDacl = ExAllocatePoolWithTag(PagedPool,
860 DefaultDacl->AclSize,
861 TAG_TOKEN_ACL);
862 if (AccessToken->DefaultDacl == NULL)
863 {
864 Status = STATUS_INSUFFICIENT_RESOURCES;
865 goto done;
866 }
867
868 RtlCopyMemory(AccessToken->DefaultDacl,
869 DefaultDacl,
870 DefaultDacl->AclSize);
871 }
872 else
873 {
874 AccessToken->DefaultDacl = NULL;
875 }
876
877 if (!SystemToken)
878 {
879 Status = ObInsertObject(AccessToken,
880 NULL,
881 DesiredAccess,
882 0,
883 NULL,
884 TokenHandle);
885 if (!NT_SUCCESS(Status))
886 {
887 DPRINT1("ObInsertObject() failed (Status 0x%lx)\n", Status);
888 }
889 }
890 else
891 {
892 /* Return pointer instead of handle */
893 *TokenHandle = (HANDLE)AccessToken;
894 }
895
896 done:
897 if (!NT_SUCCESS(Status))
898 {
899 /* Dereference the token, the delete procedure will clean up */
900 ObDereferenceObject(AccessToken);
901 }
902
903 return Status;
904 }
905
906 PTOKEN
907 NTAPI
908 SepCreateSystemProcessToken(VOID)
909 {
910 LUID_AND_ATTRIBUTES Privileges[25];
911 ULONG GroupAttributes, OwnerAttributes;
912 SID_AND_ATTRIBUTES Groups[32];
913 LARGE_INTEGER Expiration;
914 SID_AND_ATTRIBUTES UserSid;
915 ULONG GroupsLength;
916 PSID PrimaryGroup;
917 OBJECT_ATTRIBUTES ObjectAttributes;
918 PSID Owner;
919 ULONG i;
920 PTOKEN Token;
921 NTSTATUS Status;
922
923 /* Don't ever expire */
924 Expiration.QuadPart = -1;
925
926 /* All groups mandatory and enabled */
927 GroupAttributes = SE_GROUP_ENABLED | SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT;
928 OwnerAttributes = SE_GROUP_ENABLED | SE_GROUP_OWNER | SE_GROUP_ENABLED_BY_DEFAULT;
929
930 /* User is system */
931 UserSid.Sid = SeLocalSystemSid;
932 UserSid.Attributes = 0;
933
934 /* Primary group is local system */
935 PrimaryGroup = SeLocalSystemSid;
936
937 /* Owner is admins */
938 Owner = SeAliasAdminsSid;
939
940 /* Groups are admins, world, and authenticated users */
941 Groups[0].Sid = SeAliasAdminsSid;
942 Groups[0].Attributes = OwnerAttributes;
943 Groups[1].Sid = SeWorldSid;
944 Groups[1].Attributes = GroupAttributes;
945 Groups[2].Sid = SeAuthenticatedUserSid;
946 Groups[2].Attributes = OwnerAttributes;
947 GroupsLength = sizeof(SID_AND_ATTRIBUTES) +
948 SeLengthSid(Groups[0].Sid) +
949 SeLengthSid(Groups[1].Sid) +
950 SeLengthSid(Groups[2].Sid);
951 ASSERT(GroupsLength <= sizeof(Groups));
952
953 /* Setup the privileges */
954 i = 0;
955 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
956 Privileges[i++].Luid = SeTcbPrivilege;
957
958 Privileges[i].Attributes = 0;
959 Privileges[i++].Luid = SeCreateTokenPrivilege;
960
961 Privileges[i].Attributes = 0;
962 Privileges[i++].Luid = SeTakeOwnershipPrivilege;
963
964 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
965 Privileges[i++].Luid = SeCreatePagefilePrivilege;
966
967 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
968 Privileges[i++].Luid = SeLockMemoryPrivilege;
969
970 Privileges[i].Attributes = 0;
971 Privileges[i++].Luid = SeAssignPrimaryTokenPrivilege;
972
973 Privileges[i].Attributes = 0;
974 Privileges[i++].Luid = SeIncreaseQuotaPrivilege;
975
976 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
977 Privileges[i++].Luid = SeIncreaseBasePriorityPrivilege;
978
979 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
980 Privileges[i++].Luid = SeCreatePermanentPrivilege;
981
982 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
983 Privileges[i++].Luid = SeDebugPrivilege;
984
985 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
986 Privileges[i++].Luid = SeAuditPrivilege;
987
988 Privileges[i].Attributes = 0;
989 Privileges[i++].Luid = SeSecurityPrivilege;
990
991 Privileges[i].Attributes = 0;
992 Privileges[i++].Luid = SeSystemEnvironmentPrivilege;
993
994 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
995 Privileges[i++].Luid = SeChangeNotifyPrivilege;
996
997 Privileges[i].Attributes = 0;
998 Privileges[i++].Luid = SeBackupPrivilege;
999
1000 Privileges[i].Attributes = 0;
1001 Privileges[i++].Luid = SeRestorePrivilege;
1002
1003 Privileges[i].Attributes = 0;
1004 Privileges[i++].Luid = SeShutdownPrivilege;
1005
1006 Privileges[i].Attributes = 0;
1007 Privileges[i++].Luid = SeLoadDriverPrivilege;
1008
1009 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
1010 Privileges[i++].Luid = SeProfileSingleProcessPrivilege;
1011
1012 Privileges[i].Attributes = 0;
1013 Privileges[i++].Luid = SeSystemtimePrivilege;
1014 ASSERT(i == 20);
1015
1016 /* Setup the object attributes */
1017 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
1018 ASSERT(SeSystemDefaultDacl != NULL);
1019
1020 /* Create the token */
1021 Status = SepCreateToken((PHANDLE)&Token,
1022 KernelMode,
1023 0,
1024 &ObjectAttributes,
1025 TokenPrimary,
1026 0,
1027 &SeSystemAuthenticationId,
1028 &Expiration,
1029 &UserSid,
1030 3,
1031 Groups,
1032 GroupsLength,
1033 20,
1034 Privileges,
1035 Owner,
1036 PrimaryGroup,
1037 SeSystemDefaultDacl,
1038 &SeSystemTokenSource,
1039 TRUE);
1040 ASSERT(Status == STATUS_SUCCESS);
1041
1042 /* Return the token */
1043 return Token;
1044 }
1045
1046 /* PUBLIC FUNCTIONS ***********************************************************/
1047
1048 /*
1049 * @unimplemented
1050 */
1051 NTSTATUS
1052 NTAPI
1053 SeFilterToken(IN PACCESS_TOKEN ExistingToken,
1054 IN ULONG Flags,
1055 IN PTOKEN_GROUPS SidsToDisable OPTIONAL,
1056 IN PTOKEN_PRIVILEGES PrivilegesToDelete OPTIONAL,
1057 IN PTOKEN_GROUPS RestrictedSids OPTIONAL,
1058 OUT PACCESS_TOKEN * FilteredToken)
1059 {
1060 UNIMPLEMENTED;
1061 return STATUS_NOT_IMPLEMENTED;
1062 }
1063
1064 /*
1065 * @implemented
1066 *
1067 * NOTE: SeQueryInformationToken is just NtQueryInformationToken without all
1068 * the bells and whistles needed for user-mode buffer access protection.
1069 */
1070 NTSTATUS
1071 NTAPI
1072 SeQueryInformationToken(IN PACCESS_TOKEN AccessToken,
1073 IN TOKEN_INFORMATION_CLASS TokenInformationClass,
1074 OUT PVOID *TokenInformation)
1075 {
1076 NTSTATUS Status;
1077 PTOKEN Token = (PTOKEN)AccessToken;
1078 ULONG RequiredLength;
1079 union
1080 {
1081 PSID PSid;
1082 ULONG Ulong;
1083 } Unused;
1084
1085 PAGED_CODE();
1086
1087 if (TokenInformationClass >= MaxTokenInfoClass)
1088 {
1089 DPRINT1("SeQueryInformationToken(%d) invalid information class\n", TokenInformationClass);
1090 return STATUS_INVALID_INFO_CLASS;
1091 }
1092
1093 switch (TokenInformationClass)
1094 {
1095 case TokenUser:
1096 {
1097 PTOKEN_USER tu;
1098
1099 DPRINT("SeQueryInformationToken(TokenUser)\n");
1100 RequiredLength = sizeof(TOKEN_USER) +
1101 RtlLengthSid(Token->UserAndGroups[0].Sid);
1102
1103 /* Allocate the output buffer */
1104 tu = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
1105 if (tu == NULL)
1106 {
1107 Status = STATUS_INSUFFICIENT_RESOURCES;
1108 break;
1109 }
1110
1111 Status = RtlCopySidAndAttributesArray(1,
1112 &Token->UserAndGroups[0],
1113 RequiredLength - sizeof(TOKEN_USER),
1114 &tu->User,
1115 (PSID)(tu + 1),
1116 &Unused.PSid,
1117 &Unused.Ulong);
1118
1119 /* Return the structure */
1120 *TokenInformation = tu;
1121 Status = STATUS_SUCCESS;
1122 break;
1123 }
1124
1125 case TokenGroups:
1126 {
1127 PTOKEN_GROUPS tg;
1128 ULONG SidLen;
1129 PSID Sid;
1130
1131 DPRINT("SeQueryInformationToken(TokenGroups)\n");
1132 RequiredLength = sizeof(tg->GroupCount) +
1133 RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]);
1134
1135 SidLen = RequiredLength - sizeof(tg->GroupCount) -
1136 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES));
1137
1138 /* Allocate the output buffer */
1139 tg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
1140 if (tg == NULL)
1141 {
1142 Status = STATUS_INSUFFICIENT_RESOURCES;
1143 break;
1144 }
1145
1146 Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
1147 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES)));
1148
1149 tg->GroupCount = Token->UserAndGroupCount - 1;
1150 Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1,
1151 &Token->UserAndGroups[1],
1152 SidLen,
1153 &tg->Groups[0],
1154 Sid,
1155 &Unused.PSid,
1156 &Unused.Ulong);
1157
1158 /* Return the structure */
1159 *TokenInformation = tg;
1160 Status = STATUS_SUCCESS;
1161 break;
1162 }
1163
1164 case TokenPrivileges:
1165 {
1166 PTOKEN_PRIVILEGES tp;
1167
1168 DPRINT("SeQueryInformationToken(TokenPrivileges)\n");
1169 RequiredLength = sizeof(tp->PrivilegeCount) +
1170 (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
1171
1172 /* Allocate the output buffer */
1173 tp = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
1174 if (tp == NULL)
1175 {
1176 Status = STATUS_INSUFFICIENT_RESOURCES;
1177 break;
1178 }
1179
1180 tp->PrivilegeCount = Token->PrivilegeCount;
1181 RtlCopyLuidAndAttributesArray(Token->PrivilegeCount,
1182 Token->Privileges,
1183 &tp->Privileges[0]);
1184
1185 /* Return the structure */
1186 *TokenInformation = tp;
1187 Status = STATUS_SUCCESS;
1188 break;
1189 }
1190
1191 case TokenOwner:
1192 {
1193 PTOKEN_OWNER to;
1194 ULONG SidLen;
1195
1196 DPRINT("SeQueryInformationToken(TokenOwner)\n");
1197 SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
1198 RequiredLength = sizeof(TOKEN_OWNER) + SidLen;
1199
1200 /* Allocate the output buffer */
1201 to = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
1202 if (to == NULL)
1203 {
1204 Status = STATUS_INSUFFICIENT_RESOURCES;
1205 break;
1206 }
1207
1208 to->Owner = (PSID)(to + 1);
1209 Status = RtlCopySid(SidLen,
1210 to->Owner,
1211 Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
1212
1213 /* Return the structure */
1214 *TokenInformation = to;
1215 Status = STATUS_SUCCESS;
1216 break;
1217 }
1218
1219 case TokenPrimaryGroup:
1220 {
1221 PTOKEN_PRIMARY_GROUP tpg;
1222 ULONG SidLen;
1223
1224 DPRINT("SeQueryInformationToken(TokenPrimaryGroup)\n");
1225 SidLen = RtlLengthSid(Token->PrimaryGroup);
1226 RequiredLength = sizeof(TOKEN_PRIMARY_GROUP) + SidLen;
1227
1228 /* Allocate the output buffer */
1229 tpg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
1230 if (tpg == NULL)
1231 {
1232 Status = STATUS_INSUFFICIENT_RESOURCES;
1233 break;
1234 }
1235
1236 tpg->PrimaryGroup = (PSID)(tpg + 1);
1237 Status = RtlCopySid(SidLen,
1238 tpg->PrimaryGroup,
1239 Token->PrimaryGroup);
1240
1241 /* Return the structure */
1242 *TokenInformation = tpg;
1243 Status = STATUS_SUCCESS;
1244 break;
1245 }
1246
1247 case TokenDefaultDacl:
1248 {
1249 PTOKEN_DEFAULT_DACL tdd;
1250
1251 DPRINT("SeQueryInformationToken(TokenDefaultDacl)\n");
1252 RequiredLength = sizeof(TOKEN_DEFAULT_DACL);
1253
1254 if (Token->DefaultDacl != NULL)
1255 RequiredLength += Token->DefaultDacl->AclSize;
1256
1257 /* Allocate the output buffer */
1258 tdd = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
1259 if (tdd == NULL)
1260 {
1261 Status = STATUS_INSUFFICIENT_RESOURCES;
1262 break;
1263 }
1264
1265 if (Token->DefaultDacl != NULL)
1266 {
1267 tdd->DefaultDacl = (PACL)(tdd + 1);
1268 RtlCopyMemory(tdd->DefaultDacl,
1269 Token->DefaultDacl,
1270 Token->DefaultDacl->AclSize);
1271 }
1272 else
1273 {
1274 tdd->DefaultDacl = NULL;
1275 }
1276
1277 /* Return the structure */
1278 *TokenInformation = tdd;
1279 Status = STATUS_SUCCESS;
1280 break;
1281 }
1282
1283 case TokenSource:
1284 {
1285 PTOKEN_SOURCE ts;
1286
1287 DPRINT("SeQueryInformationToken(TokenSource)\n");
1288 RequiredLength = sizeof(TOKEN_SOURCE);
1289
1290 /* Allocate the output buffer */
1291 ts = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
1292 if (ts == NULL)
1293 {
1294 Status = STATUS_INSUFFICIENT_RESOURCES;
1295 break;
1296 }
1297
1298 *ts = Token->TokenSource;
1299
1300 /* Return the structure */
1301 *TokenInformation = ts;
1302 Status = STATUS_SUCCESS;
1303 break;
1304 }
1305
1306 case TokenType:
1307 {
1308 PTOKEN_TYPE tt;
1309
1310 DPRINT("SeQueryInformationToken(TokenType)\n");
1311 RequiredLength = sizeof(TOKEN_TYPE);
1312
1313 /* Allocate the output buffer */
1314 tt = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
1315 if (tt == NULL)
1316 {
1317 Status = STATUS_INSUFFICIENT_RESOURCES;
1318 break;
1319 }
1320
1321 *tt = Token->TokenType;
1322
1323 /* Return the structure */
1324 *TokenInformation = tt;
1325 Status = STATUS_SUCCESS;
1326 break;
1327 }
1328
1329 case TokenImpersonationLevel:
1330 {
1331 PSECURITY_IMPERSONATION_LEVEL sil;
1332
1333 DPRINT("SeQueryInformationToken(TokenImpersonationLevel)\n");
1334 RequiredLength = sizeof(SECURITY_IMPERSONATION_LEVEL);
1335
1336 /* Fail if the token is not an impersonation token */
1337 if (Token->TokenType != TokenImpersonation)
1338 {
1339 Status = STATUS_INVALID_INFO_CLASS;
1340 break;
1341 }
1342
1343 /* Allocate the output buffer */
1344 sil = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
1345 if (sil == NULL)
1346 {
1347 Status = STATUS_INSUFFICIENT_RESOURCES;
1348 break;
1349 }
1350
1351 *sil = Token->ImpersonationLevel;
1352
1353 /* Return the structure */
1354 *TokenInformation = sil;
1355 Status = STATUS_SUCCESS;
1356 break;
1357 }
1358
1359 case TokenStatistics:
1360 {
1361 PTOKEN_STATISTICS ts;
1362
1363 DPRINT("SeQueryInformationToken(TokenStatistics)\n");
1364 RequiredLength = sizeof(TOKEN_STATISTICS);
1365
1366 /* Allocate the output buffer */
1367 ts = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
1368 if (ts == NULL)
1369 {
1370 Status = STATUS_INSUFFICIENT_RESOURCES;
1371 break;
1372 }
1373
1374 ts->TokenId = Token->TokenId;
1375 ts->AuthenticationId = Token->AuthenticationId;
1376 ts->ExpirationTime = Token->ExpirationTime;
1377 ts->TokenType = Token->TokenType;
1378 ts->ImpersonationLevel = Token->ImpersonationLevel;
1379 ts->DynamicCharged = Token->DynamicCharged;
1380 ts->DynamicAvailable = Token->DynamicAvailable;
1381 ts->GroupCount = Token->UserAndGroupCount - 1;
1382 ts->PrivilegeCount = Token->PrivilegeCount;
1383 ts->ModifiedId = Token->ModifiedId;
1384
1385 /* Return the structure */
1386 *TokenInformation = ts;
1387 Status = STATUS_SUCCESS;
1388 break;
1389 }
1390
1391 /*
1392 * The following 4 cases are only implemented in NtQueryInformationToken
1393 */
1394 #if 0
1395
1396 case TokenOrigin:
1397 {
1398 PTOKEN_ORIGIN to;
1399
1400 DPRINT("SeQueryInformationToken(TokenOrigin)\n");
1401 RequiredLength = sizeof(TOKEN_ORIGIN);
1402
1403 /* Allocate the output buffer */
1404 to = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
1405 if (to == NULL)
1406 {
1407 Status = STATUS_INSUFFICIENT_RESOURCES;
1408 break;
1409 }
1410
1411 RtlCopyLuid(&to->OriginatingLogonSession,
1412 &Token->AuthenticationId);
1413
1414 /* Return the structure */
1415 *TokenInformation = to;
1416 Status = STATUS_SUCCESS;
1417 break;
1418 }
1419
1420 case TokenGroupsAndPrivileges:
1421 DPRINT1("SeQueryInformationToken(TokenGroupsAndPrivileges) not implemented\n");
1422 Status = STATUS_NOT_IMPLEMENTED;
1423 break;
1424
1425 case TokenRestrictedSids:
1426 {
1427 PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation;
1428 ULONG SidLen;
1429 PSID Sid;
1430
1431 DPRINT("SeQueryInformationToken(TokenRestrictedSids)\n");
1432 RequiredLength = sizeof(tg->GroupCount) +
1433 RtlLengthSidAndAttributes(Token->RestrictedSidCount, Token->RestrictedSids);
1434
1435 SidLen = RequiredLength - sizeof(tg->GroupCount) -
1436 (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES));
1437
1438 /* Allocate the output buffer */
1439 tg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
1440 if (tg == NULL)
1441 {
1442 Status = STATUS_INSUFFICIENT_RESOURCES;
1443 break;
1444 }
1445
1446 Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
1447 (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)));
1448
1449 tg->GroupCount = Token->RestrictedSidCount;
1450 Status = RtlCopySidAndAttributesArray(Token->RestrictedSidCount,
1451 Token->RestrictedSids,
1452 SidLen,
1453 &tg->Groups[0],
1454 Sid,
1455 &Unused.PSid,
1456 &Unused.Ulong);
1457
1458 /* Return the structure */
1459 *TokenInformation = tg;
1460 Status = STATUS_SUCCESS;
1461 break;
1462 }
1463
1464 case TokenSandBoxInert:
1465 DPRINT1("SeQueryInformationToken(TokenSandboxInert) not implemented\n");
1466 Status = STATUS_NOT_IMPLEMENTED;
1467 break;
1468
1469 #endif
1470
1471 case TokenSessionId:
1472 {
1473 DPRINT("SeQueryInformationToken(TokenSessionId)\n");
1474
1475 Status = SeQuerySessionIdToken(Token, (PULONG)TokenInformation);
1476
1477 // Status = STATUS_SUCCESS;
1478 break;
1479 }
1480
1481 default:
1482 DPRINT1("SeQueryInformationToken(%d) invalid information class\n", TokenInformationClass);
1483 Status = STATUS_INVALID_INFO_CLASS;
1484 break;
1485 }
1486
1487 return Status;
1488 }
1489
1490 /*
1491 * @implemented
1492 */
1493 NTSTATUS
1494 NTAPI
1495 SeQuerySessionIdToken(IN PACCESS_TOKEN Token,
1496 IN PULONG pSessionId)
1497 {
1498 *pSessionId = ((PTOKEN)Token)->SessionId;
1499 return STATUS_SUCCESS;
1500 }
1501
1502 /*
1503 * @implemented
1504 */
1505 NTSTATUS
1506 NTAPI
1507 SeQueryAuthenticationIdToken(IN PACCESS_TOKEN Token,
1508 OUT PLUID LogonId)
1509 {
1510 PAGED_CODE();
1511
1512 *LogonId = ((PTOKEN)Token)->AuthenticationId;
1513
1514 return STATUS_SUCCESS;
1515 }
1516
1517
1518 /*
1519 * @implemented
1520 */
1521 SECURITY_IMPERSONATION_LEVEL
1522 NTAPI
1523 SeTokenImpersonationLevel(IN PACCESS_TOKEN Token)
1524 {
1525 PAGED_CODE();
1526
1527 return ((PTOKEN)Token)->ImpersonationLevel;
1528 }
1529
1530
1531 /*
1532 * @implemented
1533 */
1534 TOKEN_TYPE NTAPI
1535 SeTokenType(IN PACCESS_TOKEN Token)
1536 {
1537 PAGED_CODE();
1538
1539 return ((PTOKEN)Token)->TokenType;
1540 }
1541
1542
1543 /*
1544 * @implemented
1545 */
1546 BOOLEAN
1547 NTAPI
1548 SeTokenIsAdmin(IN PACCESS_TOKEN Token)
1549 {
1550 PAGED_CODE();
1551
1552 return (((PTOKEN)Token)->TokenFlags & TOKEN_WRITE_RESTRICTED) != 0;
1553 }
1554
1555 /*
1556 * @implemented
1557 */
1558 BOOLEAN
1559 NTAPI
1560 SeTokenIsRestricted(IN PACCESS_TOKEN Token)
1561 {
1562 PAGED_CODE();
1563
1564 return (((PTOKEN)Token)->TokenFlags & TOKEN_IS_RESTRICTED) != 0;
1565 }
1566
1567 /*
1568 * @implemented
1569 */
1570 BOOLEAN
1571 NTAPI
1572 SeTokenIsWriteRestricted(IN PACCESS_TOKEN Token)
1573 {
1574 PAGED_CODE();
1575
1576 return (((PTOKEN)Token)->TokenFlags & TOKEN_HAS_RESTORE_PRIVILEGE) != 0;
1577 }
1578
1579 /* SYSTEM CALLS ***************************************************************/
1580
1581 /*
1582 * @implemented
1583 */
1584 NTSTATUS NTAPI
1585 NtQueryInformationToken(IN HANDLE TokenHandle,
1586 IN TOKEN_INFORMATION_CLASS TokenInformationClass,
1587 OUT PVOID TokenInformation,
1588 IN ULONG TokenInformationLength,
1589 OUT PULONG ReturnLength)
1590 {
1591 NTSTATUS Status;
1592 KPROCESSOR_MODE PreviousMode;
1593 PTOKEN Token;
1594 ULONG RequiredLength;
1595 union
1596 {
1597 PSID PSid;
1598 ULONG Ulong;
1599 } Unused;
1600
1601 PAGED_CODE();
1602
1603 PreviousMode = ExGetPreviousMode();
1604
1605 /* Check buffers and class validity */
1606 Status = DefaultQueryInfoBufferCheck(TokenInformationClass,
1607 SeTokenInformationClass,
1608 RTL_NUMBER_OF(SeTokenInformationClass),
1609 TokenInformation,
1610 TokenInformationLength,
1611 ReturnLength,
1612 NULL,
1613 PreviousMode);
1614 if (!NT_SUCCESS(Status))
1615 {
1616 DPRINT("NtQueryInformationToken() failed, Status: 0x%x\n", Status);
1617 return Status;
1618 }
1619
1620 Status = ObReferenceObjectByHandle(TokenHandle,
1621 (TokenInformationClass == TokenSource) ? TOKEN_QUERY_SOURCE : TOKEN_QUERY,
1622 SeTokenObjectType,
1623 PreviousMode,
1624 (PVOID*)&Token,
1625 NULL);
1626 if (NT_SUCCESS(Status))
1627 {
1628 switch (TokenInformationClass)
1629 {
1630 case TokenUser:
1631 {
1632 PTOKEN_USER tu = (PTOKEN_USER)TokenInformation;
1633
1634 DPRINT("NtQueryInformationToken(TokenUser)\n");
1635 RequiredLength = sizeof(TOKEN_USER) +
1636 RtlLengthSid(Token->UserAndGroups[0].Sid);
1637
1638 _SEH2_TRY
1639 {
1640 if (TokenInformationLength >= RequiredLength)
1641 {
1642 Status = RtlCopySidAndAttributesArray(1,
1643 &Token->UserAndGroups[0],
1644 RequiredLength - sizeof(TOKEN_USER),
1645 &tu->User,
1646 (PSID)(tu + 1),
1647 &Unused.PSid,
1648 &Unused.Ulong);
1649 }
1650 else
1651 {
1652 Status = STATUS_BUFFER_TOO_SMALL;
1653 }
1654
1655 if (ReturnLength != NULL)
1656 {
1657 *ReturnLength = RequiredLength;
1658 }
1659 }
1660 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1661 {
1662 Status = _SEH2_GetExceptionCode();
1663 }
1664 _SEH2_END;
1665
1666 break;
1667 }
1668
1669 case TokenGroups:
1670 {
1671 PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation;
1672
1673 DPRINT("NtQueryInformationToken(TokenGroups)\n");
1674 RequiredLength = sizeof(tg->GroupCount) +
1675 RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]);
1676
1677 _SEH2_TRY
1678 {
1679 if (TokenInformationLength >= RequiredLength)
1680 {
1681 ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) -
1682 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES));
1683 PSID Sid = (PSID_AND_ATTRIBUTES)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
1684 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES)));
1685
1686 tg->GroupCount = Token->UserAndGroupCount - 1;
1687 Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1,
1688 &Token->UserAndGroups[1],
1689 SidLen,
1690 &tg->Groups[0],
1691 Sid,
1692 &Unused.PSid,
1693 &Unused.Ulong);
1694 }
1695 else
1696 {
1697 Status = STATUS_BUFFER_TOO_SMALL;
1698 }
1699
1700 if (ReturnLength != NULL)
1701 {
1702 *ReturnLength = RequiredLength;
1703 }
1704 }
1705 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1706 {
1707 Status = _SEH2_GetExceptionCode();
1708 }
1709 _SEH2_END;
1710
1711 break;
1712 }
1713
1714 case TokenPrivileges:
1715 {
1716 PTOKEN_PRIVILEGES tp = (PTOKEN_PRIVILEGES)TokenInformation;
1717
1718 DPRINT("NtQueryInformationToken(TokenPrivileges)\n");
1719 RequiredLength = sizeof(tp->PrivilegeCount) +
1720 (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
1721
1722 _SEH2_TRY
1723 {
1724 if (TokenInformationLength >= RequiredLength)
1725 {
1726 tp->PrivilegeCount = Token->PrivilegeCount;
1727 RtlCopyLuidAndAttributesArray(Token->PrivilegeCount,
1728 Token->Privileges,
1729 &tp->Privileges[0]);
1730 }
1731 else
1732 {
1733 Status = STATUS_BUFFER_TOO_SMALL;
1734 }
1735
1736 if (ReturnLength != NULL)
1737 {
1738 *ReturnLength = RequiredLength;
1739 }
1740 }
1741 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1742 {
1743 Status = _SEH2_GetExceptionCode();
1744 }
1745 _SEH2_END;
1746
1747 break;
1748 }
1749
1750 case TokenOwner:
1751 {
1752 PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation;
1753 ULONG SidLen;
1754
1755 DPRINT("NtQueryInformationToken(TokenOwner)\n");
1756 SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
1757 RequiredLength = sizeof(TOKEN_OWNER) + SidLen;
1758
1759 _SEH2_TRY
1760 {
1761 if (TokenInformationLength >= RequiredLength)
1762 {
1763 to->Owner = (PSID)(to + 1);
1764 Status = RtlCopySid(SidLen,
1765 to->Owner,
1766 Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
1767 }
1768 else
1769 {
1770 Status = STATUS_BUFFER_TOO_SMALL;
1771 }
1772
1773 if (ReturnLength != NULL)
1774 {
1775 *ReturnLength = RequiredLength;
1776 }
1777 }
1778 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1779 {
1780 Status = _SEH2_GetExceptionCode();
1781 }
1782 _SEH2_END;
1783
1784 break;
1785 }
1786
1787 case TokenPrimaryGroup:
1788 {
1789 PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation;
1790 ULONG SidLen;
1791
1792 DPRINT("NtQueryInformationToken(TokenPrimaryGroup)\n");
1793 SidLen = RtlLengthSid(Token->PrimaryGroup);
1794 RequiredLength = sizeof(TOKEN_PRIMARY_GROUP) + SidLen;
1795
1796 _SEH2_TRY
1797 {
1798 if (TokenInformationLength >= RequiredLength)
1799 {
1800 tpg->PrimaryGroup = (PSID)(tpg + 1);
1801 Status = RtlCopySid(SidLen,
1802 tpg->PrimaryGroup,
1803 Token->PrimaryGroup);
1804 }
1805 else
1806 {
1807 Status = STATUS_BUFFER_TOO_SMALL;
1808 }
1809
1810 if (ReturnLength != NULL)
1811 {
1812 *ReturnLength = RequiredLength;
1813 }
1814 }
1815 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1816 {
1817 Status = _SEH2_GetExceptionCode();
1818 }
1819 _SEH2_END;
1820
1821 break;
1822 }
1823
1824 case TokenDefaultDacl:
1825 {
1826 PTOKEN_DEFAULT_DACL tdd = (PTOKEN_DEFAULT_DACL)TokenInformation;
1827
1828 DPRINT("NtQueryInformationToken(TokenDefaultDacl)\n");
1829 RequiredLength = sizeof(TOKEN_DEFAULT_DACL);
1830
1831 if (Token->DefaultDacl != NULL)
1832 RequiredLength += Token->DefaultDacl->AclSize;
1833
1834 _SEH2_TRY
1835 {
1836 if (TokenInformationLength >= RequiredLength)
1837 {
1838 if (Token->DefaultDacl != NULL)
1839 {
1840 tdd->DefaultDacl = (PACL)(tdd + 1);
1841 RtlCopyMemory(tdd->DefaultDacl,
1842 Token->DefaultDacl,
1843 Token->DefaultDacl->AclSize);
1844 }
1845 else
1846 {
1847 tdd->DefaultDacl = NULL;
1848 }
1849 }
1850 else
1851 {
1852 Status = STATUS_BUFFER_TOO_SMALL;
1853 }
1854
1855 if (ReturnLength != NULL)
1856 {
1857 *ReturnLength = RequiredLength;
1858 }
1859 }
1860 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1861 {
1862 Status = _SEH2_GetExceptionCode();
1863 }
1864 _SEH2_END;
1865
1866 break;
1867 }
1868
1869 case TokenSource:
1870 {
1871 PTOKEN_SOURCE ts = (PTOKEN_SOURCE)TokenInformation;
1872
1873 DPRINT("NtQueryInformationToken(TokenSource)\n");
1874 RequiredLength = sizeof(TOKEN_SOURCE);
1875
1876 _SEH2_TRY
1877 {
1878 if (TokenInformationLength >= RequiredLength)
1879 {
1880 *ts = Token->TokenSource;
1881 }
1882 else
1883 {
1884 Status = STATUS_BUFFER_TOO_SMALL;
1885 }
1886
1887 if (ReturnLength != NULL)
1888 {
1889 *ReturnLength = RequiredLength;
1890 }
1891 }
1892 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1893 {
1894 Status = _SEH2_GetExceptionCode();
1895 }
1896 _SEH2_END;
1897
1898 break;
1899 }
1900
1901 case TokenType:
1902 {
1903 PTOKEN_TYPE tt = (PTOKEN_TYPE)TokenInformation;
1904
1905 DPRINT("NtQueryInformationToken(TokenType)\n");
1906 RequiredLength = sizeof(TOKEN_TYPE);
1907
1908 _SEH2_TRY
1909 {
1910 if (TokenInformationLength >= RequiredLength)
1911 {
1912 *tt = Token->TokenType;
1913 }
1914 else
1915 {
1916 Status = STATUS_BUFFER_TOO_SMALL;
1917 }
1918
1919 if (ReturnLength != NULL)
1920 {
1921 *ReturnLength = RequiredLength;
1922 }
1923 }
1924 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1925 {
1926 Status = _SEH2_GetExceptionCode();
1927 }
1928 _SEH2_END;
1929
1930 break;
1931 }
1932
1933 case TokenImpersonationLevel:
1934 {
1935 PSECURITY_IMPERSONATION_LEVEL sil = (PSECURITY_IMPERSONATION_LEVEL)TokenInformation;
1936
1937 DPRINT("NtQueryInformationToken(TokenImpersonationLevel)\n");
1938
1939 /* Fail if the token is not an impersonation token */
1940 if (Token->TokenType != TokenImpersonation)
1941 {
1942 Status = STATUS_INVALID_INFO_CLASS;
1943 break;
1944 }
1945
1946 RequiredLength = sizeof(SECURITY_IMPERSONATION_LEVEL);
1947
1948 _SEH2_TRY
1949 {
1950 if (TokenInformationLength >= RequiredLength)
1951 {
1952 *sil = Token->ImpersonationLevel;
1953 }
1954 else
1955 {
1956 Status = STATUS_BUFFER_TOO_SMALL;
1957 }
1958
1959 if (ReturnLength != NULL)
1960 {
1961 *ReturnLength = RequiredLength;
1962 }
1963 }
1964 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1965 {
1966 Status = _SEH2_GetExceptionCode();
1967 }
1968 _SEH2_END;
1969
1970 break;
1971 }
1972
1973 case TokenStatistics:
1974 {
1975 PTOKEN_STATISTICS ts = (PTOKEN_STATISTICS)TokenInformation;
1976
1977 DPRINT("NtQueryInformationToken(TokenStatistics)\n");
1978 RequiredLength = sizeof(TOKEN_STATISTICS);
1979
1980 _SEH2_TRY
1981 {
1982 if (TokenInformationLength >= RequiredLength)
1983 {
1984 ts->TokenId = Token->TokenId;
1985 ts->AuthenticationId = Token->AuthenticationId;
1986 ts->ExpirationTime = Token->ExpirationTime;
1987 ts->TokenType = Token->TokenType;
1988 ts->ImpersonationLevel = Token->ImpersonationLevel;
1989 ts->DynamicCharged = Token->DynamicCharged;
1990 ts->DynamicAvailable = Token->DynamicAvailable;
1991 ts->GroupCount = Token->UserAndGroupCount - 1;
1992 ts->PrivilegeCount = Token->PrivilegeCount;
1993 ts->ModifiedId = Token->ModifiedId;
1994 }
1995 else
1996 {
1997 Status = STATUS_BUFFER_TOO_SMALL;
1998 }
1999
2000 if (ReturnLength != NULL)
2001 {
2002 *ReturnLength = RequiredLength;
2003 }
2004 }
2005 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2006 {
2007 Status = _SEH2_GetExceptionCode();
2008 }
2009 _SEH2_END;
2010
2011 break;
2012 }
2013
2014 case TokenOrigin:
2015 {
2016 PTOKEN_ORIGIN to = (PTOKEN_ORIGIN)TokenInformation;
2017
2018 DPRINT("NtQueryInformationToken(TokenOrigin)\n");
2019 RequiredLength = sizeof(TOKEN_ORIGIN);
2020
2021 _SEH2_TRY
2022 {
2023 if (TokenInformationLength >= RequiredLength)
2024 {
2025 RtlCopyLuid(&to->OriginatingLogonSession,
2026 &Token->AuthenticationId);
2027 }
2028 else
2029 {
2030 Status = STATUS_BUFFER_TOO_SMALL;
2031 }
2032
2033 if (ReturnLength != NULL)
2034 {
2035 *ReturnLength = RequiredLength;
2036 }
2037 }
2038 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2039 {
2040 Status = _SEH2_GetExceptionCode();
2041 }
2042 _SEH2_END;
2043
2044 break;
2045 }
2046
2047 case TokenGroupsAndPrivileges:
2048 DPRINT1("NtQueryInformationToken(TokenGroupsAndPrivileges) not implemented\n");
2049 Status = STATUS_NOT_IMPLEMENTED;
2050 break;
2051
2052 case TokenRestrictedSids:
2053 {
2054 PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation;
2055
2056 DPRINT("NtQueryInformationToken(TokenRestrictedSids)\n");
2057 RequiredLength = sizeof(tg->GroupCount) +
2058 RtlLengthSidAndAttributes(Token->RestrictedSidCount, Token->RestrictedSids);
2059
2060 _SEH2_TRY
2061 {
2062 if (TokenInformationLength >= RequiredLength)
2063 {
2064 ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) -
2065 (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES));
2066 PSID Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
2067 (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)));
2068
2069 tg->GroupCount = Token->RestrictedSidCount;
2070 Status = RtlCopySidAndAttributesArray(Token->RestrictedSidCount,
2071 Token->RestrictedSids,
2072 SidLen,
2073 &tg->Groups[0],
2074 Sid,
2075 &Unused.PSid,
2076 &Unused.Ulong);
2077 }
2078 else
2079 {
2080 Status = STATUS_BUFFER_TOO_SMALL;
2081 }
2082
2083 if (ReturnLength != NULL)
2084 {
2085 *ReturnLength = RequiredLength;
2086 }
2087 }
2088 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2089 {
2090 Status = _SEH2_GetExceptionCode();
2091 }
2092 _SEH2_END;
2093
2094 break;
2095 }
2096
2097 case TokenSandBoxInert:
2098 DPRINT1("NtQueryInformationToken(TokenSandboxInert) not implemented\n");
2099 Status = STATUS_NOT_IMPLEMENTED;
2100 break;
2101
2102 case TokenSessionId:
2103 {
2104 ULONG SessionId = 0;
2105
2106 DPRINT("NtQueryInformationToken(TokenSessionId)\n");
2107
2108 Status = SeQuerySessionIdToken(Token, &SessionId);
2109 if (NT_SUCCESS(Status))
2110 {
2111 _SEH2_TRY
2112 {
2113 /* Buffer size was already verified, no need to check here again */
2114 *(PULONG)TokenInformation = SessionId;
2115
2116 if (ReturnLength != NULL)
2117 {
2118 *ReturnLength = sizeof(ULONG);
2119 }
2120 }
2121 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2122 {
2123 Status = _SEH2_GetExceptionCode();
2124 }
2125 _SEH2_END;
2126 }
2127
2128 break;
2129 }
2130
2131 default:
2132 DPRINT1("NtQueryInformationToken(%d) invalid information class\n", TokenInformationClass);
2133 Status = STATUS_INVALID_INFO_CLASS;
2134 break;
2135 }
2136
2137 ObDereferenceObject(Token);
2138 }
2139
2140 return Status;
2141 }
2142
2143
2144 /*
2145 * NtSetTokenInformation: Partly implemented.
2146 * Unimplemented:
2147 * TokenOrigin, TokenDefaultDacl
2148 */
2149 NTSTATUS NTAPI
2150 NtSetInformationToken(IN HANDLE TokenHandle,
2151 IN TOKEN_INFORMATION_CLASS TokenInformationClass,
2152 IN PVOID TokenInformation,
2153 IN ULONG TokenInformationLength)
2154 {
2155 PTOKEN Token;
2156 KPROCESSOR_MODE PreviousMode;
2157 ULONG NeededAccess = TOKEN_ADJUST_DEFAULT;
2158 NTSTATUS Status;
2159
2160 PAGED_CODE();
2161
2162 PreviousMode = ExGetPreviousMode();
2163
2164 Status = DefaultSetInfoBufferCheck(TokenInformationClass,
2165 SeTokenInformationClass,
2166 RTL_NUMBER_OF(SeTokenInformationClass),
2167 TokenInformation,
2168 TokenInformationLength,
2169 PreviousMode);
2170 if (!NT_SUCCESS(Status))
2171 {
2172 /* Invalid buffers */
2173 DPRINT("NtSetInformationToken() failed, Status: 0x%x\n", Status);
2174 return Status;
2175 }
2176
2177 if (TokenInformationClass == TokenSessionId)
2178 {
2179 NeededAccess |= TOKEN_ADJUST_SESSIONID;
2180 }
2181
2182 Status = ObReferenceObjectByHandle(TokenHandle,
2183 NeededAccess,
2184 SeTokenObjectType,
2185 PreviousMode,
2186 (PVOID*)&Token,
2187 NULL);
2188 if (NT_SUCCESS(Status))
2189 {
2190 switch (TokenInformationClass)
2191 {
2192 case TokenOwner:
2193 {
2194 if (TokenInformationLength >= sizeof(TOKEN_OWNER))
2195 {
2196 PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation;
2197 PSID InputSid = NULL, CapturedSid;
2198
2199 _SEH2_TRY
2200 {
2201 InputSid = to->Owner;
2202 }
2203 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2204 {
2205 Status = _SEH2_GetExceptionCode();
2206 _SEH2_YIELD(goto Cleanup);
2207 }
2208 _SEH2_END;
2209
2210 Status = SepCaptureSid(InputSid,
2211 PreviousMode,
2212 PagedPool,
2213 FALSE,
2214 &CapturedSid);
2215 if (NT_SUCCESS(Status))
2216 {
2217 RtlCopySid(RtlLengthSid(CapturedSid),
2218 Token->UserAndGroups[Token->DefaultOwnerIndex].Sid,
2219 CapturedSid);
2220 SepReleaseSid(CapturedSid,
2221 PreviousMode,
2222 FALSE);
2223 }
2224 }
2225 else
2226 {
2227 Status = STATUS_INFO_LENGTH_MISMATCH;
2228 }
2229 break;
2230 }
2231
2232 case TokenPrimaryGroup:
2233 {
2234 if (TokenInformationLength >= sizeof(TOKEN_PRIMARY_GROUP))
2235 {
2236 PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation;
2237 PSID InputSid = NULL, CapturedSid;
2238
2239 _SEH2_TRY
2240 {
2241 InputSid = tpg->PrimaryGroup;
2242 }
2243 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2244 {
2245 Status = _SEH2_GetExceptionCode();
2246 _SEH2_YIELD(goto Cleanup);
2247 }
2248 _SEH2_END;
2249
2250 Status = SepCaptureSid(InputSid,
2251 PreviousMode,
2252 PagedPool,
2253 FALSE,
2254 &CapturedSid);
2255 if (NT_SUCCESS(Status))
2256 {
2257 RtlCopySid(RtlLengthSid(CapturedSid),
2258 Token->PrimaryGroup,
2259 CapturedSid);
2260 SepReleaseSid(CapturedSid,
2261 PreviousMode,
2262 FALSE);
2263 }
2264 }
2265 else
2266 {
2267 Status = STATUS_INFO_LENGTH_MISMATCH;
2268 }
2269 break;
2270 }
2271
2272 case TokenDefaultDacl:
2273 {
2274 if (TokenInformationLength >= sizeof(TOKEN_DEFAULT_DACL))
2275 {
2276 PTOKEN_DEFAULT_DACL tdd = (PTOKEN_DEFAULT_DACL)TokenInformation;
2277 PACL InputAcl = NULL;
2278
2279 _SEH2_TRY
2280 {
2281 InputAcl = tdd->DefaultDacl;
2282 }
2283 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2284 {
2285 Status = _SEH2_GetExceptionCode();
2286 _SEH2_YIELD(goto Cleanup);
2287 }
2288 _SEH2_END;
2289
2290 if (InputAcl != NULL)
2291 {
2292 PACL CapturedAcl;
2293
2294 /* Capture and copy the dacl */
2295 Status = SepCaptureAcl(InputAcl,
2296 PreviousMode,
2297 PagedPool,
2298 TRUE,
2299 &CapturedAcl);
2300 if (NT_SUCCESS(Status))
2301 {
2302 /* Free the previous dacl if present */
2303 if(Token->DefaultDacl != NULL)
2304 {
2305 ExFreePoolWithTag(Token->DefaultDacl, TAG_TOKEN_ACL);
2306 }
2307
2308 Token->DefaultDacl = ExAllocatePoolWithTag(PagedPool,
2309 CapturedAcl->AclSize,
2310 TAG_TOKEN_ACL);
2311 if (!Token->DefaultDacl)
2312 {
2313 ExFreePoolWithTag(CapturedAcl, TAG_ACL);
2314 Status = STATUS_NO_MEMORY;
2315 }
2316 else
2317 {
2318 /* Set the new dacl */
2319 RtlCopyMemory(Token->DefaultDacl, CapturedAcl, CapturedAcl->AclSize);
2320 ExFreePoolWithTag(CapturedAcl, TAG_ACL);
2321 }
2322 }
2323 }
2324 else
2325 {
2326 /* Clear and free the default dacl if present */
2327 if (Token->DefaultDacl != NULL)
2328 {
2329 ExFreePoolWithTag(Token->DefaultDacl, TAG_TOKEN_ACL);
2330 Token->DefaultDacl = NULL;
2331 }
2332 }
2333 }
2334 else
2335 {
2336 Status = STATUS_INFO_LENGTH_MISMATCH;
2337 }
2338 break;
2339 }
2340
2341 case TokenSessionId:
2342 {
2343 ULONG SessionId = 0;
2344
2345 _SEH2_TRY
2346 {
2347 /* Buffer size was already verified, no need to check here again */
2348 SessionId = *(PULONG)TokenInformation;
2349 }
2350 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2351 {
2352 Status = _SEH2_GetExceptionCode();
2353 _SEH2_YIELD(goto Cleanup);
2354 }
2355 _SEH2_END;
2356
2357 if (!SeSinglePrivilegeCheck(SeTcbPrivilege,
2358 PreviousMode))
2359 {
2360 Status = STATUS_PRIVILEGE_NOT_HELD;
2361 break;
2362 }
2363
2364 Token->SessionId = SessionId;
2365 break;
2366 }
2367
2368 case TokenSessionReference:
2369 {
2370 ULONG SessionReference;
2371
2372 _SEH2_TRY
2373 {
2374 /* Buffer size was already verified, no need to check here again */
2375 SessionReference = *(PULONG)TokenInformation;
2376 }
2377 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2378 {
2379 Status = _SEH2_GetExceptionCode();
2380 _SEH2_YIELD(goto Cleanup);
2381 }
2382 _SEH2_END;
2383
2384 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
2385 {
2386 Status = STATUS_PRIVILEGE_NOT_HELD;
2387 goto Cleanup;
2388 }
2389
2390 /* Check if it is 0 */
2391 if (SessionReference == 0)
2392 {
2393 /* Atomically set the flag in the token */
2394 RtlInterlockedSetBits(&Token->TokenFlags,
2395 TOKEN_SESSION_NOT_REFERENCED);
2396 }
2397
2398 break;
2399 }
2400
2401 case TokenAuditPolicy:
2402 {
2403 PTOKEN_AUDIT_POLICY_INFORMATION PolicyInformation =
2404 (PTOKEN_AUDIT_POLICY_INFORMATION)TokenInformation;
2405 SEP_AUDIT_POLICY AuditPolicy;
2406 ULONG i;
2407
2408 _SEH2_TRY
2409 {
2410 ProbeForRead(PolicyInformation,
2411 FIELD_OFFSET(TOKEN_AUDIT_POLICY_INFORMATION,
2412 Policies[PolicyInformation->PolicyCount]),
2413 sizeof(ULONG));
2414
2415 /* Loop all policies in the structure */
2416 for (i = 0; i < PolicyInformation->PolicyCount; i++)
2417 {
2418 /* Set the corresponding bits in the packed structure */
2419 switch (PolicyInformation->Policies[i].Category)
2420 {
2421 case AuditCategorySystem:
2422 AuditPolicy.PolicyElements.System = PolicyInformation->Policies[i].Value;
2423 break;
2424
2425 case AuditCategoryLogon:
2426 AuditPolicy.PolicyElements.Logon = PolicyInformation->Policies[i].Value;
2427 break;
2428
2429 case AuditCategoryObjectAccess:
2430 AuditPolicy.PolicyElements.ObjectAccess = PolicyInformation->Policies[i].Value;
2431 break;
2432
2433 case AuditCategoryPrivilegeUse:
2434 AuditPolicy.PolicyElements.PrivilegeUse = PolicyInformation->Policies[i].Value;
2435 break;
2436
2437 case AuditCategoryDetailedTracking:
2438 AuditPolicy.PolicyElements.DetailedTracking = PolicyInformation->Policies[i].Value;
2439 break;
2440
2441 case AuditCategoryPolicyChange:
2442 AuditPolicy.PolicyElements.PolicyChange = PolicyInformation->Policies[i].Value;
2443 break;
2444
2445 case AuditCategoryAccountManagement:
2446 AuditPolicy.PolicyElements.AccountManagement = PolicyInformation->Policies[i].Value;
2447 break;
2448
2449 case AuditCategoryDirectoryServiceAccess:
2450 AuditPolicy.PolicyElements.DirectoryServiceAccess = PolicyInformation->Policies[i].Value;
2451 break;
2452
2453 case AuditCategoryAccountLogon:
2454 AuditPolicy.PolicyElements.AccountLogon = PolicyInformation->Policies[i].Value;
2455 break;
2456 }
2457 }
2458 }
2459 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2460 {
2461 Status = _SEH2_GetExceptionCode();
2462 _SEH2_YIELD(goto Cleanup);
2463 }
2464 _SEH2_END;
2465
2466 if (!SeSinglePrivilegeCheck(SeTcbPrivilege,
2467 PreviousMode))
2468 {
2469 Status = STATUS_PRIVILEGE_NOT_HELD;
2470 break;
2471 }
2472
2473 /* Lock the token */
2474 SepAcquireTokenLockExclusive(Token);
2475
2476 /* Set the new audit policy */
2477 Token->AuditPolicy = AuditPolicy;
2478
2479 /* Unlock the token */
2480 SepReleaseTokenLock(Token);
2481
2482 break;
2483 }
2484
2485 case TokenOrigin:
2486 {
2487 TOKEN_ORIGIN TokenOrigin;
2488
2489 _SEH2_TRY
2490 {
2491 /* Copy the token origin */
2492 TokenOrigin = *(PTOKEN_ORIGIN)TokenInformation;
2493 }
2494 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2495 {
2496 Status = _SEH2_GetExceptionCode();
2497 _SEH2_YIELD(goto Cleanup);
2498 }
2499 _SEH2_END;
2500
2501 /* Check for TCB privilege */
2502 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
2503 {
2504 Status = STATUS_PRIVILEGE_NOT_HELD;
2505 break;
2506 }
2507
2508 /* Lock the token */
2509 SepAcquireTokenLockExclusive(Token);
2510
2511 /* Check if there is no token origin set yet */
2512 if ((Token->OriginatingLogonSession.LowPart == 0) &&
2513 (Token->OriginatingLogonSession.HighPart == 0))
2514 {
2515 /* Set the token origin */
2516 Token->OriginatingLogonSession =
2517 TokenOrigin.OriginatingLogonSession;
2518 }
2519
2520 /* Unlock the token */
2521 SepReleaseTokenLock(Token);
2522
2523 break;
2524 }
2525
2526 default:
2527 {
2528 DPRINT1("Invalid TokenInformationClass: 0x%lx\n",
2529 TokenInformationClass);
2530 Status = STATUS_INVALID_INFO_CLASS;
2531 break;
2532 }
2533 }
2534 Cleanup:
2535 ObDereferenceObject(Token);
2536 }
2537
2538 if (!NT_SUCCESS(Status))
2539 {
2540 DPRINT1("NtSetInformationToken failed with Status 0x%lx\n", Status);
2541 }
2542
2543 return Status;
2544 }
2545
2546
2547 /*
2548 * @implemented
2549 *
2550 * NOTE: Some sources claim 4th param is ImpersonationLevel, but on W2K
2551 * this is certainly NOT true, although I can't say for sure that EffectiveOnly
2552 * is correct either. -Gunnar
2553 * This is true. EffectiveOnly overrides SQOS.EffectiveOnly. - IAI
2554 * NOTE for readers: http://hex.pp.ua/nt/NtDuplicateToken.php is therefore
2555 * wrong in that regard.
2556 */
2557 NTSTATUS NTAPI
2558 NtDuplicateToken(IN HANDLE ExistingTokenHandle,
2559 IN ACCESS_MASK DesiredAccess,
2560 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
2561 IN BOOLEAN EffectiveOnly,
2562 IN TOKEN_TYPE TokenType,
2563 OUT PHANDLE NewTokenHandle)
2564 {
2565 KPROCESSOR_MODE PreviousMode;
2566 HANDLE hToken;
2567 PTOKEN Token;
2568 PTOKEN NewToken;
2569 PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService;
2570 BOOLEAN QoSPresent;
2571 OBJECT_HANDLE_INFORMATION HandleInformation;
2572 NTSTATUS Status;
2573
2574 PAGED_CODE();
2575
2576 if (TokenType != TokenImpersonation &&
2577 TokenType != TokenPrimary)
2578 return STATUS_INVALID_PARAMETER;
2579
2580 PreviousMode = KeGetPreviousMode();
2581
2582 if (PreviousMode != KernelMode)
2583 {
2584 _SEH2_TRY
2585 {
2586 ProbeForWriteHandle(NewTokenHandle);
2587 }
2588 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2589 {
2590 /* Return the exception code */
2591 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2592 }
2593 _SEH2_END;
2594 }
2595
2596 Status = SepCaptureSecurityQualityOfService(ObjectAttributes,
2597 PreviousMode,
2598 PagedPool,
2599 FALSE,
2600 &CapturedSecurityQualityOfService,
2601 &QoSPresent);
2602 if (!NT_SUCCESS(Status))
2603 {
2604 DPRINT1("NtDuplicateToken() failed to capture QoS! Status: 0x%x\n", Status);
2605 return Status;
2606 }
2607
2608 Status = ObReferenceObjectByHandle(ExistingTokenHandle,
2609 TOKEN_DUPLICATE,
2610 SeTokenObjectType,
2611 PreviousMode,
2612 (PVOID*)&Token,
2613 &HandleInformation);
2614 if (!NT_SUCCESS(Status))
2615 {
2616 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
2617 PreviousMode,
2618 FALSE);
2619 return Status;
2620 }
2621
2622 /*
2623 * Fail, if the original token is an impersonation token and the caller
2624 * tries to raise the impersonation level of the new token above the
2625 * impersonation level of the original token.
2626 */
2627 if (Token->TokenType == TokenImpersonation)
2628 {
2629 if (QoSPresent &&
2630 CapturedSecurityQualityOfService->ImpersonationLevel >Token->ImpersonationLevel)
2631 {
2632 ObDereferenceObject(Token);
2633 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
2634 PreviousMode,
2635 FALSE);
2636 return STATUS_BAD_IMPERSONATION_LEVEL;
2637 }
2638 }
2639
2640 /*
2641 * Fail, if a primary token is to be created from an impersonation token
2642 * and and the impersonation level of the impersonation token is below SecurityImpersonation.
2643 */
2644 if (Token->TokenType == TokenImpersonation &&
2645 TokenType == TokenPrimary &&
2646 Token->ImpersonationLevel < SecurityImpersonation)
2647 {
2648 ObDereferenceObject(Token);
2649 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
2650 PreviousMode,
2651 FALSE);
2652 return STATUS_BAD_IMPERSONATION_LEVEL;
2653 }
2654
2655 Status = SepDuplicateToken(Token,
2656 ObjectAttributes,
2657 EffectiveOnly,
2658 TokenType,
2659 (QoSPresent ? CapturedSecurityQualityOfService->ImpersonationLevel : SecurityAnonymous),
2660 PreviousMode,
2661 &NewToken);
2662
2663 ObDereferenceObject(Token);
2664
2665 if (NT_SUCCESS(Status))
2666 {
2667 Status = ObInsertObject(NewToken,
2668 NULL,
2669 (DesiredAccess ? DesiredAccess : HandleInformation.GrantedAccess),
2670 0,
2671 NULL,
2672 &hToken);
2673 if (NT_SUCCESS(Status))
2674 {
2675 _SEH2_TRY
2676 {
2677 *NewTokenHandle = hToken;
2678 }
2679 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2680 {
2681 Status = _SEH2_GetExceptionCode();
2682 }
2683 _SEH2_END;
2684 }
2685 }
2686
2687 /* Free the captured structure */
2688 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
2689 PreviousMode,
2690 FALSE);
2691
2692 return Status;
2693 }
2694
2695 NTSTATUS NTAPI
2696 NtAdjustGroupsToken(IN HANDLE TokenHandle,
2697 IN BOOLEAN ResetToDefault,
2698 IN PTOKEN_GROUPS NewState,
2699 IN ULONG BufferLength,
2700 OUT PTOKEN_GROUPS PreviousState OPTIONAL,
2701 OUT PULONG ReturnLength)
2702 {
2703 UNIMPLEMENTED;
2704 return STATUS_NOT_IMPLEMENTED;
2705 }
2706
2707
2708 static
2709 ULONG
2710 SepAdjustPrivileges(
2711 _Inout_ PTOKEN Token,
2712 _In_ BOOLEAN DisableAllPrivileges,
2713 _In_opt_ PLUID_AND_ATTRIBUTES NewState,
2714 _In_ ULONG NewStateCount,
2715 _Out_opt_ PTOKEN_PRIVILEGES PreviousState,
2716 _In_ BOOLEAN ApplyChanges,
2717 _Out_ PULONG ChangedPrivileges)
2718 {
2719 ULONG i, j, PrivilegeCount, ChangeCount, NewAttributes;
2720
2721 /* Count the found privileges and those that need to be changed */
2722 PrivilegeCount = 0;
2723 ChangeCount = 0;
2724
2725 /* Loop all privileges in the token */
2726 for (i = 0; i < Token->PrivilegeCount; i++)
2727 {
2728 /* Shall all of them be disabled? */
2729 if (DisableAllPrivileges)
2730 {
2731 /* The new attributes are the old ones, but disabled */
2732 NewAttributes = Token->Privileges[i].Attributes & ~SE_PRIVILEGE_ENABLED;
2733 }
2734 else
2735 {
2736 /* Otherwise loop all provided privileges */
2737 for (j = 0; j < NewStateCount; j++)
2738 {
2739 /* Check if this is the LUID we are looking for */
2740 if (RtlEqualLuid(&Token->Privileges[i].Luid, &NewState[j].Luid))
2741 {
2742 DPRINT("Found privilege\n");
2743
2744 /* Copy SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED */
2745 NewAttributes = NewState[j].Attributes;
2746 NewAttributes &= (SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED);
2747 NewAttributes |= Token->Privileges[i].Attributes & ~SE_PRIVILEGE_ENABLED;
2748
2749 /* Stop looking */
2750 break;
2751 }
2752 }
2753
2754 /* Check if we didn't find the privilege */
2755 if (j == NewStateCount)
2756 {
2757 /* Continue with the token's next privilege */
2758 continue;
2759 }
2760 }
2761
2762 /* We found a privilege, count it */
2763 PrivilegeCount++;
2764
2765 /* Does the privilege need to be changed? */
2766 if (Token->Privileges[i].Attributes != NewAttributes)
2767 {
2768 /* Does the caller want the old privileges? */
2769 if (PreviousState != NULL)
2770 {
2771 /* Copy the old privilege */
2772 PreviousState->Privileges[ChangeCount] = Token->Privileges[i];
2773 }
2774
2775 /* Does the caller want to apply the changes? */
2776 if (ApplyChanges)
2777 {
2778 /* Shall we remove the privilege? */
2779 if (NewAttributes & SE_PRIVILEGE_REMOVED)
2780 {
2781 /* Set the token as disabled and update flags for it */
2782 Token->Privileges[i].Attributes &= ~SE_PRIVILEGE_ENABLED;
2783 SepUpdateSinglePrivilegeFlagToken(Token, i);
2784
2785 /* Remove the privilege */
2786 SepRemovePrivilegeToken(Token, i);
2787
2788 /* Fix the running index */
2789 i--;
2790
2791 /* Continue with next */
2792 continue;
2793 }
2794
2795 /* Set the new attributes and update flags */
2796 Token->Privileges[i].Attributes = NewAttributes;
2797 SepUpdateSinglePrivilegeFlagToken(Token, i);
2798 }
2799
2800 /* Increment the change count */
2801 ChangeCount++;
2802 }
2803 }
2804
2805 /* Set the number of saved privileges */
2806 if (PreviousState != NULL)
2807 PreviousState->PrivilegeCount = ChangeCount;
2808
2809 /* Return the number of changed privileges */
2810 *ChangedPrivileges = ChangeCount;
2811
2812 /* Check if we missed some */
2813 if (!DisableAllPrivileges && (PrivilegeCount < NewStateCount))
2814 {
2815 return STATUS_NOT_ALL_ASSIGNED;
2816 }
2817
2818 return STATUS_SUCCESS;
2819 }
2820
2821
2822 /*
2823 * @implemented
2824 */
2825 _Must_inspect_result_
2826 __kernel_entry
2827 NTSTATUS
2828 NTAPI
2829 NtAdjustPrivilegesToken(
2830 _In_ HANDLE TokenHandle,
2831 _In_ BOOLEAN DisableAllPrivileges,
2832 _In_opt_ PTOKEN_PRIVILEGES NewState,
2833 _In_ ULONG BufferLength,
2834 _Out_writes_bytes_to_opt_(BufferLength,*ReturnLength)
2835 PTOKEN_PRIVILEGES PreviousState,
2836 _When_(PreviousState!=NULL, _Out_) PULONG ReturnLength)
2837 {
2838 PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
2839 KPROCESSOR_MODE PreviousMode;
2840 ULONG CapturedCount = 0;
2841 ULONG CapturedLength = 0;
2842 ULONG NewStateSize = 0;
2843 ULONG ChangeCount;
2844 ULONG RequiredLength;
2845 PTOKEN Token;
2846 NTSTATUS Status;
2847 PAGED_CODE();
2848
2849 DPRINT("NtAdjustPrivilegesToken() called\n");
2850
2851 /* Fail, if we do not disable all privileges but NewState is NULL */
2852 if (DisableAllPrivileges == FALSE && NewState == NULL)
2853 return STATUS_INVALID_PARAMETER;
2854
2855 PreviousMode = KeGetPreviousMode();
2856 if (PreviousMode != KernelMode)
2857 {
2858 _SEH2_TRY
2859 {
2860 /* Probe NewState */
2861 if (DisableAllPrivileges == FALSE)
2862 {
2863 /* First probe the header */
2864 ProbeForRead(NewState, sizeof(TOKEN_PRIVILEGES), sizeof(ULONG));
2865
2866 CapturedCount = NewState->PrivilegeCount;
2867 NewStateSize = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[CapturedCount]);
2868
2869 ProbeForRead(NewState, NewStateSize, sizeof(ULONG));
2870 }
2871
2872 /* Probe PreviousState and ReturnLength */
2873 if (PreviousState != NULL)
2874 {
2875 ProbeForWrite(PreviousState, BufferLength, sizeof(ULONG));
2876 ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG));
2877 }
2878 }
2879 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2880 {
2881 /* Return the exception code */
2882 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2883 }
2884 _SEH2_END;
2885 }
2886 else
2887 {
2888 /* This is kernel mode, we trust the caller */
2889 if (DisableAllPrivileges == FALSE)
2890 CapturedCount = NewState->PrivilegeCount;
2891 }
2892
2893 /* Do we need to capture the new state? */
2894 if (DisableAllPrivileges == FALSE)
2895 {
2896 _SEH2_TRY
2897 {
2898 /* Capture the new state array of privileges */
2899 Status = SeCaptureLuidAndAttributesArray(NewState->Privileges,
2900 CapturedCount,
2901 PreviousMode,
2902 NULL,
2903 0,
2904 PagedPool,
2905 TRUE,
2906 &CapturedPrivileges,
2907 &CapturedLength);
2908 }
2909 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2910 {
2911 /* Return the exception code */
2912 Status = _SEH2_GetExceptionCode();
2913 }
2914 _SEH2_END;
2915
2916 if (!NT_SUCCESS(Status))
2917 return Status;
2918 }
2919
2920 /* Reference the token */
2921 Status = ObReferenceObjectByHandle(TokenHandle,
2922 TOKEN_ADJUST_PRIVILEGES | (PreviousState != NULL ? TOKEN_QUERY : 0),
2923 SeTokenObjectType,
2924 PreviousMode,
2925 (PVOID*)&Token,
2926 NULL);
2927 if (!NT_SUCCESS(Status))
2928 {
2929 DPRINT1("Failed to reference token (Status 0x%lx)\n", Status);
2930
2931 /* Release the captured privileges */
2932 if (CapturedPrivileges != NULL)
2933 SeReleaseLuidAndAttributesArray(CapturedPrivileges,
2934 PreviousMode,
2935 TRUE);
2936
2937 return Status;
2938 }
2939
2940 /* Lock the token */
2941 ExEnterCriticalRegionAndAcquireResourceExclusive(Token->TokenLock);
2942
2943 /* Count the privileges that need to be changed, do not apply them yet */
2944 Status = SepAdjustPrivileges(Token,
2945 DisableAllPrivileges,
2946 CapturedPrivileges,
2947 CapturedCount,
2948 NULL,
2949 FALSE,
2950 &ChangeCount);
2951
2952 /* Check if the caller asked for the previous state */
2953 if (PreviousState != NULL)
2954 {
2955 /* Calculate the required length */
2956 RequiredLength = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[ChangeCount]);
2957
2958 /* Try to return the required buffer length */
2959 _SEH2_TRY
2960 {
2961 *ReturnLength = RequiredLength;
2962 }
2963 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2964 {
2965 /* Do cleanup and return the exception code */
2966 Status = _SEH2_GetExceptionCode();
2967 _SEH2_YIELD(goto Cleanup);
2968 }
2969 _SEH2_END;
2970
2971 /* Fail, if the buffer length is smaller than the required length */
2972 if (BufferLength < RequiredLength)
2973 {
2974 Status = STATUS_BUFFER_TOO_SMALL;
2975 goto Cleanup;
2976 }
2977 }
2978
2979 /* Now enter SEH, since we might return the old privileges */
2980 _SEH2_TRY
2981 {
2982 /* This time apply the changes */
2983 Status = SepAdjustPrivileges(Token,
2984 DisableAllPrivileges,
2985 CapturedPrivileges,
2986 CapturedCount,
2987 PreviousState,
2988 TRUE,
2989 &ChangeCount);
2990 }
2991 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2992 {
2993 /* Do cleanup and return the exception code */
2994 Status = _SEH2_GetExceptionCode();
2995 _SEH2_YIELD(goto Cleanup);
2996 }
2997 _SEH2_END;
2998
2999 Cleanup:
3000 /* Unlock and dereference the token */
3001 ExReleaseResourceAndLeaveCriticalRegion(Token->TokenLock);
3002 ObDereferenceObject(Token);
3003
3004 /* Release the captured privileges */
3005 if (CapturedPrivileges != NULL)
3006 SeReleaseLuidAndAttributesArray(CapturedPrivileges,
3007 PreviousMode,
3008 TRUE);
3009
3010 DPRINT ("NtAdjustPrivilegesToken() done\n");
3011 return Status;
3012 }
3013
3014 NTSTATUS
3015 NTAPI
3016 NtCreateToken(
3017 _Out_ PHANDLE TokenHandle,
3018 _In_ ACCESS_MASK DesiredAccess,
3019 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
3020 _In_ TOKEN_TYPE TokenType,
3021 _In_ PLUID AuthenticationId,
3022 _In_ PLARGE_INTEGER ExpirationTime,
3023 _In_ PTOKEN_USER TokenUser,
3024 _In_ PTOKEN_GROUPS TokenGroups,
3025 _In_ PTOKEN_PRIVILEGES TokenPrivileges,
3026 _In_opt_ PTOKEN_OWNER TokenOwner,
3027 _In_ PTOKEN_PRIMARY_GROUP TokenPrimaryGroup,
3028 _In_opt_ PTOKEN_DEFAULT_DACL TokenDefaultDacl,
3029 _In_ PTOKEN_SOURCE TokenSource)
3030 {
3031 HANDLE hToken;
3032 KPROCESSOR_MODE PreviousMode;
3033 ULONG PrivilegeCount, GroupCount;
3034 PSID OwnerSid, PrimaryGroupSid;
3035 PACL DefaultDacl;
3036 LARGE_INTEGER LocalExpirationTime = {{0, 0}};
3037 LUID LocalAuthenticationId;
3038 TOKEN_SOURCE LocalTokenSource;
3039 SECURITY_QUALITY_OF_SERVICE LocalSecurityQos;
3040 PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
3041 PSID_AND_ATTRIBUTES CapturedUser = NULL;
3042 PSID_AND_ATTRIBUTES CapturedGroups = NULL;
3043 PSID CapturedOwnerSid = NULL;
3044 PSID CapturedPrimaryGroupSid = NULL;
3045 PACL CapturedDefaultDacl = NULL;
3046 ULONG PrivilegesLength, UserLength, GroupsLength;
3047 NTSTATUS Status;
3048
3049 PAGED_CODE();
3050
3051 PreviousMode = ExGetPreviousMode();
3052
3053 if (PreviousMode != KernelMode)
3054 {
3055 _SEH2_TRY
3056 {
3057 ProbeForWriteHandle(TokenHandle);
3058
3059 if (ObjectAttributes != NULL)
3060 {
3061 ProbeForRead(ObjectAttributes,
3062 sizeof(OBJECT_ATTRIBUTES),
3063 sizeof(ULONG));
3064 LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService;
3065 }
3066
3067 ProbeForRead(AuthenticationId,
3068 sizeof(LUID),
3069 sizeof(ULONG));
3070 LocalAuthenticationId = *AuthenticationId;
3071
3072 LocalExpirationTime = ProbeForReadLargeInteger(ExpirationTime);
3073
3074 ProbeForRead(TokenUser,
3075 sizeof(TOKEN_USER),
3076 sizeof(ULONG));
3077
3078 ProbeForRead(TokenGroups,
3079 sizeof(TOKEN_GROUPS),
3080 sizeof(ULONG));
3081 GroupCount = TokenGroups->GroupCount;
3082
3083 ProbeForRead(TokenPrivileges,
3084 sizeof(TOKEN_PRIVILEGES),
3085 sizeof(ULONG));
3086 PrivilegeCount = TokenPrivileges->PrivilegeCount;
3087
3088 if (TokenOwner != NULL)
3089 {
3090 ProbeForRead(TokenOwner,
3091 sizeof(TOKEN_OWNER),
3092 sizeof(ULONG));
3093 OwnerSid = TokenOwner->Owner;
3094 }
3095 else
3096 {
3097 OwnerSid = NULL;
3098 }
3099
3100 ProbeForRead(TokenPrimaryGroup,
3101 sizeof(TOKEN_PRIMARY_GROUP),
3102 sizeof(ULONG));
3103 PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup;
3104
3105 if (TokenDefaultDacl != NULL)
3106 {
3107 ProbeForRead(TokenDefaultDacl,
3108 sizeof(TOKEN_DEFAULT_DACL),
3109 sizeof(ULONG));
3110 DefaultDacl = TokenDefaultDacl->DefaultDacl;
3111 }
3112 else
3113 {
3114 DefaultDacl = NULL;
3115 }
3116
3117 ProbeForRead(TokenSource,
3118 sizeof(TOKEN_SOURCE),
3119 sizeof(ULONG));
3120 LocalTokenSource = *TokenSource;
3121 }
3122 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3123 {
3124 /* Return the exception code */
3125 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3126 }
3127 _SEH2_END;
3128 }
3129 else
3130 {
3131 if (ObjectAttributes != NULL)
3132 LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService;
3133 LocalAuthenticationId = *AuthenticationId;
3134 LocalExpirationTime = *ExpirationTime;
3135 GroupCount = TokenGroups->GroupCount;
3136 PrivilegeCount = TokenPrivileges->PrivilegeCount;
3137 OwnerSid = TokenOwner ? TokenOwner->Owner : NULL;
3138 PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup;
3139 DefaultDacl = TokenDefaultDacl ? TokenDefaultDacl->DefaultDacl : NULL;
3140 LocalTokenSource = *TokenSource;
3141 }
3142
3143 /* Check token type */
3144 if ((TokenType < TokenPrimary) ||
3145 (TokenType > TokenImpersonation))
3146 {
3147 return STATUS_BAD_TOKEN_TYPE;
3148 }
3149
3150 /* Capture the user SID and attributes */
3151 Status = SeCaptureSidAndAttributesArray(&TokenUser->User,
3152 1,
3153 PreviousMode,
3154 NULL,
3155 0,
3156 PagedPool,
3157 FALSE,
3158 &CapturedUser,
3159 &UserLength);
3160 if (!NT_SUCCESS(Status))
3161 {
3162 goto Cleanup;
3163 }
3164
3165 /* Capture the groups SID and attributes array */
3166 Status = SeCaptureSidAndAttributesArray(&TokenGroups->Groups[0],
3167 GroupCount,
3168 PreviousMode,
3169 NULL,
3170 0,
3171 PagedPool,
3172 FALSE,
3173 &CapturedGroups,
3174 &GroupsLength);
3175 if (!NT_SUCCESS(Status))
3176 {
3177 goto Cleanup;
3178 }
3179
3180 /* Capture privileges */
3181 Status = SeCaptureLuidAndAttributesArray(&TokenPrivileges->Privileges[0],
3182 PrivilegeCount,
3183 PreviousMode,
3184 NULL,
3185 0,
3186 PagedPool,
3187 FALSE,
3188 &CapturedPrivileges,
3189 &PrivilegesLength);
3190 if (!NT_SUCCESS(Status))
3191 {
3192 goto Cleanup;
3193 }
3194
3195 /* Capture the token owner SID */
3196 if (TokenOwner != NULL)
3197 {
3198 Status = SepCaptureSid(OwnerSid,
3199 PreviousMode,
3200 PagedPool,
3201 FALSE,
3202 &CapturedOwnerSid);
3203 if (!NT_SUCCESS(Status))
3204 {
3205 goto Cleanup;
3206 }
3207 }
3208
3209 /* Capture the token primary group SID */
3210 Status = SepCaptureSid(PrimaryGroupSid,
3211 PreviousMode,
3212 PagedPool,
3213 FALSE,
3214 &CapturedPrimaryGroupSid);
3215 if (!NT_SUCCESS(Status))
3216 {
3217 goto Cleanup;
3218 }
3219
3220 /* Capture DefaultDacl */
3221 if (DefaultDacl != NULL)
3222 {
3223 Status = SepCaptureAcl(DefaultDacl,
3224 PreviousMode,
3225 NonPagedPool,
3226 FALSE,
3227 &CapturedDefaultDacl);
3228 if (!NT_SUCCESS(Status))
3229 {
3230 goto Cleanup;
3231 }
3232 }
3233
3234 /* Call the internal function */
3235 Status = SepCreateToken(&hToken,
3236 PreviousMode,
3237 DesiredAccess,
3238 ObjectAttributes,
3239 TokenType,
3240 LocalSecurityQos.ImpersonationLevel,
3241 &LocalAuthenticationId,
3242 &LocalExpirationTime,
3243 CapturedUser,
3244 GroupCount,
3245 CapturedGroups,
3246 0, // FIXME: Should capture
3247 PrivilegeCount,
3248 CapturedPrivileges,
3249 CapturedOwnerSid,
3250 CapturedPrimaryGroupSid,
3251 CapturedDefaultDacl,
3252 &LocalTokenSource,
3253 FALSE);
3254 if (NT_SUCCESS(Status))
3255 {
3256 _SEH2_TRY
3257 {
3258 *TokenHandle = hToken;
3259 }
3260 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3261 {
3262 Status = _SEH2_GetExceptionCode();
3263 }
3264 _SEH2_END;
3265 }
3266
3267 Cleanup:
3268
3269 /* Release what we captured */
3270 SeReleaseSidAndAttributesArray(CapturedUser, PreviousMode, FALSE);
3271 SeReleaseSidAndAttributesArray(CapturedGroups, PreviousMode, FALSE);
3272 SeReleaseLuidAndAttributesArray(CapturedPrivileges, PreviousMode, FALSE);
3273 SepReleaseSid(CapturedOwnerSid, PreviousMode, FALSE);
3274 SepReleaseSid(CapturedPrimaryGroupSid, PreviousMode, FALSE);
3275 SepReleaseAcl(CapturedDefaultDacl, PreviousMode, FALSE);
3276
3277 return Status;
3278 }
3279
3280 /*
3281 * @implemented
3282 */
3283 NTSTATUS
3284 NTAPI
3285 NtOpenThreadTokenEx(IN HANDLE ThreadHandle,
3286 IN ACCESS_MASK DesiredAccess,
3287 IN BOOLEAN OpenAsSelf,
3288 IN ULONG HandleAttributes,
3289 OUT PHANDLE TokenHandle)
3290 {
3291 PETHREAD Thread, NewThread;
3292 HANDLE hToken;
3293 PTOKEN Token, NewToken = NULL, PrimaryToken;
3294 BOOLEAN CopyOnOpen, EffectiveOnly;
3295 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
3296 SE_IMPERSONATION_STATE ImpersonationState;
3297 OBJECT_ATTRIBUTES ObjectAttributes;
3298 SECURITY_DESCRIPTOR SecurityDescriptor;
3299 PACL Dacl = NULL;
3300 KPROCESSOR_MODE PreviousMode;
3301 NTSTATUS Status;
3302 BOOLEAN RestoreImpersonation = FALSE;
3303
3304 PAGED_CODE();
3305
3306 PreviousMode = ExGetPreviousMode();
3307
3308 if (PreviousMode != KernelMode)
3309 {
3310 _SEH2_TRY
3311 {
3312 ProbeForWriteHandle(TokenHandle);
3313 }
3314 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3315 {
3316 /* Return the exception code */
3317 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3318 }
3319 _SEH2_END;
3320 }
3321
3322 /* Validate object attributes */
3323 HandleAttributes = ObpValidateAttributes(HandleAttributes, PreviousMode);
3324
3325 /*
3326 * At first open the thread token for information access and verify
3327 * that the token associated with thread is valid.
3328 */
3329
3330 Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_QUERY_INFORMATION,
3331 PsThreadType, PreviousMode, (PVOID*)&Thread,
3332 NULL);
3333 if (!NT_SUCCESS(Status))
3334 {
3335 return Status;
3336 }
3337
3338 Token = PsReferenceImpersonationToken(Thread, &CopyOnOpen, &EffectiveOnly,
3339 &ImpersonationLevel);
3340 if (Token == NULL)
3341 {
3342 ObDereferenceObject(Thread);
3343 return STATUS_NO_TOKEN;
3344 }
3345
3346 if (ImpersonationLevel == SecurityAnonymous)
3347 {
3348 PsDereferenceImpersonationToken(Token);
3349 ObDereferenceObject(Thread);
3350 return STATUS_CANT_OPEN_ANONYMOUS;
3351 }
3352
3353 /*
3354 * Revert to self if OpenAsSelf is specified.
3355 */
3356
3357 if (OpenAsSelf)
3358 {
3359 RestoreImpersonation = PsDisableImpersonation(PsGetCurrentThread(),
3360 &ImpersonationState);
3361 }
3362
3363 if (CopyOnOpen)
3364 {
3365 Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_ALL_ACCESS,
3366 PsThreadType, KernelMode,
3367 (PVOID*)&NewThread, NULL);
3368 if (NT_SUCCESS(Status))
3369 {
3370 PrimaryToken = PsReferencePrimaryToken(NewThread->ThreadsProcess);
3371
3372 Status = SepCreateImpersonationTokenDacl(Token, PrimaryToken, &Dacl);
3373
3374 ObFastDereferenceObject(&NewThread->ThreadsProcess->Token, PrimaryToken);
3375
3376 if (NT_SUCCESS(Status))
3377 {
3378 if (Dacl)
3379 {
3380 RtlCreateSecurityDescriptor(&SecurityDescriptor,
3381 SECURITY_DESCRIPTOR_REVISION);
3382 RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl,
3383 FALSE);
3384 }
3385
3386 InitializeObjectAttributes(&ObjectAttributes, NULL, HandleAttributes,
3387 NULL, Dacl ? &SecurityDescriptor : NULL);
3388
3389 Status = SepDuplicateToken(Token, &ObjectAttributes, EffectiveOnly,
3390 TokenImpersonation, ImpersonationLevel,
3391 KernelMode, &NewToken);
3392 if (NT_SUCCESS(Status))
3393 {
3394 ObReferenceObject(NewToken);
3395 Status = ObInsertObject(NewToken, NULL, DesiredAccess, 0, NULL,
3396 &hToken);
3397 }
3398 }
3399 }
3400 }
3401 else
3402 {
3403 Status = ObOpenObjectByPointer(Token, HandleAttributes,
3404 NULL, DesiredAccess, SeTokenObjectType,
3405 PreviousMode, &hToken);
3406 }
3407
3408 if (Dacl) ExFreePoolWithTag(Dacl, TAG_ACL);
3409
3410 if (RestoreImpersonation)
3411 {
3412 PsRestoreImpersonation(PsGetCurrentThread(), &ImpersonationState);
3413 }
3414
3415 ObDereferenceObject(Token);
3416
3417 if (NT_SUCCESS(Status) && CopyOnOpen)
3418 {
3419 PsImpersonateClient(Thread, NewToken, FALSE, EffectiveOnly, ImpersonationLevel);
3420 }
3421
3422 if (NewToken) ObDereferenceObject(NewToken);
3423
3424 if (CopyOnOpen && NewThread) ObDereferenceObject(NewThread);
3425
3426 ObDereferenceObject(Thread);
3427
3428 if (NT_SUCCESS(Status))
3429 {
3430 _SEH2_TRY
3431 {
3432 *TokenHandle = hToken;
3433 }
3434 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3435 {
3436 Status = _SEH2_GetExceptionCode();
3437 }
3438 _SEH2_END;
3439 }
3440
3441 return Status;
3442 }
3443
3444 /*
3445 * @implemented
3446 */
3447 NTSTATUS NTAPI
3448 NtOpenThreadToken(IN HANDLE ThreadHandle,
3449 IN ACCESS_MASK DesiredAccess,
3450 IN BOOLEAN OpenAsSelf,
3451 OUT PHANDLE TokenHandle)
3452 {
3453 return NtOpenThreadTokenEx(ThreadHandle, DesiredAccess, OpenAsSelf, 0,
3454 TokenHandle);
3455 }
3456
3457 /*
3458 * @unimplemented
3459 */
3460 NTSTATUS
3461 NTAPI
3462 NtCompareTokens(IN HANDLE FirstTokenHandle,
3463 IN HANDLE SecondTokenHandle,
3464 OUT PBOOLEAN Equal)
3465 {
3466 KPROCESSOR_MODE PreviousMode;
3467 PTOKEN FirstToken, SecondToken;
3468 BOOLEAN IsEqual;
3469 NTSTATUS Status;
3470
3471 PAGED_CODE();
3472
3473 PreviousMode = ExGetPreviousMode();
3474
3475 if (PreviousMode != KernelMode)
3476 {
3477 _SEH2_TRY
3478 {
3479 ProbeForWriteBoolean(Equal);
3480 }
3481 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3482 {
3483 /* Return the exception code */
3484 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3485 }
3486 _SEH2_END;
3487 }
3488
3489 Status = ObReferenceObjectByHandle(FirstTokenHandle,
3490 TOKEN_QUERY,
3491 SeTokenObjectType,
3492 PreviousMode,
3493 (PVOID*)&FirstToken,
3494 NULL);
3495 if (!NT_SUCCESS(Status))
3496 return Status;
3497
3498 Status = ObReferenceObjectByHandle(SecondTokenHandle,
3499 TOKEN_QUERY,
3500 SeTokenObjectType,
3501 PreviousMode,
3502 (PVOID*)&SecondToken,
3503 NULL);
3504 if (!NT_SUCCESS(Status))
3505 {
3506 ObDereferenceObject(FirstToken);
3507 return Status;
3508 }
3509
3510 if (FirstToken != SecondToken)
3511 {
3512 Status = SepCompareTokens(FirstToken,
3513 SecondToken,
3514 &IsEqual);
3515 }
3516 else
3517 {
3518 IsEqual = TRUE;
3519 }
3520
3521 ObDereferenceObject(FirstToken);
3522 ObDereferenceObject(SecondToken);
3523
3524 if (NT_SUCCESS(Status))
3525 {
3526 _SEH2_TRY
3527 {
3528 *Equal = IsEqual;
3529 }
3530 _SEH2_EXCEPT(ExSystemExceptionFilter())
3531 {
3532 Status = _SEH2_GetExceptionCode();
3533 }
3534 _SEH2_END;
3535 }
3536
3537 return Status;
3538 }
3539
3540 NTSTATUS
3541 NTAPI
3542 NtFilterToken(IN HANDLE ExistingTokenHandle,
3543 IN ULONG Flags,
3544 IN PTOKEN_GROUPS SidsToDisable OPTIONAL,
3545 IN PTOKEN_PRIVILEGES PrivilegesToDelete OPTIONAL,
3546 IN PTOKEN_GROUPS RestrictedSids OPTIONAL,
3547 OUT PHANDLE NewTokenHandle)
3548 {
3549 UNIMPLEMENTED;
3550 return STATUS_NOT_IMPLEMENTED;
3551 }
3552
3553 /*
3554 * @unimplemented
3555 */
3556 NTSTATUS
3557 NTAPI
3558 NtImpersonateAnonymousToken(IN HANDLE Thread)
3559 {
3560 UNIMPLEMENTED;
3561 return STATUS_NOT_IMPLEMENTED;
3562 }
3563
3564 /* EOF */