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