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