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