[NTOSKRNL] Place INIT_FUNCTION before the return type (#2823)
[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 #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; // FIXME: Global lock!
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 MS! */
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 /* Lock the tokens */
101 SepAcquireTokenLockShared(FirstToken);
102 SepAcquireTokenLockShared(SecondToken);
103
104 /* FIXME: Check if every SID that is present in either token is also present in the other one */
105
106 Restricted = SeTokenIsRestricted(FirstToken);
107 if (Restricted == SeTokenIsRestricted(SecondToken))
108 {
109 if (Restricted)
110 {
111 /* FIXME: Check if every SID that is restricted in either token is also restricted in the other one */
112 }
113
114 /* FIXME: Check if every privilege that is present in either token is also present in the other one */
115 DPRINT1("FIXME: Pretending tokens are equal!\n");
116 IsEqual = TRUE;
117 }
118
119 /* Unlock the tokens */
120 SepReleaseTokenLock(SecondToken);
121 SepReleaseTokenLock(FirstToken);
122
123 *Equal = IsEqual;
124 return STATUS_SUCCESS;
125 }
126
127 static
128 VOID
129 SepUpdateSinglePrivilegeFlagToken(
130 _Inout_ PTOKEN Token,
131 _In_ ULONG Index)
132 {
133 ULONG TokenFlag;
134 ASSERT(Index < Token->PrivilegeCount);
135
136 /* The high part of all values we are interested in is 0 */
137 if (Token->Privileges[Index].Luid.HighPart != 0)
138 {
139 return;
140 }
141
142 /* Check for certain privileges to update flags */
143 if (Token->Privileges[Index].Luid.LowPart == SE_CHANGE_NOTIFY_PRIVILEGE)
144 {
145 TokenFlag = TOKEN_HAS_TRAVERSE_PRIVILEGE;
146 }
147 else if (Token->Privileges[Index].Luid.LowPart == SE_BACKUP_PRIVILEGE)
148 {
149 TokenFlag = TOKEN_HAS_BACKUP_PRIVILEGE;
150 }
151 else if (Token->Privileges[Index].Luid.LowPart == SE_RESTORE_PRIVILEGE)
152 {
153 TokenFlag = TOKEN_HAS_RESTORE_PRIVILEGE;
154 }
155 else if (Token->Privileges[Index].Luid.LowPart == SE_IMPERSONATE_PRIVILEGE)
156 {
157 TokenFlag = TOKEN_HAS_IMPERSONATE_PRIVILEGE;
158 }
159 else
160 {
161 /* Nothing to do */
162 return;
163 }
164
165 /* Check if the specified privilege is enabled */
166 if (Token->Privileges[Index].Attributes & SE_PRIVILEGE_ENABLED)
167 {
168 /* It is enabled, so set the flag */
169 Token->TokenFlags |= TokenFlag;
170 }
171 else
172 {
173 /* Is is disabled, so remove the flag */
174 Token->TokenFlags &= ~TokenFlag;
175 }
176 }
177
178 static
179 VOID
180 SepUpdatePrivilegeFlagsToken(
181 _Inout_ PTOKEN Token)
182 {
183 ULONG i;
184
185 /* Loop all privileges */
186 for (i = 0; i < Token->PrivilegeCount; i++)
187 {
188 /* Updates the flags dor this privilege */
189 SepUpdateSinglePrivilegeFlagToken(Token, i);
190 }
191 }
192
193 static
194 VOID
195 SepRemovePrivilegeToken(
196 _Inout_ PTOKEN Token,
197 _In_ ULONG Index)
198 {
199 ULONG MoveCount;
200 ASSERT(Index < Token->PrivilegeCount);
201
202 /* Calculate the number of trailing privileges */
203 MoveCount = Token->PrivilegeCount - Index - 1;
204 if (MoveCount != 0)
205 {
206 /* Move them one location ahead */
207 RtlMoveMemory(&Token->Privileges[Index],
208 &Token->Privileges[Index + 1],
209 MoveCount * sizeof(LUID_AND_ATTRIBUTES));
210 }
211
212 /* Update privilege count */
213 Token->PrivilegeCount--;
214 }
215
216 VOID
217 NTAPI
218 SepFreeProxyData(PVOID ProxyData)
219 {
220 UNIMPLEMENTED;
221 }
222
223 NTSTATUS
224 NTAPI
225 SepCopyProxyData(PVOID* Dest,
226 PVOID Src)
227 {
228 UNIMPLEMENTED;
229 return STATUS_NOT_IMPLEMENTED;
230 }
231
232 NTSTATUS
233 NTAPI
234 SeExchangePrimaryToken(
235 _In_ PEPROCESS Process,
236 _In_ PACCESS_TOKEN NewAccessToken,
237 _Out_ PACCESS_TOKEN* OldAccessToken)
238 {
239 PTOKEN OldToken;
240 PTOKEN NewToken = (PTOKEN)NewAccessToken;
241
242 PAGED_CODE();
243
244 if (NewToken->TokenType != TokenPrimary)
245 return STATUS_BAD_TOKEN_TYPE;
246
247 if (NewToken->TokenInUse)
248 {
249 BOOLEAN IsEqual;
250 NTSTATUS Status;
251
252 /* Maybe we're trying to set the same token */
253 OldToken = PsReferencePrimaryToken(Process);
254 if (OldToken == NewToken)
255 {
256 /* So it's a nop. */
257 *OldAccessToken = OldToken;
258 return STATUS_SUCCESS;
259 }
260
261 Status = SepCompareTokens(OldToken, NewToken, &IsEqual);
262 if (!NT_SUCCESS(Status))
263 {
264 PsDereferencePrimaryToken(OldToken);
265 *OldAccessToken = NULL;
266 return Status;
267 }
268
269 if (!IsEqual)
270 {
271 PsDereferencePrimaryToken(OldToken);
272 *OldAccessToken = NULL;
273 return STATUS_TOKEN_ALREADY_IN_USE;
274 }
275 /* Silently return STATUS_SUCCESS but do not set the new token,
276 * as it's already in use elsewhere. */
277 *OldAccessToken = OldToken;
278 return STATUS_SUCCESS;
279 }
280
281 /* Lock the new token */
282 SepAcquireTokenLockExclusive(NewToken);
283
284 /* Mark new token in use */
285 NewToken->TokenInUse = TRUE;
286
287 // TODO: Set a correct SessionId for NewToken
288
289 /* Unlock the new token */
290 SepReleaseTokenLock(NewToken);
291
292 /* Reference the new token */
293 ObReferenceObject(NewToken);
294
295 /* Replace the old with the new */
296 OldToken = ObFastReplaceObject(&Process->Token, NewToken);
297
298 /* Lock the old token */
299 SepAcquireTokenLockExclusive(OldToken);
300
301 /* Mark the old token as free */
302 OldToken->TokenInUse = FALSE;
303
304 /* Unlock the old token */
305 SepReleaseTokenLock(OldToken);
306
307 *OldAccessToken = (PACCESS_TOKEN)OldToken;
308 return STATUS_SUCCESS;
309 }
310
311 VOID
312 NTAPI
313 SeDeassignPrimaryToken(PEPROCESS Process)
314 {
315 PTOKEN OldToken;
316
317 /* Remove the Token */
318 OldToken = ObFastReplaceObject(&Process->Token, NULL);
319
320 /* Mark the Old Token as free */
321 OldToken->TokenInUse = FALSE;
322
323 /* Dereference the Token */
324 ObDereferenceObject(OldToken);
325 }
326
327 static ULONG
328 RtlLengthSidAndAttributes(ULONG Count,
329 PSID_AND_ATTRIBUTES Src)
330 {
331 ULONG i;
332 ULONG uLength;
333
334 PAGED_CODE();
335
336 uLength = Count * sizeof(SID_AND_ATTRIBUTES);
337 for (i = 0; i < Count; i++)
338 uLength += RtlLengthSid(Src[i].Sid);
339
340 return uLength;
341 }
342
343
344 static NTSTATUS
345 SepFindPrimaryGroupAndDefaultOwner(
346 _In_ PTOKEN Token,
347 _In_ PSID PrimaryGroup,
348 _In_opt_ PSID DefaultOwner,
349 _Out_opt_ PULONG PrimaryGroupIndex,
350 _Out_opt_ PULONG DefaultOwnerIndex)
351 {
352 ULONG i;
353
354 /* We should return at least a search result */
355 if (!PrimaryGroupIndex && !DefaultOwnerIndex)
356 return STATUS_INVALID_PARAMETER;
357
358 if (PrimaryGroupIndex)
359 {
360 /* Initialize with an invalid index */
361 // Token->PrimaryGroup = NULL;
362 *PrimaryGroupIndex = Token->UserAndGroupCount;
363 }
364
365 if (DefaultOwnerIndex)
366 {
367 if (DefaultOwner)
368 {
369 /* An owner is specified: check whether this is actually the user */
370 if (RtlEqualSid(Token->UserAndGroups[0].Sid, DefaultOwner))
371 {
372 /*
373 * It's the user (first element in array): set it
374 * as the owner and stop the search for it.
375 */
376 *DefaultOwnerIndex = 0;
377 DefaultOwnerIndex = NULL;
378 }
379 else
380 {
381 /* An owner is specified: initialize with an invalid index */
382 *DefaultOwnerIndex = Token->UserAndGroupCount;
383 }
384 }
385 else
386 {
387 /*
388 * No owner specified: set the user (first element in array)
389 * as the owner and stop the search for it.
390 */
391 *DefaultOwnerIndex = 0;
392 DefaultOwnerIndex = NULL;
393 }
394 }
395
396 /* Validate and set the primary group and default owner indices */
397 for (i = 0; i < Token->UserAndGroupCount; i++)
398 {
399 /* Stop the search if we have found what we searched for */
400 if (!PrimaryGroupIndex && !DefaultOwnerIndex)
401 break;
402
403 if (DefaultOwnerIndex && DefaultOwner &&
404 RtlEqualSid(Token->UserAndGroups[i].Sid, DefaultOwner) &&
405 (Token->UserAndGroups[i].Attributes & SE_GROUP_OWNER))
406 {
407 /* Owner is found, stop the search for it */
408 *DefaultOwnerIndex = i;
409 DefaultOwnerIndex = NULL;
410 }
411
412 if (PrimaryGroupIndex &&
413 RtlEqualSid(Token->UserAndGroups[i].Sid, PrimaryGroup))
414 {
415 /* Primary group is found, stop the search for it */
416 // Token->PrimaryGroup = Token->UserAndGroups[i].Sid;
417 *PrimaryGroupIndex = i;
418 PrimaryGroupIndex = NULL;
419 }
420 }
421
422 if (DefaultOwnerIndex)
423 {
424 if (*DefaultOwnerIndex == Token->UserAndGroupCount)
425 return STATUS_INVALID_OWNER;
426 }
427
428 if (PrimaryGroupIndex)
429 {
430 if (*PrimaryGroupIndex == Token->UserAndGroupCount)
431 // if (Token->PrimaryGroup == NULL)
432 return STATUS_INVALID_PRIMARY_GROUP;
433 }
434
435 return STATUS_SUCCESS;
436 }
437
438
439 NTSTATUS
440 NTAPI
441 SepDuplicateToken(
442 _In_ PTOKEN Token,
443 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
444 _In_ BOOLEAN EffectiveOnly,
445 _In_ TOKEN_TYPE TokenType,
446 _In_ SECURITY_IMPERSONATION_LEVEL Level,
447 _In_ KPROCESSOR_MODE PreviousMode,
448 _Out_ PTOKEN* NewAccessToken)
449 {
450 NTSTATUS Status;
451 PTOKEN AccessToken;
452 PVOID EndMem;
453 ULONG VariableLength;
454 ULONG TotalSize;
455
456 PAGED_CODE();
457
458 /* Compute how much size we need to allocate for the token */
459 VariableLength = Token->VariableLength;
460 TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength;
461
462 Status = ObCreateObject(PreviousMode,
463 SeTokenObjectType,
464 ObjectAttributes,
465 PreviousMode,
466 NULL,
467 TotalSize,
468 0,
469 0,
470 (PVOID*)&AccessToken);
471 if (!NT_SUCCESS(Status))
472 {
473 DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status);
474 return Status;
475 }
476
477 /* Zero out the buffer and initialize the token */
478 RtlZeroMemory(AccessToken, TotalSize);
479
480 ExAllocateLocallyUniqueId(&AccessToken->TokenId);
481
482 AccessToken->TokenType = TokenType;
483 AccessToken->ImpersonationLevel = Level;
484
485 AccessToken->TokenLock = &SepTokenLock; // FIXME: Global lock!
486
487 /* Copy the immutable fields */
488 RtlCopyLuid(&AccessToken->TokenSource.SourceIdentifier,
489 &Token->TokenSource.SourceIdentifier);
490 RtlCopyMemory(AccessToken->TokenSource.SourceName,
491 Token->TokenSource.SourceName,
492 sizeof(Token->TokenSource.SourceName));
493
494 AccessToken->AuthenticationId = Token->AuthenticationId;
495 AccessToken->ParentTokenId = Token->ParentTokenId;
496 AccessToken->ExpirationTime = Token->ExpirationTime;
497 AccessToken->OriginatingLogonSession = Token->OriginatingLogonSession;
498
499
500 /* Lock the source token and copy the mutable fields */
501 SepAcquireTokenLockExclusive(Token);
502
503 AccessToken->SessionId = Token->SessionId;
504 RtlCopyLuid(&AccessToken->ModifiedId, &Token->ModifiedId);
505
506 AccessToken->TokenFlags = Token->TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED;
507
508 /* Copy and reference the logon session */
509 // RtlCopyLuid(&AccessToken->AuthenticationId, &Token->AuthenticationId);
510 Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId);
511 if (!NT_SUCCESS(Status))
512 {
513 /* No logon session could be found, bail out */
514 DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n", Status);
515 /* Set the flag for proper cleanup by the delete procedure */
516 AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED;
517 goto Quit;
518 }
519
520 /* Assign the data that reside in the TOKEN's variable information area */
521 AccessToken->VariableLength = VariableLength;
522 EndMem = (PVOID)&AccessToken->VariablePart;
523
524 /* Copy the privileges */
525 AccessToken->PrivilegeCount = 0;
526 AccessToken->Privileges = NULL;
527 if (Token->Privileges && (Token->PrivilegeCount > 0))
528 {
529 ULONG PrivilegesLength = Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
530 PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID));
531
532 ASSERT(VariableLength >= PrivilegesLength);
533
534 AccessToken->PrivilegeCount = Token->PrivilegeCount;
535 AccessToken->Privileges = EndMem;
536 EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength);
537 VariableLength -= PrivilegesLength;
538
539 RtlCopyMemory(AccessToken->Privileges,
540 Token->Privileges,
541 AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
542 }
543
544 /* Copy the user and groups */
545 AccessToken->UserAndGroupCount = 0;
546 AccessToken->UserAndGroups = NULL;
547 if (Token->UserAndGroups && (Token->UserAndGroupCount > 0))
548 {
549 AccessToken->UserAndGroupCount = Token->UserAndGroupCount;
550 AccessToken->UserAndGroups = EndMem;
551 EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
552 VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups);
553
554 Status = RtlCopySidAndAttributesArray(AccessToken->UserAndGroupCount,
555 Token->UserAndGroups,
556 VariableLength,
557 AccessToken->UserAndGroups,
558 EndMem,
559 &EndMem,
560 &VariableLength);
561 if (!NT_SUCCESS(Status))
562 {
563 DPRINT1("RtlCopySidAndAttributesArray(UserAndGroups) failed (Status 0x%lx)\n", Status);
564 goto Quit;
565 }
566 }
567
568 #if 1
569 {
570 ULONG PrimaryGroupIndex;
571
572 /* Find the token primary group */
573 Status = SepFindPrimaryGroupAndDefaultOwner(AccessToken,
574 Token->PrimaryGroup,
575 NULL,
576 &PrimaryGroupIndex,
577 NULL);
578 if (!NT_SUCCESS(Status))
579 {
580 DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n", Status);
581 goto Quit;
582 }
583 AccessToken->PrimaryGroup = AccessToken->UserAndGroups[PrimaryGroupIndex].Sid;
584 }
585 #else
586 AccessToken->PrimaryGroup = (PVOID)((ULONG_PTR)AccessToken + (ULONG_PTR)Token->PrimaryGroup - (ULONG_PTR)Token->UserAndGroups);
587 #endif
588 AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex;
589
590 /* Copy the restricted SIDs */
591 AccessToken->RestrictedSidCount = 0;
592 AccessToken->RestrictedSids = NULL;
593 if (Token->RestrictedSids && (Token->RestrictedSidCount > 0))
594 {
595 AccessToken->RestrictedSidCount = Token->RestrictedSidCount;
596 AccessToken->RestrictedSids = EndMem;
597 EndMem = &AccessToken->RestrictedSids[AccessToken->RestrictedSidCount];
598 VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->RestrictedSids);
599
600 Status = RtlCopySidAndAttributesArray(AccessToken->RestrictedSidCount,
601 Token->RestrictedSids,
602 VariableLength,
603 AccessToken->RestrictedSids,
604 EndMem,
605 &EndMem,
606 &VariableLength);
607 if (!NT_SUCCESS(Status))
608 {
609 DPRINT1("RtlCopySidAndAttributesArray(RestrictedSids) failed (Status 0x%lx)\n", Status);
610 goto Quit;
611 }
612 }
613
614
615 //
616 // FIXME: Implement the "EffectiveOnly" option, that removes all
617 // the disabled parts (privileges and groups) of the token.
618 //
619
620
621 //
622 // NOTE: So far our dynamic area only contains
623 // the default dacl, so this makes the following
624 // code pretty simple. The day where it stores
625 // other data, the code will require adaptations.
626 //
627
628 /* Now allocate the TOKEN's dynamic information area and set the data */
629 AccessToken->DynamicAvailable = 0; // Unused memory in the dynamic area.
630 AccessToken->DynamicPart = NULL;
631 if (Token->DynamicPart && Token->DefaultDacl)
632 {
633 AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool,
634 Token->DefaultDacl->AclSize,
635 TAG_TOKEN_DYNAMIC);
636 if (AccessToken->DynamicPart == NULL)
637 {
638 Status = STATUS_INSUFFICIENT_RESOURCES;
639 goto Quit;
640 }
641 EndMem = (PVOID)AccessToken->DynamicPart;
642
643 AccessToken->DefaultDacl = EndMem;
644
645 RtlCopyMemory(AccessToken->DefaultDacl,
646 Token->DefaultDacl,
647 Token->DefaultDacl->AclSize);
648 }
649
650 /* Unlock the source token */
651 SepReleaseTokenLock(Token);
652
653 /* Return the token */
654 *NewAccessToken = AccessToken;
655 Status = STATUS_SUCCESS;
656
657 Quit:
658 if (!NT_SUCCESS(Status))
659 {
660 /* Unlock the source token */
661 SepReleaseTokenLock(Token);
662
663 /* Dereference the token, the delete procedure will clean it up */
664 ObDereferenceObject(AccessToken);
665 }
666
667 return Status;
668 }
669
670 NTSTATUS
671 NTAPI
672 SeSubProcessToken(IN PTOKEN ParentToken,
673 OUT PTOKEN *Token,
674 IN BOOLEAN InUse,
675 IN ULONG SessionId)
676 {
677 PTOKEN NewToken;
678 OBJECT_ATTRIBUTES ObjectAttributes;
679 NTSTATUS Status;
680
681 /* Initialize the attributes and duplicate it */
682 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
683 Status = SepDuplicateToken(ParentToken,
684 &ObjectAttributes,
685 FALSE,
686 TokenPrimary,
687 ParentToken->ImpersonationLevel,
688 KernelMode,
689 &NewToken);
690 if (NT_SUCCESS(Status))
691 {
692 /* Insert it */
693 Status = ObInsertObject(NewToken,
694 NULL,
695 0,
696 0,
697 NULL,
698 NULL);
699 if (NT_SUCCESS(Status))
700 {
701 /* Set the session ID */
702 NewToken->SessionId = SessionId;
703 NewToken->TokenInUse = InUse;
704
705 /* Return the token */
706 *Token = NewToken;
707 }
708 }
709
710 /* Return status */
711 return Status;
712 }
713
714 NTSTATUS
715 NTAPI
716 SeIsTokenChild(IN PTOKEN Token,
717 OUT PBOOLEAN IsChild)
718 {
719 PTOKEN ProcessToken;
720 LUID ProcessTokenId, CallerParentId;
721
722 /* Assume failure */
723 *IsChild = FALSE;
724
725 /* Reference the process token */
726 ProcessToken = PsReferencePrimaryToken(PsGetCurrentProcess());
727 if (!ProcessToken)
728 return STATUS_UNSUCCESSFUL;
729
730 /* Get its token ID */
731 ProcessTokenId = ProcessToken->TokenId;
732
733 /* Dereference the token */
734 ObFastDereferenceObject(&PsGetCurrentProcess()->Token, ProcessToken);
735
736 /* Get our parent token ID */
737 CallerParentId = Token->ParentTokenId;
738
739 /* Compare the token IDs */
740 if (RtlEqualLuid(&CallerParentId, &ProcessTokenId))
741 *IsChild = TRUE;
742
743 /* Return success */
744 return STATUS_SUCCESS;
745 }
746
747 NTSTATUS
748 NTAPI
749 SeIsTokenSibling(IN PTOKEN Token,
750 OUT PBOOLEAN IsSibling)
751 {
752 PTOKEN ProcessToken;
753 LUID ProcessParentId, ProcessAuthId;
754 LUID CallerParentId, CallerAuthId;
755
756 /* Assume failure */
757 *IsSibling = FALSE;
758
759 /* Reference the process token */
760 ProcessToken = PsReferencePrimaryToken(PsGetCurrentProcess());
761 if (!ProcessToken)
762 return STATUS_UNSUCCESSFUL;
763
764 /* Get its parent and authentication IDs */
765 ProcessParentId = ProcessToken->ParentTokenId;
766 ProcessAuthId = ProcessToken->AuthenticationId;
767
768 /* Dereference the token */
769 ObFastDereferenceObject(&PsGetCurrentProcess()->Token, ProcessToken);
770
771 /* Get our parent and authentication IDs */
772 CallerParentId = Token->ParentTokenId;
773 CallerAuthId = Token->AuthenticationId;
774
775 /* Compare the token IDs */
776 if (RtlEqualLuid(&CallerParentId, &ProcessParentId) &&
777 RtlEqualLuid(&CallerAuthId, &ProcessAuthId))
778 {
779 *IsSibling = TRUE;
780 }
781
782 /* Return success */
783 return STATUS_SUCCESS;
784 }
785
786 NTSTATUS
787 NTAPI
788 SeCopyClientToken(IN PACCESS_TOKEN Token,
789 IN SECURITY_IMPERSONATION_LEVEL Level,
790 IN KPROCESSOR_MODE PreviousMode,
791 OUT PACCESS_TOKEN* NewToken)
792 {
793 NTSTATUS Status;
794 OBJECT_ATTRIBUTES ObjectAttributes;
795
796 PAGED_CODE();
797
798 InitializeObjectAttributes(&ObjectAttributes,
799 NULL,
800 0,
801 NULL,
802 NULL);
803
804 Status = SepDuplicateToken(Token,
805 &ObjectAttributes,
806 FALSE,
807 TokenImpersonation,
808 Level,
809 PreviousMode,
810 (PTOKEN*)NewToken);
811
812 return Status;
813 }
814
815 VOID
816 NTAPI
817 SepDeleteToken(PVOID ObjectBody)
818 {
819 PTOKEN AccessToken = (PTOKEN)ObjectBody;
820
821 DPRINT("SepDeleteToken()\n");
822
823 /* Dereference the logon session */
824 if ((AccessToken->TokenFlags & TOKEN_SESSION_NOT_REFERENCED) == 0)
825 SepRmDereferenceLogonSession(&AccessToken->AuthenticationId);
826
827 /* Delete the dynamic information area */
828 if (AccessToken->DynamicPart)
829 ExFreePoolWithTag(AccessToken->DynamicPart, TAG_TOKEN_DYNAMIC);
830 }
831
832
833 INIT_FUNCTION
834 VOID
835 NTAPI
836 SepInitializeTokenImplementation(VOID)
837 {
838 UNICODE_STRING Name;
839 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
840
841 ExInitializeResource(&SepTokenLock); // FIXME: Global lock!
842
843 DPRINT("Creating Token Object Type\n");
844
845 /* Initialize the Token type */
846 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
847 RtlInitUnicodeString(&Name, L"Token");
848 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
849 ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
850 ObjectTypeInitializer.SecurityRequired = TRUE;
851 ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(TOKEN);
852 ObjectTypeInitializer.GenericMapping = SepTokenMapping;
853 ObjectTypeInitializer.PoolType = PagedPool;
854 ObjectTypeInitializer.ValidAccessMask = TOKEN_ALL_ACCESS;
855 ObjectTypeInitializer.UseDefaultObject = TRUE;
856 ObjectTypeInitializer.DeleteProcedure = SepDeleteToken;
857 ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &SeTokenObjectType);
858 }
859
860 VOID
861 NTAPI
862 SeAssignPrimaryToken(IN PEPROCESS Process,
863 IN PTOKEN Token)
864 {
865 PAGED_CODE();
866
867 /* Sanity checks */
868 ASSERT(Token->TokenType == TokenPrimary);
869 ASSERT(!Token->TokenInUse);
870
871 /* Clean any previous token */
872 if (Process->Token.Object) SeDeassignPrimaryToken(Process);
873
874 /* Set the new token */
875 ObReferenceObject(Token);
876 Token->TokenInUse = TRUE;
877 ObInitializeFastReference(&Process->Token, Token);
878 }
879
880 NTSTATUS
881 NTAPI
882 SepCreateToken(
883 _Out_ PHANDLE TokenHandle,
884 _In_ KPROCESSOR_MODE PreviousMode,
885 _In_ ACCESS_MASK DesiredAccess,
886 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
887 _In_ TOKEN_TYPE TokenType,
888 _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
889 _In_ PLUID AuthenticationId,
890 _In_ PLARGE_INTEGER ExpirationTime,
891 _In_ PSID_AND_ATTRIBUTES User,
892 _In_ ULONG GroupCount,
893 _In_ PSID_AND_ATTRIBUTES Groups,
894 _In_ ULONG GroupsLength,
895 _In_ ULONG PrivilegeCount,
896 _In_ PLUID_AND_ATTRIBUTES Privileges,
897 _In_opt_ PSID Owner,
898 _In_ PSID PrimaryGroup,
899 _In_opt_ PACL DefaultDacl,
900 _In_ PTOKEN_SOURCE TokenSource,
901 _In_ BOOLEAN SystemToken)
902 {
903 NTSTATUS Status;
904 PTOKEN AccessToken;
905 ULONG TokenFlags = 0;
906 ULONG PrimaryGroupIndex, DefaultOwnerIndex;
907 LUID TokenId;
908 LUID ModifiedId;
909 PVOID EndMem;
910 ULONG PrivilegesLength;
911 ULONG UserGroupsLength;
912 ULONG VariableLength;
913 ULONG TotalSize;
914 ULONG i;
915
916 PAGED_CODE();
917
918 /* Loop all groups */
919 for (i = 0; i < GroupCount; i++)
920 {
921 /* Check for mandatory groups */
922 if (Groups[i].Attributes & SE_GROUP_MANDATORY)
923 {
924 /* Force them to be enabled */
925 Groups[i].Attributes |= (SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT);
926 }
927
928 /* Check of the group is an admin group */
929 if (RtlEqualSid(SeAliasAdminsSid, Groups[i].Sid))
930 {
931 /* Remember this so we can optimize queries later */
932 TokenFlags |= TOKEN_HAS_ADMIN_GROUP;
933 }
934 }
935
936 /* Allocate unique IDs for the token */
937 ExAllocateLocallyUniqueId(&TokenId);
938 ExAllocateLocallyUniqueId(&ModifiedId);
939
940 /* Compute how much size we need to allocate for the token */
941
942 /* Privileges size */
943 PrivilegesLength = PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
944 PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID));
945
946 /* User and groups size */
947 UserGroupsLength = (1 + GroupCount) * sizeof(SID_AND_ATTRIBUTES);
948 UserGroupsLength += RtlLengthSid(User->Sid);
949 for (i = 0; i < GroupCount; i++)
950 {
951 UserGroupsLength += RtlLengthSid(Groups[i].Sid);
952 }
953 UserGroupsLength = ALIGN_UP_BY(UserGroupsLength, sizeof(PVOID));
954
955 /* Add the additional groups array length */
956 UserGroupsLength += ALIGN_UP_BY(GroupsLength, sizeof(PVOID));
957
958 VariableLength = PrivilegesLength + UserGroupsLength;
959 TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength;
960
961 Status = ObCreateObject(PreviousMode,
962 SeTokenObjectType,
963 ObjectAttributes,
964 PreviousMode,
965 NULL,
966 TotalSize,
967 0,
968 0,
969 (PVOID*)&AccessToken);
970 if (!NT_SUCCESS(Status))
971 {
972 DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status);
973 return Status;
974 }
975
976 /* Zero out the buffer and initialize the token */
977 RtlZeroMemory(AccessToken, TotalSize);
978
979 RtlCopyLuid(&AccessToken->TokenId, &TokenId);
980
981 AccessToken->TokenType = TokenType;
982 AccessToken->ImpersonationLevel = ImpersonationLevel;
983
984 AccessToken->TokenLock = &SepTokenLock; // FIXME: Global lock!
985
986 RtlCopyLuid(&AccessToken->TokenSource.SourceIdentifier,
987 &TokenSource->SourceIdentifier);
988 RtlCopyMemory(AccessToken->TokenSource.SourceName,
989 TokenSource->SourceName,
990 sizeof(TokenSource->SourceName));
991
992 AccessToken->ExpirationTime = *ExpirationTime;
993 RtlCopyLuid(&AccessToken->ModifiedId, &ModifiedId);
994
995 AccessToken->TokenFlags = TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED;
996
997 /* Copy and reference the logon session */
998 RtlCopyLuid(&AccessToken->AuthenticationId, AuthenticationId);
999 Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId);
1000 if (!NT_SUCCESS(Status))
1001 {
1002 /* No logon session could be found, bail out */
1003 DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n", Status);
1004 /* Set the flag for proper cleanup by the delete procedure */
1005 AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED;
1006 goto Quit;
1007 }
1008
1009 /* Assign the data that reside in the TOKEN's variable information area */
1010 AccessToken->VariableLength = VariableLength;
1011 EndMem = (PVOID)&AccessToken->VariablePart;
1012
1013 /* Copy the privileges */
1014 AccessToken->PrivilegeCount = PrivilegeCount;
1015 AccessToken->Privileges = NULL;
1016 if (PrivilegeCount > 0)
1017 {
1018 AccessToken->Privileges = EndMem;
1019 EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength);
1020 VariableLength -= PrivilegesLength;
1021
1022 if (PreviousMode != KernelMode)
1023 {
1024 _SEH2_TRY
1025 {
1026 RtlCopyMemory(AccessToken->Privileges,
1027 Privileges,
1028 PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
1029 }
1030 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1031 {
1032 Status = _SEH2_GetExceptionCode();
1033 }
1034 _SEH2_END;
1035 }
1036 else
1037 {
1038 RtlCopyMemory(AccessToken->Privileges,
1039 Privileges,
1040 PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
1041 }
1042
1043 if (!NT_SUCCESS(Status))
1044 goto Quit;
1045 }
1046
1047 /* Update the privilege flags */
1048 SepUpdatePrivilegeFlagsToken(AccessToken);
1049
1050 /* Copy the user and groups */
1051 AccessToken->UserAndGroupCount = 1 + GroupCount;
1052 AccessToken->UserAndGroups = EndMem;
1053 EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
1054 VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups);
1055
1056 Status = RtlCopySidAndAttributesArray(1,
1057 User,
1058 VariableLength,
1059 &AccessToken->UserAndGroups[0],
1060 EndMem,
1061 &EndMem,
1062 &VariableLength);
1063 if (!NT_SUCCESS(Status))
1064 goto Quit;
1065
1066 Status = RtlCopySidAndAttributesArray(GroupCount,
1067 Groups,
1068 VariableLength,
1069 &AccessToken->UserAndGroups[1],
1070 EndMem,
1071 &EndMem,
1072 &VariableLength);
1073 if (!NT_SUCCESS(Status))
1074 goto Quit;
1075
1076 /* Find the token primary group and default owner */
1077 Status = SepFindPrimaryGroupAndDefaultOwner(AccessToken,
1078 PrimaryGroup,
1079 Owner,
1080 &PrimaryGroupIndex,
1081 &DefaultOwnerIndex);
1082 if (!NT_SUCCESS(Status))
1083 {
1084 DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n", Status);
1085 goto Quit;
1086 }
1087
1088 AccessToken->PrimaryGroup = AccessToken->UserAndGroups[PrimaryGroupIndex].Sid;
1089 AccessToken->DefaultOwnerIndex = DefaultOwnerIndex;
1090
1091 /* Now allocate the TOKEN's dynamic information area and set the data */
1092 AccessToken->DynamicAvailable = 0; // Unused memory in the dynamic area.
1093 AccessToken->DynamicPart = NULL;
1094 if (DefaultDacl != NULL)
1095 {
1096 AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool,
1097 DefaultDacl->AclSize,
1098 TAG_TOKEN_DYNAMIC);
1099 if (AccessToken->DynamicPart == NULL)
1100 {
1101 Status = STATUS_INSUFFICIENT_RESOURCES;
1102 goto Quit;
1103 }
1104 EndMem = (PVOID)AccessToken->DynamicPart;
1105
1106 AccessToken->DefaultDacl = EndMem;
1107
1108 RtlCopyMemory(AccessToken->DefaultDacl,
1109 DefaultDacl,
1110 DefaultDacl->AclSize);
1111 }
1112
1113 /* Insert the token only if it's not the system token, otherwise return it directly */
1114 if (!SystemToken)
1115 {
1116 Status = ObInsertObject(AccessToken,
1117 NULL,
1118 DesiredAccess,
1119 0,
1120 NULL,
1121 TokenHandle);
1122 if (!NT_SUCCESS(Status))
1123 {
1124 DPRINT1("ObInsertObject() failed (Status 0x%lx)\n", Status);
1125 }
1126 }
1127 else
1128 {
1129 /* Return pointer instead of handle */
1130 *TokenHandle = (HANDLE)AccessToken;
1131 }
1132
1133 Quit:
1134 if (!NT_SUCCESS(Status))
1135 {
1136 /* Dereference the token, the delete procedure will clean it up */
1137 ObDereferenceObject(AccessToken);
1138 }
1139
1140 return Status;
1141 }
1142
1143 PTOKEN
1144 NTAPI
1145 SepCreateSystemProcessToken(VOID)
1146 {
1147 LUID_AND_ATTRIBUTES Privileges[25];
1148 ULONG GroupAttributes, OwnerAttributes;
1149 SID_AND_ATTRIBUTES Groups[32];
1150 LARGE_INTEGER Expiration;
1151 SID_AND_ATTRIBUTES UserSid;
1152 ULONG GroupsLength;
1153 PSID PrimaryGroup;
1154 OBJECT_ATTRIBUTES ObjectAttributes;
1155 PSID Owner;
1156 ULONG i;
1157 PTOKEN Token;
1158 NTSTATUS Status;
1159
1160 /* Don't ever expire */
1161 Expiration.QuadPart = -1;
1162
1163 /* All groups mandatory and enabled */
1164 GroupAttributes = SE_GROUP_ENABLED | SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT;
1165 OwnerAttributes = SE_GROUP_ENABLED | SE_GROUP_OWNER | SE_GROUP_ENABLED_BY_DEFAULT;
1166
1167 /* User is Local System */
1168 UserSid.Sid = SeLocalSystemSid;
1169 UserSid.Attributes = 0;
1170
1171 /* Primary group is Local System */
1172 PrimaryGroup = SeLocalSystemSid;
1173
1174 /* Owner is Administrators */
1175 Owner = SeAliasAdminsSid;
1176
1177 /* Groups are Administrators, World, and Authenticated Users */
1178 Groups[0].Sid = SeAliasAdminsSid;
1179 Groups[0].Attributes = OwnerAttributes;
1180 Groups[1].Sid = SeWorldSid;
1181 Groups[1].Attributes = GroupAttributes;
1182 Groups[2].Sid = SeAuthenticatedUsersSid;
1183 Groups[2].Attributes = GroupAttributes;
1184 GroupsLength = sizeof(SID_AND_ATTRIBUTES) +
1185 SeLengthSid(Groups[0].Sid) +
1186 SeLengthSid(Groups[1].Sid) +
1187 SeLengthSid(Groups[2].Sid);
1188 ASSERT(GroupsLength <= sizeof(Groups));
1189
1190 /* Setup the privileges */
1191 i = 0;
1192 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
1193 Privileges[i++].Luid = SeTcbPrivilege;
1194
1195 Privileges[i].Attributes = 0;
1196 Privileges[i++].Luid = SeCreateTokenPrivilege;
1197
1198 Privileges[i].Attributes = 0;
1199 Privileges[i++].Luid = SeTakeOwnershipPrivilege;
1200
1201 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
1202 Privileges[i++].Luid = SeCreatePagefilePrivilege;
1203
1204 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
1205 Privileges[i++].Luid = SeLockMemoryPrivilege;
1206
1207 Privileges[i].Attributes = 0;
1208 Privileges[i++].Luid = SeAssignPrimaryTokenPrivilege;
1209
1210 Privileges[i].Attributes = 0;
1211 Privileges[i++].Luid = SeIncreaseQuotaPrivilege;
1212
1213 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
1214 Privileges[i++].Luid = SeIncreaseBasePriorityPrivilege;
1215
1216 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
1217 Privileges[i++].Luid = SeCreatePermanentPrivilege;
1218
1219 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
1220 Privileges[i++].Luid = SeDebugPrivilege;
1221
1222 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
1223 Privileges[i++].Luid = SeAuditPrivilege;
1224
1225 Privileges[i].Attributes = 0;
1226 Privileges[i++].Luid = SeSecurityPrivilege;
1227
1228 Privileges[i].Attributes = 0;
1229 Privileges[i++].Luid = SeSystemEnvironmentPrivilege;
1230
1231 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
1232 Privileges[i++].Luid = SeChangeNotifyPrivilege;
1233
1234 Privileges[i].Attributes = 0;
1235 Privileges[i++].Luid = SeBackupPrivilege;
1236
1237 Privileges[i].Attributes = 0;
1238 Privileges[i++].Luid = SeRestorePrivilege;
1239
1240 Privileges[i].Attributes = 0;
1241 Privileges[i++].Luid = SeShutdownPrivilege;
1242
1243 Privileges[i].Attributes = 0;
1244 Privileges[i++].Luid = SeLoadDriverPrivilege;
1245
1246 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
1247 Privileges[i++].Luid = SeProfileSingleProcessPrivilege;
1248
1249 Privileges[i].Attributes = 0;
1250 Privileges[i++].Luid = SeSystemtimePrivilege;
1251 ASSERT(i == 20);
1252
1253 /* Setup the object attributes */
1254 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
1255 ASSERT(SeSystemDefaultDacl != NULL);
1256
1257 /* Create the token */
1258 Status = SepCreateToken((PHANDLE)&Token,
1259 KernelMode,
1260 0,
1261 &ObjectAttributes,
1262 TokenPrimary,
1263 SecurityAnonymous,
1264 &SeSystemAuthenticationId,
1265 &Expiration,
1266 &UserSid,
1267 3,
1268 Groups,
1269 GroupsLength,
1270 20,
1271 Privileges,
1272 Owner,
1273 PrimaryGroup,
1274 SeSystemDefaultDacl,
1275 &SeSystemTokenSource,
1276 TRUE);
1277 ASSERT(Status == STATUS_SUCCESS);
1278
1279 /* Return the token */
1280 return Token;
1281 }
1282
1283 /* PUBLIC FUNCTIONS ***********************************************************/
1284
1285 /*
1286 * @unimplemented
1287 */
1288 NTSTATUS
1289 NTAPI
1290 SeFilterToken(IN PACCESS_TOKEN ExistingToken,
1291 IN ULONG Flags,
1292 IN PTOKEN_GROUPS SidsToDisable OPTIONAL,
1293 IN PTOKEN_PRIVILEGES PrivilegesToDelete OPTIONAL,
1294 IN PTOKEN_GROUPS RestrictedSids OPTIONAL,
1295 OUT PACCESS_TOKEN * FilteredToken)
1296 {
1297 UNIMPLEMENTED;
1298 return STATUS_NOT_IMPLEMENTED;
1299 }
1300
1301 /*
1302 * @implemented
1303 *
1304 * NOTE: SeQueryInformationToken is just NtQueryInformationToken without all
1305 * the bells and whistles needed for user-mode buffer access protection.
1306 */
1307 NTSTATUS
1308 NTAPI
1309 SeQueryInformationToken(IN PACCESS_TOKEN AccessToken,
1310 IN TOKEN_INFORMATION_CLASS TokenInformationClass,
1311 OUT PVOID *TokenInformation)
1312 {
1313 NTSTATUS Status;
1314 PTOKEN Token = (PTOKEN)AccessToken;
1315 ULONG RequiredLength;
1316 union
1317 {
1318 PSID PSid;
1319 ULONG Ulong;
1320 } Unused;
1321
1322 PAGED_CODE();
1323
1324 if (TokenInformationClass >= MaxTokenInfoClass)
1325 {
1326 DPRINT1("SeQueryInformationToken(%d) invalid information class\n", TokenInformationClass);
1327 return STATUS_INVALID_INFO_CLASS;
1328 }
1329
1330 // TODO: Lock the token
1331
1332 switch (TokenInformationClass)
1333 {
1334 case TokenUser:
1335 {
1336 PTOKEN_USER tu;
1337
1338 DPRINT("SeQueryInformationToken(TokenUser)\n");
1339 RequiredLength = sizeof(TOKEN_USER) +
1340 RtlLengthSid(Token->UserAndGroups[0].Sid);
1341
1342 /* Allocate the output buffer */
1343 tu = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
1344 if (tu == NULL)
1345 {
1346 Status = STATUS_INSUFFICIENT_RESOURCES;
1347 break;
1348 }
1349
1350 Status = RtlCopySidAndAttributesArray(1,
1351 &Token->UserAndGroups[0],
1352 RequiredLength - sizeof(TOKEN_USER),
1353 &tu->User,
1354 (PSID)(tu + 1),
1355 &Unused.PSid,
1356 &Unused.Ulong);
1357
1358 /* Return the structure */
1359 *TokenInformation = tu;
1360 Status = STATUS_SUCCESS;
1361 break;
1362 }
1363
1364 case TokenGroups:
1365 {
1366 PTOKEN_GROUPS tg;
1367 ULONG SidLen;
1368 PSID Sid;
1369
1370 DPRINT("SeQueryInformationToken(TokenGroups)\n");
1371 RequiredLength = sizeof(tg->GroupCount) +
1372 RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]);
1373
1374 SidLen = RequiredLength - sizeof(tg->GroupCount) -
1375 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES));
1376
1377 /* Allocate the output buffer */
1378 tg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
1379 if (tg == NULL)
1380 {
1381 Status = STATUS_INSUFFICIENT_RESOURCES;
1382 break;
1383 }
1384
1385 Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
1386 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES)));
1387
1388 tg->GroupCount = Token->UserAndGroupCount - 1;
1389 Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1,
1390 &Token->UserAndGroups[1],
1391 SidLen,
1392 &tg->Groups[0],
1393 Sid,
1394 &Unused.PSid,
1395 &Unused.Ulong);
1396
1397 /* Return the structure */
1398 *TokenInformation = tg;
1399 Status = STATUS_SUCCESS;
1400 break;
1401 }
1402
1403 case TokenPrivileges:
1404 {
1405 PTOKEN_PRIVILEGES tp;
1406
1407 DPRINT("SeQueryInformationToken(TokenPrivileges)\n");
1408 RequiredLength = sizeof(tp->PrivilegeCount) +
1409 (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
1410
1411 /* Allocate the output buffer */
1412 tp = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
1413 if (tp == NULL)
1414 {
1415 Status = STATUS_INSUFFICIENT_RESOURCES;
1416 break;
1417 }
1418
1419 tp->PrivilegeCount = Token->PrivilegeCount;
1420 RtlCopyLuidAndAttributesArray(Token->PrivilegeCount,
1421 Token->Privileges,
1422 &tp->Privileges[0]);
1423
1424 /* Return the structure */
1425 *TokenInformation = tp;
1426 Status = STATUS_SUCCESS;
1427 break;
1428 }
1429
1430 case TokenOwner:
1431 {
1432 PTOKEN_OWNER to;
1433 ULONG SidLen;
1434
1435 DPRINT("SeQueryInformationToken(TokenOwner)\n");
1436 SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
1437 RequiredLength = sizeof(TOKEN_OWNER) + SidLen;
1438
1439 /* Allocate the output buffer */
1440 to = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
1441 if (to == NULL)
1442 {
1443 Status = STATUS_INSUFFICIENT_RESOURCES;
1444 break;
1445 }
1446
1447 to->Owner = (PSID)(to + 1);
1448 Status = RtlCopySid(SidLen,
1449 to->Owner,
1450 Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
1451
1452 /* Return the structure */
1453 *TokenInformation = to;
1454 Status = STATUS_SUCCESS;
1455 break;
1456 }
1457
1458 case TokenPrimaryGroup:
1459 {
1460 PTOKEN_PRIMARY_GROUP tpg;
1461 ULONG SidLen;
1462
1463 DPRINT("SeQueryInformationToken(TokenPrimaryGroup)\n");
1464 SidLen = RtlLengthSid(Token->PrimaryGroup);
1465 RequiredLength = sizeof(TOKEN_PRIMARY_GROUP) + SidLen;
1466
1467 /* Allocate the output buffer */
1468 tpg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
1469 if (tpg == NULL)
1470 {
1471 Status = STATUS_INSUFFICIENT_RESOURCES;
1472 break;
1473 }
1474
1475 tpg->PrimaryGroup = (PSID)(tpg + 1);
1476 Status = RtlCopySid(SidLen,
1477 tpg->PrimaryGroup,
1478 Token->PrimaryGroup);
1479
1480 /* Return the structure */
1481 *TokenInformation = tpg;
1482 Status = STATUS_SUCCESS;
1483 break;
1484 }
1485
1486 case TokenDefaultDacl:
1487 {
1488 PTOKEN_DEFAULT_DACL tdd;
1489
1490 DPRINT("SeQueryInformationToken(TokenDefaultDacl)\n");
1491 RequiredLength = sizeof(TOKEN_DEFAULT_DACL);
1492
1493 if (Token->DefaultDacl != NULL)
1494 RequiredLength += Token->DefaultDacl->AclSize;
1495
1496 /* Allocate the output buffer */
1497 tdd = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
1498 if (tdd == NULL)
1499 {
1500 Status = STATUS_INSUFFICIENT_RESOURCES;
1501 break;
1502 }
1503
1504 if (Token->DefaultDacl != NULL)
1505 {
1506 tdd->DefaultDacl = (PACL)(tdd + 1);
1507 RtlCopyMemory(tdd->DefaultDacl,
1508 Token->DefaultDacl,
1509 Token->DefaultDacl->AclSize);
1510 }
1511 else
1512 {
1513 tdd->DefaultDacl = NULL;
1514 }
1515
1516 /* Return the structure */
1517 *TokenInformation = tdd;
1518 Status = STATUS_SUCCESS;
1519 break;
1520 }
1521
1522 case TokenSource:
1523 {
1524 PTOKEN_SOURCE ts;
1525
1526 DPRINT("SeQueryInformationToken(TokenSource)\n");
1527 RequiredLength = sizeof(TOKEN_SOURCE);
1528
1529 /* Allocate the output buffer */
1530 ts = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
1531 if (ts == NULL)
1532 {
1533 Status = STATUS_INSUFFICIENT_RESOURCES;
1534 break;
1535 }
1536
1537 *ts = Token->TokenSource;
1538
1539 /* Return the structure */
1540 *TokenInformation = ts;
1541 Status = STATUS_SUCCESS;
1542 break;
1543 }
1544
1545 case TokenType:
1546 {
1547 PTOKEN_TYPE tt;
1548
1549 DPRINT("SeQueryInformationToken(TokenType)\n");
1550 RequiredLength = sizeof(TOKEN_TYPE);
1551
1552 /* Allocate the output buffer */
1553 tt = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
1554 if (tt == NULL)
1555 {
1556 Status = STATUS_INSUFFICIENT_RESOURCES;
1557 break;
1558 }
1559
1560 *tt = Token->TokenType;
1561
1562 /* Return the structure */
1563 *TokenInformation = tt;
1564 Status = STATUS_SUCCESS;
1565 break;
1566 }
1567
1568 case TokenImpersonationLevel:
1569 {
1570 PSECURITY_IMPERSONATION_LEVEL sil;
1571
1572 DPRINT("SeQueryInformationToken(TokenImpersonationLevel)\n");
1573 RequiredLength = sizeof(SECURITY_IMPERSONATION_LEVEL);
1574
1575 /* Fail if the token is not an impersonation token */
1576 if (Token->TokenType != TokenImpersonation)
1577 {
1578 Status = STATUS_INVALID_INFO_CLASS;
1579 break;
1580 }
1581
1582 /* Allocate the output buffer */
1583 sil = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
1584 if (sil == NULL)
1585 {
1586 Status = STATUS_INSUFFICIENT_RESOURCES;
1587 break;
1588 }
1589
1590 *sil = Token->ImpersonationLevel;
1591
1592 /* Return the structure */
1593 *TokenInformation = sil;
1594 Status = STATUS_SUCCESS;
1595 break;
1596 }
1597
1598 case TokenStatistics:
1599 {
1600 PTOKEN_STATISTICS ts;
1601
1602 DPRINT("SeQueryInformationToken(TokenStatistics)\n");
1603 RequiredLength = sizeof(TOKEN_STATISTICS);
1604
1605 /* Allocate the output buffer */
1606 ts = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
1607 if (ts == NULL)
1608 {
1609 Status = STATUS_INSUFFICIENT_RESOURCES;
1610 break;
1611 }
1612
1613 ts->TokenId = Token->TokenId;
1614 ts->AuthenticationId = Token->AuthenticationId;
1615 ts->ExpirationTime = Token->ExpirationTime;
1616 ts->TokenType = Token->TokenType;
1617 ts->ImpersonationLevel = Token->ImpersonationLevel;
1618 ts->DynamicCharged = Token->DynamicCharged;
1619 ts->DynamicAvailable = Token->DynamicAvailable;
1620 ts->GroupCount = Token->UserAndGroupCount - 1;
1621 ts->PrivilegeCount = Token->PrivilegeCount;
1622 ts->ModifiedId = Token->ModifiedId;
1623
1624 /* Return the structure */
1625 *TokenInformation = ts;
1626 Status = STATUS_SUCCESS;
1627 break;
1628 }
1629
1630 /*
1631 * The following 4 cases are only implemented in NtQueryInformationToken
1632 */
1633 #if 0
1634
1635 case TokenOrigin:
1636 {
1637 PTOKEN_ORIGIN to;
1638
1639 DPRINT("SeQueryInformationToken(TokenOrigin)\n");
1640 RequiredLength = sizeof(TOKEN_ORIGIN);
1641
1642 /* Allocate the output buffer */
1643 to = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
1644 if (to == NULL)
1645 {
1646 Status = STATUS_INSUFFICIENT_RESOURCES;
1647 break;
1648 }
1649
1650 RtlCopyLuid(&to->OriginatingLogonSession,
1651 &Token->AuthenticationId);
1652
1653 /* Return the structure */
1654 *TokenInformation = to;
1655 Status = STATUS_SUCCESS;
1656 break;
1657 }
1658
1659 case TokenGroupsAndPrivileges:
1660 DPRINT1("SeQueryInformationToken(TokenGroupsAndPrivileges) not implemented\n");
1661 Status = STATUS_NOT_IMPLEMENTED;
1662 break;
1663
1664 case TokenRestrictedSids:
1665 {
1666 PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation;
1667 ULONG SidLen;
1668 PSID Sid;
1669
1670 DPRINT("SeQueryInformationToken(TokenRestrictedSids)\n");
1671 RequiredLength = sizeof(tg->GroupCount) +
1672 RtlLengthSidAndAttributes(Token->RestrictedSidCount, Token->RestrictedSids);
1673
1674 SidLen = RequiredLength - sizeof(tg->GroupCount) -
1675 (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES));
1676
1677 /* Allocate the output buffer */
1678 tg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
1679 if (tg == NULL)
1680 {
1681 Status = STATUS_INSUFFICIENT_RESOURCES;
1682 break;
1683 }
1684
1685 Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
1686 (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)));
1687
1688 tg->GroupCount = Token->RestrictedSidCount;
1689 Status = RtlCopySidAndAttributesArray(Token->RestrictedSidCount,
1690 Token->RestrictedSids,
1691 SidLen,
1692 &tg->Groups[0],
1693 Sid,
1694 &Unused.PSid,
1695 &Unused.Ulong);
1696
1697 /* Return the structure */
1698 *TokenInformation = tg;
1699 Status = STATUS_SUCCESS;
1700 break;
1701 }
1702
1703 case TokenSandBoxInert:
1704 DPRINT1("SeQueryInformationToken(TokenSandboxInert) not implemented\n");
1705 Status = STATUS_NOT_IMPLEMENTED;
1706 break;
1707
1708 #endif
1709
1710 case TokenSessionId:
1711 {
1712 DPRINT("SeQueryInformationToken(TokenSessionId)\n");
1713 Status = SeQuerySessionIdToken(Token, (PULONG)TokenInformation);
1714 break;
1715 }
1716
1717 default:
1718 DPRINT1("SeQueryInformationToken(%d) invalid information class\n", TokenInformationClass);
1719 Status = STATUS_INVALID_INFO_CLASS;
1720 break;
1721 }
1722
1723 return Status;
1724 }
1725
1726 /*
1727 * @implemented
1728 */
1729 NTSTATUS
1730 NTAPI
1731 SeQuerySessionIdToken(IN PACCESS_TOKEN Token,
1732 IN PULONG pSessionId)
1733 {
1734 PAGED_CODE();
1735
1736 /* Lock the token */
1737 SepAcquireTokenLockShared(Token);
1738
1739 *pSessionId = ((PTOKEN)Token)->SessionId;
1740
1741 /* Unlock the token */
1742 SepReleaseTokenLock(Token);
1743
1744 return STATUS_SUCCESS;
1745 }
1746
1747 /*
1748 * @implemented
1749 */
1750 NTSTATUS
1751 NTAPI
1752 SeQueryAuthenticationIdToken(IN PACCESS_TOKEN Token,
1753 OUT PLUID LogonId)
1754 {
1755 PAGED_CODE();
1756
1757 *LogonId = ((PTOKEN)Token)->AuthenticationId;
1758
1759 return STATUS_SUCCESS;
1760 }
1761
1762
1763 /*
1764 * @implemented
1765 */
1766 SECURITY_IMPERSONATION_LEVEL
1767 NTAPI
1768 SeTokenImpersonationLevel(IN PACCESS_TOKEN Token)
1769 {
1770 PAGED_CODE();
1771
1772 return ((PTOKEN)Token)->ImpersonationLevel;
1773 }
1774
1775
1776 /*
1777 * @implemented
1778 */
1779 TOKEN_TYPE NTAPI
1780 SeTokenType(IN PACCESS_TOKEN Token)
1781 {
1782 PAGED_CODE();
1783
1784 return ((PTOKEN)Token)->TokenType;
1785 }
1786
1787
1788 /*
1789 * @implemented
1790 */
1791 BOOLEAN
1792 NTAPI
1793 SeTokenIsAdmin(IN PACCESS_TOKEN Token)
1794 {
1795 PAGED_CODE();
1796
1797 // NOTE: Win7+ instead really checks the list of groups in the token
1798 // (since TOKEN_HAS_ADMIN_GROUP == TOKEN_WRITE_RESTRICTED ...)
1799 return (((PTOKEN)Token)->TokenFlags & TOKEN_HAS_ADMIN_GROUP) != 0;
1800 }
1801
1802 /*
1803 * @implemented
1804 */
1805 BOOLEAN
1806 NTAPI
1807 SeTokenIsRestricted(IN PACCESS_TOKEN Token)
1808 {
1809 PAGED_CODE();
1810
1811 return (((PTOKEN)Token)->TokenFlags & TOKEN_IS_RESTRICTED) != 0;
1812 }
1813
1814 /*
1815 * @implemented
1816 * @note First introduced in NT 5.1 SP2 x86 (5.1.2600.2622), absent in NT 5.2,
1817 * then finally re-introduced in Vista+.
1818 */
1819 BOOLEAN
1820 NTAPI
1821 SeTokenIsWriteRestricted(IN PACCESS_TOKEN Token)
1822 {
1823 PAGED_CODE();
1824
1825 // NOTE: NT 5.1 SP2 x86 checks the SE_BACKUP_PRIVILEGES_CHECKED flag
1826 // while Vista+ checks the TOKEN_WRITE_RESTRICTED flag as one expects.
1827 return (((PTOKEN)Token)->TokenFlags & SE_BACKUP_PRIVILEGES_CHECKED) != 0;
1828 }
1829
1830 /* SYSTEM CALLS ***************************************************************/
1831
1832 /*
1833 * @implemented
1834 */
1835 _Must_inspect_result_
1836 __kernel_entry
1837 NTSTATUS
1838 NTAPI
1839 NtQueryInformationToken(
1840 _In_ HANDLE TokenHandle,
1841 _In_ TOKEN_INFORMATION_CLASS TokenInformationClass,
1842 _Out_writes_bytes_to_opt_(TokenInformationLength, *ReturnLength)
1843 PVOID TokenInformation,
1844 _In_ ULONG TokenInformationLength,
1845 _Out_ PULONG ReturnLength)
1846 {
1847 NTSTATUS Status;
1848 KPROCESSOR_MODE PreviousMode;
1849 PTOKEN Token;
1850 ULONG RequiredLength;
1851 union
1852 {
1853 PSID PSid;
1854 ULONG Ulong;
1855 } Unused;
1856
1857 PAGED_CODE();
1858
1859 PreviousMode = ExGetPreviousMode();
1860
1861 /* Check buffers and class validity */
1862 Status = DefaultQueryInfoBufferCheck(TokenInformationClass,
1863 SeTokenInformationClass,
1864 RTL_NUMBER_OF(SeTokenInformationClass),
1865 TokenInformation,
1866 TokenInformationLength,
1867 ReturnLength,
1868 NULL,
1869 PreviousMode);
1870 if (!NT_SUCCESS(Status))
1871 {
1872 DPRINT("NtQueryInformationToken() failed, Status: 0x%x\n", Status);
1873 return Status;
1874 }
1875
1876 Status = ObReferenceObjectByHandle(TokenHandle,
1877 (TokenInformationClass == TokenSource) ? TOKEN_QUERY_SOURCE : TOKEN_QUERY,
1878 SeTokenObjectType,
1879 PreviousMode,
1880 (PVOID*)&Token,
1881 NULL);
1882 if (NT_SUCCESS(Status))
1883 {
1884 /* Lock the token */
1885 SepAcquireTokenLockShared(Token);
1886
1887 switch (TokenInformationClass)
1888 {
1889 case TokenUser:
1890 {
1891 PTOKEN_USER tu = (PTOKEN_USER)TokenInformation;
1892
1893 DPRINT("NtQueryInformationToken(TokenUser)\n");
1894 RequiredLength = sizeof(TOKEN_USER) +
1895 RtlLengthSid(Token->UserAndGroups[0].Sid);
1896
1897 _SEH2_TRY
1898 {
1899 if (TokenInformationLength >= RequiredLength)
1900 {
1901 Status = RtlCopySidAndAttributesArray(1,
1902 &Token->UserAndGroups[0],
1903 RequiredLength - sizeof(TOKEN_USER),
1904 &tu->User,
1905 (PSID)(tu + 1),
1906 &Unused.PSid,
1907 &Unused.Ulong);
1908 }
1909 else
1910 {
1911 Status = STATUS_BUFFER_TOO_SMALL;
1912 }
1913
1914 if (ReturnLength != NULL)
1915 {
1916 *ReturnLength = RequiredLength;
1917 }
1918 }
1919 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1920 {
1921 Status = _SEH2_GetExceptionCode();
1922 }
1923 _SEH2_END;
1924
1925 break;
1926 }
1927
1928 case TokenGroups:
1929 {
1930 PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation;
1931
1932 DPRINT("NtQueryInformationToken(TokenGroups)\n");
1933 RequiredLength = sizeof(tg->GroupCount) +
1934 RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]);
1935
1936 _SEH2_TRY
1937 {
1938 if (TokenInformationLength >= RequiredLength)
1939 {
1940 ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) -
1941 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES));
1942 PSID Sid = (PSID_AND_ATTRIBUTES)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
1943 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES)));
1944
1945 tg->GroupCount = Token->UserAndGroupCount - 1;
1946 Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1,
1947 &Token->UserAndGroups[1],
1948 SidLen,
1949 &tg->Groups[0],
1950 Sid,
1951 &Unused.PSid,
1952 &Unused.Ulong);
1953 }
1954 else
1955 {
1956 Status = STATUS_BUFFER_TOO_SMALL;
1957 }
1958
1959 if (ReturnLength != NULL)
1960 {
1961 *ReturnLength = RequiredLength;
1962 }
1963 }
1964 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1965 {
1966 Status = _SEH2_GetExceptionCode();
1967 }
1968 _SEH2_END;
1969
1970 break;
1971 }
1972
1973 case TokenPrivileges:
1974 {
1975 PTOKEN_PRIVILEGES tp = (PTOKEN_PRIVILEGES)TokenInformation;
1976
1977 DPRINT("NtQueryInformationToken(TokenPrivileges)\n");
1978 RequiredLength = sizeof(tp->PrivilegeCount) +
1979 (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
1980
1981 _SEH2_TRY
1982 {
1983 if (TokenInformationLength >= RequiredLength)
1984 {
1985 tp->PrivilegeCount = Token->PrivilegeCount;
1986 RtlCopyLuidAndAttributesArray(Token->PrivilegeCount,
1987 Token->Privileges,
1988 &tp->Privileges[0]);
1989 }
1990 else
1991 {
1992 Status = STATUS_BUFFER_TOO_SMALL;
1993 }
1994
1995 if (ReturnLength != NULL)
1996 {
1997 *ReturnLength = RequiredLength;
1998 }
1999 }
2000 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2001 {
2002 Status = _SEH2_GetExceptionCode();
2003 }
2004 _SEH2_END;
2005
2006 break;
2007 }
2008
2009 case TokenOwner:
2010 {
2011 PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation;
2012 ULONG SidLen;
2013
2014 DPRINT("NtQueryInformationToken(TokenOwner)\n");
2015 SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
2016 RequiredLength = sizeof(TOKEN_OWNER) + SidLen;
2017
2018 _SEH2_TRY
2019 {
2020 if (TokenInformationLength >= RequiredLength)
2021 {
2022 to->Owner = (PSID)(to + 1);
2023 Status = RtlCopySid(SidLen,
2024 to->Owner,
2025 Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
2026 }
2027 else
2028 {
2029 Status = STATUS_BUFFER_TOO_SMALL;
2030 }
2031
2032 if (ReturnLength != NULL)
2033 {
2034 *ReturnLength = RequiredLength;
2035 }
2036 }
2037 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2038 {
2039 Status = _SEH2_GetExceptionCode();
2040 }
2041 _SEH2_END;
2042
2043 break;
2044 }
2045
2046 case TokenPrimaryGroup:
2047 {
2048 PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation;
2049 ULONG SidLen;
2050
2051 DPRINT("NtQueryInformationToken(TokenPrimaryGroup)\n");
2052 SidLen = RtlLengthSid(Token->PrimaryGroup);
2053 RequiredLength = sizeof(TOKEN_PRIMARY_GROUP) + SidLen;
2054
2055 _SEH2_TRY
2056 {
2057 if (TokenInformationLength >= RequiredLength)
2058 {
2059 tpg->PrimaryGroup = (PSID)(tpg + 1);
2060 Status = RtlCopySid(SidLen,
2061 tpg->PrimaryGroup,
2062 Token->PrimaryGroup);
2063 }
2064 else
2065 {
2066 Status = STATUS_BUFFER_TOO_SMALL;
2067 }
2068
2069 if (ReturnLength != NULL)
2070 {
2071 *ReturnLength = RequiredLength;
2072 }
2073 }
2074 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2075 {
2076 Status = _SEH2_GetExceptionCode();
2077 }
2078 _SEH2_END;
2079
2080 break;
2081 }
2082
2083 case TokenDefaultDacl:
2084 {
2085 PTOKEN_DEFAULT_DACL tdd = (PTOKEN_DEFAULT_DACL)TokenInformation;
2086
2087 DPRINT("NtQueryInformationToken(TokenDefaultDacl)\n");
2088 RequiredLength = sizeof(TOKEN_DEFAULT_DACL);
2089
2090 if (Token->DefaultDacl != NULL)
2091 RequiredLength += Token->DefaultDacl->AclSize;
2092
2093 _SEH2_TRY
2094 {
2095 if (TokenInformationLength >= RequiredLength)
2096 {
2097 if (Token->DefaultDacl != NULL)
2098 {
2099 tdd->DefaultDacl = (PACL)(tdd + 1);
2100 RtlCopyMemory(tdd->DefaultDacl,
2101 Token->DefaultDacl,
2102 Token->DefaultDacl->AclSize);
2103 }
2104 else
2105 {
2106 tdd->DefaultDacl = NULL;
2107 }
2108 }
2109 else
2110 {
2111 Status = STATUS_BUFFER_TOO_SMALL;
2112 }
2113
2114 if (ReturnLength != NULL)
2115 {
2116 *ReturnLength = RequiredLength;
2117 }
2118 }
2119 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2120 {
2121 Status = _SEH2_GetExceptionCode();
2122 }
2123 _SEH2_END;
2124
2125 break;
2126 }
2127
2128 case TokenSource:
2129 {
2130 PTOKEN_SOURCE ts = (PTOKEN_SOURCE)TokenInformation;
2131
2132 DPRINT("NtQueryInformationToken(TokenSource)\n");
2133 RequiredLength = sizeof(TOKEN_SOURCE);
2134
2135 _SEH2_TRY
2136 {
2137 if (TokenInformationLength >= RequiredLength)
2138 {
2139 *ts = Token->TokenSource;
2140 }
2141 else
2142 {
2143 Status = STATUS_BUFFER_TOO_SMALL;
2144 }
2145
2146 if (ReturnLength != NULL)
2147 {
2148 *ReturnLength = RequiredLength;
2149 }
2150 }
2151 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2152 {
2153 Status = _SEH2_GetExceptionCode();
2154 }
2155 _SEH2_END;
2156
2157 break;
2158 }
2159
2160 case TokenType:
2161 {
2162 PTOKEN_TYPE tt = (PTOKEN_TYPE)TokenInformation;
2163
2164 DPRINT("NtQueryInformationToken(TokenType)\n");
2165 RequiredLength = sizeof(TOKEN_TYPE);
2166
2167 _SEH2_TRY
2168 {
2169 if (TokenInformationLength >= RequiredLength)
2170 {
2171 *tt = Token->TokenType;
2172 }
2173 else
2174 {
2175 Status = STATUS_BUFFER_TOO_SMALL;
2176 }
2177
2178 if (ReturnLength != NULL)
2179 {
2180 *ReturnLength = RequiredLength;
2181 }
2182 }
2183 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2184 {
2185 Status = _SEH2_GetExceptionCode();
2186 }
2187 _SEH2_END;
2188
2189 break;
2190 }
2191
2192 case TokenImpersonationLevel:
2193 {
2194 PSECURITY_IMPERSONATION_LEVEL sil = (PSECURITY_IMPERSONATION_LEVEL)TokenInformation;
2195
2196 DPRINT("NtQueryInformationToken(TokenImpersonationLevel)\n");
2197
2198 /* Fail if the token is not an impersonation token */
2199 if (Token->TokenType != TokenImpersonation)
2200 {
2201 Status = STATUS_INVALID_INFO_CLASS;
2202 break;
2203 }
2204
2205 RequiredLength = sizeof(SECURITY_IMPERSONATION_LEVEL);
2206
2207 _SEH2_TRY
2208 {
2209 if (TokenInformationLength >= RequiredLength)
2210 {
2211 *sil = Token->ImpersonationLevel;
2212 }
2213 else
2214 {
2215 Status = STATUS_BUFFER_TOO_SMALL;
2216 }
2217
2218 if (ReturnLength != NULL)
2219 {
2220 *ReturnLength = RequiredLength;
2221 }
2222 }
2223 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2224 {
2225 Status = _SEH2_GetExceptionCode();
2226 }
2227 _SEH2_END;
2228
2229 break;
2230 }
2231
2232 case TokenStatistics:
2233 {
2234 PTOKEN_STATISTICS ts = (PTOKEN_STATISTICS)TokenInformation;
2235
2236 DPRINT("NtQueryInformationToken(TokenStatistics)\n");
2237 RequiredLength = sizeof(TOKEN_STATISTICS);
2238
2239 _SEH2_TRY
2240 {
2241 if (TokenInformationLength >= RequiredLength)
2242 {
2243 ts->TokenId = Token->TokenId;
2244 ts->AuthenticationId = Token->AuthenticationId;
2245 ts->ExpirationTime = Token->ExpirationTime;
2246 ts->TokenType = Token->TokenType;
2247 ts->ImpersonationLevel = Token->ImpersonationLevel;
2248 ts->DynamicCharged = Token->DynamicCharged;
2249 ts->DynamicAvailable = Token->DynamicAvailable;
2250 ts->GroupCount = Token->UserAndGroupCount - 1;
2251 ts->PrivilegeCount = Token->PrivilegeCount;
2252 ts->ModifiedId = Token->ModifiedId;
2253 }
2254 else
2255 {
2256 Status = STATUS_BUFFER_TOO_SMALL;
2257 }
2258
2259 if (ReturnLength != NULL)
2260 {
2261 *ReturnLength = RequiredLength;
2262 }
2263 }
2264 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2265 {
2266 Status = _SEH2_GetExceptionCode();
2267 }
2268 _SEH2_END;
2269
2270 break;
2271 }
2272
2273 case TokenOrigin:
2274 {
2275 PTOKEN_ORIGIN to = (PTOKEN_ORIGIN)TokenInformation;
2276
2277 DPRINT("NtQueryInformationToken(TokenOrigin)\n");
2278 RequiredLength = sizeof(TOKEN_ORIGIN);
2279
2280 _SEH2_TRY
2281 {
2282 if (TokenInformationLength >= RequiredLength)
2283 {
2284 RtlCopyLuid(&to->OriginatingLogonSession,
2285 &Token->AuthenticationId);
2286 }
2287 else
2288 {
2289 Status = STATUS_BUFFER_TOO_SMALL;
2290 }
2291
2292 if (ReturnLength != NULL)
2293 {
2294 *ReturnLength = RequiredLength;
2295 }
2296 }
2297 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2298 {
2299 Status = _SEH2_GetExceptionCode();
2300 }
2301 _SEH2_END;
2302
2303 break;
2304 }
2305
2306 case TokenGroupsAndPrivileges:
2307 DPRINT1("NtQueryInformationToken(TokenGroupsAndPrivileges) not implemented\n");
2308 Status = STATUS_NOT_IMPLEMENTED;
2309 break;
2310
2311 case TokenRestrictedSids:
2312 {
2313 PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation;
2314
2315 DPRINT("NtQueryInformationToken(TokenRestrictedSids)\n");
2316 RequiredLength = sizeof(tg->GroupCount) +
2317 RtlLengthSidAndAttributes(Token->RestrictedSidCount, Token->RestrictedSids);
2318
2319 _SEH2_TRY
2320 {
2321 if (TokenInformationLength >= RequiredLength)
2322 {
2323 ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) -
2324 (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES));
2325 PSID Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
2326 (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)));
2327
2328 tg->GroupCount = Token->RestrictedSidCount;
2329 Status = RtlCopySidAndAttributesArray(Token->RestrictedSidCount,
2330 Token->RestrictedSids,
2331 SidLen,
2332 &tg->Groups[0],
2333 Sid,
2334 &Unused.PSid,
2335 &Unused.Ulong);
2336 }
2337 else
2338 {
2339 Status = STATUS_BUFFER_TOO_SMALL;
2340 }
2341
2342 if (ReturnLength != NULL)
2343 {
2344 *ReturnLength = RequiredLength;
2345 }
2346 }
2347 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2348 {
2349 Status = _SEH2_GetExceptionCode();
2350 }
2351 _SEH2_END;
2352
2353 break;
2354 }
2355
2356 case TokenSandBoxInert:
2357 DPRINT1("NtQueryInformationToken(TokenSandboxInert) not implemented\n");
2358 Status = STATUS_NOT_IMPLEMENTED;
2359 break;
2360
2361 case TokenSessionId:
2362 {
2363 ULONG SessionId = 0;
2364
2365 DPRINT("NtQueryInformationToken(TokenSessionId)\n");
2366
2367 Status = SeQuerySessionIdToken(Token, &SessionId);
2368 if (NT_SUCCESS(Status))
2369 {
2370 _SEH2_TRY
2371 {
2372 /* Buffer size was already verified, no need to check here again */
2373 *(PULONG)TokenInformation = SessionId;
2374
2375 if (ReturnLength != NULL)
2376 {
2377 *ReturnLength = sizeof(ULONG);
2378 }
2379 }
2380 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2381 {
2382 Status = _SEH2_GetExceptionCode();
2383 }
2384 _SEH2_END;
2385 }
2386
2387 break;
2388 }
2389
2390 default:
2391 DPRINT1("NtQueryInformationToken(%d) invalid information class\n", TokenInformationClass);
2392 Status = STATUS_INVALID_INFO_CLASS;
2393 break;
2394 }
2395
2396 /* Unlock and dereference the token */
2397 SepReleaseTokenLock(Token);
2398 ObDereferenceObject(Token);
2399 }
2400
2401 return Status;
2402 }
2403
2404
2405 /*
2406 * NtSetTokenInformation: Partly implemented.
2407 * Unimplemented:
2408 * TokenOrigin, TokenDefaultDacl
2409 */
2410 _Must_inspect_result_
2411 __kernel_entry
2412 NTSTATUS
2413 NTAPI
2414 NtSetInformationToken(
2415 _In_ HANDLE TokenHandle,
2416 _In_ TOKEN_INFORMATION_CLASS TokenInformationClass,
2417 _In_reads_bytes_(TokenInformationLength) PVOID TokenInformation,
2418 _In_ ULONG TokenInformationLength)
2419 {
2420 NTSTATUS Status;
2421 PTOKEN Token;
2422 KPROCESSOR_MODE PreviousMode;
2423 ULONG NeededAccess = TOKEN_ADJUST_DEFAULT;
2424
2425 PAGED_CODE();
2426
2427 PreviousMode = ExGetPreviousMode();
2428
2429 Status = DefaultSetInfoBufferCheck(TokenInformationClass,
2430 SeTokenInformationClass,
2431 RTL_NUMBER_OF(SeTokenInformationClass),
2432 TokenInformation,
2433 TokenInformationLength,
2434 PreviousMode);
2435 if (!NT_SUCCESS(Status))
2436 {
2437 /* Invalid buffers */
2438 DPRINT("NtSetInformationToken() failed, Status: 0x%x\n", Status);
2439 return Status;
2440 }
2441
2442 if (TokenInformationClass == TokenSessionId)
2443 {
2444 NeededAccess |= TOKEN_ADJUST_SESSIONID;
2445 }
2446
2447 Status = ObReferenceObjectByHandle(TokenHandle,
2448 NeededAccess,
2449 SeTokenObjectType,
2450 PreviousMode,
2451 (PVOID*)&Token,
2452 NULL);
2453 if (NT_SUCCESS(Status))
2454 {
2455 switch (TokenInformationClass)
2456 {
2457 case TokenOwner:
2458 {
2459 if (TokenInformationLength >= sizeof(TOKEN_OWNER))
2460 {
2461 PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation;
2462 PSID InputSid = NULL, CapturedSid;
2463 ULONG DefaultOwnerIndex;
2464
2465 _SEH2_TRY
2466 {
2467 InputSid = to->Owner;
2468 }
2469 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2470 {
2471 Status = _SEH2_GetExceptionCode();
2472 _SEH2_YIELD(goto Cleanup);
2473 }
2474 _SEH2_END;
2475
2476 Status = SepCaptureSid(InputSid,
2477 PreviousMode,
2478 PagedPool,
2479 FALSE,
2480 &CapturedSid);
2481 if (NT_SUCCESS(Status))
2482 {
2483 /* Lock the token */
2484 SepAcquireTokenLockExclusive(Token);
2485
2486 /* Find the owner amongst the existing token user and groups */
2487 Status = SepFindPrimaryGroupAndDefaultOwner(Token,
2488 NULL,
2489 CapturedSid,
2490 NULL,
2491 &DefaultOwnerIndex);
2492 if (NT_SUCCESS(Status))
2493 {
2494 /* Found it */
2495 Token->DefaultOwnerIndex = DefaultOwnerIndex;
2496 ExAllocateLocallyUniqueId(&Token->ModifiedId);
2497 }
2498
2499 /* Unlock the token */
2500 SepReleaseTokenLock(Token);
2501
2502 SepReleaseSid(CapturedSid,
2503 PreviousMode,
2504 FALSE);
2505 }
2506 }
2507 else
2508 {
2509 Status = STATUS_INFO_LENGTH_MISMATCH;
2510 }
2511 break;
2512 }
2513
2514 case TokenPrimaryGroup:
2515 {
2516 if (TokenInformationLength >= sizeof(TOKEN_PRIMARY_GROUP))
2517 {
2518 PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation;
2519 PSID InputSid = NULL, CapturedSid;
2520 ULONG PrimaryGroupIndex;
2521
2522 _SEH2_TRY
2523 {
2524 InputSid = tpg->PrimaryGroup;
2525 }
2526 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2527 {
2528 Status = _SEH2_GetExceptionCode();
2529 _SEH2_YIELD(goto Cleanup);
2530 }
2531 _SEH2_END;
2532
2533 Status = SepCaptureSid(InputSid,
2534 PreviousMode,
2535 PagedPool,
2536 FALSE,
2537 &CapturedSid);
2538 if (NT_SUCCESS(Status))
2539 {
2540 /* Lock the token */
2541 SepAcquireTokenLockExclusive(Token);
2542
2543 /* Find the primary group amongst the existing token user and groups */
2544 Status = SepFindPrimaryGroupAndDefaultOwner(Token,
2545 CapturedSid,
2546 NULL,
2547 &PrimaryGroupIndex,
2548 NULL);
2549 if (NT_SUCCESS(Status))
2550 {
2551 /* Found it */
2552 Token->PrimaryGroup = Token->UserAndGroups[PrimaryGroupIndex].Sid;
2553 ExAllocateLocallyUniqueId(&Token->ModifiedId);
2554 }
2555
2556 /* Unlock the token */
2557 SepReleaseTokenLock(Token);
2558
2559 SepReleaseSid(CapturedSid,
2560 PreviousMode,
2561 FALSE);
2562 }
2563 }
2564 else
2565 {
2566 Status = STATUS_INFO_LENGTH_MISMATCH;
2567 }
2568 break;
2569 }
2570
2571 case TokenDefaultDacl:
2572 {
2573 if (TokenInformationLength >= sizeof(TOKEN_DEFAULT_DACL))
2574 {
2575 PTOKEN_DEFAULT_DACL tdd = (PTOKEN_DEFAULT_DACL)TokenInformation;
2576 PACL InputAcl = NULL;
2577
2578 _SEH2_TRY
2579 {
2580 InputAcl = tdd->DefaultDacl;
2581 }
2582 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2583 {
2584 Status = _SEH2_GetExceptionCode();
2585 _SEH2_YIELD(goto Cleanup);
2586 }
2587 _SEH2_END;
2588
2589 if (InputAcl != NULL)
2590 {
2591 PACL CapturedAcl;
2592
2593 /* Capture and copy the dacl */
2594 Status = SepCaptureAcl(InputAcl,
2595 PreviousMode,
2596 PagedPool,
2597 TRUE,
2598 &CapturedAcl);
2599 if (NT_SUCCESS(Status))
2600 {
2601 ULONG DynamicLength;
2602
2603 /* Lock the token */
2604 SepAcquireTokenLockExclusive(Token);
2605
2606 //
2607 // NOTE: So far our dynamic area only contains
2608 // the default dacl, so this makes the following
2609 // code pretty simple. The day where it stores
2610 // other data, the code will require adaptations.
2611 //
2612
2613 DynamicLength = Token->DynamicAvailable;
2614 // Add here any other data length present in the dynamic area...
2615 if (Token->DefaultDacl)
2616 DynamicLength += Token->DefaultDacl->AclSize;
2617
2618 /* Reallocate the dynamic area if it is too small */
2619 Status = STATUS_SUCCESS;
2620 if ((DynamicLength < CapturedAcl->AclSize) ||
2621 (Token->DynamicPart == NULL))
2622 {
2623 PVOID NewDynamicPart;
2624
2625 NewDynamicPart = ExAllocatePoolWithTag(PagedPool,
2626 CapturedAcl->AclSize,
2627 TAG_TOKEN_DYNAMIC);
2628 if (NewDynamicPart == NULL)
2629 {
2630 Status = STATUS_INSUFFICIENT_RESOURCES;
2631 }
2632 else
2633 {
2634 if (Token->DynamicPart != NULL)
2635 {
2636 // RtlCopyMemory(NewDynamicPart, Token->DynamicPart, DynamicLength);
2637 ExFreePoolWithTag(Token->DynamicPart, TAG_TOKEN_DYNAMIC);
2638 }
2639 Token->DynamicPart = NewDynamicPart;
2640 Token->DynamicAvailable = 0;
2641 }
2642 }
2643 else
2644 {
2645 Token->DynamicAvailable = DynamicLength - CapturedAcl->AclSize;
2646 }
2647
2648 if (NT_SUCCESS(Status))
2649 {
2650 /* Set the new dacl */
2651 Token->DefaultDacl = (PVOID)Token->DynamicPart;
2652 RtlCopyMemory(Token->DefaultDacl,
2653 CapturedAcl,
2654 CapturedAcl->AclSize);
2655
2656 ExAllocateLocallyUniqueId(&Token->ModifiedId);
2657 }
2658
2659 /* Unlock the token */
2660 SepReleaseTokenLock(Token);
2661
2662 ExFreePoolWithTag(CapturedAcl, TAG_ACL);
2663 }
2664 }
2665 else
2666 {
2667 /* Lock the token */
2668 SepAcquireTokenLockExclusive(Token);
2669
2670 /* Clear the default dacl if present */
2671 if (Token->DefaultDacl != NULL)
2672 {
2673 Token->DynamicAvailable += Token->DefaultDacl->AclSize;
2674 RtlZeroMemory(Token->DefaultDacl, Token->DefaultDacl->AclSize);
2675 Token->DefaultDacl = NULL;
2676
2677 ExAllocateLocallyUniqueId(&Token->ModifiedId);
2678 }
2679
2680 /* Unlock the token */
2681 SepReleaseTokenLock(Token);
2682 }
2683 }
2684 else
2685 {
2686 Status = STATUS_INFO_LENGTH_MISMATCH;
2687 }
2688 break;
2689 }
2690
2691 case TokenSessionId:
2692 {
2693 ULONG SessionId = 0;
2694
2695 _SEH2_TRY
2696 {
2697 /* Buffer size was already verified, no need to check here again */
2698 SessionId = *(PULONG)TokenInformation;
2699 }
2700 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2701 {
2702 Status = _SEH2_GetExceptionCode();
2703 _SEH2_YIELD(goto Cleanup);
2704 }
2705 _SEH2_END;
2706
2707 /* Check for TCB privilege */
2708 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
2709 {
2710 Status = STATUS_PRIVILEGE_NOT_HELD;
2711 break;
2712 }
2713
2714 /* Lock the token */
2715 SepAcquireTokenLockExclusive(Token);
2716
2717 Token->SessionId = SessionId;
2718 ExAllocateLocallyUniqueId(&Token->ModifiedId);
2719
2720 /* Unlock the token */
2721 SepReleaseTokenLock(Token);
2722
2723 break;
2724 }
2725
2726 case TokenSessionReference:
2727 {
2728 ULONG SessionReference;
2729
2730 _SEH2_TRY
2731 {
2732 /* Buffer size was already verified, no need to check here again */
2733 SessionReference = *(PULONG)TokenInformation;
2734 }
2735 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2736 {
2737 Status = _SEH2_GetExceptionCode();
2738 _SEH2_YIELD(goto Cleanup);
2739 }
2740 _SEH2_END;
2741
2742 /* Check for TCB privilege */
2743 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
2744 {
2745 Status = STATUS_PRIVILEGE_NOT_HELD;
2746 goto Cleanup;
2747 }
2748
2749 /* Check if it is 0 */
2750 if (SessionReference == 0)
2751 {
2752 ULONG OldTokenFlags;
2753
2754 /* Lock the token */
2755 SepAcquireTokenLockExclusive(Token);
2756
2757 /* Atomically set the flag in the token */
2758 OldTokenFlags = RtlInterlockedSetBits(&Token->TokenFlags,
2759 TOKEN_SESSION_NOT_REFERENCED);
2760 /*
2761 * If the flag was already set, do not dereference again
2762 * the logon session. Use SessionReference as an indicator
2763 * to know whether to really dereference the session.
2764 */
2765 if (OldTokenFlags == Token->TokenFlags)
2766 SessionReference = ULONG_MAX;
2767
2768 /* Unlock the token */
2769 SepReleaseTokenLock(Token);
2770 }
2771
2772 /* Dereference the logon session if needed */
2773 if (SessionReference == 0)
2774 SepRmDereferenceLogonSession(&Token->AuthenticationId);
2775
2776 break;
2777 }
2778
2779 case TokenAuditPolicy:
2780 {
2781 PTOKEN_AUDIT_POLICY_INFORMATION PolicyInformation =
2782 (PTOKEN_AUDIT_POLICY_INFORMATION)TokenInformation;
2783 SEP_AUDIT_POLICY AuditPolicy;
2784 ULONG i;
2785
2786 _SEH2_TRY
2787 {
2788 ProbeForRead(PolicyInformation,
2789 FIELD_OFFSET(TOKEN_AUDIT_POLICY_INFORMATION,
2790 Policies[PolicyInformation->PolicyCount]),
2791 sizeof(ULONG));
2792
2793 /* Loop all policies in the structure */
2794 for (i = 0; i < PolicyInformation->PolicyCount; i++)
2795 {
2796 /* Set the corresponding bits in the packed structure */
2797 switch (PolicyInformation->Policies[i].Category)
2798 {
2799 case AuditCategorySystem:
2800 AuditPolicy.PolicyElements.System = PolicyInformation->Policies[i].Value;
2801 break;
2802
2803 case AuditCategoryLogon:
2804 AuditPolicy.PolicyElements.Logon = PolicyInformation->Policies[i].Value;
2805 break;
2806
2807 case AuditCategoryObjectAccess:
2808 AuditPolicy.PolicyElements.ObjectAccess = PolicyInformation->Policies[i].Value;
2809 break;
2810
2811 case AuditCategoryPrivilegeUse:
2812 AuditPolicy.PolicyElements.PrivilegeUse = PolicyInformation->Policies[i].Value;
2813 break;
2814
2815 case AuditCategoryDetailedTracking:
2816 AuditPolicy.PolicyElements.DetailedTracking = PolicyInformation->Policies[i].Value;
2817 break;
2818
2819 case AuditCategoryPolicyChange:
2820 AuditPolicy.PolicyElements.PolicyChange = PolicyInformation->Policies[i].Value;
2821 break;
2822
2823 case AuditCategoryAccountManagement:
2824 AuditPolicy.PolicyElements.AccountManagement = PolicyInformation->Policies[i].Value;
2825 break;
2826
2827 case AuditCategoryDirectoryServiceAccess:
2828 AuditPolicy.PolicyElements.DirectoryServiceAccess = PolicyInformation->Policies[i].Value;
2829 break;
2830
2831 case AuditCategoryAccountLogon:
2832 AuditPolicy.PolicyElements.AccountLogon = PolicyInformation->Policies[i].Value;
2833 break;
2834 }
2835 }
2836 }
2837 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2838 {
2839 Status = _SEH2_GetExceptionCode();
2840 _SEH2_YIELD(goto Cleanup);
2841 }
2842 _SEH2_END;
2843
2844 /* Check for TCB privilege */
2845 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
2846 {
2847 Status = STATUS_PRIVILEGE_NOT_HELD;
2848 break;
2849 }
2850
2851 /* Lock the token */
2852 SepAcquireTokenLockExclusive(Token);
2853
2854 /* Set the new audit policy */
2855 Token->AuditPolicy = AuditPolicy;
2856 ExAllocateLocallyUniqueId(&Token->ModifiedId);
2857
2858 /* Unlock the token */
2859 SepReleaseTokenLock(Token);
2860
2861 break;
2862 }
2863
2864 case TokenOrigin:
2865 {
2866 TOKEN_ORIGIN TokenOrigin;
2867
2868 _SEH2_TRY
2869 {
2870 /* Copy the token origin */
2871 TokenOrigin = *(PTOKEN_ORIGIN)TokenInformation;
2872 }
2873 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2874 {
2875 Status = _SEH2_GetExceptionCode();
2876 _SEH2_YIELD(goto Cleanup);
2877 }
2878 _SEH2_END;
2879
2880 /* Check for TCB privilege */
2881 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
2882 {
2883 Status = STATUS_PRIVILEGE_NOT_HELD;
2884 break;
2885 }
2886
2887 /* Lock the token */
2888 SepAcquireTokenLockExclusive(Token);
2889
2890 /* Check if there is no token origin set yet */
2891 if (RtlIsZeroLuid(&Token->OriginatingLogonSession))
2892 {
2893 /* Set the token origin */
2894 Token->OriginatingLogonSession =
2895 TokenOrigin.OriginatingLogonSession;
2896
2897 ExAllocateLocallyUniqueId(&Token->ModifiedId);
2898 }
2899
2900 /* Unlock the token */
2901 SepReleaseTokenLock(Token);
2902
2903 break;
2904 }
2905
2906 default:
2907 {
2908 DPRINT1("Invalid TokenInformationClass: 0x%lx\n",
2909 TokenInformationClass);
2910 Status = STATUS_INVALID_INFO_CLASS;
2911 break;
2912 }
2913 }
2914 Cleanup:
2915 ObDereferenceObject(Token);
2916 }
2917
2918 if (!NT_SUCCESS(Status))
2919 {
2920 DPRINT1("NtSetInformationToken failed with Status 0x%lx\n", Status);
2921 }
2922
2923 return Status;
2924 }
2925
2926
2927 /*
2928 * @implemented
2929 *
2930 * NOTE: Some sources claim 4th param is ImpersonationLevel, but on W2K
2931 * this is certainly NOT true, although I can't say for sure that EffectiveOnly
2932 * is correct either. -Gunnar
2933 * This is true. EffectiveOnly overrides SQOS.EffectiveOnly. - IAI
2934 * NOTE for readers: http://hex.pp.ua/nt/NtDuplicateToken.php is therefore
2935 * wrong in that regard, while MSDN documentation is correct.
2936 */
2937 _Must_inspect_result_
2938 __kernel_entry
2939 NTSTATUS
2940 NTAPI
2941 NtDuplicateToken(
2942 _In_ HANDLE ExistingTokenHandle,
2943 _In_ ACCESS_MASK DesiredAccess,
2944 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
2945 _In_ BOOLEAN EffectiveOnly,
2946 _In_ TOKEN_TYPE TokenType,
2947 _Out_ PHANDLE NewTokenHandle)
2948 {
2949 KPROCESSOR_MODE PreviousMode;
2950 HANDLE hToken;
2951 PTOKEN Token;
2952 PTOKEN NewToken;
2953 PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService;
2954 BOOLEAN QoSPresent;
2955 OBJECT_HANDLE_INFORMATION HandleInformation;
2956 NTSTATUS Status;
2957
2958 PAGED_CODE();
2959
2960 if (TokenType != TokenImpersonation &&
2961 TokenType != TokenPrimary)
2962 {
2963 return STATUS_INVALID_PARAMETER;
2964 }
2965
2966 PreviousMode = KeGetPreviousMode();
2967
2968 if (PreviousMode != KernelMode)
2969 {
2970 _SEH2_TRY
2971 {
2972 ProbeForWriteHandle(NewTokenHandle);
2973 }
2974 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2975 {
2976 /* Return the exception code */
2977 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2978 }
2979 _SEH2_END;
2980 }
2981
2982 Status = SepCaptureSecurityQualityOfService(ObjectAttributes,
2983 PreviousMode,
2984 PagedPool,
2985 FALSE,
2986 &CapturedSecurityQualityOfService,
2987 &QoSPresent);
2988 if (!NT_SUCCESS(Status))
2989 {
2990 DPRINT1("NtDuplicateToken() failed to capture QoS! Status: 0x%x\n", Status);
2991 return Status;
2992 }
2993
2994 Status = ObReferenceObjectByHandle(ExistingTokenHandle,
2995 TOKEN_DUPLICATE,
2996 SeTokenObjectType,
2997 PreviousMode,
2998 (PVOID*)&Token,
2999 &HandleInformation);
3000 if (!NT_SUCCESS(Status))
3001 {
3002 DPRINT1("Failed to reference token (Status 0x%lx)\n", Status);
3003 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
3004 PreviousMode,
3005 FALSE);
3006 return Status;
3007 }
3008
3009 /*
3010 * Fail, if the original token is an impersonation token and the caller
3011 * tries to raise the impersonation level of the new token above the
3012 * impersonation level of the original token.
3013 */
3014 if (Token->TokenType == TokenImpersonation)
3015 {
3016 if (QoSPresent &&
3017 CapturedSecurityQualityOfService->ImpersonationLevel >Token->ImpersonationLevel)
3018 {
3019 ObDereferenceObject(Token);
3020 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
3021 PreviousMode,
3022 FALSE);
3023 return STATUS_BAD_IMPERSONATION_LEVEL;
3024 }
3025 }
3026
3027 /*
3028 * Fail, if a primary token is to be created from an impersonation token
3029 * and and the impersonation level of the impersonation token is below SecurityImpersonation.
3030 */
3031 if (Token->TokenType == TokenImpersonation &&
3032 TokenType == TokenPrimary &&
3033 Token->ImpersonationLevel < SecurityImpersonation)
3034 {
3035 ObDereferenceObject(Token);
3036 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
3037 PreviousMode,
3038 FALSE);
3039 return STATUS_BAD_IMPERSONATION_LEVEL;
3040 }
3041
3042 Status = SepDuplicateToken(Token,
3043 ObjectAttributes,
3044 EffectiveOnly,
3045 TokenType,
3046 (QoSPresent ? CapturedSecurityQualityOfService->ImpersonationLevel : SecurityAnonymous),
3047 PreviousMode,
3048 &NewToken);
3049
3050 ObDereferenceObject(Token);
3051
3052 if (NT_SUCCESS(Status))
3053 {
3054 Status = ObInsertObject(NewToken,
3055 NULL,
3056 (DesiredAccess ? DesiredAccess : HandleInformation.GrantedAccess),
3057 0,
3058 NULL,
3059 &hToken);
3060 if (NT_SUCCESS(Status))
3061 {
3062 _SEH2_TRY
3063 {
3064 *NewTokenHandle = hToken;
3065 }
3066 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3067 {
3068 Status = _SEH2_GetExceptionCode();
3069 }
3070 _SEH2_END;
3071 }
3072 }
3073
3074 /* Free the captured structure */
3075 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
3076 PreviousMode,
3077 FALSE);
3078
3079 return Status;
3080 }
3081
3082 NTSTATUS NTAPI
3083 NtAdjustGroupsToken(IN HANDLE TokenHandle,
3084 IN BOOLEAN ResetToDefault,
3085 IN PTOKEN_GROUPS NewState,
3086 IN ULONG BufferLength,
3087 OUT PTOKEN_GROUPS PreviousState OPTIONAL,
3088 OUT PULONG ReturnLength)
3089 {
3090 UNIMPLEMENTED;
3091 return STATUS_NOT_IMPLEMENTED;
3092 }
3093
3094
3095 static
3096 NTSTATUS
3097 SepAdjustPrivileges(
3098 _Inout_ PTOKEN Token,
3099 _In_ BOOLEAN DisableAllPrivileges,
3100 _In_opt_ PLUID_AND_ATTRIBUTES NewState,
3101 _In_ ULONG NewStateCount,
3102 _Out_opt_ PTOKEN_PRIVILEGES PreviousState,
3103 _In_ BOOLEAN ApplyChanges,
3104 _Out_ PULONG ChangedPrivileges,
3105 _Out_ PBOOLEAN ChangesMade)
3106 {
3107 ULONG i, j, PrivilegeCount, ChangeCount, NewAttributes;
3108
3109 /* Count the found privileges and those that need to be changed */
3110 PrivilegeCount = 0;
3111 ChangeCount = 0;
3112 *ChangesMade = FALSE;
3113
3114 /* Loop all privileges in the token */
3115 for (i = 0; i < Token->PrivilegeCount; i++)
3116 {
3117 /* Shall all of them be disabled? */
3118 if (DisableAllPrivileges)
3119 {
3120 /* The new attributes are the old ones, but disabled */
3121 NewAttributes = Token->Privileges[i].Attributes & ~SE_PRIVILEGE_ENABLED;
3122 }
3123 else
3124 {
3125 /* Otherwise loop all provided privileges */
3126 for (j = 0; j < NewStateCount; j++)
3127 {
3128 /* Check if this is the LUID we are looking for */
3129 if (RtlEqualLuid(&Token->Privileges[i].Luid, &NewState[j].Luid))
3130 {
3131 DPRINT("Found privilege\n");
3132
3133 /* Copy SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED */
3134 NewAttributes = NewState[j].Attributes;
3135 NewAttributes &= (SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED);
3136 NewAttributes |= Token->Privileges[i].Attributes & ~SE_PRIVILEGE_ENABLED;
3137
3138 /* Stop looking */
3139 break;
3140 }
3141 }
3142
3143 /* Check if we didn't find the privilege */
3144 if (j == NewStateCount)
3145 {
3146 /* Continue with the token's next privilege */
3147 continue;
3148 }
3149 }
3150
3151 /* We found a privilege, count it */
3152 PrivilegeCount++;
3153
3154 /* Does the privilege need to be changed? */
3155 if (Token->Privileges[i].Attributes != NewAttributes)
3156 {
3157 /* Does the caller want the old privileges? */
3158 if (PreviousState != NULL)
3159 {
3160 /* Copy the old privilege */
3161 PreviousState->Privileges[ChangeCount] = Token->Privileges[i];
3162 }
3163
3164 /* Does the caller want to apply the changes? */
3165 if (ApplyChanges)
3166 {
3167 /* Shall we remove the privilege? */
3168 if (NewAttributes & SE_PRIVILEGE_REMOVED)
3169 {
3170 /* Set the token as disabled and update flags for it */
3171 Token->Privileges[i].Attributes &= ~SE_PRIVILEGE_ENABLED;
3172 SepUpdateSinglePrivilegeFlagToken(Token, i);
3173
3174 /* Remove the privilege */
3175 SepRemovePrivilegeToken(Token, i);
3176
3177 *ChangesMade = TRUE;
3178
3179 /* Fix the running index and continue with next one */
3180 i--;
3181 continue;
3182 }
3183
3184 /* Set the new attributes and update flags */
3185 Token->Privileges[i].Attributes = NewAttributes;
3186 SepUpdateSinglePrivilegeFlagToken(Token, i);
3187 *ChangesMade = TRUE;
3188 }
3189
3190 /* Increment the change count */
3191 ChangeCount++;
3192 }
3193 }
3194
3195 /* Set the number of saved privileges */
3196 if (PreviousState != NULL)
3197 PreviousState->PrivilegeCount = ChangeCount;
3198
3199 /* Return the number of changed privileges */
3200 *ChangedPrivileges = ChangeCount;
3201
3202 /* Check if we missed some */
3203 if (!DisableAllPrivileges && (PrivilegeCount < NewStateCount))
3204 {
3205 return STATUS_NOT_ALL_ASSIGNED;
3206 }
3207
3208 return STATUS_SUCCESS;
3209 }
3210
3211
3212 /*
3213 * @implemented
3214 */
3215 _Must_inspect_result_
3216 __kernel_entry
3217 NTSTATUS
3218 NTAPI
3219 NtAdjustPrivilegesToken(
3220 _In_ HANDLE TokenHandle,
3221 _In_ BOOLEAN DisableAllPrivileges,
3222 _In_opt_ PTOKEN_PRIVILEGES NewState,
3223 _In_ ULONG BufferLength,
3224 _Out_writes_bytes_to_opt_(BufferLength,*ReturnLength)
3225 PTOKEN_PRIVILEGES PreviousState,
3226 _When_(PreviousState!=NULL, _Out_) PULONG ReturnLength)
3227 {
3228 NTSTATUS Status;
3229 KPROCESSOR_MODE PreviousMode;
3230 PTOKEN Token;
3231 PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
3232 ULONG CapturedCount = 0;
3233 ULONG CapturedLength = 0;
3234 ULONG NewStateSize = 0;
3235 ULONG ChangeCount;
3236 ULONG RequiredLength;
3237 BOOLEAN ChangesMade = FALSE;
3238
3239 PAGED_CODE();
3240
3241 DPRINT("NtAdjustPrivilegesToken() called\n");
3242
3243 /* Fail, if we do not disable all privileges but NewState is NULL */
3244 if (DisableAllPrivileges == FALSE && NewState == NULL)
3245 return STATUS_INVALID_PARAMETER;
3246
3247 PreviousMode = KeGetPreviousMode();
3248 if (PreviousMode != KernelMode)
3249 {
3250 _SEH2_TRY
3251 {
3252 /* Probe NewState */
3253 if (DisableAllPrivileges == FALSE)
3254 {
3255 /* First probe the header */
3256 ProbeForRead(NewState, sizeof(TOKEN_PRIVILEGES), sizeof(ULONG));
3257
3258 CapturedCount = NewState->PrivilegeCount;
3259 NewStateSize = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[CapturedCount]);
3260
3261 ProbeForRead(NewState, NewStateSize, sizeof(ULONG));
3262 }
3263
3264 /* Probe PreviousState and ReturnLength */
3265 if (PreviousState != NULL)
3266 {
3267 ProbeForWrite(PreviousState, BufferLength, sizeof(ULONG));
3268 ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG));
3269 }
3270 }
3271 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3272 {
3273 /* Return the exception code */
3274 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3275 }
3276 _SEH2_END;
3277 }
3278 else
3279 {
3280 /* This is kernel mode, we trust the caller */
3281 if (DisableAllPrivileges == FALSE)
3282 CapturedCount = NewState->PrivilegeCount;
3283 }
3284
3285 /* Do we need to capture the new state? */
3286 if (DisableAllPrivileges == FALSE)
3287 {
3288 _SEH2_TRY
3289 {
3290 /* Capture the new state array of privileges */
3291 Status = SeCaptureLuidAndAttributesArray(NewState->Privileges,
3292 CapturedCount,
3293 PreviousMode,
3294 NULL,
3295 0,
3296 PagedPool,
3297 TRUE,
3298 &CapturedPrivileges,
3299 &CapturedLength);
3300 }
3301 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3302 {
3303 /* Return the exception code */
3304 Status = _SEH2_GetExceptionCode();
3305 }
3306 _SEH2_END;
3307
3308 if (!NT_SUCCESS(Status))
3309 return Status;
3310 }
3311
3312 /* Reference the token */
3313 Status = ObReferenceObjectByHandle(TokenHandle,
3314 TOKEN_ADJUST_PRIVILEGES | (PreviousState != NULL ? TOKEN_QUERY : 0),
3315 SeTokenObjectType,
3316 PreviousMode,
3317 (PVOID*)&Token,
3318 NULL);
3319 if (!NT_SUCCESS(Status))
3320 {
3321 DPRINT1("Failed to reference token (Status 0x%lx)\n", Status);
3322
3323 /* Release the captured privileges */
3324 if (CapturedPrivileges != NULL)
3325 {
3326 SeReleaseLuidAndAttributesArray(CapturedPrivileges,
3327 PreviousMode,
3328 TRUE);
3329 }
3330
3331 return Status;
3332 }
3333
3334 /* Lock the token */
3335 SepAcquireTokenLockExclusive(Token);
3336
3337 /* Count the privileges that need to be changed, do not apply them yet */
3338 Status = SepAdjustPrivileges(Token,
3339 DisableAllPrivileges,
3340 CapturedPrivileges,
3341 CapturedCount,
3342 NULL,
3343 FALSE,
3344 &ChangeCount,
3345 &ChangesMade);
3346
3347 /* Check if the caller asked for the previous state */
3348 if (PreviousState != NULL)
3349 {
3350 /* Calculate the required length */
3351 RequiredLength = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[ChangeCount]);
3352
3353 /* Try to return the required buffer length */
3354 _SEH2_TRY
3355 {
3356 *ReturnLength = RequiredLength;
3357 }
3358 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3359 {
3360 /* Do cleanup and return the exception code */
3361 Status = _SEH2_GetExceptionCode();
3362 _SEH2_YIELD(goto Cleanup);
3363 }
3364 _SEH2_END;
3365
3366 /* Fail, if the buffer length is smaller than the required length */
3367 if (BufferLength < RequiredLength)
3368 {
3369 Status = STATUS_BUFFER_TOO_SMALL;
3370 goto Cleanup;
3371 }
3372 }
3373
3374 /* Now enter SEH, since we might return the old privileges */
3375 _SEH2_TRY
3376 {
3377 /* This time apply the changes */
3378 Status = SepAdjustPrivileges(Token,
3379 DisableAllPrivileges,
3380 CapturedPrivileges,
3381 CapturedCount,
3382 PreviousState,
3383 TRUE,
3384 &ChangeCount,
3385 &ChangesMade);
3386 }
3387 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3388 {
3389 /* Do cleanup and return the exception code */
3390 Status = _SEH2_GetExceptionCode();
3391 ChangesMade = TRUE; // Force write.
3392 _SEH2_YIELD(goto Cleanup);
3393 }
3394 _SEH2_END;
3395
3396 Cleanup:
3397 /* Touch the token if we made changes */
3398 if (ChangesMade)
3399 ExAllocateLocallyUniqueId(&Token->ModifiedId);
3400
3401 /* Unlock and dereference the token */
3402 SepReleaseTokenLock(Token);
3403 ObDereferenceObject(Token);
3404
3405 /* Release the captured privileges */
3406 if (CapturedPrivileges != NULL)
3407 {
3408 SeReleaseLuidAndAttributesArray(CapturedPrivileges,
3409 PreviousMode,
3410 TRUE);
3411 }
3412
3413 DPRINT ("NtAdjustPrivilegesToken() done\n");
3414 return Status;
3415 }
3416
3417 __kernel_entry
3418 NTSTATUS
3419 NTAPI
3420 NtCreateToken(
3421 _Out_ PHANDLE TokenHandle,
3422 _In_ ACCESS_MASK DesiredAccess,
3423 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
3424 _In_ TOKEN_TYPE TokenType,
3425 _In_ PLUID AuthenticationId,
3426 _In_ PLARGE_INTEGER ExpirationTime,
3427 _In_ PTOKEN_USER TokenUser,
3428 _In_ PTOKEN_GROUPS TokenGroups,
3429 _In_ PTOKEN_PRIVILEGES TokenPrivileges,
3430 _In_opt_ PTOKEN_OWNER TokenOwner,
3431 _In_ PTOKEN_PRIMARY_GROUP TokenPrimaryGroup,
3432 _In_opt_ PTOKEN_DEFAULT_DACL TokenDefaultDacl,
3433 _In_ PTOKEN_SOURCE TokenSource)
3434 {
3435 HANDLE hToken;
3436 KPROCESSOR_MODE PreviousMode;
3437 ULONG PrivilegeCount, GroupCount;
3438 PSID OwnerSid, PrimaryGroupSid;
3439 PACL DefaultDacl;
3440 LARGE_INTEGER LocalExpirationTime = {{0, 0}};
3441 LUID LocalAuthenticationId;
3442 TOKEN_SOURCE LocalTokenSource;
3443 SECURITY_QUALITY_OF_SERVICE LocalSecurityQos;
3444 PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
3445 PSID_AND_ATTRIBUTES CapturedUser = NULL;
3446 PSID_AND_ATTRIBUTES CapturedGroups = NULL;
3447 PSID CapturedOwnerSid = NULL;
3448 PSID CapturedPrimaryGroupSid = NULL;
3449 PACL CapturedDefaultDacl = NULL;
3450 ULONG PrivilegesLength, UserLength, GroupsLength;
3451 NTSTATUS Status;
3452
3453 PAGED_CODE();
3454
3455 PreviousMode = ExGetPreviousMode();
3456
3457 if (PreviousMode != KernelMode)
3458 {
3459 _SEH2_TRY
3460 {
3461 ProbeForWriteHandle(TokenHandle);
3462
3463 if (ObjectAttributes != NULL)
3464 {
3465 ProbeForRead(ObjectAttributes,
3466 sizeof(OBJECT_ATTRIBUTES),
3467 sizeof(ULONG));
3468 LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService;
3469 }
3470
3471 ProbeForRead(AuthenticationId,
3472 sizeof(LUID),
3473 sizeof(ULONG));
3474 LocalAuthenticationId = *AuthenticationId;
3475
3476 LocalExpirationTime = ProbeForReadLargeInteger(ExpirationTime);
3477
3478 ProbeForRead(TokenUser,
3479 sizeof(TOKEN_USER),
3480 sizeof(ULONG));
3481
3482 ProbeForRead(TokenGroups,
3483 sizeof(TOKEN_GROUPS),
3484 sizeof(ULONG));
3485 GroupCount = TokenGroups->GroupCount;
3486
3487 ProbeForRead(TokenPrivileges,
3488 sizeof(TOKEN_PRIVILEGES),
3489 sizeof(ULONG));
3490 PrivilegeCount = TokenPrivileges->PrivilegeCount;
3491
3492 if (TokenOwner != NULL)
3493 {
3494 ProbeForRead(TokenOwner,
3495 sizeof(TOKEN_OWNER),
3496 sizeof(ULONG));
3497 OwnerSid = TokenOwner->Owner;
3498 }
3499 else
3500 {
3501 OwnerSid = NULL;
3502 }
3503
3504 ProbeForRead(TokenPrimaryGroup,
3505 sizeof(TOKEN_PRIMARY_GROUP),
3506 sizeof(ULONG));
3507 PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup;
3508
3509 if (TokenDefaultDacl != NULL)
3510 {
3511 ProbeForRead(TokenDefaultDacl,
3512 sizeof(TOKEN_DEFAULT_DACL),
3513 sizeof(ULONG));
3514 DefaultDacl = TokenDefaultDacl->DefaultDacl;
3515 }
3516 else
3517 {
3518 DefaultDacl = NULL;
3519 }
3520
3521 ProbeForRead(TokenSource,
3522 sizeof(TOKEN_SOURCE),
3523 sizeof(ULONG));
3524 LocalTokenSource = *TokenSource;
3525 }
3526 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3527 {
3528 /* Return the exception code */
3529 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3530 }
3531 _SEH2_END;
3532 }
3533 else
3534 {
3535 if (ObjectAttributes != NULL)
3536 LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService;
3537 LocalAuthenticationId = *AuthenticationId;
3538 LocalExpirationTime = *ExpirationTime;
3539 GroupCount = TokenGroups->GroupCount;
3540 PrivilegeCount = TokenPrivileges->PrivilegeCount;
3541 OwnerSid = TokenOwner ? TokenOwner->Owner : NULL;
3542 PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup;
3543 DefaultDacl = TokenDefaultDacl ? TokenDefaultDacl->DefaultDacl : NULL;
3544 LocalTokenSource = *TokenSource;
3545 }
3546
3547 /* Check token type */
3548 if ((TokenType < TokenPrimary) ||
3549 (TokenType > TokenImpersonation))
3550 {
3551 return STATUS_BAD_TOKEN_TYPE;
3552 }
3553
3554 /* Check for token creation privilege */
3555 if (!SeSinglePrivilegeCheck(SeCreateTokenPrivilege, PreviousMode))
3556 {
3557 return STATUS_PRIVILEGE_NOT_HELD;
3558 }
3559
3560 /* Capture the user SID and attributes */
3561 Status = SeCaptureSidAndAttributesArray(&TokenUser->User,
3562 1,
3563 PreviousMode,
3564 NULL,
3565 0,
3566 PagedPool,
3567 FALSE,
3568 &CapturedUser,
3569 &UserLength);
3570 if (!NT_SUCCESS(Status))
3571 {
3572 goto Cleanup;
3573 }
3574
3575 /* Capture the groups SID and attributes array */
3576 Status = SeCaptureSidAndAttributesArray(&TokenGroups->Groups[0],
3577 GroupCount,
3578 PreviousMode,
3579 NULL,
3580 0,
3581 PagedPool,
3582 FALSE,
3583 &CapturedGroups,
3584 &GroupsLength);
3585 if (!NT_SUCCESS(Status))
3586 {
3587 goto Cleanup;
3588 }
3589
3590 /* Capture privileges */
3591 Status = SeCaptureLuidAndAttributesArray(&TokenPrivileges->Privileges[0],
3592 PrivilegeCount,
3593 PreviousMode,
3594 NULL,
3595 0,
3596 PagedPool,
3597 FALSE,
3598 &CapturedPrivileges,
3599 &PrivilegesLength);
3600 if (!NT_SUCCESS(Status))
3601 {
3602 goto Cleanup;
3603 }
3604
3605 /* Capture the token owner SID */
3606 if (TokenOwner != NULL)
3607 {
3608 Status = SepCaptureSid(OwnerSid,
3609 PreviousMode,
3610 PagedPool,
3611 FALSE,
3612 &CapturedOwnerSid);
3613 if (!NT_SUCCESS(Status))
3614 {
3615 goto Cleanup;
3616 }
3617 }
3618
3619 /* Capture the token primary group SID */
3620 Status = SepCaptureSid(PrimaryGroupSid,
3621 PreviousMode,
3622 PagedPool,
3623 FALSE,
3624 &CapturedPrimaryGroupSid);
3625 if (!NT_SUCCESS(Status))
3626 {
3627 goto Cleanup;
3628 }
3629
3630 /* Capture DefaultDacl */
3631 if (DefaultDacl != NULL)
3632 {
3633 Status = SepCaptureAcl(DefaultDacl,
3634 PreviousMode,
3635 NonPagedPool,
3636 FALSE,
3637 &CapturedDefaultDacl);
3638 if (!NT_SUCCESS(Status))
3639 {
3640 goto Cleanup;
3641 }
3642 }
3643
3644 /* Call the internal function */
3645 Status = SepCreateToken(&hToken,
3646 PreviousMode,
3647 DesiredAccess,
3648 ObjectAttributes,
3649 TokenType,
3650 LocalSecurityQos.ImpersonationLevel,
3651 &LocalAuthenticationId,
3652 &LocalExpirationTime,
3653 CapturedUser,
3654 GroupCount,
3655 CapturedGroups,
3656 0, // FIXME: Should capture
3657 PrivilegeCount,
3658 CapturedPrivileges,
3659 CapturedOwnerSid,
3660 CapturedPrimaryGroupSid,
3661 CapturedDefaultDacl,
3662 &LocalTokenSource,
3663 FALSE);
3664 if (NT_SUCCESS(Status))
3665 {
3666 _SEH2_TRY
3667 {
3668 *TokenHandle = hToken;
3669 }
3670 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3671 {
3672 Status = _SEH2_GetExceptionCode();
3673 }
3674 _SEH2_END;
3675 }
3676
3677 Cleanup:
3678
3679 /* Release what we captured */
3680 SeReleaseSidAndAttributesArray(CapturedUser, PreviousMode, FALSE);
3681 SeReleaseSidAndAttributesArray(CapturedGroups, PreviousMode, FALSE);
3682 SeReleaseLuidAndAttributesArray(CapturedPrivileges, PreviousMode, FALSE);
3683 SepReleaseSid(CapturedOwnerSid, PreviousMode, FALSE);
3684 SepReleaseSid(CapturedPrimaryGroupSid, PreviousMode, FALSE);
3685 SepReleaseAcl(CapturedDefaultDacl, PreviousMode, FALSE);
3686
3687 return Status;
3688 }
3689
3690 /*
3691 * @implemented
3692 */
3693 NTSTATUS
3694 NTAPI
3695 NtOpenThreadTokenEx(IN HANDLE ThreadHandle,
3696 IN ACCESS_MASK DesiredAccess,
3697 IN BOOLEAN OpenAsSelf,
3698 IN ULONG HandleAttributes,
3699 OUT PHANDLE TokenHandle)
3700 {
3701 PETHREAD Thread, NewThread;
3702 HANDLE hToken;
3703 PTOKEN Token, NewToken = NULL, PrimaryToken;
3704 BOOLEAN CopyOnOpen, EffectiveOnly;
3705 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
3706 SE_IMPERSONATION_STATE ImpersonationState;
3707 OBJECT_ATTRIBUTES ObjectAttributes;
3708 SECURITY_DESCRIPTOR SecurityDescriptor;
3709 PACL Dacl = NULL;
3710 KPROCESSOR_MODE PreviousMode;
3711 NTSTATUS Status;
3712 BOOLEAN RestoreImpersonation = FALSE;
3713
3714 PAGED_CODE();
3715
3716 PreviousMode = ExGetPreviousMode();
3717
3718 if (PreviousMode != KernelMode)
3719 {
3720 _SEH2_TRY
3721 {
3722 ProbeForWriteHandle(TokenHandle);
3723 }
3724 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3725 {
3726 /* Return the exception code */
3727 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3728 }
3729 _SEH2_END;
3730 }
3731
3732 /* Validate object attributes */
3733 HandleAttributes = ObpValidateAttributes(HandleAttributes, PreviousMode);
3734
3735 /*
3736 * At first open the thread token for information access and verify
3737 * that the token associated with thread is valid.
3738 */
3739
3740 Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_QUERY_INFORMATION,
3741 PsThreadType, PreviousMode, (PVOID*)&Thread,
3742 NULL);
3743 if (!NT_SUCCESS(Status))
3744 {
3745 return Status;
3746 }
3747
3748 Token = PsReferenceImpersonationToken(Thread, &CopyOnOpen, &EffectiveOnly,
3749 &ImpersonationLevel);
3750 if (Token == NULL)
3751 {
3752 ObDereferenceObject(Thread);
3753 return STATUS_NO_TOKEN;
3754 }
3755
3756 if (ImpersonationLevel == SecurityAnonymous)
3757 {
3758 PsDereferenceImpersonationToken(Token);
3759 ObDereferenceObject(Thread);
3760 return STATUS_CANT_OPEN_ANONYMOUS;
3761 }
3762
3763 /*
3764 * Revert to self if OpenAsSelf is specified.
3765 */
3766
3767 if (OpenAsSelf)
3768 {
3769 RestoreImpersonation = PsDisableImpersonation(PsGetCurrentThread(),
3770 &ImpersonationState);
3771 }
3772
3773 if (CopyOnOpen)
3774 {
3775 Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_ALL_ACCESS,
3776 PsThreadType, KernelMode,
3777 (PVOID*)&NewThread, NULL);
3778 if (NT_SUCCESS(Status))
3779 {
3780 PrimaryToken = PsReferencePrimaryToken(NewThread->ThreadsProcess);
3781
3782 Status = SepCreateImpersonationTokenDacl(Token, PrimaryToken, &Dacl);
3783
3784 ObFastDereferenceObject(&NewThread->ThreadsProcess->Token, PrimaryToken);
3785
3786 if (NT_SUCCESS(Status))
3787 {
3788 if (Dacl)
3789 {
3790 RtlCreateSecurityDescriptor(&SecurityDescriptor,
3791 SECURITY_DESCRIPTOR_REVISION);
3792 RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl,
3793 FALSE);
3794 }
3795
3796 InitializeObjectAttributes(&ObjectAttributes, NULL, HandleAttributes,
3797 NULL, Dacl ? &SecurityDescriptor : NULL);
3798
3799 Status = SepDuplicateToken(Token, &ObjectAttributes, EffectiveOnly,
3800 TokenImpersonation, ImpersonationLevel,
3801 KernelMode, &NewToken);
3802 if (NT_SUCCESS(Status))
3803 {
3804 ObReferenceObject(NewToken);
3805 Status = ObInsertObject(NewToken, NULL, DesiredAccess, 0, NULL,
3806 &hToken);
3807 }
3808 }
3809 }
3810 }
3811 else
3812 {
3813 Status = ObOpenObjectByPointer(Token, HandleAttributes,
3814 NULL, DesiredAccess, SeTokenObjectType,
3815 PreviousMode, &hToken);
3816 }
3817
3818 if (Dacl) ExFreePoolWithTag(Dacl, TAG_ACL);
3819
3820 if (RestoreImpersonation)
3821 {
3822 PsRestoreImpersonation(PsGetCurrentThread(), &ImpersonationState);
3823 }
3824
3825 ObDereferenceObject(Token);
3826
3827 if (NT_SUCCESS(Status) && CopyOnOpen)
3828 {
3829 PsImpersonateClient(Thread, NewToken, FALSE, EffectiveOnly, ImpersonationLevel);
3830 }
3831
3832 if (NewToken) ObDereferenceObject(NewToken);
3833
3834 if (CopyOnOpen && NewThread) ObDereferenceObject(NewThread);
3835
3836 ObDereferenceObject(Thread);
3837
3838 if (NT_SUCCESS(Status))
3839 {
3840 _SEH2_TRY
3841 {
3842 *TokenHandle = hToken;
3843 }
3844 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3845 {
3846 Status = _SEH2_GetExceptionCode();
3847 }
3848 _SEH2_END;
3849 }
3850
3851 return Status;
3852 }
3853
3854 /*
3855 * @implemented
3856 */
3857 NTSTATUS NTAPI
3858 NtOpenThreadToken(IN HANDLE ThreadHandle,
3859 IN ACCESS_MASK DesiredAccess,
3860 IN BOOLEAN OpenAsSelf,
3861 OUT PHANDLE TokenHandle)
3862 {
3863 return NtOpenThreadTokenEx(ThreadHandle, DesiredAccess, OpenAsSelf, 0,
3864 TokenHandle);
3865 }
3866
3867 /*
3868 * @unimplemented
3869 */
3870 NTSTATUS
3871 NTAPI
3872 NtCompareTokens(IN HANDLE FirstTokenHandle,
3873 IN HANDLE SecondTokenHandle,
3874 OUT PBOOLEAN Equal)
3875 {
3876 KPROCESSOR_MODE PreviousMode;
3877 PTOKEN FirstToken, SecondToken;
3878 BOOLEAN IsEqual;
3879 NTSTATUS Status;
3880
3881 PAGED_CODE();
3882
3883 PreviousMode = ExGetPreviousMode();
3884
3885 if (PreviousMode != KernelMode)
3886 {
3887 _SEH2_TRY
3888 {
3889 ProbeForWriteBoolean(Equal);
3890 }
3891 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3892 {
3893 /* Return the exception code */
3894 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3895 }
3896 _SEH2_END;
3897 }
3898
3899 Status = ObReferenceObjectByHandle(FirstTokenHandle,
3900 TOKEN_QUERY,
3901 SeTokenObjectType,
3902 PreviousMode,
3903 (PVOID*)&FirstToken,
3904 NULL);
3905 if (!NT_SUCCESS(Status))
3906 return Status;
3907
3908 Status = ObReferenceObjectByHandle(SecondTokenHandle,
3909 TOKEN_QUERY,
3910 SeTokenObjectType,
3911 PreviousMode,
3912 (PVOID*)&SecondToken,
3913 NULL);
3914 if (!NT_SUCCESS(Status))
3915 {
3916 ObDereferenceObject(FirstToken);
3917 return Status;
3918 }
3919
3920 if (FirstToken != SecondToken)
3921 {
3922 Status = SepCompareTokens(FirstToken,
3923 SecondToken,
3924 &IsEqual);
3925 }
3926 else
3927 {
3928 IsEqual = TRUE;
3929 }
3930
3931 ObDereferenceObject(SecondToken);
3932 ObDereferenceObject(FirstToken);
3933
3934 if (NT_SUCCESS(Status))
3935 {
3936 _SEH2_TRY
3937 {
3938 *Equal = IsEqual;
3939 }
3940 _SEH2_EXCEPT(ExSystemExceptionFilter())
3941 {
3942 Status = _SEH2_GetExceptionCode();
3943 }
3944 _SEH2_END;
3945 }
3946
3947 return Status;
3948 }
3949
3950 NTSTATUS
3951 NTAPI
3952 NtFilterToken(IN HANDLE ExistingTokenHandle,
3953 IN ULONG Flags,
3954 IN PTOKEN_GROUPS SidsToDisable OPTIONAL,
3955 IN PTOKEN_PRIVILEGES PrivilegesToDelete OPTIONAL,
3956 IN PTOKEN_GROUPS RestrictedSids OPTIONAL,
3957 OUT PHANDLE NewTokenHandle)
3958 {
3959 UNIMPLEMENTED;
3960 return STATUS_NOT_IMPLEMENTED;
3961 }
3962
3963 /*
3964 * @unimplemented
3965 */
3966 NTSTATUS
3967 NTAPI
3968 NtImpersonateAnonymousToken(IN HANDLE Thread)
3969 {
3970 UNIMPLEMENTED;
3971 return STATUS_NOT_IMPLEMENTED;
3972 }
3973
3974 /* EOF */