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