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