[CLT2012]
[reactos.git] / ntoskrnl / se / token.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/se/token.c
5 * PURPOSE: Security manager
6 *
7 * PROGRAMMERS: David Welch <welch@cwcom.net>
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 #if defined (ALLOC_PRAGMA)
17 #pragma alloc_text(INIT, SepInitializeTokenImplementation)
18 #endif
19
20 /* GLOBALS ********************************************************************/
21
22 POBJECT_TYPE SepTokenObjectType = NULL;
23 ERESOURCE SepTokenLock;
24
25 TOKEN_SOURCE SeSystemTokenSource = {"*SYSTEM*", {0}};
26 LUID SeSystemAuthenticationId = SYSTEM_LUID;
27
28 static GENERIC_MAPPING SepTokenMapping = {
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 TAG_TOKEN_USERS);
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 TAG_TOKEN_PRIVILAGES);
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 TAG_TOKEN_ACL);
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 ExFreePoolWithTag(AccessToken->UserAndGroups, TAG_TOKEN_USERS);
464
465 if (AccessToken->Privileges)
466 ExFreePoolWithTag(AccessToken->Privileges, TAG_TOKEN_PRIVILAGES);
467
468 if (AccessToken->DefaultDacl)
469 ExFreePoolWithTag(AccessToken->DefaultDacl, TAG_TOKEN_ACL);
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 TAG_TOKEN_USERS);
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 TAG_TOKEN_PRIVILAGES);
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 TAG_TOKEN_ACL);
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 ExFreePoolWithTag(Token->DefaultDacl, TAG_TOKEN_ACL);
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 ExFreePoolWithTag(Token->DefaultDacl, TAG_TOKEN_ACL);
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 ChangeCount;
1962 PTOKEN Token;
1963 ULONG i;
1964 ULONG j;
1965 NTSTATUS Status;
1966
1967 PAGED_CODE();
1968
1969 DPRINT ("NtAdjustPrivilegesToken() called\n");
1970
1971 /* Fail, if we do not disable all privileges but NewState is NULL */
1972 if (DisableAllPrivileges == FALSE && NewState == NULL)
1973 return STATUS_INVALID_PARAMETER;
1974
1975 PreviousMode = KeGetPreviousMode ();
1976 if (PreviousMode != KernelMode)
1977 {
1978 _SEH2_TRY
1979 {
1980 /* Probe NewState */
1981 if (DisableAllPrivileges == FALSE)
1982 {
1983 ProbeForRead(NewState,
1984 sizeof(TOKEN_PRIVILEGES),
1985 sizeof(ULONG));
1986
1987 CapturedCount = NewState->PrivilegeCount;
1988 NewStateSize = (ULONG)sizeof(TOKEN_PRIVILEGES) +
1989 ((CapturedCount - ANYSIZE_ARRAY) * (ULONG)sizeof(LUID_AND_ATTRIBUTES));
1990
1991 ProbeForRead(NewState,
1992 NewStateSize,
1993 sizeof(ULONG));
1994 }
1995
1996 /* Probe PreviousState and ReturnLength */
1997 if (PreviousState != NULL)
1998 {
1999 ProbeForWrite(PreviousState,
2000 BufferLength,
2001 sizeof(ULONG));
2002
2003 ProbeForWrite(ReturnLength,
2004 sizeof(ULONG),
2005 sizeof(ULONG));
2006 }
2007 }
2008 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2009 {
2010 /* Return the exception code */
2011 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2012 }
2013 _SEH2_END;
2014 }
2015 else
2016 {
2017 if (DisableAllPrivileges == FALSE)
2018 CapturedCount = NewState->PrivilegeCount;
2019 }
2020
2021 if (DisableAllPrivileges == FALSE)
2022 {
2023 _SEH2_TRY
2024 {
2025 /* Capture the new state array of privileges */
2026 Status = SeCaptureLuidAndAttributesArray(NewState->Privileges,
2027 CapturedCount,
2028 PreviousMode,
2029 NULL,
2030 0,
2031 PagedPool,
2032 TRUE,
2033 &CapturedPrivileges,
2034 &CapturedLength);
2035 }
2036 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2037 {
2038 /* Return the exception code */
2039 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2040 }
2041 _SEH2_END;
2042
2043 if (!NT_SUCCESS(Status))
2044 return Status;
2045 }
2046
2047 /* Reference the token */
2048 Status = ObReferenceObjectByHandle(TokenHandle,
2049 TOKEN_ADJUST_PRIVILEGES | (PreviousState != NULL ? TOKEN_QUERY : 0),
2050 SepTokenObjectType,
2051 PreviousMode,
2052 (PVOID*)&Token,
2053 NULL);
2054 if (!NT_SUCCESS(Status))
2055 {
2056 DPRINT1 ("Failed to reference token (Status %lx)\n", Status);
2057
2058 /* Release the captured privileges */
2059 if (CapturedPrivileges != NULL)
2060 SeReleaseLuidAndAttributesArray(CapturedPrivileges,
2061 PreviousMode,
2062 TRUE);
2063
2064 return Status;
2065 }
2066
2067 /* Count the privileges that need to be changed */
2068 ChangeCount = 0;
2069 for (i = 0; i < Token->PrivilegeCount; i++)
2070 {
2071 if (DisableAllPrivileges)
2072 {
2073 if (Token->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED)
2074 {
2075 DPRINT("Privilege enabled\n");
2076
2077 ChangeCount++;
2078 }
2079 }
2080 else
2081 {
2082 for (j = 0; j < CapturedCount; j++)
2083 {
2084 if (Token->Privileges[i].Luid.LowPart == CapturedPrivileges[j].Luid.LowPart &&
2085 Token->Privileges[i].Luid.HighPart == CapturedPrivileges[j].Luid.HighPart)
2086 {
2087 DPRINT("Found privilege\n");
2088
2089 if ((Token->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED) !=
2090 (CapturedPrivileges[j].Attributes & SE_PRIVILEGE_ENABLED))
2091 {
2092 DPRINT("Attributes differ\n");
2093 DPRINT("Current attributes %lx New attributes %lx\n",
2094 Token->Privileges[i].Attributes,
2095 CapturedPrivileges[j].Attributes);
2096
2097 ChangeCount++;
2098 }
2099 }
2100 }
2101 }
2102 }
2103
2104 /*
2105 * Return the required buffer size and
2106 * check if the available buffer is large enough
2107 */
2108 if (PreviousState != NULL)
2109 {
2110 ULONG RequiredLength = (ULONG)sizeof(TOKEN_PRIVILEGES) +
2111 ((ChangeCount - ANYSIZE_ARRAY) * (ULONG)sizeof(LUID_AND_ATTRIBUTES));
2112
2113 /* Try to return the required buffer length */
2114 _SEH2_TRY
2115 {
2116 *ReturnLength = RequiredLength;
2117 }
2118 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2119 {
2120 /* Dereference the token */
2121 ObDereferenceObject(Token);
2122
2123 /* Release the captured privileges */
2124 if (CapturedPrivileges != NULL)
2125 SeReleaseLuidAndAttributesArray(CapturedPrivileges,
2126 PreviousMode,
2127 TRUE);
2128
2129 /* Return the exception code */
2130 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2131 }
2132 _SEH2_END;
2133
2134 /* Fail, if the buffer length is smaller than the required length */
2135 if (BufferLength < RequiredLength)
2136 {
2137 /* Dereference the token */
2138 ObDereferenceObject(Token);
2139
2140 /* Release the captured privileges */
2141 if (CapturedPrivileges != NULL)
2142 SeReleaseLuidAndAttributesArray(CapturedPrivileges,
2143 PreviousMode,
2144 TRUE);
2145
2146 return STATUS_BUFFER_TOO_SMALL;
2147 }
2148 }
2149
2150 /* Change the privilege attributes */
2151 ChangeCount = 0;
2152 _SEH2_TRY
2153 {
2154 for (i = 0; i < Token->PrivilegeCount; i++)
2155 {
2156 if (DisableAllPrivileges == TRUE)
2157 {
2158 if (Token->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED)
2159 {
2160 DPRINT("Privilege enabled\n");
2161
2162 /* Save the current privilege */
2163 if (PreviousState != NULL)
2164 {
2165 PreviousState->Privileges[ChangeCount].Luid = Token->Privileges[i].Luid;
2166 PreviousState->Privileges[ChangeCount].Attributes = Token->Privileges[i].Attributes;
2167 }
2168
2169 /* Disable the current privlege */
2170 Token->Privileges[i].Attributes &= ~SE_PRIVILEGE_ENABLED;
2171
2172 ChangeCount++;
2173 }
2174 }
2175 else
2176 {
2177 for (j = 0; j < CapturedCount; j++)
2178 {
2179 if (Token->Privileges[i].Luid.LowPart == CapturedPrivileges[j].Luid.LowPart &&
2180 Token->Privileges[i].Luid.HighPart == CapturedPrivileges[j].Luid.HighPart)
2181 {
2182 DPRINT("Found privilege\n");
2183
2184 /* Check whether the attributes differ */
2185 if ((Token->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED) !=
2186 (CapturedPrivileges[j].Attributes & SE_PRIVILEGE_ENABLED))
2187 {
2188 DPRINT("Attributes differ\n");
2189 DPRINT("Current attributes %lx New attributes %lx\n",
2190 Token->Privileges[i].Attributes,
2191 CapturedPrivileges[j].Attributes);
2192
2193 /* Save the current privilege */
2194 if (PreviousState != NULL)
2195 {
2196 PreviousState->Privileges[ChangeCount].Luid = Token->Privileges[i].Luid;
2197 PreviousState->Privileges[ChangeCount].Attributes = Token->Privileges[i].Attributes;
2198 }
2199
2200 /* Update the current privlege */
2201 Token->Privileges[i].Attributes &= ~SE_PRIVILEGE_ENABLED;
2202 Token->Privileges[i].Attributes |=
2203 (CapturedPrivileges[j].Attributes & SE_PRIVILEGE_ENABLED);
2204 DPRINT("New attributes %lx\n",
2205 Token->Privileges[i].Attributes);
2206
2207 ChangeCount++;
2208 }
2209 }
2210 }
2211 }
2212 }
2213
2214 /* Set the number of saved privileges */
2215 if (PreviousState != NULL)
2216 PreviousState->PrivilegeCount = ChangeCount;
2217 }
2218 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2219 {
2220 /* Dereference the token */
2221 ObDereferenceObject(Token);
2222
2223 /* Release the captured privileges */
2224 if (CapturedPrivileges != NULL)
2225 SeReleaseLuidAndAttributesArray(CapturedPrivileges,
2226 PreviousMode,
2227 TRUE);
2228
2229 /* Return the exception code */
2230 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2231 }
2232 _SEH2_END;
2233
2234 /* Set the status */
2235 Status = (ChangeCount < CapturedCount) ? STATUS_NOT_ALL_ASSIGNED : STATUS_SUCCESS;
2236
2237 /* Dereference the token */
2238 ObDereferenceObject (Token);
2239
2240 /* Release the captured privileges */
2241 if (CapturedPrivileges != NULL)
2242 SeReleaseLuidAndAttributesArray(CapturedPrivileges,
2243 PreviousMode,
2244 TRUE);
2245
2246 DPRINT ("NtAdjustPrivilegesToken() done\n");
2247
2248 return Status;
2249 }
2250
2251 NTSTATUS
2252 NTAPI
2253 NtCreateToken(OUT PHANDLE TokenHandle,
2254 IN ACCESS_MASK DesiredAccess,
2255 IN POBJECT_ATTRIBUTES ObjectAttributes,
2256 IN TOKEN_TYPE TokenType,
2257 IN PLUID AuthenticationId,
2258 IN PLARGE_INTEGER ExpirationTime,
2259 IN PTOKEN_USER TokenUser,
2260 IN PTOKEN_GROUPS TokenGroups,
2261 IN PTOKEN_PRIVILEGES TokenPrivileges,
2262 IN PTOKEN_OWNER TokenOwner,
2263 IN PTOKEN_PRIMARY_GROUP TokenPrimaryGroup,
2264 IN PTOKEN_DEFAULT_DACL TokenDefaultDacl,
2265 IN PTOKEN_SOURCE TokenSource)
2266 {
2267 HANDLE hToken;
2268 KPROCESSOR_MODE PreviousMode;
2269 ULONG nTokenPrivileges = 0;
2270 LARGE_INTEGER LocalExpirationTime = {{0, 0}};
2271 NTSTATUS Status;
2272
2273 PAGED_CODE();
2274
2275 PreviousMode = ExGetPreviousMode();
2276
2277 if (PreviousMode != KernelMode)
2278 {
2279 _SEH2_TRY
2280 {
2281 ProbeForWriteHandle(TokenHandle);
2282 ProbeForRead(AuthenticationId,
2283 sizeof(LUID),
2284 sizeof(ULONG));
2285 LocalExpirationTime = ProbeForReadLargeInteger(ExpirationTime);
2286 ProbeForRead(TokenUser,
2287 sizeof(TOKEN_USER),
2288 sizeof(ULONG));
2289 ProbeForRead(TokenGroups,
2290 sizeof(TOKEN_GROUPS),
2291 sizeof(ULONG));
2292 ProbeForRead(TokenPrivileges,
2293 sizeof(TOKEN_PRIVILEGES),
2294 sizeof(ULONG));
2295 ProbeForRead(TokenOwner,
2296 sizeof(TOKEN_OWNER),
2297 sizeof(ULONG));
2298 ProbeForRead(TokenPrimaryGroup,
2299 sizeof(TOKEN_PRIMARY_GROUP),
2300 sizeof(ULONG));
2301 ProbeForRead(TokenDefaultDacl,
2302 sizeof(TOKEN_DEFAULT_DACL),
2303 sizeof(ULONG));
2304 ProbeForRead(TokenSource,
2305 sizeof(TOKEN_SOURCE),
2306 sizeof(ULONG));
2307 nTokenPrivileges = TokenPrivileges->PrivilegeCount;
2308 }
2309 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2310 {
2311 /* Return the exception code */
2312 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2313 }
2314 _SEH2_END;
2315 }
2316 else
2317 {
2318 nTokenPrivileges = TokenPrivileges->PrivilegeCount;
2319 LocalExpirationTime = *ExpirationTime;
2320 }
2321
2322 Status = SepCreateToken(&hToken,
2323 PreviousMode,
2324 DesiredAccess,
2325 ObjectAttributes,
2326 TokenType,
2327 ((PSECURITY_QUALITY_OF_SERVICE)(ObjectAttributes->SecurityQualityOfService))->ImpersonationLevel,
2328 AuthenticationId,
2329 &LocalExpirationTime,
2330 &TokenUser->User,
2331 TokenGroups->GroupCount,
2332 TokenGroups->Groups,
2333 0, // FIXME: Should capture
2334 nTokenPrivileges,
2335 TokenPrivileges->Privileges,
2336 TokenOwner->Owner,
2337 TokenPrimaryGroup->PrimaryGroup,
2338 TokenDefaultDacl->DefaultDacl,
2339 TokenSource,
2340 FALSE);
2341 if (NT_SUCCESS(Status))
2342 {
2343 _SEH2_TRY
2344 {
2345 *TokenHandle = hToken;
2346 }
2347 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2348 {
2349 Status = _SEH2_GetExceptionCode();
2350 }
2351 _SEH2_END;
2352 }
2353
2354 return Status;
2355 }
2356
2357 /*
2358 * @implemented
2359 */
2360 NTSTATUS
2361 NTAPI
2362 NtOpenThreadTokenEx(IN HANDLE ThreadHandle,
2363 IN ACCESS_MASK DesiredAccess,
2364 IN BOOLEAN OpenAsSelf,
2365 IN ULONG HandleAttributes,
2366 OUT PHANDLE TokenHandle)
2367 {
2368 PETHREAD Thread, NewThread;
2369 HANDLE hToken;
2370 PTOKEN Token, NewToken = NULL, PrimaryToken;
2371 BOOLEAN CopyOnOpen, EffectiveOnly;
2372 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
2373 SE_IMPERSONATION_STATE ImpersonationState;
2374 OBJECT_ATTRIBUTES ObjectAttributes;
2375 SECURITY_DESCRIPTOR SecurityDescriptor;
2376 PACL Dacl = NULL;
2377 KPROCESSOR_MODE PreviousMode;
2378 NTSTATUS Status;
2379
2380 PAGED_CODE();
2381
2382 PreviousMode = ExGetPreviousMode();
2383
2384 if (PreviousMode != KernelMode)
2385 {
2386 _SEH2_TRY
2387 {
2388 ProbeForWriteHandle(TokenHandle);
2389 }
2390 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2391 {
2392 /* Return the exception code */
2393 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2394 }
2395 _SEH2_END;
2396 }
2397
2398 /*
2399 * At first open the thread token for information access and verify
2400 * that the token associated with thread is valid.
2401 */
2402
2403 Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_QUERY_INFORMATION,
2404 PsThreadType, PreviousMode, (PVOID*)&Thread,
2405 NULL);
2406 if (!NT_SUCCESS(Status))
2407 {
2408 return Status;
2409 }
2410
2411 Token = PsReferenceImpersonationToken(Thread, &CopyOnOpen, &EffectiveOnly,
2412 &ImpersonationLevel);
2413 if (Token == NULL)
2414 {
2415 ObDereferenceObject(Thread);
2416 return STATUS_NO_TOKEN;
2417 }
2418
2419 if (ImpersonationLevel == SecurityAnonymous)
2420 {
2421 PsDereferenceImpersonationToken(Token);
2422 ObDereferenceObject(Thread);
2423 return STATUS_CANT_OPEN_ANONYMOUS;
2424 }
2425
2426 /*
2427 * Revert to self if OpenAsSelf is specified.
2428 */
2429
2430 if (OpenAsSelf)
2431 {
2432 PsDisableImpersonation(PsGetCurrentThread(), &ImpersonationState);
2433 }
2434
2435 if (CopyOnOpen)
2436 {
2437 Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_ALL_ACCESS,
2438 PsThreadType, KernelMode,
2439 (PVOID*)&NewThread, NULL);
2440 if (NT_SUCCESS(Status))
2441 {
2442 PrimaryToken = PsReferencePrimaryToken(NewThread->ThreadsProcess);
2443
2444 Status = SepCreateImpersonationTokenDacl(Token, PrimaryToken, &Dacl);
2445
2446 ObFastDereferenceObject(&NewThread->ThreadsProcess->Token, PrimaryToken);
2447
2448 if (NT_SUCCESS(Status))
2449 {
2450 if (Dacl)
2451 {
2452 RtlCreateSecurityDescriptor(&SecurityDescriptor,
2453 SECURITY_DESCRIPTOR_REVISION);
2454 RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl,
2455 FALSE);
2456 }
2457
2458 InitializeObjectAttributes(&ObjectAttributes, NULL, HandleAttributes,
2459 NULL, Dacl ? &SecurityDescriptor : NULL);
2460
2461
2462 Status = SepDuplicateToken(Token, &ObjectAttributes, EffectiveOnly,
2463 TokenImpersonation, ImpersonationLevel,
2464 KernelMode, &NewToken);
2465 if (NT_SUCCESS(Status))
2466 {
2467 ObReferenceObject(NewToken);
2468 Status = ObInsertObject(NewToken, NULL, DesiredAccess, 0, NULL,
2469 &hToken);
2470 }
2471 }
2472 }
2473 }
2474 else
2475 {
2476 Status = ObOpenObjectByPointer(Token, HandleAttributes,
2477 NULL, DesiredAccess, SepTokenObjectType,
2478 PreviousMode, &hToken);
2479 }
2480
2481 if (Dacl) ExFreePoolWithTag(Dacl, TAG_TOKEN_ACL);
2482
2483 if (OpenAsSelf)
2484 {
2485 PsRestoreImpersonation(PsGetCurrentThread(), &ImpersonationState);
2486 }
2487
2488 ObDereferenceObject(Token);
2489
2490 if (NT_SUCCESS(Status) && CopyOnOpen)
2491 {
2492 PsImpersonateClient(Thread, NewToken, FALSE, EffectiveOnly, ImpersonationLevel);
2493 }
2494
2495 if (NewToken) ObDereferenceObject(NewToken);
2496
2497 if (CopyOnOpen && NewThread) ObDereferenceObject(NewThread);
2498
2499 if (NT_SUCCESS(Status))
2500 {
2501 _SEH2_TRY
2502 {
2503 *TokenHandle = hToken;
2504 }
2505 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2506 {
2507 Status = _SEH2_GetExceptionCode();
2508 }
2509 _SEH2_END;
2510 }
2511
2512 return Status;
2513 }
2514
2515 /*
2516 * @implemented
2517 */
2518 NTSTATUS NTAPI
2519 NtOpenThreadToken(IN HANDLE ThreadHandle,
2520 IN ACCESS_MASK DesiredAccess,
2521 IN BOOLEAN OpenAsSelf,
2522 OUT PHANDLE TokenHandle)
2523 {
2524 return NtOpenThreadTokenEx(ThreadHandle, DesiredAccess, OpenAsSelf, 0,
2525 TokenHandle);
2526 }
2527
2528
2529
2530 /*
2531 * @unimplemented
2532 */
2533 NTSTATUS
2534 NTAPI
2535 NtCompareTokens(IN HANDLE FirstTokenHandle,
2536 IN HANDLE SecondTokenHandle,
2537 OUT PBOOLEAN Equal)
2538 {
2539 KPROCESSOR_MODE PreviousMode;
2540 PTOKEN FirstToken, SecondToken;
2541 BOOLEAN IsEqual;
2542 NTSTATUS Status;
2543
2544 PAGED_CODE();
2545
2546 PreviousMode = ExGetPreviousMode();
2547
2548 if (PreviousMode != KernelMode)
2549 {
2550 _SEH2_TRY
2551 {
2552 ProbeForWriteBoolean(Equal);
2553 }
2554 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2555 {
2556 /* Return the exception code */
2557 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2558 }
2559 _SEH2_END;
2560 }
2561
2562 Status = ObReferenceObjectByHandle(FirstTokenHandle,
2563 TOKEN_QUERY,
2564 SepTokenObjectType,
2565 PreviousMode,
2566 (PVOID*)&FirstToken,
2567 NULL);
2568 if (!NT_SUCCESS(Status))
2569 return Status;
2570
2571 Status = ObReferenceObjectByHandle(SecondTokenHandle,
2572 TOKEN_QUERY,
2573 SepTokenObjectType,
2574 PreviousMode,
2575 (PVOID*)&SecondToken,
2576 NULL);
2577 if (!NT_SUCCESS(Status))
2578 {
2579 ObDereferenceObject(FirstToken);
2580 return Status;
2581 }
2582
2583 if (FirstToken != SecondToken)
2584 {
2585 Status = SepCompareTokens(FirstToken,
2586 SecondToken,
2587 &IsEqual);
2588 }
2589 else
2590 IsEqual = TRUE;
2591
2592 ObDereferenceObject(FirstToken);
2593 ObDereferenceObject(SecondToken);
2594
2595 if (NT_SUCCESS(Status))
2596 {
2597 _SEH2_TRY
2598 {
2599 *Equal = IsEqual;
2600 }
2601 _SEH2_EXCEPT(ExSystemExceptionFilter())
2602 {
2603 Status = _SEH2_GetExceptionCode();
2604 }
2605 _SEH2_END;
2606 }
2607
2608 return Status;
2609 }
2610
2611 NTSTATUS
2612 NTAPI
2613 NtFilterToken(IN HANDLE ExistingTokenHandle,
2614 IN ULONG Flags,
2615 IN PTOKEN_GROUPS SidsToDisable OPTIONAL,
2616 IN PTOKEN_PRIVILEGES PrivilegesToDelete OPTIONAL,
2617 IN PTOKEN_GROUPS RestrictedSids OPTIONAL,
2618 OUT PHANDLE NewTokenHandle)
2619 {
2620 UNIMPLEMENTED;
2621 return STATUS_NOT_IMPLEMENTED;
2622 }
2623
2624 /*
2625 * @unimplemented
2626 */
2627 NTSTATUS
2628 NTAPI
2629 NtImpersonateAnonymousToken(IN HANDLE Thread)
2630 {
2631 UNIMPLEMENTED;
2632 return STATUS_NOT_IMPLEMENTED;
2633 }
2634
2635 /* EOF */