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