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