[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / se / token.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/se/token.c
5 * PURPOSE: Security manager
6 *
7 * PROGRAMMERS: David Welch <welch@cwcom.net>
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 #if defined (ALLOC_PRAGMA)
17 #pragma alloc_text(INIT, SepInitializeTokenImplementation)
18 #endif
19
20 /* GLOBALS ********************************************************************/
21
22 POBJECT_TYPE 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
1351 /* Fail if the token is not an impersonation token */
1352 if (Token->TokenType != TokenImpersonation)
1353 {
1354 Status = STATUS_INVALID_INFO_CLASS;
1355 break;
1356 }
1357
1358 RequiredLength = sizeof(SECURITY_IMPERSONATION_LEVEL);
1359
1360 _SEH2_TRY
1361 {
1362 if(TokenInformationLength >= RequiredLength)
1363 {
1364 *sil = Token->ImpersonationLevel;
1365 }
1366 else
1367 {
1368 Status = STATUS_BUFFER_TOO_SMALL;
1369 }
1370
1371 if(ReturnLength != NULL)
1372 {
1373 *ReturnLength = RequiredLength;
1374 }
1375 }
1376 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1377 {
1378 Status = _SEH2_GetExceptionCode();
1379 }
1380 _SEH2_END;
1381
1382 break;
1383 }
1384
1385 case TokenStatistics:
1386 {
1387 PTOKEN_STATISTICS ts = (PTOKEN_STATISTICS)TokenInformation;
1388
1389 DPRINT("NtQueryInformationToken(TokenStatistics)\n");
1390 RequiredLength = sizeof(TOKEN_STATISTICS);
1391
1392 _SEH2_TRY
1393 {
1394 if(TokenInformationLength >= RequiredLength)
1395 {
1396 ts->TokenId = Token->TokenId;
1397 ts->AuthenticationId = Token->AuthenticationId;
1398 ts->ExpirationTime = Token->ExpirationTime;
1399 ts->TokenType = Token->TokenType;
1400 ts->ImpersonationLevel = Token->ImpersonationLevel;
1401 ts->DynamicCharged = Token->DynamicCharged;
1402 ts->DynamicAvailable = Token->DynamicAvailable;
1403 ts->GroupCount = Token->UserAndGroupCount - 1;
1404 ts->PrivilegeCount = Token->PrivilegeCount;
1405 ts->ModifiedId = Token->ModifiedId;
1406 }
1407 else
1408 {
1409 Status = STATUS_BUFFER_TOO_SMALL;
1410 }
1411
1412 if(ReturnLength != NULL)
1413 {
1414 *ReturnLength = RequiredLength;
1415 }
1416 }
1417 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1418 {
1419 Status = _SEH2_GetExceptionCode();
1420 }
1421 _SEH2_END;
1422
1423 break;
1424 }
1425
1426 case TokenOrigin:
1427 {
1428 PTOKEN_ORIGIN to = (PTOKEN_ORIGIN)TokenInformation;
1429
1430 DPRINT("NtQueryInformationToken(TokenOrigin)\n");
1431 RequiredLength = sizeof(TOKEN_ORIGIN);
1432
1433 _SEH2_TRY
1434 {
1435 if(TokenInformationLength >= RequiredLength)
1436 {
1437 RtlCopyLuid(&to->OriginatingLogonSession,
1438 &Token->AuthenticationId);
1439 }
1440 else
1441 {
1442 Status = STATUS_BUFFER_TOO_SMALL;
1443 }
1444
1445 if(ReturnLength != NULL)
1446 {
1447 *ReturnLength = RequiredLength;
1448 }
1449 }
1450 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1451 {
1452 Status = _SEH2_GetExceptionCode();
1453 }
1454 _SEH2_END;
1455
1456 break;
1457 }
1458
1459 case TokenGroupsAndPrivileges:
1460 DPRINT1("NtQueryInformationToken(TokenGroupsAndPrivileges) not implemented\n");
1461 Status = STATUS_NOT_IMPLEMENTED;
1462 break;
1463
1464 case TokenRestrictedSids:
1465 {
1466 PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation;
1467
1468 DPRINT("NtQueryInformationToken(TokenRestrictedSids)\n");
1469 RequiredLength = sizeof(tg->GroupCount) +
1470 RtlLengthSidAndAttributes(Token->RestrictedSidCount, Token->RestrictedSids);
1471
1472 _SEH2_TRY
1473 {
1474 if(TokenInformationLength >= RequiredLength)
1475 {
1476 ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) -
1477 (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES));
1478 PSID_AND_ATTRIBUTES Sid = (PSID_AND_ATTRIBUTES)((ULONG_PTR)TokenInformation + sizeof(tg->GroupCount) +
1479 (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)));
1480
1481 tg->GroupCount = Token->RestrictedSidCount;
1482 Status = RtlCopySidAndAttributesArray(Token->RestrictedSidCount,
1483 Token->RestrictedSids,
1484 SidLen,
1485 &tg->Groups[0],
1486 (PSID)Sid,
1487 &Unused.Ptr,
1488 &Unused.Ulong);
1489 }
1490 else
1491 {
1492 Status = STATUS_BUFFER_TOO_SMALL;
1493 }
1494
1495 if(ReturnLength != NULL)
1496 {
1497 *ReturnLength = RequiredLength;
1498 }
1499 }
1500 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1501 {
1502 Status = _SEH2_GetExceptionCode();
1503 }
1504 _SEH2_END;
1505
1506 break;
1507 }
1508
1509 case TokenSandBoxInert:
1510 DPRINT1("NtQueryInformationToken(TokenSandboxInert) not implemented\n");
1511 Status = STATUS_NOT_IMPLEMENTED;
1512 break;
1513
1514 case TokenSessionId:
1515 {
1516 ULONG SessionId = 0;
1517
1518 DPRINT("NtQueryInformationToken(TokenSessionId)\n");
1519
1520 Status = SeQuerySessionIdToken(Token,
1521 &SessionId);
1522
1523 if(NT_SUCCESS(Status))
1524 {
1525 _SEH2_TRY
1526 {
1527 /* buffer size was already verified, no need to check here again */
1528 *(PULONG)TokenInformation = SessionId;
1529
1530 if(ReturnLength != NULL)
1531 {
1532 *ReturnLength = sizeof(ULONG);
1533 }
1534 }
1535 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1536 {
1537 Status = _SEH2_GetExceptionCode();
1538 }
1539 _SEH2_END;
1540 }
1541
1542 break;
1543 }
1544
1545 default:
1546 DPRINT1("NtQueryInformationToken(%d) invalid information class\n", TokenInformationClass);
1547 Status = STATUS_INVALID_INFO_CLASS;
1548 break;
1549 }
1550
1551 ObDereferenceObject(Token);
1552 }
1553
1554 return(Status);
1555 }
1556
1557
1558 /*
1559 * NtSetTokenInformation: Partly implemented.
1560 * Unimplemented:
1561 * TokenOrigin, TokenDefaultDacl
1562 */
1563
1564 NTSTATUS NTAPI
1565 NtSetInformationToken(IN HANDLE TokenHandle,
1566 IN TOKEN_INFORMATION_CLASS TokenInformationClass,
1567 OUT PVOID TokenInformation,
1568 IN ULONG TokenInformationLength)
1569 {
1570 PTOKEN Token;
1571 KPROCESSOR_MODE PreviousMode;
1572 ULONG NeededAccess = TOKEN_ADJUST_DEFAULT;
1573 NTSTATUS Status;
1574
1575 PAGED_CODE();
1576
1577 PreviousMode = ExGetPreviousMode();
1578
1579 Status = DefaultSetInfoBufferCheck(TokenInformationClass,
1580 SeTokenInformationClass,
1581 sizeof(SeTokenInformationClass) / sizeof(SeTokenInformationClass[0]),
1582 TokenInformation,
1583 TokenInformationLength,
1584 PreviousMode);
1585
1586 if(!NT_SUCCESS(Status))
1587 {
1588 /* Invalid buffers */
1589 DPRINT("NtSetInformationToken() failed, Status: 0x%x\n", Status);
1590 return Status;
1591 }
1592
1593 if(TokenInformationClass == TokenSessionId)
1594 {
1595 NeededAccess |= TOKEN_ADJUST_SESSIONID;
1596 }
1597
1598 Status = ObReferenceObjectByHandle(TokenHandle,
1599 NeededAccess,
1600 SepTokenObjectType,
1601 PreviousMode,
1602 (PVOID*)&Token,
1603 NULL);
1604 if (NT_SUCCESS(Status))
1605 {
1606 switch (TokenInformationClass)
1607 {
1608 case TokenOwner:
1609 {
1610 if(TokenInformationLength >= sizeof(TOKEN_OWNER))
1611 {
1612 PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation;
1613 PSID InputSid = NULL, CapturedSid;
1614
1615 _SEH2_TRY
1616 {
1617 InputSid = to->Owner;
1618 }
1619 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1620 {
1621 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1622 }
1623 _SEH2_END;
1624
1625 Status = SepCaptureSid(InputSid,
1626 PreviousMode,
1627 PagedPool,
1628 FALSE,
1629 &CapturedSid);
1630 if(NT_SUCCESS(Status))
1631 {
1632 RtlCopySid(RtlLengthSid(CapturedSid),
1633 Token->UserAndGroups[Token->DefaultOwnerIndex].Sid,
1634 CapturedSid);
1635 SepReleaseSid(CapturedSid,
1636 PreviousMode,
1637 FALSE);
1638 }
1639 }
1640 else
1641 {
1642 Status = STATUS_INFO_LENGTH_MISMATCH;
1643 }
1644 break;
1645 }
1646
1647 case TokenPrimaryGroup:
1648 {
1649 if(TokenInformationLength >= sizeof(TOKEN_PRIMARY_GROUP))
1650 {
1651 PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation;
1652 PSID InputSid = NULL, CapturedSid;
1653
1654 _SEH2_TRY
1655 {
1656 InputSid = tpg->PrimaryGroup;
1657 }
1658 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1659 {
1660 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1661 }
1662 _SEH2_END;
1663
1664 Status = SepCaptureSid(InputSid,
1665 PreviousMode,
1666 PagedPool,
1667 FALSE,
1668 &CapturedSid);
1669 if(NT_SUCCESS(Status))
1670 {
1671 RtlCopySid(RtlLengthSid(CapturedSid),
1672 Token->PrimaryGroup,
1673 CapturedSid);
1674 SepReleaseSid(CapturedSid,
1675 PreviousMode,
1676 FALSE);
1677 }
1678 }
1679 else
1680 {
1681 Status = STATUS_INFO_LENGTH_MISMATCH;
1682 }
1683 break;
1684 }
1685
1686 case TokenDefaultDacl:
1687 {
1688 if(TokenInformationLength >= sizeof(TOKEN_DEFAULT_DACL))
1689 {
1690 PTOKEN_DEFAULT_DACL tdd = (PTOKEN_DEFAULT_DACL)TokenInformation;
1691 PACL InputAcl = NULL;
1692
1693 _SEH2_TRY
1694 {
1695 InputAcl = tdd->DefaultDacl;
1696 }
1697 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1698 {
1699 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1700 }
1701 _SEH2_END;
1702
1703 if(InputAcl != NULL)
1704 {
1705 PACL CapturedAcl;
1706
1707 /* capture and copy the dacl */
1708 Status = SepCaptureAcl(InputAcl,
1709 PreviousMode,
1710 PagedPool,
1711 TRUE,
1712 &CapturedAcl);
1713 if(NT_SUCCESS(Status))
1714 {
1715 /* free the previous dacl if present */
1716 if(Token->DefaultDacl != NULL)
1717 {
1718 ExFreePool(Token->DefaultDacl);
1719 }
1720
1721 /* set the new dacl */
1722 Token->DefaultDacl = CapturedAcl;
1723 }
1724 }
1725 else
1726 {
1727 /* clear and free the default dacl if present */
1728 if(Token->DefaultDacl != NULL)
1729 {
1730 ExFreePool(Token->DefaultDacl);
1731 Token->DefaultDacl = NULL;
1732 }
1733 }
1734 }
1735 else
1736 {
1737 Status = STATUS_INFO_LENGTH_MISMATCH;
1738 }
1739 break;
1740 }
1741
1742 case TokenSessionId:
1743 {
1744 ULONG SessionId = 0;
1745
1746 _SEH2_TRY
1747 {
1748 /* buffer size was already verified, no need to check here again */
1749 SessionId = *(PULONG)TokenInformation;
1750 }
1751 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1752 {
1753 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1754 }
1755 _SEH2_END;
1756
1757 if(!SeSinglePrivilegeCheck(SeTcbPrivilege,
1758 PreviousMode))
1759 {
1760 Status = STATUS_PRIVILEGE_NOT_HELD;
1761 break;
1762 }
1763
1764 Token->SessionId = SessionId;
1765 break;
1766 }
1767
1768 default:
1769 {
1770 Status = STATUS_NOT_IMPLEMENTED;
1771 break;
1772 }
1773 }
1774
1775 ObDereferenceObject(Token);
1776 }
1777
1778 return(Status);
1779 }
1780
1781
1782 /*
1783 * @implemented
1784 *
1785 * NOTE: Some sources claim 4th param is ImpersonationLevel, but on W2K
1786 * this is certainly NOT true, thou i can't say for sure that EffectiveOnly
1787 * is correct either. -Gunnar
1788 * This is true. EffectiveOnly overrides SQOS.EffectiveOnly. - IAI
1789 */
1790 NTSTATUS NTAPI
1791 NtDuplicateToken(IN HANDLE ExistingTokenHandle,
1792 IN ACCESS_MASK DesiredAccess,
1793 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
1794 IN BOOLEAN EffectiveOnly,
1795 IN TOKEN_TYPE TokenType,
1796 OUT PHANDLE NewTokenHandle)
1797 {
1798 KPROCESSOR_MODE PreviousMode;
1799 HANDLE hToken;
1800 PTOKEN Token;
1801 PTOKEN NewToken;
1802 PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService;
1803 BOOLEAN QoSPresent;
1804 NTSTATUS Status;
1805
1806 PAGED_CODE();
1807
1808 PreviousMode = KeGetPreviousMode();
1809
1810 if (PreviousMode != KernelMode)
1811 {
1812 _SEH2_TRY
1813 {
1814 ProbeForWriteHandle(NewTokenHandle);
1815 }
1816 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1817 {
1818 /* Return the exception code */
1819 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1820 }
1821 _SEH2_END;
1822 }
1823
1824 Status = SepCaptureSecurityQualityOfService(ObjectAttributes,
1825 PreviousMode,
1826 PagedPool,
1827 FALSE,
1828 &CapturedSecurityQualityOfService,
1829 &QoSPresent);
1830 if(!NT_SUCCESS(Status))
1831 {
1832 DPRINT1("NtDuplicateToken() failed to capture QoS! Status: 0x%x\n", Status);
1833 return Status;
1834 }
1835
1836 Status = ObReferenceObjectByHandle(ExistingTokenHandle,
1837 TOKEN_DUPLICATE,
1838 SepTokenObjectType,
1839 PreviousMode,
1840 (PVOID*)&Token,
1841 NULL);
1842 if (NT_SUCCESS(Status))
1843 {
1844 Status = SepDuplicateToken(Token,
1845 ObjectAttributes,
1846 EffectiveOnly,
1847 TokenType,
1848 (QoSPresent ? CapturedSecurityQualityOfService->ImpersonationLevel : SecurityAnonymous),
1849 PreviousMode,
1850 &NewToken);
1851
1852 ObDereferenceObject(Token);
1853
1854 if (NT_SUCCESS(Status))
1855 {
1856 Status = ObInsertObject((PVOID)NewToken,
1857 NULL,
1858 DesiredAccess,
1859 0,
1860 NULL,
1861 &hToken);
1862
1863 if (NT_SUCCESS(Status))
1864 {
1865 _SEH2_TRY
1866 {
1867 *NewTokenHandle = hToken;
1868 }
1869 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1870 {
1871 Status = _SEH2_GetExceptionCode();
1872 }
1873 _SEH2_END;
1874 }
1875 }
1876 }
1877
1878 /* free the captured structure */
1879 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
1880 PreviousMode,
1881 FALSE);
1882
1883 return Status;
1884 }
1885
1886 NTSTATUS NTAPI
1887 NtAdjustGroupsToken(IN HANDLE TokenHandle,
1888 IN BOOLEAN ResetToDefault,
1889 IN PTOKEN_GROUPS NewState,
1890 IN ULONG BufferLength,
1891 OUT PTOKEN_GROUPS PreviousState OPTIONAL,
1892 OUT PULONG ReturnLength)
1893 {
1894 UNIMPLEMENTED;
1895 return(STATUS_NOT_IMPLEMENTED);
1896 }
1897
1898 /*
1899 * @implemented
1900 */
1901 NTSTATUS NTAPI
1902 NtAdjustPrivilegesToken (IN HANDLE TokenHandle,
1903 IN BOOLEAN DisableAllPrivileges,
1904 IN PTOKEN_PRIVILEGES NewState,
1905 IN ULONG BufferLength,
1906 OUT PTOKEN_PRIVILEGES PreviousState OPTIONAL,
1907 OUT PULONG ReturnLength OPTIONAL)
1908 {
1909 // PLUID_AND_ATTRIBUTES Privileges;
1910 KPROCESSOR_MODE PreviousMode;
1911 ULONG PrivilegeCount;
1912 PTOKEN Token;
1913 // ULONG Length;
1914 ULONG i;
1915 ULONG j;
1916 ULONG k;
1917 ULONG Count;
1918 #if 0
1919 ULONG a;
1920 ULONG b;
1921 ULONG c;
1922 #endif
1923 NTSTATUS Status;
1924
1925 PAGED_CODE();
1926
1927 DPRINT ("NtAdjustPrivilegesToken() called\n");
1928
1929 // PrivilegeCount = NewState->PrivilegeCount;
1930 PreviousMode = KeGetPreviousMode ();
1931 // SeCaptureLuidAndAttributesArray(NewState->Privileges,
1932 // PrivilegeCount,
1933 // PreviousMode,
1934 // NULL,
1935 // 0,
1936 // NonPagedPool,
1937 // 1,
1938 // &Privileges,
1939 // &Length);
1940
1941 Status = ObReferenceObjectByHandle (TokenHandle,
1942 TOKEN_ADJUST_PRIVILEGES | (PreviousState != NULL ? TOKEN_QUERY : 0),
1943 SepTokenObjectType,
1944 PreviousMode,
1945 (PVOID*)&Token,
1946 NULL);
1947 if (!NT_SUCCESS(Status))
1948 {
1949 DPRINT1 ("Failed to reference token (Status %lx)\n", Status);
1950 // SeReleaseLuidAndAttributesArray(Privileges,
1951 // PreviousMode,
1952 // 0);
1953 return Status;
1954 }
1955
1956
1957 #if 0
1958 SepAdjustPrivileges(Token,
1959 0,
1960 PreviousMode,
1961 PrivilegeCount,
1962 Privileges,
1963 PreviousState,
1964 &a,
1965 &b,
1966 &c);
1967 #endif
1968
1969 PrivilegeCount = (BufferLength - FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges)) /
1970 sizeof(LUID_AND_ATTRIBUTES);
1971
1972 if (PreviousState != NULL)
1973 PreviousState->PrivilegeCount = 0;
1974
1975 k = 0;
1976 if (DisableAllPrivileges == TRUE)
1977 {
1978 for (i = 0; i < Token->PrivilegeCount; i++)
1979 {
1980 if (Token->Privileges[i].Attributes != 0)
1981 {
1982 DPRINT ("Attributes differ\n");
1983
1984 /* Save current privilege */
1985 if (PreviousState != NULL)
1986 {
1987 if (k < PrivilegeCount)
1988 {
1989 PreviousState->PrivilegeCount++;
1990 PreviousState->Privileges[k].Luid = Token->Privileges[i].Luid;
1991 PreviousState->Privileges[k].Attributes = Token->Privileges[i].Attributes;
1992 }
1993 else
1994 {
1995 /* FIXME: Should revert all the changes, calculate how
1996 * much space would be needed, set ResultLength
1997 * accordingly and fail.
1998 */
1999 }
2000 k++;
2001 }
2002
2003 /* Update current privlege */
2004 Token->Privileges[i].Attributes &= ~SE_PRIVILEGE_ENABLED;
2005 }
2006 }
2007 Status = STATUS_SUCCESS;
2008 }
2009 else
2010 {
2011 Count = 0;
2012 for (i = 0; i < Token->PrivilegeCount; i++)
2013 {
2014 for (j = 0; j < NewState->PrivilegeCount; j++)
2015 {
2016 if (Token->Privileges[i].Luid.LowPart == NewState->Privileges[j].Luid.LowPart &&
2017 Token->Privileges[i].Luid.HighPart == NewState->Privileges[j].Luid.HighPart)
2018 {
2019 DPRINT ("Found privilege\n");
2020
2021 if ((Token->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED) !=
2022 (NewState->Privileges[j].Attributes & SE_PRIVILEGE_ENABLED))
2023 {
2024 DPRINT ("Attributes differ\n");
2025 DPRINT ("Current attributes %lx desired attributes %lx\n",
2026 Token->Privileges[i].Attributes,
2027 NewState->Privileges[j].Attributes);
2028
2029 /* Save current privilege */
2030 if (PreviousState != NULL)
2031 {
2032 if (k < PrivilegeCount)
2033 {
2034 PreviousState->PrivilegeCount++;
2035 PreviousState->Privileges[k].Luid = Token->Privileges[i].Luid;
2036 PreviousState->Privileges[k].Attributes = Token->Privileges[i].Attributes;
2037 }
2038 else
2039 {
2040 /* FIXME: Should revert all the changes, calculate how
2041 * much space would be needed, set ResultLength
2042 * accordingly and fail.
2043 */
2044 }
2045 k++;
2046 }
2047
2048 /* Update current privlege */
2049 Token->Privileges[i].Attributes &= ~SE_PRIVILEGE_ENABLED;
2050 Token->Privileges[i].Attributes |=
2051 (NewState->Privileges[j].Attributes & SE_PRIVILEGE_ENABLED);
2052 DPRINT ("New attributes %lx\n",
2053 Token->Privileges[i].Attributes);
2054 }
2055 Count++;
2056 }
2057 }
2058 }
2059 Status = Count < NewState->PrivilegeCount ? STATUS_NOT_ALL_ASSIGNED : STATUS_SUCCESS;
2060 }
2061
2062 if (ReturnLength != NULL)
2063 {
2064 *ReturnLength = sizeof(TOKEN_PRIVILEGES) +
2065 (sizeof(LUID_AND_ATTRIBUTES) * (k - 1));
2066 }
2067
2068 ObDereferenceObject (Token);
2069
2070 // SeReleaseLuidAndAttributesArray(Privileges,
2071 // PreviousMode,
2072 // 0);
2073
2074 DPRINT ("NtAdjustPrivilegesToken() done\n");
2075
2076 return Status;
2077 }
2078
2079 NTSTATUS
2080 NTAPI
2081 NtCreateToken(OUT PHANDLE TokenHandle,
2082 IN ACCESS_MASK DesiredAccess,
2083 IN POBJECT_ATTRIBUTES ObjectAttributes,
2084 IN TOKEN_TYPE TokenType,
2085 IN PLUID AuthenticationId,
2086 IN PLARGE_INTEGER ExpirationTime,
2087 IN PTOKEN_USER TokenUser,
2088 IN PTOKEN_GROUPS TokenGroups,
2089 IN PTOKEN_PRIVILEGES TokenPrivileges,
2090 IN PTOKEN_OWNER TokenOwner,
2091 IN PTOKEN_PRIMARY_GROUP TokenPrimaryGroup,
2092 IN PTOKEN_DEFAULT_DACL TokenDefaultDacl,
2093 IN PTOKEN_SOURCE TokenSource)
2094 {
2095 HANDLE hToken;
2096 KPROCESSOR_MODE PreviousMode;
2097 ULONG nTokenPrivileges = 0;
2098 LARGE_INTEGER LocalExpirationTime = {{0, 0}};
2099 NTSTATUS Status;
2100
2101 PAGED_CODE();
2102
2103 PreviousMode = ExGetPreviousMode();
2104
2105 if(PreviousMode != KernelMode)
2106 {
2107 _SEH2_TRY
2108 {
2109 ProbeForWriteHandle(TokenHandle);
2110 ProbeForRead(AuthenticationId,
2111 sizeof(LUID),
2112 sizeof(ULONG));
2113 LocalExpirationTime = ProbeForReadLargeInteger(ExpirationTime);
2114 ProbeForRead(TokenUser,
2115 sizeof(TOKEN_USER),
2116 sizeof(ULONG));
2117 ProbeForRead(TokenGroups,
2118 sizeof(TOKEN_GROUPS),
2119 sizeof(ULONG));
2120 ProbeForRead(TokenPrivileges,
2121 sizeof(TOKEN_PRIVILEGES),
2122 sizeof(ULONG));
2123 ProbeForRead(TokenOwner,
2124 sizeof(TOKEN_OWNER),
2125 sizeof(ULONG));
2126 ProbeForRead(TokenPrimaryGroup,
2127 sizeof(TOKEN_PRIMARY_GROUP),
2128 sizeof(ULONG));
2129 ProbeForRead(TokenDefaultDacl,
2130 sizeof(TOKEN_DEFAULT_DACL),
2131 sizeof(ULONG));
2132 ProbeForRead(TokenSource,
2133 sizeof(TOKEN_SOURCE),
2134 sizeof(ULONG));
2135 nTokenPrivileges = TokenPrivileges->PrivilegeCount;
2136 }
2137 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2138 {
2139 /* Return the exception code */
2140 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2141 }
2142 _SEH2_END;
2143 }
2144 else
2145 {
2146 nTokenPrivileges = TokenPrivileges->PrivilegeCount;
2147 LocalExpirationTime = *ExpirationTime;
2148 }
2149
2150 Status = SepCreateToken(&hToken,
2151 PreviousMode,
2152 DesiredAccess,
2153 ObjectAttributes,
2154 TokenType,
2155 ((PSECURITY_QUALITY_OF_SERVICE)(ObjectAttributes->SecurityQualityOfService))->ImpersonationLevel,
2156 AuthenticationId,
2157 &LocalExpirationTime,
2158 &TokenUser->User,
2159 TokenGroups->GroupCount,
2160 TokenGroups->Groups,
2161 0, // FIXME: Should capture
2162 nTokenPrivileges,
2163 TokenPrivileges->Privileges,
2164 TokenOwner->Owner,
2165 TokenPrimaryGroup->PrimaryGroup,
2166 TokenDefaultDacl->DefaultDacl,
2167 TokenSource,
2168 FALSE);
2169 if (NT_SUCCESS(Status))
2170 {
2171 _SEH2_TRY
2172 {
2173 *TokenHandle = hToken;
2174 }
2175 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2176 {
2177 Status = _SEH2_GetExceptionCode();
2178 }
2179 _SEH2_END;
2180 }
2181
2182 return Status;
2183 }
2184
2185 /*
2186 * @implemented
2187 */
2188 NTSTATUS
2189 NTAPI
2190 NtOpenThreadTokenEx(IN HANDLE ThreadHandle,
2191 IN ACCESS_MASK DesiredAccess,
2192 IN BOOLEAN OpenAsSelf,
2193 IN ULONG HandleAttributes,
2194 OUT PHANDLE TokenHandle)
2195 {
2196 PETHREAD Thread, NewThread;
2197 HANDLE hToken;
2198 PTOKEN Token, NewToken = NULL, PrimaryToken;
2199 BOOLEAN CopyOnOpen, EffectiveOnly;
2200 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
2201 SE_IMPERSONATION_STATE ImpersonationState;
2202 OBJECT_ATTRIBUTES ObjectAttributes;
2203 SECURITY_DESCRIPTOR SecurityDescriptor;
2204 PACL Dacl = NULL;
2205 KPROCESSOR_MODE PreviousMode;
2206 NTSTATUS Status;
2207
2208 PAGED_CODE();
2209
2210 PreviousMode = ExGetPreviousMode();
2211
2212 if (PreviousMode != KernelMode)
2213 {
2214 _SEH2_TRY
2215 {
2216 ProbeForWriteHandle(TokenHandle);
2217 }
2218 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2219 {
2220 /* Return the exception code */
2221 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2222 }
2223 _SEH2_END;
2224 }
2225
2226 /*
2227 * At first open the thread token for information access and verify
2228 * that the token associated with thread is valid.
2229 */
2230
2231 Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_QUERY_INFORMATION,
2232 PsThreadType, PreviousMode, (PVOID*)&Thread,
2233 NULL);
2234 if (!NT_SUCCESS(Status))
2235 {
2236 return Status;
2237 }
2238
2239 Token = PsReferenceImpersonationToken(Thread, &CopyOnOpen, &EffectiveOnly,
2240 &ImpersonationLevel);
2241 if (Token == NULL)
2242 {
2243 ObDereferenceObject(Thread);
2244 return STATUS_NO_TOKEN;
2245 }
2246
2247 if (ImpersonationLevel == SecurityAnonymous)
2248 {
2249 PsDereferenceImpersonationToken(Token);
2250 ObDereferenceObject(Thread);
2251 return STATUS_CANT_OPEN_ANONYMOUS;
2252 }
2253
2254 /*
2255 * Revert to self if OpenAsSelf is specified.
2256 */
2257
2258 if (OpenAsSelf)
2259 {
2260 PsDisableImpersonation(PsGetCurrentThread(), &ImpersonationState);
2261 }
2262
2263 if (CopyOnOpen)
2264 {
2265 Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_ALL_ACCESS,
2266 PsThreadType, KernelMode,
2267 (PVOID*)&NewThread, NULL);
2268 if (NT_SUCCESS(Status))
2269 {
2270 PrimaryToken = PsReferencePrimaryToken(NewThread->ThreadsProcess);
2271
2272 Status = SepCreateImpersonationTokenDacl(Token, PrimaryToken, &Dacl);
2273
2274 ObFastDereferenceObject(&NewThread->ThreadsProcess->Token, PrimaryToken);
2275
2276 if (NT_SUCCESS(Status))
2277 {
2278 if (Dacl)
2279 {
2280 RtlCreateSecurityDescriptor(&SecurityDescriptor,
2281 SECURITY_DESCRIPTOR_REVISION);
2282 RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl,
2283 FALSE);
2284 }
2285
2286 InitializeObjectAttributes(&ObjectAttributes, NULL, HandleAttributes,
2287 NULL, Dacl ? &SecurityDescriptor : NULL);
2288
2289
2290 Status = SepDuplicateToken(Token, &ObjectAttributes, EffectiveOnly,
2291 TokenImpersonation, ImpersonationLevel,
2292 KernelMode, &NewToken);
2293 if (NT_SUCCESS(Status))
2294 {
2295 ObReferenceObject(NewToken);
2296 Status = ObInsertObject(NewToken, NULL, DesiredAccess, 0, NULL,
2297 &hToken);
2298 }
2299 }
2300 }
2301 }
2302 else
2303 {
2304 Status = ObOpenObjectByPointer(Token, HandleAttributes,
2305 NULL, DesiredAccess, SepTokenObjectType,
2306 PreviousMode, &hToken);
2307 }
2308
2309 if (Dacl) ExFreePool(Dacl);
2310
2311 if (OpenAsSelf)
2312 {
2313 PsRestoreImpersonation(PsGetCurrentThread(), &ImpersonationState);
2314 }
2315
2316 ObDereferenceObject(Token);
2317
2318 if (NT_SUCCESS(Status) && CopyOnOpen)
2319 {
2320 PsImpersonateClient(Thread, NewToken, FALSE, EffectiveOnly, ImpersonationLevel);
2321 }
2322
2323 if (NewToken) ObDereferenceObject(NewToken);
2324
2325 if (CopyOnOpen && NewThread) ObDereferenceObject(NewThread);
2326
2327 if(NT_SUCCESS(Status))
2328 {
2329 _SEH2_TRY
2330 {
2331 *TokenHandle = hToken;
2332 }
2333 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2334 {
2335 Status = _SEH2_GetExceptionCode();
2336 }
2337 _SEH2_END;
2338 }
2339
2340 return Status;
2341 }
2342
2343 /*
2344 * @implemented
2345 */
2346 NTSTATUS NTAPI
2347 NtOpenThreadToken(IN HANDLE ThreadHandle,
2348 IN ACCESS_MASK DesiredAccess,
2349 IN BOOLEAN OpenAsSelf,
2350 OUT PHANDLE TokenHandle)
2351 {
2352 return NtOpenThreadTokenEx(ThreadHandle, DesiredAccess, OpenAsSelf, 0,
2353 TokenHandle);
2354 }
2355
2356
2357
2358 /*
2359 * @unimplemented
2360 */
2361 NTSTATUS
2362 NTAPI
2363 NtCompareTokens(IN HANDLE FirstTokenHandle,
2364 IN HANDLE SecondTokenHandle,
2365 OUT PBOOLEAN Equal)
2366 {
2367 KPROCESSOR_MODE PreviousMode;
2368 PTOKEN FirstToken, SecondToken;
2369 BOOLEAN IsEqual;
2370 NTSTATUS Status;
2371
2372 PAGED_CODE();
2373
2374 PreviousMode = ExGetPreviousMode();
2375
2376 if (PreviousMode != KernelMode)
2377 {
2378 _SEH2_TRY
2379 {
2380 ProbeForWriteBoolean(Equal);
2381 }
2382 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2383 {
2384 /* Return the exception code */
2385 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2386 }
2387 _SEH2_END;
2388 }
2389
2390 Status = ObReferenceObjectByHandle(FirstTokenHandle,
2391 TOKEN_QUERY,
2392 SepTokenObjectType,
2393 PreviousMode,
2394 (PVOID*)&FirstToken,
2395 NULL);
2396 if (!NT_SUCCESS(Status))
2397 return Status;
2398
2399 Status = ObReferenceObjectByHandle(SecondTokenHandle,
2400 TOKEN_QUERY,
2401 SepTokenObjectType,
2402 PreviousMode,
2403 (PVOID*)&SecondToken,
2404 NULL);
2405 if (!NT_SUCCESS(Status))
2406 {
2407 ObDereferenceObject(FirstToken);
2408 return Status;
2409 }
2410
2411 if (FirstToken != SecondToken)
2412 {
2413 Status = SepCompareTokens(FirstToken,
2414 SecondToken,
2415 &IsEqual);
2416 }
2417 else
2418 IsEqual = TRUE;
2419
2420 ObDereferenceObject(FirstToken);
2421 ObDereferenceObject(SecondToken);
2422
2423 if (NT_SUCCESS(Status))
2424 {
2425 _SEH2_TRY
2426 {
2427 *Equal = IsEqual;
2428 }
2429 _SEH2_EXCEPT(ExSystemExceptionFilter())
2430 {
2431 Status = _SEH2_GetExceptionCode();
2432 }
2433 _SEH2_END;
2434 }
2435
2436 return Status;
2437 }
2438
2439 NTSTATUS
2440 NTAPI
2441 NtFilterToken(IN HANDLE ExistingTokenHandle,
2442 IN ULONG Flags,
2443 IN PTOKEN_GROUPS SidsToDisable OPTIONAL,
2444 IN PTOKEN_PRIVILEGES PrivilegesToDelete OPTIONAL,
2445 IN PTOKEN_GROUPS RestrictedSids OPTIONAL,
2446 OUT PHANDLE NewTokenHandle)
2447 {
2448 UNIMPLEMENTED;
2449 return STATUS_NOT_IMPLEMENTED;
2450 }
2451
2452 /*
2453 * @unimplemented
2454 */
2455 NTSTATUS
2456 NTAPI
2457 NtImpersonateAnonymousToken(IN HANDLE Thread)
2458 {
2459 UNIMPLEMENTED;
2460 return STATUS_NOT_IMPLEMENTED;
2461 }
2462
2463 /* EOF */