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