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