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