NtAdjustPrivilegesToken: Probe and capture parameters before use.
[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 OBJECT_HANDLE_INFORMATION HandleInformation;
1810 NTSTATUS Status;
1811
1812 PAGED_CODE();
1813
1814 if (TokenType != TokenImpersonation &&
1815 TokenType != TokenPrimary)
1816 return STATUS_INVALID_PARAMETER;
1817
1818 PreviousMode = KeGetPreviousMode();
1819
1820 if (PreviousMode != KernelMode)
1821 {
1822 _SEH2_TRY
1823 {
1824 ProbeForWriteHandle(NewTokenHandle);
1825 }
1826 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1827 {
1828 /* Return the exception code */
1829 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1830 }
1831 _SEH2_END;
1832 }
1833
1834 Status = SepCaptureSecurityQualityOfService(ObjectAttributes,
1835 PreviousMode,
1836 PagedPool,
1837 FALSE,
1838 &CapturedSecurityQualityOfService,
1839 &QoSPresent);
1840 if (!NT_SUCCESS(Status))
1841 {
1842 DPRINT1("NtDuplicateToken() failed to capture QoS! Status: 0x%x\n", Status);
1843 return Status;
1844 }
1845
1846 Status = ObReferenceObjectByHandle(ExistingTokenHandle,
1847 TOKEN_DUPLICATE,
1848 SepTokenObjectType,
1849 PreviousMode,
1850 (PVOID*)&Token,
1851 &HandleInformation);
1852 if (!NT_SUCCESS(Status))
1853 {
1854 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
1855 PreviousMode,
1856 FALSE);
1857 return Status;
1858 }
1859
1860 /*
1861 * Fail, if the original token is an impersonation token and the caller
1862 * tries to raise the impersonation level of the new token above the
1863 * impersonation level of the original token.
1864 */
1865 if (Token->TokenType == TokenImpersonation)
1866 {
1867 if (QoSPresent &&
1868 CapturedSecurityQualityOfService->ImpersonationLevel >Token->ImpersonationLevel)
1869 {
1870 ObDereferenceObject(Token);
1871 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
1872 PreviousMode,
1873 FALSE);
1874 return STATUS_BAD_IMPERSONATION_LEVEL;
1875 }
1876 }
1877
1878 /*
1879 * Fail, if a primary token is to be created from an impersonation token
1880 * and and the impersonation level of the impersonation token is below SecurityImpersonation.
1881 */
1882 if (Token->TokenType == TokenImpersonation &&
1883 TokenType == TokenPrimary &&
1884 Token->ImpersonationLevel < SecurityImpersonation)
1885 {
1886 ObDereferenceObject(Token);
1887 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
1888 PreviousMode,
1889 FALSE);
1890 return STATUS_BAD_IMPERSONATION_LEVEL;
1891 }
1892
1893 Status = SepDuplicateToken(Token,
1894 ObjectAttributes,
1895 EffectiveOnly,
1896 TokenType,
1897 (QoSPresent ? CapturedSecurityQualityOfService->ImpersonationLevel : SecurityAnonymous),
1898 PreviousMode,
1899 &NewToken);
1900
1901 ObDereferenceObject(Token);
1902
1903 if (NT_SUCCESS(Status))
1904 {
1905 Status = ObInsertObject((PVOID)NewToken,
1906 NULL,
1907 (DesiredAccess ? DesiredAccess : HandleInformation.GrantedAccess),
1908 0,
1909 NULL,
1910 &hToken);
1911 if (NT_SUCCESS(Status))
1912 {
1913 _SEH2_TRY
1914 {
1915 *NewTokenHandle = hToken;
1916 }
1917 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1918 {
1919 Status = _SEH2_GetExceptionCode();
1920 }
1921 _SEH2_END;
1922 }
1923 }
1924
1925 /* Free the captured structure */
1926 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
1927 PreviousMode,
1928 FALSE);
1929
1930 return Status;
1931 }
1932
1933 NTSTATUS NTAPI
1934 NtAdjustGroupsToken(IN HANDLE TokenHandle,
1935 IN BOOLEAN ResetToDefault,
1936 IN PTOKEN_GROUPS NewState,
1937 IN ULONG BufferLength,
1938 OUT PTOKEN_GROUPS PreviousState OPTIONAL,
1939 OUT PULONG ReturnLength)
1940 {
1941 UNIMPLEMENTED;
1942 return(STATUS_NOT_IMPLEMENTED);
1943 }
1944
1945 /*
1946 * @implemented
1947 */
1948 NTSTATUS NTAPI
1949 NtAdjustPrivilegesToken(IN HANDLE TokenHandle,
1950 IN BOOLEAN DisableAllPrivileges,
1951 IN PTOKEN_PRIVILEGES NewState,
1952 IN ULONG BufferLength,
1953 OUT PTOKEN_PRIVILEGES PreviousState OPTIONAL,
1954 OUT PULONG ReturnLength OPTIONAL)
1955 {
1956 PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
1957 KPROCESSOR_MODE PreviousMode;
1958 ULONG CapturedCount = 0;
1959 ULONG CapturedLength = 0;
1960 ULONG NewStateSize = 0;
1961 ULONG PrivilegeCount;
1962 PTOKEN Token;
1963 ULONG i;
1964 ULONG j;
1965 ULONG k;
1966 ULONG Count;
1967 #if 0
1968 ULONG a;
1969 ULONG b;
1970 ULONG c;
1971 #endif
1972 NTSTATUS Status;
1973
1974 PAGED_CODE();
1975
1976 DPRINT ("NtAdjustPrivilegesToken() called\n");
1977
1978 PreviousMode = KeGetPreviousMode ();
1979 if (PreviousMode != KernelMode)
1980 {
1981 _SEH2_TRY
1982 {
1983 /* Probe NewState */
1984 if (DisableAllPrivileges == FALSE)
1985 {
1986 ProbeForRead(NewState,
1987 sizeof(TOKEN_PRIVILEGES),
1988 sizeof(ULONG));
1989
1990 CapturedCount = NewState->PrivilegeCount;
1991 NewStateSize = (ULONG)sizeof(TOKEN_PRIVILEGES) +
1992 ((CapturedCount - ANYSIZE_ARRAY) * (ULONG)sizeof(LUID_AND_ATTRIBUTES));
1993
1994 ProbeForRead(NewState,
1995 NewStateSize,
1996 sizeof(ULONG));
1997 }
1998
1999 /* Probe PreviousState and ReturnLength */
2000 if (PreviousState != NULL)
2001 {
2002 ProbeForWrite(PreviousState,
2003 BufferLength,
2004 sizeof(ULONG));
2005
2006 ProbeForWrite(ReturnLength,
2007 sizeof(ULONG),
2008 sizeof(ULONG));
2009 }
2010 }
2011 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2012 {
2013 /* Return the exception code */
2014 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2015 }
2016 _SEH2_END;
2017 }
2018 else
2019 {
2020 if (DisableAllPrivileges == FALSE)
2021 CapturedCount = NewState->PrivilegeCount;
2022 }
2023
2024 if (DisableAllPrivileges == FALSE)
2025 {
2026 _SEH2_TRY
2027 {
2028 /* Capture the new state array of privileges */
2029 Status = SeCaptureLuidAndAttributesArray(NewState->Privileges,
2030 CapturedCount,
2031 PreviousMode,
2032 NULL,
2033 0,
2034 PagedPool,
2035 TRUE,
2036 &CapturedPrivileges,
2037 &CapturedLength);
2038 }
2039 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2040 {
2041 /* Return the exception code */
2042 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2043 }
2044 _SEH2_END;
2045
2046 if (!NT_SUCCESS(Status))
2047 return Status;
2048 }
2049
2050 /* Reference the token */
2051 Status = ObReferenceObjectByHandle(TokenHandle,
2052 TOKEN_ADJUST_PRIVILEGES | (PreviousState != NULL ? TOKEN_QUERY : 0),
2053 SepTokenObjectType,
2054 PreviousMode,
2055 (PVOID*)&Token,
2056 NULL);
2057 if (!NT_SUCCESS(Status))
2058 {
2059 DPRINT1 ("Failed to reference token (Status %lx)\n", Status);
2060
2061 /* Release the captured privileges */
2062 if (CapturedPrivileges != NULL)
2063 SeReleaseLuidAndAttributesArray(CapturedPrivileges,
2064 PreviousMode,
2065 TRUE);
2066
2067 return Status;
2068 }
2069
2070
2071 #if 0
2072 SepAdjustPrivileges(Token,
2073 0,
2074 PreviousMode,
2075 PrivilegeCount,
2076 Privileges,
2077 PreviousState,
2078 &a,
2079 &b,
2080 &c);
2081 #endif
2082
2083 PrivilegeCount = (BufferLength - FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges)) /
2084 sizeof(LUID_AND_ATTRIBUTES);
2085
2086 if (PreviousState != NULL)
2087 PreviousState->PrivilegeCount = 0;
2088
2089 k = 0;
2090 if (DisableAllPrivileges == TRUE)
2091 {
2092 for (i = 0; i < Token->PrivilegeCount; i++)
2093 {
2094 if (Token->Privileges[i].Attributes != 0)
2095 {
2096 DPRINT ("Attributes differ\n");
2097
2098 /* Save current privilege */
2099 if (PreviousState != NULL)
2100 {
2101 if (k < PrivilegeCount)
2102 {
2103 PreviousState->PrivilegeCount++;
2104 PreviousState->Privileges[k].Luid = Token->Privileges[i].Luid;
2105 PreviousState->Privileges[k].Attributes = Token->Privileges[i].Attributes;
2106 }
2107 else
2108 {
2109 /*
2110 * FIXME: Should revert all the changes, calculate how
2111 * much space would be needed, set ResultLength
2112 * accordingly and fail.
2113 */
2114 }
2115
2116 k++;
2117 }
2118
2119 /* Update current privlege */
2120 Token->Privileges[i].Attributes &= ~SE_PRIVILEGE_ENABLED;
2121 }
2122 }
2123
2124 Status = STATUS_SUCCESS;
2125 }
2126 else
2127 {
2128 Count = 0;
2129 for (i = 0; i < Token->PrivilegeCount; i++)
2130 {
2131 for (j = 0; j < CapturedCount; j++)
2132 {
2133 if (Token->Privileges[i].Luid.LowPart == CapturedPrivileges[j].Luid.LowPart &&
2134 Token->Privileges[i].Luid.HighPart == CapturedPrivileges[j].Luid.HighPart)
2135 {
2136 DPRINT ("Found privilege\n");
2137
2138 if ((Token->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED) !=
2139 (CapturedPrivileges[j].Attributes & SE_PRIVILEGE_ENABLED))
2140 {
2141 DPRINT ("Attributes differ\n");
2142 DPRINT ("Current attributes %lx desired attributes %lx\n",
2143 Token->Privileges[i].Attributes,
2144 CapturedPrivileges[j].Attributes);
2145
2146 /* Save current privilege */
2147 if (PreviousState != NULL)
2148 {
2149 if (k < PrivilegeCount)
2150 {
2151 PreviousState->PrivilegeCount++;
2152 PreviousState->Privileges[k].Luid = Token->Privileges[i].Luid;
2153 PreviousState->Privileges[k].Attributes = Token->Privileges[i].Attributes;
2154 }
2155 else
2156 {
2157 /*
2158 * FIXME: Should revert all the changes, calculate how
2159 * much space would be needed, set ResultLength
2160 * accordingly and fail.
2161 */
2162 }
2163
2164 k++;
2165 }
2166
2167 /* Update current privlege */
2168 Token->Privileges[i].Attributes &= ~SE_PRIVILEGE_ENABLED;
2169 Token->Privileges[i].Attributes |=
2170 (CapturedPrivileges[j].Attributes & SE_PRIVILEGE_ENABLED);
2171 DPRINT ("New attributes %lx\n",
2172 Token->Privileges[i].Attributes);
2173 }
2174
2175 Count++;
2176 }
2177 }
2178 }
2179
2180 Status = Count < CapturedCount ? STATUS_NOT_ALL_ASSIGNED : STATUS_SUCCESS;
2181 }
2182
2183 if (ReturnLength != NULL)
2184 {
2185 *ReturnLength = sizeof(TOKEN_PRIVILEGES) +
2186 (sizeof(LUID_AND_ATTRIBUTES) * (k - 1));
2187 }
2188
2189 /* Dereference the token */
2190 ObDereferenceObject (Token);
2191
2192 /* Release the captured privileges */
2193 if (CapturedPrivileges != NULL)
2194 SeReleaseLuidAndAttributesArray(CapturedPrivileges,
2195 PreviousMode,
2196 TRUE);
2197
2198 DPRINT ("NtAdjustPrivilegesToken() done\n");
2199
2200 return Status;
2201 }
2202
2203 NTSTATUS
2204 NTAPI
2205 NtCreateToken(OUT PHANDLE TokenHandle,
2206 IN ACCESS_MASK DesiredAccess,
2207 IN POBJECT_ATTRIBUTES ObjectAttributes,
2208 IN TOKEN_TYPE TokenType,
2209 IN PLUID AuthenticationId,
2210 IN PLARGE_INTEGER ExpirationTime,
2211 IN PTOKEN_USER TokenUser,
2212 IN PTOKEN_GROUPS TokenGroups,
2213 IN PTOKEN_PRIVILEGES TokenPrivileges,
2214 IN PTOKEN_OWNER TokenOwner,
2215 IN PTOKEN_PRIMARY_GROUP TokenPrimaryGroup,
2216 IN PTOKEN_DEFAULT_DACL TokenDefaultDacl,
2217 IN PTOKEN_SOURCE TokenSource)
2218 {
2219 HANDLE hToken;
2220 KPROCESSOR_MODE PreviousMode;
2221 ULONG nTokenPrivileges = 0;
2222 LARGE_INTEGER LocalExpirationTime = {{0, 0}};
2223 NTSTATUS Status;
2224
2225 PAGED_CODE();
2226
2227 PreviousMode = ExGetPreviousMode();
2228
2229 if (PreviousMode != KernelMode)
2230 {
2231 _SEH2_TRY
2232 {
2233 ProbeForWriteHandle(TokenHandle);
2234 ProbeForRead(AuthenticationId,
2235 sizeof(LUID),
2236 sizeof(ULONG));
2237 LocalExpirationTime = ProbeForReadLargeInteger(ExpirationTime);
2238 ProbeForRead(TokenUser,
2239 sizeof(TOKEN_USER),
2240 sizeof(ULONG));
2241 ProbeForRead(TokenGroups,
2242 sizeof(TOKEN_GROUPS),
2243 sizeof(ULONG));
2244 ProbeForRead(TokenPrivileges,
2245 sizeof(TOKEN_PRIVILEGES),
2246 sizeof(ULONG));
2247 ProbeForRead(TokenOwner,
2248 sizeof(TOKEN_OWNER),
2249 sizeof(ULONG));
2250 ProbeForRead(TokenPrimaryGroup,
2251 sizeof(TOKEN_PRIMARY_GROUP),
2252 sizeof(ULONG));
2253 ProbeForRead(TokenDefaultDacl,
2254 sizeof(TOKEN_DEFAULT_DACL),
2255 sizeof(ULONG));
2256 ProbeForRead(TokenSource,
2257 sizeof(TOKEN_SOURCE),
2258 sizeof(ULONG));
2259 nTokenPrivileges = TokenPrivileges->PrivilegeCount;
2260 }
2261 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2262 {
2263 /* Return the exception code */
2264 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2265 }
2266 _SEH2_END;
2267 }
2268 else
2269 {
2270 nTokenPrivileges = TokenPrivileges->PrivilegeCount;
2271 LocalExpirationTime = *ExpirationTime;
2272 }
2273
2274 Status = SepCreateToken(&hToken,
2275 PreviousMode,
2276 DesiredAccess,
2277 ObjectAttributes,
2278 TokenType,
2279 ((PSECURITY_QUALITY_OF_SERVICE)(ObjectAttributes->SecurityQualityOfService))->ImpersonationLevel,
2280 AuthenticationId,
2281 &LocalExpirationTime,
2282 &TokenUser->User,
2283 TokenGroups->GroupCount,
2284 TokenGroups->Groups,
2285 0, // FIXME: Should capture
2286 nTokenPrivileges,
2287 TokenPrivileges->Privileges,
2288 TokenOwner->Owner,
2289 TokenPrimaryGroup->PrimaryGroup,
2290 TokenDefaultDacl->DefaultDacl,
2291 TokenSource,
2292 FALSE);
2293 if (NT_SUCCESS(Status))
2294 {
2295 _SEH2_TRY
2296 {
2297 *TokenHandle = hToken;
2298 }
2299 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2300 {
2301 Status = _SEH2_GetExceptionCode();
2302 }
2303 _SEH2_END;
2304 }
2305
2306 return Status;
2307 }
2308
2309 /*
2310 * @implemented
2311 */
2312 NTSTATUS
2313 NTAPI
2314 NtOpenThreadTokenEx(IN HANDLE ThreadHandle,
2315 IN ACCESS_MASK DesiredAccess,
2316 IN BOOLEAN OpenAsSelf,
2317 IN ULONG HandleAttributes,
2318 OUT PHANDLE TokenHandle)
2319 {
2320 PETHREAD Thread, NewThread;
2321 HANDLE hToken;
2322 PTOKEN Token, NewToken = NULL, PrimaryToken;
2323 BOOLEAN CopyOnOpen, EffectiveOnly;
2324 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
2325 SE_IMPERSONATION_STATE ImpersonationState;
2326 OBJECT_ATTRIBUTES ObjectAttributes;
2327 SECURITY_DESCRIPTOR SecurityDescriptor;
2328 PACL Dacl = NULL;
2329 KPROCESSOR_MODE PreviousMode;
2330 NTSTATUS Status;
2331
2332 PAGED_CODE();
2333
2334 PreviousMode = ExGetPreviousMode();
2335
2336 if (PreviousMode != KernelMode)
2337 {
2338 _SEH2_TRY
2339 {
2340 ProbeForWriteHandle(TokenHandle);
2341 }
2342 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2343 {
2344 /* Return the exception code */
2345 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2346 }
2347 _SEH2_END;
2348 }
2349
2350 /*
2351 * At first open the thread token for information access and verify
2352 * that the token associated with thread is valid.
2353 */
2354
2355 Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_QUERY_INFORMATION,
2356 PsThreadType, PreviousMode, (PVOID*)&Thread,
2357 NULL);
2358 if (!NT_SUCCESS(Status))
2359 {
2360 return Status;
2361 }
2362
2363 Token = PsReferenceImpersonationToken(Thread, &CopyOnOpen, &EffectiveOnly,
2364 &ImpersonationLevel);
2365 if (Token == NULL)
2366 {
2367 ObDereferenceObject(Thread);
2368 return STATUS_NO_TOKEN;
2369 }
2370
2371 if (ImpersonationLevel == SecurityAnonymous)
2372 {
2373 PsDereferenceImpersonationToken(Token);
2374 ObDereferenceObject(Thread);
2375 return STATUS_CANT_OPEN_ANONYMOUS;
2376 }
2377
2378 /*
2379 * Revert to self if OpenAsSelf is specified.
2380 */
2381
2382 if (OpenAsSelf)
2383 {
2384 PsDisableImpersonation(PsGetCurrentThread(), &ImpersonationState);
2385 }
2386
2387 if (CopyOnOpen)
2388 {
2389 Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_ALL_ACCESS,
2390 PsThreadType, KernelMode,
2391 (PVOID*)&NewThread, NULL);
2392 if (NT_SUCCESS(Status))
2393 {
2394 PrimaryToken = PsReferencePrimaryToken(NewThread->ThreadsProcess);
2395
2396 Status = SepCreateImpersonationTokenDacl(Token, PrimaryToken, &Dacl);
2397
2398 ObFastDereferenceObject(&NewThread->ThreadsProcess->Token, PrimaryToken);
2399
2400 if (NT_SUCCESS(Status))
2401 {
2402 if (Dacl)
2403 {
2404 RtlCreateSecurityDescriptor(&SecurityDescriptor,
2405 SECURITY_DESCRIPTOR_REVISION);
2406 RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl,
2407 FALSE);
2408 }
2409
2410 InitializeObjectAttributes(&ObjectAttributes, NULL, HandleAttributes,
2411 NULL, Dacl ? &SecurityDescriptor : NULL);
2412
2413
2414 Status = SepDuplicateToken(Token, &ObjectAttributes, EffectiveOnly,
2415 TokenImpersonation, ImpersonationLevel,
2416 KernelMode, &NewToken);
2417 if (NT_SUCCESS(Status))
2418 {
2419 ObReferenceObject(NewToken);
2420 Status = ObInsertObject(NewToken, NULL, DesiredAccess, 0, NULL,
2421 &hToken);
2422 }
2423 }
2424 }
2425 }
2426 else
2427 {
2428 Status = ObOpenObjectByPointer(Token, HandleAttributes,
2429 NULL, DesiredAccess, SepTokenObjectType,
2430 PreviousMode, &hToken);
2431 }
2432
2433 if (Dacl) ExFreePool(Dacl);
2434
2435 if (OpenAsSelf)
2436 {
2437 PsRestoreImpersonation(PsGetCurrentThread(), &ImpersonationState);
2438 }
2439
2440 ObDereferenceObject(Token);
2441
2442 if (NT_SUCCESS(Status) && CopyOnOpen)
2443 {
2444 PsImpersonateClient(Thread, NewToken, FALSE, EffectiveOnly, ImpersonationLevel);
2445 }
2446
2447 if (NewToken) ObDereferenceObject(NewToken);
2448
2449 if (CopyOnOpen && NewThread) ObDereferenceObject(NewThread);
2450
2451 if (NT_SUCCESS(Status))
2452 {
2453 _SEH2_TRY
2454 {
2455 *TokenHandle = hToken;
2456 }
2457 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2458 {
2459 Status = _SEH2_GetExceptionCode();
2460 }
2461 _SEH2_END;
2462 }
2463
2464 return Status;
2465 }
2466
2467 /*
2468 * @implemented
2469 */
2470 NTSTATUS NTAPI
2471 NtOpenThreadToken(IN HANDLE ThreadHandle,
2472 IN ACCESS_MASK DesiredAccess,
2473 IN BOOLEAN OpenAsSelf,
2474 OUT PHANDLE TokenHandle)
2475 {
2476 return NtOpenThreadTokenEx(ThreadHandle, DesiredAccess, OpenAsSelf, 0,
2477 TokenHandle);
2478 }
2479
2480
2481
2482 /*
2483 * @unimplemented
2484 */
2485 NTSTATUS
2486 NTAPI
2487 NtCompareTokens(IN HANDLE FirstTokenHandle,
2488 IN HANDLE SecondTokenHandle,
2489 OUT PBOOLEAN Equal)
2490 {
2491 KPROCESSOR_MODE PreviousMode;
2492 PTOKEN FirstToken, SecondToken;
2493 BOOLEAN IsEqual;
2494 NTSTATUS Status;
2495
2496 PAGED_CODE();
2497
2498 PreviousMode = ExGetPreviousMode();
2499
2500 if (PreviousMode != KernelMode)
2501 {
2502 _SEH2_TRY
2503 {
2504 ProbeForWriteBoolean(Equal);
2505 }
2506 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2507 {
2508 /* Return the exception code */
2509 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2510 }
2511 _SEH2_END;
2512 }
2513
2514 Status = ObReferenceObjectByHandle(FirstTokenHandle,
2515 TOKEN_QUERY,
2516 SepTokenObjectType,
2517 PreviousMode,
2518 (PVOID*)&FirstToken,
2519 NULL);
2520 if (!NT_SUCCESS(Status))
2521 return Status;
2522
2523 Status = ObReferenceObjectByHandle(SecondTokenHandle,
2524 TOKEN_QUERY,
2525 SepTokenObjectType,
2526 PreviousMode,
2527 (PVOID*)&SecondToken,
2528 NULL);
2529 if (!NT_SUCCESS(Status))
2530 {
2531 ObDereferenceObject(FirstToken);
2532 return Status;
2533 }
2534
2535 if (FirstToken != SecondToken)
2536 {
2537 Status = SepCompareTokens(FirstToken,
2538 SecondToken,
2539 &IsEqual);
2540 }
2541 else
2542 IsEqual = TRUE;
2543
2544 ObDereferenceObject(FirstToken);
2545 ObDereferenceObject(SecondToken);
2546
2547 if (NT_SUCCESS(Status))
2548 {
2549 _SEH2_TRY
2550 {
2551 *Equal = IsEqual;
2552 }
2553 _SEH2_EXCEPT(ExSystemExceptionFilter())
2554 {
2555 Status = _SEH2_GetExceptionCode();
2556 }
2557 _SEH2_END;
2558 }
2559
2560 return Status;
2561 }
2562
2563 NTSTATUS
2564 NTAPI
2565 NtFilterToken(IN HANDLE ExistingTokenHandle,
2566 IN ULONG Flags,
2567 IN PTOKEN_GROUPS SidsToDisable OPTIONAL,
2568 IN PTOKEN_PRIVILEGES PrivilegesToDelete OPTIONAL,
2569 IN PTOKEN_GROUPS RestrictedSids OPTIONAL,
2570 OUT PHANDLE NewTokenHandle)
2571 {
2572 UNIMPLEMENTED;
2573 return STATUS_NOT_IMPLEMENTED;
2574 }
2575
2576 /*
2577 * @unimplemented
2578 */
2579 NTSTATUS
2580 NTAPI
2581 NtImpersonateAnonymousToken(IN HANDLE Thread)
2582 {
2583 UNIMPLEMENTED;
2584 return STATUS_NOT_IMPLEMENTED;
2585 }
2586
2587 /* EOF */