Sync up with trunk r61578.
[reactos.git] / 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 AccessToken->UserAndGroups = ExAllocatePoolWithTag(PagedPool,
742 uLength,
743 TAG_TOKEN_USERS);
744 if (AccessToken->UserAndGroups == NULL)
745 {
746 Status = STATUS_INSUFFICIENT_RESOURCES;
747 goto done;
748 }
749
750 EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
751
752 Status = RtlCopySidAndAttributesArray(1,
753 User,
754 uLength,
755 AccessToken->UserAndGroups,
756 EndMem,
757 &EndMem,
758 &uLength);
759 if (!NT_SUCCESS(Status))
760 goto done;
761
762 Status = RtlCopySidAndAttributesArray(GroupCount,
763 Groups,
764 uLength,
765 &AccessToken->UserAndGroups[1],
766 EndMem,
767 &EndMem,
768 &uLength);
769 if (!NT_SUCCESS(Status))
770 goto done;
771
772 Status = SepFindPrimaryGroupAndDefaultOwner(AccessToken,
773 PrimaryGroup,
774 Owner);
775 if (!NT_SUCCESS(Status))
776 goto done;
777
778 uLength = PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
779 AccessToken->Privileges = ExAllocatePoolWithTag(PagedPool,
780 uLength,
781 TAG_TOKEN_PRIVILAGES);
782 if (AccessToken->Privileges == NULL)
783 {
784 Status = STATUS_INSUFFICIENT_RESOURCES;
785 goto done;
786 }
787
788 if (PreviousMode != KernelMode)
789 {
790 _SEH2_TRY
791 {
792 RtlCopyMemory(AccessToken->Privileges,
793 Privileges,
794 PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
795 }
796 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
797 {
798 Status = _SEH2_GetExceptionCode();
799 }
800 _SEH2_END;
801 }
802 else
803 {
804 RtlCopyMemory(AccessToken->Privileges,
805 Privileges,
806 PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
807 }
808
809 if (!NT_SUCCESS(Status))
810 goto done;
811
812 /* Update privilege flags */
813 SepUpdatePrivilegeFlagsToken(AccessToken);
814
815 AccessToken->DefaultDacl = ExAllocatePoolWithTag(PagedPool,
816 DefaultDacl->AclSize,
817 TAG_TOKEN_ACL);
818 if (AccessToken->DefaultDacl == NULL)
819 {
820 Status = STATUS_INSUFFICIENT_RESOURCES;
821 goto done;
822 }
823
824 RtlCopyMemory(AccessToken->DefaultDacl,
825 DefaultDacl,
826 DefaultDacl->AclSize);
827
828 if (!SystemToken)
829 {
830 Status = ObInsertObject((PVOID)AccessToken,
831 NULL,
832 DesiredAccess,
833 0,
834 NULL,
835 TokenHandle);
836 if (!NT_SUCCESS(Status))
837 {
838 DPRINT1("ObInsertObject() failed (Status %lx)\n", Status);
839 }
840 }
841 else
842 {
843 /* Return pointer instead of handle */
844 *TokenHandle = (HANDLE)AccessToken;
845 }
846
847 done:
848 if (!NT_SUCCESS(Status))
849 {
850 if (AccessToken)
851 {
852 /* Dereference the token, the delete procedure will clean up */
853 ObDereferenceObject(AccessToken);
854 }
855 }
856
857 return Status;
858 }
859
860 PTOKEN
861 NTAPI
862 SepCreateSystemProcessToken(VOID)
863 {
864 LUID_AND_ATTRIBUTES Privileges[25];
865 ULONG GroupAttributes, OwnerAttributes;
866 SID_AND_ATTRIBUTES Groups[32];
867 LARGE_INTEGER Expiration;
868 SID_AND_ATTRIBUTES UserSid;
869 ULONG GroupLength;
870 PSID PrimaryGroup;
871 OBJECT_ATTRIBUTES ObjectAttributes;
872 PSID Owner;
873 ULONG i;
874 PTOKEN Token;
875 NTSTATUS Status;
876
877 /* Don't ever expire */
878 Expiration.QuadPart = -1;
879
880 /* All groups mandatory and enabled */
881 GroupAttributes = SE_GROUP_ENABLED | SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT;
882 OwnerAttributes = SE_GROUP_ENABLED | SE_GROUP_OWNER | SE_GROUP_ENABLED_BY_DEFAULT;
883
884 /* User is system */
885 UserSid.Sid = SeLocalSystemSid;
886 UserSid.Attributes = 0;
887
888 /* Primary group is local system */
889 PrimaryGroup = SeLocalSystemSid;
890
891 /* Owner is admins */
892 Owner = SeAliasAdminsSid;
893
894 /* Groups are admins, world, and authenticated users */
895 Groups[0].Sid = SeAliasAdminsSid;
896 Groups[0].Attributes = OwnerAttributes;
897 Groups[1].Sid = SeWorldSid;
898 Groups[1].Attributes = GroupAttributes;
899 Groups[2].Sid = SeAuthenticatedUserSid;
900 Groups[2].Attributes = OwnerAttributes;
901 GroupLength = sizeof(SID_AND_ATTRIBUTES) +
902 SeLengthSid(Groups[0].Sid) +
903 SeLengthSid(Groups[1].Sid) +
904 SeLengthSid(Groups[2].Sid);
905 ASSERT(GroupLength <= sizeof(Groups));
906
907 /* Setup the privileges */
908 i = 0;
909 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
910 Privileges[i++].Luid = SeTcbPrivilege;
911
912 Privileges[i].Attributes = 0;
913 Privileges[i++].Luid = SeCreateTokenPrivilege;
914
915 Privileges[i].Attributes = 0;
916 Privileges[i++].Luid = SeTakeOwnershipPrivilege;
917
918 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
919 Privileges[i++].Luid = SeCreatePagefilePrivilege;
920
921 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
922 Privileges[i++].Luid = SeLockMemoryPrivilege;
923
924 Privileges[i].Attributes = 0;
925 Privileges[i++].Luid = SeAssignPrimaryTokenPrivilege;
926
927 Privileges[i].Attributes = 0;
928 Privileges[i++].Luid = SeIncreaseQuotaPrivilege;
929
930 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
931 Privileges[i++].Luid = SeIncreaseBasePriorityPrivilege;
932
933 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
934 Privileges[i++].Luid = SeCreatePermanentPrivilege;
935
936 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
937 Privileges[i++].Luid = SeDebugPrivilege;
938
939 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
940 Privileges[i++].Luid = SeAuditPrivilege;
941
942 Privileges[i].Attributes = 0;
943 Privileges[i++].Luid = SeSecurityPrivilege;
944
945 Privileges[i].Attributes = 0;
946 Privileges[i++].Luid = SeSystemEnvironmentPrivilege;
947
948 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
949 Privileges[i++].Luid = SeChangeNotifyPrivilege;
950
951 Privileges[i].Attributes = 0;
952 Privileges[i++].Luid = SeBackupPrivilege;
953
954 Privileges[i].Attributes = 0;
955 Privileges[i++].Luid = SeRestorePrivilege;
956
957 Privileges[i].Attributes = 0;
958 Privileges[i++].Luid = SeShutdownPrivilege;
959
960 Privileges[i].Attributes = 0;
961 Privileges[i++].Luid = SeLoadDriverPrivilege;
962
963 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
964 Privileges[i++].Luid = SeProfileSingleProcessPrivilege;
965
966 Privileges[i].Attributes = 0;
967 Privileges[i++].Luid = SeSystemtimePrivilege;
968 ASSERT(i == 20);
969
970 /* Setup the object attributes */
971 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
972 ASSERT(SeSystemDefaultDacl != NULL);
973
974 /* Create the token */
975 Status = SepCreateToken((PHANDLE)&Token,
976 KernelMode,
977 0,
978 &ObjectAttributes,
979 TokenPrimary,
980 0,
981 &SeSystemAuthenticationId,
982 &Expiration,
983 &UserSid,
984 3,
985 Groups,
986 GroupLength,
987 20,
988 Privileges,
989 Owner,
990 PrimaryGroup,
991 SeSystemDefaultDacl,
992 &SeSystemTokenSource,
993 TRUE);
994 ASSERT(Status == STATUS_SUCCESS);
995
996 /* Return the token */
997 return Token;
998 }
999
1000 /* PUBLIC FUNCTIONS ***********************************************************/
1001
1002 /*
1003 * @unimplemented
1004 */
1005 NTSTATUS
1006 NTAPI
1007 SeFilterToken(IN PACCESS_TOKEN ExistingToken,
1008 IN ULONG Flags,
1009 IN PTOKEN_GROUPS SidsToDisable OPTIONAL,
1010 IN PTOKEN_PRIVILEGES PrivilegesToDelete OPTIONAL,
1011 IN PTOKEN_GROUPS RestrictedSids OPTIONAL,
1012 OUT PACCESS_TOKEN * FilteredToken)
1013 {
1014 UNIMPLEMENTED;
1015 return STATUS_NOT_IMPLEMENTED;
1016 }
1017
1018 /*
1019 * @unimplemented
1020 */
1021 NTSTATUS
1022 NTAPI
1023 SeQueryInformationToken(IN PACCESS_TOKEN Token,
1024 IN TOKEN_INFORMATION_CLASS TokenInformationClass,
1025 OUT PVOID *TokenInformation)
1026 {
1027 UNIMPLEMENTED;
1028 return STATUS_NOT_IMPLEMENTED;
1029 }
1030
1031 /*
1032 * @implemented
1033 */
1034 NTSTATUS
1035 NTAPI
1036 SeQuerySessionIdToken(IN PACCESS_TOKEN Token,
1037 IN PULONG pSessionId)
1038 {
1039 *pSessionId = ((PTOKEN)Token)->SessionId;
1040 return STATUS_SUCCESS;
1041 }
1042
1043 /*
1044 * @implemented
1045 */
1046 NTSTATUS
1047 NTAPI
1048 SeQueryAuthenticationIdToken(IN PACCESS_TOKEN Token,
1049 OUT PLUID LogonId)
1050 {
1051 PAGED_CODE();
1052
1053 *LogonId = ((PTOKEN)Token)->AuthenticationId;
1054
1055 return STATUS_SUCCESS;
1056 }
1057
1058
1059 /*
1060 * @implemented
1061 */
1062 SECURITY_IMPERSONATION_LEVEL
1063 NTAPI
1064 SeTokenImpersonationLevel(IN PACCESS_TOKEN Token)
1065 {
1066 PAGED_CODE();
1067
1068 return ((PTOKEN)Token)->ImpersonationLevel;
1069 }
1070
1071
1072 /*
1073 * @implemented
1074 */
1075 TOKEN_TYPE NTAPI
1076 SeTokenType(IN PACCESS_TOKEN Token)
1077 {
1078 PAGED_CODE();
1079
1080 return ((PTOKEN)Token)->TokenType;
1081 }
1082
1083
1084 /*
1085 * @implemented
1086 */
1087 BOOLEAN
1088 NTAPI
1089 SeTokenIsAdmin(IN PACCESS_TOKEN Token)
1090 {
1091 PAGED_CODE();
1092
1093 return (((PTOKEN)Token)->TokenFlags & TOKEN_WRITE_RESTRICTED) != 0;
1094 }
1095
1096 /*
1097 * @implemented
1098 */
1099 BOOLEAN
1100 NTAPI
1101 SeTokenIsRestricted(IN PACCESS_TOKEN Token)
1102 {
1103 PAGED_CODE();
1104
1105 return (((PTOKEN)Token)->TokenFlags & TOKEN_IS_RESTRICTED) != 0;
1106 }
1107
1108 /*
1109 * @implemented
1110 */
1111 BOOLEAN
1112 NTAPI
1113 SeTokenIsWriteRestricted(IN PACCESS_TOKEN Token)
1114 {
1115 PAGED_CODE();
1116
1117 return (((PTOKEN)Token)->TokenFlags & TOKEN_HAS_RESTORE_PRIVILEGE) != 0;
1118 }
1119
1120 /* SYSTEM CALLS ***************************************************************/
1121
1122 /*
1123 * @implemented
1124 */
1125 NTSTATUS NTAPI
1126 NtQueryInformationToken(IN HANDLE TokenHandle,
1127 IN TOKEN_INFORMATION_CLASS TokenInformationClass,
1128 OUT PVOID TokenInformation,
1129 IN ULONG TokenInformationLength,
1130 OUT PULONG ReturnLength)
1131 {
1132 union
1133 {
1134 PVOID Ptr;
1135 ULONG Ulong;
1136 } Unused;
1137 PTOKEN Token;
1138 ULONG RequiredLength;
1139 KPROCESSOR_MODE PreviousMode;
1140 NTSTATUS Status;
1141
1142 PAGED_CODE();
1143
1144 PreviousMode = ExGetPreviousMode();
1145
1146 /* Check buffers and class validity */
1147 Status = DefaultQueryInfoBufferCheck(TokenInformationClass,
1148 SeTokenInformationClass,
1149 sizeof(SeTokenInformationClass) / sizeof(SeTokenInformationClass[0]),
1150 TokenInformation,
1151 TokenInformationLength,
1152 ReturnLength,
1153 NULL,
1154 PreviousMode);
1155 if (!NT_SUCCESS(Status))
1156 {
1157 DPRINT("NtQueryInformationToken() failed, Status: 0x%x\n", Status);
1158 return Status;
1159 }
1160
1161 Status = ObReferenceObjectByHandle(TokenHandle,
1162 (TokenInformationClass == TokenSource) ? TOKEN_QUERY_SOURCE : TOKEN_QUERY,
1163 SeTokenObjectType,
1164 PreviousMode,
1165 (PVOID*)&Token,
1166 NULL);
1167 if (NT_SUCCESS(Status))
1168 {
1169 switch (TokenInformationClass)
1170 {
1171 case TokenUser:
1172 {
1173 PTOKEN_USER tu = (PTOKEN_USER)TokenInformation;
1174
1175 DPRINT("NtQueryInformationToken(TokenUser)\n");
1176 RequiredLength = sizeof(TOKEN_USER) +
1177 RtlLengthSid(Token->UserAndGroups[0].Sid);
1178
1179 _SEH2_TRY
1180 {
1181 if (TokenInformationLength >= RequiredLength)
1182 {
1183 Status = RtlCopySidAndAttributesArray(1,
1184 &Token->UserAndGroups[0],
1185 RequiredLength - sizeof(TOKEN_USER),
1186 &tu->User,
1187 (PSID)(tu + 1),
1188 &Unused.Ptr,
1189 &Unused.Ulong);
1190 }
1191 else
1192 {
1193 Status = STATUS_BUFFER_TOO_SMALL;
1194 }
1195
1196 if (ReturnLength != NULL)
1197 {
1198 *ReturnLength = RequiredLength;
1199 }
1200 }
1201 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1202 {
1203 Status = _SEH2_GetExceptionCode();
1204 }
1205 _SEH2_END;
1206
1207 break;
1208 }
1209
1210 case TokenGroups:
1211 {
1212 PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation;
1213
1214 DPRINT("NtQueryInformationToken(TokenGroups)\n");
1215 RequiredLength = sizeof(tg->GroupCount) +
1216 RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]);
1217
1218 _SEH2_TRY
1219 {
1220 if (TokenInformationLength >= RequiredLength)
1221 {
1222 ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) -
1223 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES));
1224 PSID_AND_ATTRIBUTES Sid = (PSID_AND_ATTRIBUTES)((ULONG_PTR)TokenInformation + sizeof(tg->GroupCount) +
1225 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES)));
1226
1227 tg->GroupCount = Token->UserAndGroupCount - 1;
1228 Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1,
1229 &Token->UserAndGroups[1],
1230 SidLen,
1231 &tg->Groups[0],
1232 (PSID)Sid,
1233 &Unused.Ptr,
1234 &Unused.Ulong);
1235 }
1236 else
1237 {
1238 Status = STATUS_BUFFER_TOO_SMALL;
1239 }
1240
1241 if (ReturnLength != NULL)
1242 {
1243 *ReturnLength = RequiredLength;
1244 }
1245 }
1246 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1247 {
1248 Status = _SEH2_GetExceptionCode();
1249 }
1250 _SEH2_END;
1251
1252 break;
1253 }
1254
1255 case TokenPrivileges:
1256 {
1257 PTOKEN_PRIVILEGES tp = (PTOKEN_PRIVILEGES)TokenInformation;
1258
1259 DPRINT("NtQueryInformationToken(TokenPrivileges)\n");
1260 RequiredLength = sizeof(tp->PrivilegeCount) +
1261 (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
1262
1263 _SEH2_TRY
1264 {
1265 if (TokenInformationLength >= RequiredLength)
1266 {
1267 tp->PrivilegeCount = Token->PrivilegeCount;
1268 RtlCopyLuidAndAttributesArray(Token->PrivilegeCount,
1269 Token->Privileges,
1270 &tp->Privileges[0]);
1271 }
1272 else
1273 {
1274 Status = STATUS_BUFFER_TOO_SMALL;
1275 }
1276
1277 if (ReturnLength != NULL)
1278 {
1279 *ReturnLength = RequiredLength;
1280 }
1281 }
1282 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1283 {
1284 Status = _SEH2_GetExceptionCode();
1285 }
1286 _SEH2_END;
1287
1288 break;
1289 }
1290
1291 case TokenOwner:
1292 {
1293 ULONG SidLen;
1294 PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation;
1295
1296 DPRINT("NtQueryInformationToken(TokenOwner)\n");
1297 SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
1298 RequiredLength = sizeof(TOKEN_OWNER) + SidLen;
1299
1300 _SEH2_TRY
1301 {
1302 if (TokenInformationLength >= RequiredLength)
1303 {
1304 to->Owner = (PSID)(to + 1);
1305 Status = RtlCopySid(SidLen,
1306 to->Owner,
1307 Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
1308 }
1309 else
1310 {
1311 Status = STATUS_BUFFER_TOO_SMALL;
1312 }
1313
1314 if (ReturnLength != NULL)
1315 {
1316 *ReturnLength = RequiredLength;
1317 }
1318 }
1319 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1320 {
1321 Status = _SEH2_GetExceptionCode();
1322 }
1323 _SEH2_END;
1324
1325 break;
1326 }
1327
1328 case TokenPrimaryGroup:
1329 {
1330 ULONG SidLen;
1331 PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation;
1332
1333 DPRINT("NtQueryInformationToken(TokenPrimaryGroup)\n");
1334 SidLen = RtlLengthSid(Token->PrimaryGroup);
1335 RequiredLength = sizeof(TOKEN_PRIMARY_GROUP) + SidLen;
1336
1337 _SEH2_TRY
1338 {
1339 if (TokenInformationLength >= RequiredLength)
1340 {
1341 tpg->PrimaryGroup = (PSID)(tpg + 1);
1342 Status = RtlCopySid(SidLen,
1343 tpg->PrimaryGroup,
1344 Token->PrimaryGroup);
1345 }
1346 else
1347 {
1348 Status = STATUS_BUFFER_TOO_SMALL;
1349 }
1350
1351 if (ReturnLength != NULL)
1352 {
1353 *ReturnLength = RequiredLength;
1354 }
1355 }
1356 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1357 {
1358 Status = _SEH2_GetExceptionCode();
1359 }
1360 _SEH2_END;
1361
1362 break;
1363 }
1364
1365 case TokenDefaultDacl:
1366 {
1367 PTOKEN_DEFAULT_DACL tdd = (PTOKEN_DEFAULT_DACL)TokenInformation;
1368
1369 DPRINT("NtQueryInformationToken(TokenDefaultDacl)\n");
1370 RequiredLength = sizeof(TOKEN_DEFAULT_DACL);
1371
1372 if (Token->DefaultDacl != NULL)
1373 {
1374 RequiredLength += Token->DefaultDacl->AclSize;
1375 }
1376
1377 _SEH2_TRY
1378 {
1379 if (TokenInformationLength >= RequiredLength)
1380 {
1381 if (Token->DefaultDacl != NULL)
1382 {
1383 tdd->DefaultDacl = (PACL)(tdd + 1);
1384 RtlCopyMemory(tdd->DefaultDacl,
1385 Token->DefaultDacl,
1386 Token->DefaultDacl->AclSize);
1387 }
1388 else
1389 {
1390 tdd->DefaultDacl = NULL;
1391 }
1392 }
1393 else
1394 {
1395 Status = STATUS_BUFFER_TOO_SMALL;
1396 }
1397
1398 if (ReturnLength != NULL)
1399 {
1400 *ReturnLength = RequiredLength;
1401 }
1402 }
1403 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1404 {
1405 Status = _SEH2_GetExceptionCode();
1406 }
1407 _SEH2_END;
1408
1409 break;
1410 }
1411
1412 case TokenSource:
1413 {
1414 PTOKEN_SOURCE ts = (PTOKEN_SOURCE)TokenInformation;
1415
1416 DPRINT("NtQueryInformationToken(TokenSource)\n");
1417 RequiredLength = sizeof(TOKEN_SOURCE);
1418
1419 _SEH2_TRY
1420 {
1421 if (TokenInformationLength >= RequiredLength)
1422 {
1423 *ts = Token->TokenSource;
1424 }
1425 else
1426 {
1427 Status = STATUS_BUFFER_TOO_SMALL;
1428 }
1429
1430 if (ReturnLength != NULL)
1431 {
1432 *ReturnLength = RequiredLength;
1433 }
1434 }
1435 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1436 {
1437 Status = _SEH2_GetExceptionCode();
1438 }
1439 _SEH2_END;
1440
1441 break;
1442 }
1443
1444 case TokenType:
1445 {
1446 PTOKEN_TYPE tt = (PTOKEN_TYPE)TokenInformation;
1447
1448 DPRINT("NtQueryInformationToken(TokenType)\n");
1449 RequiredLength = sizeof(TOKEN_TYPE);
1450
1451 _SEH2_TRY
1452 {
1453 if (TokenInformationLength >= RequiredLength)
1454 {
1455 *tt = Token->TokenType;
1456 }
1457 else
1458 {
1459 Status = STATUS_BUFFER_TOO_SMALL;
1460 }
1461
1462 if (ReturnLength != NULL)
1463 {
1464 *ReturnLength = RequiredLength;
1465 }
1466 }
1467 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1468 {
1469 Status = _SEH2_GetExceptionCode();
1470 }
1471 _SEH2_END;
1472
1473 break;
1474 }
1475
1476 case TokenImpersonationLevel:
1477 {
1478 PSECURITY_IMPERSONATION_LEVEL sil = (PSECURITY_IMPERSONATION_LEVEL)TokenInformation;
1479
1480 DPRINT("NtQueryInformationToken(TokenImpersonationLevel)\n");
1481
1482 /* Fail if the token is not an impersonation token */
1483 if (Token->TokenType != TokenImpersonation)
1484 {
1485 Status = STATUS_INVALID_INFO_CLASS;
1486 break;
1487 }
1488
1489 RequiredLength = sizeof(SECURITY_IMPERSONATION_LEVEL);
1490
1491 _SEH2_TRY
1492 {
1493 if (TokenInformationLength >= RequiredLength)
1494 {
1495 *sil = Token->ImpersonationLevel;
1496 }
1497 else
1498 {
1499 Status = STATUS_BUFFER_TOO_SMALL;
1500 }
1501
1502 if (ReturnLength != NULL)
1503 {
1504 *ReturnLength = RequiredLength;
1505 }
1506 }
1507 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1508 {
1509 Status = _SEH2_GetExceptionCode();
1510 }
1511 _SEH2_END;
1512
1513 break;
1514 }
1515
1516 case TokenStatistics:
1517 {
1518 PTOKEN_STATISTICS ts = (PTOKEN_STATISTICS)TokenInformation;
1519
1520 DPRINT("NtQueryInformationToken(TokenStatistics)\n");
1521 RequiredLength = sizeof(TOKEN_STATISTICS);
1522
1523 _SEH2_TRY
1524 {
1525 if (TokenInformationLength >= RequiredLength)
1526 {
1527 ts->TokenId = Token->TokenId;
1528 ts->AuthenticationId = Token->AuthenticationId;
1529 ts->ExpirationTime = Token->ExpirationTime;
1530 ts->TokenType = Token->TokenType;
1531 ts->ImpersonationLevel = Token->ImpersonationLevel;
1532 ts->DynamicCharged = Token->DynamicCharged;
1533 ts->DynamicAvailable = Token->DynamicAvailable;
1534 ts->GroupCount = Token->UserAndGroupCount - 1;
1535 ts->PrivilegeCount = Token->PrivilegeCount;
1536 ts->ModifiedId = Token->ModifiedId;
1537 }
1538 else
1539 {
1540 Status = STATUS_BUFFER_TOO_SMALL;
1541 }
1542
1543 if (ReturnLength != NULL)
1544 {
1545 *ReturnLength = RequiredLength;
1546 }
1547 }
1548 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1549 {
1550 Status = _SEH2_GetExceptionCode();
1551 }
1552 _SEH2_END;
1553
1554 break;
1555 }
1556
1557 case TokenOrigin:
1558 {
1559 PTOKEN_ORIGIN to = (PTOKEN_ORIGIN)TokenInformation;
1560
1561 DPRINT("NtQueryInformationToken(TokenOrigin)\n");
1562 RequiredLength = sizeof(TOKEN_ORIGIN);
1563
1564 _SEH2_TRY
1565 {
1566 if (TokenInformationLength >= RequiredLength)
1567 {
1568 RtlCopyLuid(&to->OriginatingLogonSession,
1569 &Token->AuthenticationId);
1570 }
1571 else
1572 {
1573 Status = STATUS_BUFFER_TOO_SMALL;
1574 }
1575
1576 if (ReturnLength != NULL)
1577 {
1578 *ReturnLength = RequiredLength;
1579 }
1580 }
1581 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1582 {
1583 Status = _SEH2_GetExceptionCode();
1584 }
1585 _SEH2_END;
1586
1587 break;
1588 }
1589
1590 case TokenGroupsAndPrivileges:
1591 DPRINT1("NtQueryInformationToken(TokenGroupsAndPrivileges) not implemented\n");
1592 Status = STATUS_NOT_IMPLEMENTED;
1593 break;
1594
1595 case TokenRestrictedSids:
1596 {
1597 PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation;
1598
1599 DPRINT("NtQueryInformationToken(TokenRestrictedSids)\n");
1600 RequiredLength = sizeof(tg->GroupCount) +
1601 RtlLengthSidAndAttributes(Token->RestrictedSidCount, Token->RestrictedSids);
1602
1603 _SEH2_TRY
1604 {
1605 if (TokenInformationLength >= RequiredLength)
1606 {
1607 ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) -
1608 (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES));
1609 PSID_AND_ATTRIBUTES Sid = (PSID_AND_ATTRIBUTES)((ULONG_PTR)TokenInformation + sizeof(tg->GroupCount) +
1610 (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)));
1611
1612 tg->GroupCount = Token->RestrictedSidCount;
1613 Status = RtlCopySidAndAttributesArray(Token->RestrictedSidCount,
1614 Token->RestrictedSids,
1615 SidLen,
1616 &tg->Groups[0],
1617 (PSID)Sid,
1618 &Unused.Ptr,
1619 &Unused.Ulong);
1620 }
1621 else
1622 {
1623 Status = STATUS_BUFFER_TOO_SMALL;
1624 }
1625
1626 if (ReturnLength != NULL)
1627 {
1628 *ReturnLength = RequiredLength;
1629 }
1630 }
1631 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1632 {
1633 Status = _SEH2_GetExceptionCode();
1634 }
1635 _SEH2_END;
1636
1637 break;
1638 }
1639
1640 case TokenSandBoxInert:
1641 DPRINT1("NtQueryInformationToken(TokenSandboxInert) not implemented\n");
1642 Status = STATUS_NOT_IMPLEMENTED;
1643 break;
1644
1645 case TokenSessionId:
1646 {
1647 ULONG SessionId = 0;
1648
1649 DPRINT("NtQueryInformationToken(TokenSessionId)\n");
1650
1651 Status = SeQuerySessionIdToken(Token,
1652 &SessionId);
1653
1654 if (NT_SUCCESS(Status))
1655 {
1656 _SEH2_TRY
1657 {
1658 /* buffer size was already verified, no need to check here again */
1659 *(PULONG)TokenInformation = SessionId;
1660
1661 if (ReturnLength != NULL)
1662 {
1663 *ReturnLength = sizeof(ULONG);
1664 }
1665 }
1666 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1667 {
1668 Status = _SEH2_GetExceptionCode();
1669 }
1670 _SEH2_END;
1671 }
1672
1673 break;
1674 }
1675
1676 default:
1677 DPRINT1("NtQueryInformationToken(%d) invalid information class\n", TokenInformationClass);
1678 Status = STATUS_INVALID_INFO_CLASS;
1679 break;
1680 }
1681
1682 ObDereferenceObject(Token);
1683 }
1684
1685 return Status;
1686 }
1687
1688
1689 /*
1690 * NtSetTokenInformation: Partly implemented.
1691 * Unimplemented:
1692 * TokenOrigin, TokenDefaultDacl
1693 */
1694
1695 NTSTATUS NTAPI
1696 NtSetInformationToken(IN HANDLE TokenHandle,
1697 IN TOKEN_INFORMATION_CLASS TokenInformationClass,
1698 OUT PVOID TokenInformation,
1699 IN ULONG TokenInformationLength)
1700 {
1701 PTOKEN Token;
1702 KPROCESSOR_MODE PreviousMode;
1703 ULONG NeededAccess = TOKEN_ADJUST_DEFAULT;
1704 NTSTATUS Status;
1705
1706 PAGED_CODE();
1707
1708 PreviousMode = ExGetPreviousMode();
1709
1710 Status = DefaultSetInfoBufferCheck(TokenInformationClass,
1711 SeTokenInformationClass,
1712 sizeof(SeTokenInformationClass) / sizeof(SeTokenInformationClass[0]),
1713 TokenInformation,
1714 TokenInformationLength,
1715 PreviousMode);
1716 if (!NT_SUCCESS(Status))
1717 {
1718 /* Invalid buffers */
1719 DPRINT("NtSetInformationToken() failed, Status: 0x%x\n", Status);
1720 return Status;
1721 }
1722
1723 if (TokenInformationClass == TokenSessionId)
1724 {
1725 NeededAccess |= TOKEN_ADJUST_SESSIONID;
1726 }
1727
1728 Status = ObReferenceObjectByHandle(TokenHandle,
1729 NeededAccess,
1730 SeTokenObjectType,
1731 PreviousMode,
1732 (PVOID*)&Token,
1733 NULL);
1734 if (NT_SUCCESS(Status))
1735 {
1736 switch (TokenInformationClass)
1737 {
1738 case TokenOwner:
1739 {
1740 if (TokenInformationLength >= sizeof(TOKEN_OWNER))
1741 {
1742 PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation;
1743 PSID InputSid = NULL, CapturedSid;
1744
1745 _SEH2_TRY
1746 {
1747 InputSid = to->Owner;
1748 }
1749 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1750 {
1751 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1752 }
1753 _SEH2_END;
1754
1755 Status = SepCaptureSid(InputSid,
1756 PreviousMode,
1757 PagedPool,
1758 FALSE,
1759 &CapturedSid);
1760 if (NT_SUCCESS(Status))
1761 {
1762 RtlCopySid(RtlLengthSid(CapturedSid),
1763 Token->UserAndGroups[Token->DefaultOwnerIndex].Sid,
1764 CapturedSid);
1765 SepReleaseSid(CapturedSid,
1766 PreviousMode,
1767 FALSE);
1768 }
1769 }
1770 else
1771 {
1772 Status = STATUS_INFO_LENGTH_MISMATCH;
1773 }
1774 break;
1775 }
1776
1777 case TokenPrimaryGroup:
1778 {
1779 if (TokenInformationLength >= sizeof(TOKEN_PRIMARY_GROUP))
1780 {
1781 PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation;
1782 PSID InputSid = NULL, CapturedSid;
1783
1784 _SEH2_TRY
1785 {
1786 InputSid = tpg->PrimaryGroup;
1787 }
1788 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1789 {
1790 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1791 }
1792 _SEH2_END;
1793
1794 Status = SepCaptureSid(InputSid,
1795 PreviousMode,
1796 PagedPool,
1797 FALSE,
1798 &CapturedSid);
1799 if (NT_SUCCESS(Status))
1800 {
1801 RtlCopySid(RtlLengthSid(CapturedSid),
1802 Token->PrimaryGroup,
1803 CapturedSid);
1804 SepReleaseSid(CapturedSid,
1805 PreviousMode,
1806 FALSE);
1807 }
1808 }
1809 else
1810 {
1811 Status = STATUS_INFO_LENGTH_MISMATCH;
1812 }
1813 break;
1814 }
1815
1816 case TokenDefaultDacl:
1817 {
1818 if (TokenInformationLength >= sizeof(TOKEN_DEFAULT_DACL))
1819 {
1820 PTOKEN_DEFAULT_DACL tdd = (PTOKEN_DEFAULT_DACL)TokenInformation;
1821 PACL InputAcl = NULL;
1822
1823 _SEH2_TRY
1824 {
1825 InputAcl = tdd->DefaultDacl;
1826 }
1827 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1828 {
1829 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1830 }
1831 _SEH2_END;
1832
1833 if (InputAcl != NULL)
1834 {
1835 PACL CapturedAcl;
1836
1837 /* Capture and copy the dacl */
1838 Status = SepCaptureAcl(InputAcl,
1839 PreviousMode,
1840 PagedPool,
1841 TRUE,
1842 &CapturedAcl);
1843 if (NT_SUCCESS(Status))
1844 {
1845 /* Free the previous dacl if present */
1846 if(Token->DefaultDacl != NULL)
1847 {
1848 ExFreePoolWithTag(Token->DefaultDacl, TAG_TOKEN_ACL);
1849 }
1850
1851 /* Set the new dacl */
1852 Token->DefaultDacl = CapturedAcl;
1853 }
1854 }
1855 else
1856 {
1857 /* Clear and free the default dacl if present */
1858 if (Token->DefaultDacl != NULL)
1859 {
1860 ExFreePoolWithTag(Token->DefaultDacl, TAG_TOKEN_ACL);
1861 Token->DefaultDacl = NULL;
1862 }
1863 }
1864 }
1865 else
1866 {
1867 Status = STATUS_INFO_LENGTH_MISMATCH;
1868 }
1869 break;
1870 }
1871
1872 case TokenSessionId:
1873 {
1874 ULONG SessionId = 0;
1875
1876 _SEH2_TRY
1877 {
1878 /* Buffer size was already verified, no need to check here again */
1879 SessionId = *(PULONG)TokenInformation;
1880 }
1881 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1882 {
1883 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1884 }
1885 _SEH2_END;
1886
1887 if (!SeSinglePrivilegeCheck(SeTcbPrivilege,
1888 PreviousMode))
1889 {
1890 Status = STATUS_PRIVILEGE_NOT_HELD;
1891 break;
1892 }
1893
1894 Token->SessionId = SessionId;
1895 break;
1896 }
1897
1898 default:
1899 {
1900 Status = STATUS_NOT_IMPLEMENTED;
1901 break;
1902 }
1903 }
1904
1905 ObDereferenceObject(Token);
1906 }
1907
1908 return Status;
1909 }
1910
1911
1912 /*
1913 * @implemented
1914 *
1915 * NOTE: Some sources claim 4th param is ImpersonationLevel, but on W2K
1916 * this is certainly NOT true, thou i can't say for sure that EffectiveOnly
1917 * is correct either. -Gunnar
1918 * This is true. EffectiveOnly overrides SQOS.EffectiveOnly. - IAI
1919 */
1920 NTSTATUS NTAPI
1921 NtDuplicateToken(IN HANDLE ExistingTokenHandle,
1922 IN ACCESS_MASK DesiredAccess,
1923 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
1924 IN BOOLEAN EffectiveOnly,
1925 IN TOKEN_TYPE TokenType,
1926 OUT PHANDLE NewTokenHandle)
1927 {
1928 KPROCESSOR_MODE PreviousMode;
1929 HANDLE hToken;
1930 PTOKEN Token;
1931 PTOKEN NewToken;
1932 PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService;
1933 BOOLEAN QoSPresent;
1934 OBJECT_HANDLE_INFORMATION HandleInformation;
1935 NTSTATUS Status;
1936
1937 PAGED_CODE();
1938
1939 if (TokenType != TokenImpersonation &&
1940 TokenType != TokenPrimary)
1941 return STATUS_INVALID_PARAMETER;
1942
1943 PreviousMode = KeGetPreviousMode();
1944
1945 if (PreviousMode != KernelMode)
1946 {
1947 _SEH2_TRY
1948 {
1949 ProbeForWriteHandle(NewTokenHandle);
1950 }
1951 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1952 {
1953 /* Return the exception code */
1954 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1955 }
1956 _SEH2_END;
1957 }
1958
1959 Status = SepCaptureSecurityQualityOfService(ObjectAttributes,
1960 PreviousMode,
1961 PagedPool,
1962 FALSE,
1963 &CapturedSecurityQualityOfService,
1964 &QoSPresent);
1965 if (!NT_SUCCESS(Status))
1966 {
1967 DPRINT1("NtDuplicateToken() failed to capture QoS! Status: 0x%x\n", Status);
1968 return Status;
1969 }
1970
1971 Status = ObReferenceObjectByHandle(ExistingTokenHandle,
1972 TOKEN_DUPLICATE,
1973 SeTokenObjectType,
1974 PreviousMode,
1975 (PVOID*)&Token,
1976 &HandleInformation);
1977 if (!NT_SUCCESS(Status))
1978 {
1979 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
1980 PreviousMode,
1981 FALSE);
1982 return Status;
1983 }
1984
1985 /*
1986 * Fail, if the original token is an impersonation token and the caller
1987 * tries to raise the impersonation level of the new token above the
1988 * impersonation level of the original token.
1989 */
1990 if (Token->TokenType == TokenImpersonation)
1991 {
1992 if (QoSPresent &&
1993 CapturedSecurityQualityOfService->ImpersonationLevel >Token->ImpersonationLevel)
1994 {
1995 ObDereferenceObject(Token);
1996 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
1997 PreviousMode,
1998 FALSE);
1999 return STATUS_BAD_IMPERSONATION_LEVEL;
2000 }
2001 }
2002
2003 /*
2004 * Fail, if a primary token is to be created from an impersonation token
2005 * and and the impersonation level of the impersonation token is below SecurityImpersonation.
2006 */
2007 if (Token->TokenType == TokenImpersonation &&
2008 TokenType == TokenPrimary &&
2009 Token->ImpersonationLevel < SecurityImpersonation)
2010 {
2011 ObDereferenceObject(Token);
2012 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
2013 PreviousMode,
2014 FALSE);
2015 return STATUS_BAD_IMPERSONATION_LEVEL;
2016 }
2017
2018 Status = SepDuplicateToken(Token,
2019 ObjectAttributes,
2020 EffectiveOnly,
2021 TokenType,
2022 (QoSPresent ? CapturedSecurityQualityOfService->ImpersonationLevel : SecurityAnonymous),
2023 PreviousMode,
2024 &NewToken);
2025
2026 ObDereferenceObject(Token);
2027
2028 if (NT_SUCCESS(Status))
2029 {
2030 Status = ObInsertObject((PVOID)NewToken,
2031 NULL,
2032 (DesiredAccess ? DesiredAccess : HandleInformation.GrantedAccess),
2033 0,
2034 NULL,
2035 &hToken);
2036 if (NT_SUCCESS(Status))
2037 {
2038 _SEH2_TRY
2039 {
2040 *NewTokenHandle = hToken;
2041 }
2042 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2043 {
2044 Status = _SEH2_GetExceptionCode();
2045 }
2046 _SEH2_END;
2047 }
2048 }
2049
2050 /* Free the captured structure */
2051 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
2052 PreviousMode,
2053 FALSE);
2054
2055 return Status;
2056 }
2057
2058 NTSTATUS NTAPI
2059 NtAdjustGroupsToken(IN HANDLE TokenHandle,
2060 IN BOOLEAN ResetToDefault,
2061 IN PTOKEN_GROUPS NewState,
2062 IN ULONG BufferLength,
2063 OUT PTOKEN_GROUPS PreviousState OPTIONAL,
2064 OUT PULONG ReturnLength)
2065 {
2066 UNIMPLEMENTED;
2067 return(STATUS_NOT_IMPLEMENTED);
2068 }
2069
2070
2071 static
2072 ULONG
2073 SepAdjustPrivileges(
2074 _Inout_ PTOKEN Token,
2075 _In_ BOOLEAN DisableAllPrivileges,
2076 _In_opt_ PLUID_AND_ATTRIBUTES NewState,
2077 _In_ ULONG NewStateCount,
2078 _Out_opt_ PTOKEN_PRIVILEGES PreviousState,
2079 _In_ BOOLEAN ApplyChanges,
2080 _Out_ PULONG ChangedPrivileges)
2081 {
2082 ULONG i, j, PrivilegeCount, ChangeCount, NewAttributes;
2083
2084 /* Count the found privileges and those that need to be changed */
2085 PrivilegeCount = 0;
2086 ChangeCount = 0;
2087
2088 /* Loop all privileges in the token */
2089 for (i = 0; i < Token->PrivilegeCount; i++)
2090 {
2091 /* Shall all of them be disabled? */
2092 if (DisableAllPrivileges)
2093 {
2094 /* The new attributes are the old ones, but disabled */
2095 NewAttributes = Token->Privileges[i].Attributes & ~SE_PRIVILEGE_ENABLED;
2096 }
2097 else
2098 {
2099 /* Otherwise loop all provided privileges */
2100 for (j = 0; j < NewStateCount; j++)
2101 {
2102 /* Check if this is the LUID we are looking for */
2103 if (RtlEqualLuid(&Token->Privileges[i].Luid, &NewState[j].Luid))
2104 {
2105 DPRINT("Found privilege\n");
2106
2107 /* Copy SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED */
2108 NewAttributes = NewState[j].Attributes;
2109 NewAttributes &= (SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED);
2110 NewAttributes |= Token->Privileges[i].Attributes & ~SE_PRIVILEGE_ENABLED;
2111
2112 /* Stop looking */
2113 break;
2114 }
2115 }
2116
2117 /* Check if we didn't find the privilege */
2118 if (j == NewStateCount)
2119 {
2120 /* Continue with the token's next privilege */
2121 continue;
2122 }
2123 }
2124
2125 /* We found a privilege, count it */
2126 PrivilegeCount++;
2127
2128 /* Does the privilege need to be changed? */
2129 if (Token->Privileges[i].Attributes != NewAttributes)
2130 {
2131 /* Does the caller want the old privileges? */
2132 if (PreviousState != NULL)
2133 {
2134 /* Copy the old privilege */
2135 PreviousState->Privileges[ChangeCount] = Token->Privileges[i];
2136 }
2137
2138 /* Does the caller want to apply the changes? */
2139 if (ApplyChanges)
2140 {
2141 /* Shall we remove the privilege? */
2142 if (NewAttributes & SE_PRIVILEGE_REMOVED)
2143 {
2144 /* Set the token as disabled and update flags for it */
2145 Token->Privileges[i].Attributes &= ~SE_PRIVILEGE_ENABLED;
2146 SepUpdateSinglePrivilegeFlagToken(Token, i);
2147
2148 /* Remove the privilege */
2149 SepRemovePrivilegeToken(Token, i);
2150
2151 /* Fix the running index */
2152 i--;
2153
2154 /* Continue with next */
2155 continue;
2156 }
2157
2158 /* Set the new attributes and update flags */
2159 Token->Privileges[i].Attributes = NewAttributes;
2160 SepUpdateSinglePrivilegeFlagToken(Token, i);
2161 }
2162
2163 /* Increment the change count */
2164 ChangeCount++;
2165 }
2166 }
2167
2168 /* Set the number of saved privileges */
2169 if (PreviousState != NULL)
2170 PreviousState->PrivilegeCount = ChangeCount;
2171
2172 /* Return the number of changed privileges */
2173 *ChangedPrivileges = ChangeCount;
2174
2175 /* Check if we missed some */
2176 if (!DisableAllPrivileges && (PrivilegeCount < NewStateCount))
2177 {
2178 return STATUS_NOT_ALL_ASSIGNED;
2179 }
2180
2181 return STATUS_SUCCESS;
2182 }
2183
2184
2185 /*
2186 * @implemented
2187 */
2188 _Must_inspect_result_
2189 __kernel_entry
2190 NTSTATUS
2191 NTAPI
2192 NtAdjustPrivilegesToken(
2193 _In_ HANDLE TokenHandle,
2194 _In_ BOOLEAN DisableAllPrivileges,
2195 _In_opt_ PTOKEN_PRIVILEGES NewState,
2196 _In_ ULONG BufferLength,
2197 _Out_writes_bytes_to_opt_(BufferLength,*ReturnLength)
2198 PTOKEN_PRIVILEGES PreviousState,
2199 _When_(PreviousState!=NULL, _Out_) PULONG ReturnLength)
2200 {
2201 PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
2202 KPROCESSOR_MODE PreviousMode;
2203 ULONG CapturedCount = 0;
2204 ULONG CapturedLength = 0;
2205 ULONG NewStateSize = 0;
2206 ULONG ChangeCount;
2207 ULONG RequiredLength;
2208 PTOKEN Token;
2209 NTSTATUS Status;
2210 PAGED_CODE();
2211
2212 DPRINT("NtAdjustPrivilegesToken() called\n");
2213
2214 /* Fail, if we do not disable all privileges but NewState is NULL */
2215 if (DisableAllPrivileges == FALSE && NewState == NULL)
2216 return STATUS_INVALID_PARAMETER;
2217
2218 PreviousMode = KeGetPreviousMode ();
2219 if (PreviousMode != KernelMode)
2220 {
2221 _SEH2_TRY
2222 {
2223 /* Probe NewState */
2224 if (DisableAllPrivileges == FALSE)
2225 {
2226 /* First probe the header */
2227 ProbeForRead(NewState, sizeof(TOKEN_PRIVILEGES), sizeof(ULONG));
2228
2229 CapturedCount = NewState->PrivilegeCount;
2230 NewStateSize = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[CapturedCount]);
2231
2232 ProbeForRead(NewState, NewStateSize, sizeof(ULONG));
2233 }
2234
2235 /* Probe PreviousState and ReturnLength */
2236 if (PreviousState != NULL)
2237 {
2238 ProbeForWrite(PreviousState, BufferLength, sizeof(ULONG));
2239 ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG));
2240 }
2241 }
2242 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2243 {
2244 /* Return the exception code */
2245 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2246 }
2247 _SEH2_END;
2248 }
2249 else
2250 {
2251 /* This is kernel mode, we trust the caller */
2252 if (DisableAllPrivileges == FALSE)
2253 CapturedCount = NewState->PrivilegeCount;
2254 }
2255
2256 /* Do we need to capture the new state? */
2257 if (DisableAllPrivileges == FALSE)
2258 {
2259 _SEH2_TRY
2260 {
2261 /* Capture the new state array of privileges */
2262 Status = SeCaptureLuidAndAttributesArray(NewState->Privileges,
2263 CapturedCount,
2264 PreviousMode,
2265 NULL,
2266 0,
2267 PagedPool,
2268 TRUE,
2269 &CapturedPrivileges,
2270 &CapturedLength);
2271 }
2272 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2273 {
2274 /* Return the exception code */
2275 Status = _SEH2_GetExceptionCode();
2276 }
2277 _SEH2_END;
2278
2279 if (!NT_SUCCESS(Status))
2280 return Status;
2281 }
2282
2283 /* Reference the token */
2284 Status = ObReferenceObjectByHandle(TokenHandle,
2285 TOKEN_ADJUST_PRIVILEGES | (PreviousState != NULL ? TOKEN_QUERY : 0),
2286 SeTokenObjectType,
2287 PreviousMode,
2288 (PVOID*)&Token,
2289 NULL);
2290 if (!NT_SUCCESS(Status))
2291 {
2292 DPRINT1("Failed to reference token (Status %lx)\n", Status);
2293
2294 /* Release the captured privileges */
2295 if (CapturedPrivileges != NULL)
2296 SeReleaseLuidAndAttributesArray(CapturedPrivileges,
2297 PreviousMode,
2298 TRUE);
2299
2300 return Status;
2301 }
2302
2303 /* Lock the token */
2304 ExEnterCriticalRegionAndAcquireResourceExclusive(Token->TokenLock);
2305
2306 /* Count the privileges that need to be changed, do not apply them yet */
2307 Status = SepAdjustPrivileges(Token,
2308 DisableAllPrivileges,
2309 CapturedPrivileges,
2310 CapturedCount,
2311 NULL,
2312 FALSE,
2313 &ChangeCount);
2314
2315 /* Check if the caller asked for the previous state */
2316 if (PreviousState != NULL)
2317 {
2318 /* Calculate the required length */
2319 RequiredLength = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[ChangeCount]);
2320
2321 /* Try to return the required buffer length */
2322 _SEH2_TRY
2323 {
2324 *ReturnLength = RequiredLength;
2325 }
2326 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2327 {
2328 /* Do cleanup and return the exception code */
2329 Status = _SEH2_GetExceptionCode();
2330 goto Cleanup;
2331 }
2332 _SEH2_END;
2333
2334 /* Fail, if the buffer length is smaller than the required length */
2335 if (BufferLength < RequiredLength)
2336 {
2337 Status = STATUS_BUFFER_TOO_SMALL;
2338 goto Cleanup;
2339 }
2340 }
2341
2342 /* Now enter SEH, since we might return the old privileges */
2343 _SEH2_TRY
2344 {
2345 /* This time apply the changes */
2346 Status = SepAdjustPrivileges(Token,
2347 DisableAllPrivileges,
2348 CapturedPrivileges,
2349 CapturedCount,
2350 PreviousState,
2351 TRUE,
2352 &ChangeCount);
2353 }
2354 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2355 {
2356 /* Do cleanup and return the exception code */
2357 Status = _SEH2_GetExceptionCode();
2358 goto Cleanup;
2359 }
2360 _SEH2_END;
2361
2362 Cleanup:
2363 /* Unlock and dereference the token */
2364 ExReleaseResourceAndLeaveCriticalRegion(Token->TokenLock);
2365 ObDereferenceObject(Token);
2366
2367 /* Release the captured privileges */
2368 if (CapturedPrivileges != NULL)
2369 SeReleaseLuidAndAttributesArray(CapturedPrivileges,
2370 PreviousMode,
2371 TRUE);
2372
2373 DPRINT ("NtAdjustPrivilegesToken() done\n");
2374 return Status;
2375 }
2376
2377 NTSTATUS
2378 NTAPI
2379 NtCreateToken(OUT PHANDLE TokenHandle,
2380 IN ACCESS_MASK DesiredAccess,
2381 IN POBJECT_ATTRIBUTES ObjectAttributes,
2382 IN TOKEN_TYPE TokenType,
2383 IN PLUID AuthenticationId,
2384 IN PLARGE_INTEGER ExpirationTime,
2385 IN PTOKEN_USER TokenUser,
2386 IN PTOKEN_GROUPS TokenGroups,
2387 IN PTOKEN_PRIVILEGES TokenPrivileges,
2388 IN PTOKEN_OWNER TokenOwner,
2389 IN PTOKEN_PRIMARY_GROUP TokenPrimaryGroup,
2390 IN PTOKEN_DEFAULT_DACL TokenDefaultDacl,
2391 IN PTOKEN_SOURCE TokenSource)
2392 {
2393 HANDLE hToken;
2394 KPROCESSOR_MODE PreviousMode;
2395 ULONG nTokenPrivileges = 0;
2396 LARGE_INTEGER LocalExpirationTime = {{0, 0}};
2397 NTSTATUS Status;
2398
2399 PAGED_CODE();
2400
2401 PreviousMode = ExGetPreviousMode();
2402
2403 if (PreviousMode != KernelMode)
2404 {
2405 _SEH2_TRY
2406 {
2407 ProbeForWriteHandle(TokenHandle);
2408 ProbeForRead(AuthenticationId,
2409 sizeof(LUID),
2410 sizeof(ULONG));
2411 LocalExpirationTime = ProbeForReadLargeInteger(ExpirationTime);
2412 ProbeForRead(TokenUser,
2413 sizeof(TOKEN_USER),
2414 sizeof(ULONG));
2415 ProbeForRead(TokenGroups,
2416 sizeof(TOKEN_GROUPS),
2417 sizeof(ULONG));
2418 ProbeForRead(TokenPrivileges,
2419 sizeof(TOKEN_PRIVILEGES),
2420 sizeof(ULONG));
2421 ProbeForRead(TokenOwner,
2422 sizeof(TOKEN_OWNER),
2423 sizeof(ULONG));
2424 ProbeForRead(TokenPrimaryGroup,
2425 sizeof(TOKEN_PRIMARY_GROUP),
2426 sizeof(ULONG));
2427 ProbeForRead(TokenDefaultDacl,
2428 sizeof(TOKEN_DEFAULT_DACL),
2429 sizeof(ULONG));
2430 ProbeForRead(TokenSource,
2431 sizeof(TOKEN_SOURCE),
2432 sizeof(ULONG));
2433 nTokenPrivileges = TokenPrivileges->PrivilegeCount;
2434 }
2435 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2436 {
2437 /* Return the exception code */
2438 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2439 }
2440 _SEH2_END;
2441 }
2442 else
2443 {
2444 nTokenPrivileges = TokenPrivileges->PrivilegeCount;
2445 LocalExpirationTime = *ExpirationTime;
2446 }
2447
2448 Status = SepCreateToken(&hToken,
2449 PreviousMode,
2450 DesiredAccess,
2451 ObjectAttributes,
2452 TokenType,
2453 ((PSECURITY_QUALITY_OF_SERVICE)(ObjectAttributes->SecurityQualityOfService))->ImpersonationLevel,
2454 AuthenticationId,
2455 &LocalExpirationTime,
2456 &TokenUser->User,
2457 TokenGroups->GroupCount,
2458 TokenGroups->Groups,
2459 0, // FIXME: Should capture
2460 nTokenPrivileges,
2461 TokenPrivileges->Privileges,
2462 TokenOwner->Owner,
2463 TokenPrimaryGroup->PrimaryGroup,
2464 TokenDefaultDacl->DefaultDacl,
2465 TokenSource,
2466 FALSE);
2467 if (NT_SUCCESS(Status))
2468 {
2469 _SEH2_TRY
2470 {
2471 *TokenHandle = hToken;
2472 }
2473 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2474 {
2475 Status = _SEH2_GetExceptionCode();
2476 }
2477 _SEH2_END;
2478 }
2479
2480 return Status;
2481 }
2482
2483 /*
2484 * @implemented
2485 */
2486 NTSTATUS
2487 NTAPI
2488 NtOpenThreadTokenEx(IN HANDLE ThreadHandle,
2489 IN ACCESS_MASK DesiredAccess,
2490 IN BOOLEAN OpenAsSelf,
2491 IN ULONG HandleAttributes,
2492 OUT PHANDLE TokenHandle)
2493 {
2494 PETHREAD Thread, NewThread;
2495 HANDLE hToken;
2496 PTOKEN Token, NewToken = NULL, PrimaryToken;
2497 BOOLEAN CopyOnOpen, EffectiveOnly;
2498 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
2499 SE_IMPERSONATION_STATE ImpersonationState;
2500 OBJECT_ATTRIBUTES ObjectAttributes;
2501 SECURITY_DESCRIPTOR SecurityDescriptor;
2502 PACL Dacl = NULL;
2503 KPROCESSOR_MODE PreviousMode;
2504 NTSTATUS Status;
2505 BOOLEAN RestoreImpersonation = FALSE;
2506
2507 PAGED_CODE();
2508
2509 PreviousMode = ExGetPreviousMode();
2510
2511 if (PreviousMode != KernelMode)
2512 {
2513 _SEH2_TRY
2514 {
2515 ProbeForWriteHandle(TokenHandle);
2516 }
2517 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2518 {
2519 /* Return the exception code */
2520 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2521 }
2522 _SEH2_END;
2523 }
2524
2525 /*
2526 * At first open the thread token for information access and verify
2527 * that the token associated with thread is valid.
2528 */
2529
2530 Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_QUERY_INFORMATION,
2531 PsThreadType, PreviousMode, (PVOID*)&Thread,
2532 NULL);
2533 if (!NT_SUCCESS(Status))
2534 {
2535 return Status;
2536 }
2537
2538 Token = PsReferenceImpersonationToken(Thread, &CopyOnOpen, &EffectiveOnly,
2539 &ImpersonationLevel);
2540 if (Token == NULL)
2541 {
2542 ObDereferenceObject(Thread);
2543 return STATUS_NO_TOKEN;
2544 }
2545
2546 if (ImpersonationLevel == SecurityAnonymous)
2547 {
2548 PsDereferenceImpersonationToken(Token);
2549 ObDereferenceObject(Thread);
2550 return STATUS_CANT_OPEN_ANONYMOUS;
2551 }
2552
2553 /*
2554 * Revert to self if OpenAsSelf is specified.
2555 */
2556
2557 if (OpenAsSelf)
2558 {
2559 RestoreImpersonation = PsDisableImpersonation(PsGetCurrentThread(),
2560 &ImpersonationState);
2561 }
2562
2563 if (CopyOnOpen)
2564 {
2565 Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_ALL_ACCESS,
2566 PsThreadType, KernelMode,
2567 (PVOID*)&NewThread, NULL);
2568 if (NT_SUCCESS(Status))
2569 {
2570 PrimaryToken = PsReferencePrimaryToken(NewThread->ThreadsProcess);
2571
2572 Status = SepCreateImpersonationTokenDacl(Token, PrimaryToken, &Dacl);
2573
2574 ObFastDereferenceObject(&NewThread->ThreadsProcess->Token, PrimaryToken);
2575
2576 if (NT_SUCCESS(Status))
2577 {
2578 if (Dacl)
2579 {
2580 RtlCreateSecurityDescriptor(&SecurityDescriptor,
2581 SECURITY_DESCRIPTOR_REVISION);
2582 RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl,
2583 FALSE);
2584 }
2585
2586 InitializeObjectAttributes(&ObjectAttributes, NULL, HandleAttributes,
2587 NULL, Dacl ? &SecurityDescriptor : NULL);
2588
2589
2590 Status = SepDuplicateToken(Token, &ObjectAttributes, EffectiveOnly,
2591 TokenImpersonation, ImpersonationLevel,
2592 KernelMode, &NewToken);
2593 if (NT_SUCCESS(Status))
2594 {
2595 ObReferenceObject(NewToken);
2596 Status = ObInsertObject(NewToken, NULL, DesiredAccess, 0, NULL,
2597 &hToken);
2598 }
2599 }
2600 }
2601 }
2602 else
2603 {
2604 Status = ObOpenObjectByPointer(Token, HandleAttributes,
2605 NULL, DesiredAccess, SeTokenObjectType,
2606 PreviousMode, &hToken);
2607 }
2608
2609 if (Dacl) ExFreePoolWithTag(Dacl, TAG_TOKEN_ACL);
2610
2611 if (RestoreImpersonation)
2612 {
2613 PsRestoreImpersonation(PsGetCurrentThread(), &ImpersonationState);
2614 }
2615
2616 ObDereferenceObject(Token);
2617
2618 if (NT_SUCCESS(Status) && CopyOnOpen)
2619 {
2620 PsImpersonateClient(Thread, NewToken, FALSE, EffectiveOnly, ImpersonationLevel);
2621 }
2622
2623 if (NewToken) ObDereferenceObject(NewToken);
2624
2625 if (CopyOnOpen && NewThread) ObDereferenceObject(NewThread);
2626
2627 if (NT_SUCCESS(Status))
2628 {
2629 _SEH2_TRY
2630 {
2631 *TokenHandle = hToken;
2632 }
2633 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2634 {
2635 Status = _SEH2_GetExceptionCode();
2636 }
2637 _SEH2_END;
2638 }
2639
2640 return Status;
2641 }
2642
2643 /*
2644 * @implemented
2645 */
2646 NTSTATUS NTAPI
2647 NtOpenThreadToken(IN HANDLE ThreadHandle,
2648 IN ACCESS_MASK DesiredAccess,
2649 IN BOOLEAN OpenAsSelf,
2650 OUT PHANDLE TokenHandle)
2651 {
2652 return NtOpenThreadTokenEx(ThreadHandle, DesiredAccess, OpenAsSelf, 0,
2653 TokenHandle);
2654 }
2655
2656
2657
2658 /*
2659 * @unimplemented
2660 */
2661 NTSTATUS
2662 NTAPI
2663 NtCompareTokens(IN HANDLE FirstTokenHandle,
2664 IN HANDLE SecondTokenHandle,
2665 OUT PBOOLEAN Equal)
2666 {
2667 KPROCESSOR_MODE PreviousMode;
2668 PTOKEN FirstToken, SecondToken;
2669 BOOLEAN IsEqual;
2670 NTSTATUS Status;
2671
2672 PAGED_CODE();
2673
2674 PreviousMode = ExGetPreviousMode();
2675
2676 if (PreviousMode != KernelMode)
2677 {
2678 _SEH2_TRY
2679 {
2680 ProbeForWriteBoolean(Equal);
2681 }
2682 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2683 {
2684 /* Return the exception code */
2685 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2686 }
2687 _SEH2_END;
2688 }
2689
2690 Status = ObReferenceObjectByHandle(FirstTokenHandle,
2691 TOKEN_QUERY,
2692 SeTokenObjectType,
2693 PreviousMode,
2694 (PVOID*)&FirstToken,
2695 NULL);
2696 if (!NT_SUCCESS(Status))
2697 return Status;
2698
2699 Status = ObReferenceObjectByHandle(SecondTokenHandle,
2700 TOKEN_QUERY,
2701 SeTokenObjectType,
2702 PreviousMode,
2703 (PVOID*)&SecondToken,
2704 NULL);
2705 if (!NT_SUCCESS(Status))
2706 {
2707 ObDereferenceObject(FirstToken);
2708 return Status;
2709 }
2710
2711 if (FirstToken != SecondToken)
2712 {
2713 Status = SepCompareTokens(FirstToken,
2714 SecondToken,
2715 &IsEqual);
2716 }
2717 else
2718 IsEqual = TRUE;
2719
2720 ObDereferenceObject(FirstToken);
2721 ObDereferenceObject(SecondToken);
2722
2723 if (NT_SUCCESS(Status))
2724 {
2725 _SEH2_TRY
2726 {
2727 *Equal = IsEqual;
2728 }
2729 _SEH2_EXCEPT(ExSystemExceptionFilter())
2730 {
2731 Status = _SEH2_GetExceptionCode();
2732 }
2733 _SEH2_END;
2734 }
2735
2736 return Status;
2737 }
2738
2739 NTSTATUS
2740 NTAPI
2741 NtFilterToken(IN HANDLE ExistingTokenHandle,
2742 IN ULONG Flags,
2743 IN PTOKEN_GROUPS SidsToDisable OPTIONAL,
2744 IN PTOKEN_PRIVILEGES PrivilegesToDelete OPTIONAL,
2745 IN PTOKEN_GROUPS RestrictedSids OPTIONAL,
2746 OUT PHANDLE NewTokenHandle)
2747 {
2748 UNIMPLEMENTED;
2749 return STATUS_NOT_IMPLEMENTED;
2750 }
2751
2752 /*
2753 * @unimplemented
2754 */
2755 NTSTATUS
2756 NTAPI
2757 NtImpersonateAnonymousToken(IN HANDLE Thread)
2758 {
2759 UNIMPLEMENTED;
2760 return STATUS_NOT_IMPLEMENTED;
2761 }
2762
2763 /* EOF */