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