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