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