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