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