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