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