Add a stub for NtCompareTokens
[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 VOID
1900 NTAPI
1901 SeAssignPrimaryToken(IN PEPROCESS Process,
1902 IN PTOKEN Token)
1903 {
1904 PAGED_CODE();
1905
1906 /* Sanity checks */
1907 ASSERT(Token->TokenType == TokenPrimary);
1908 ASSERT(!Token->TokenInUse);
1909
1910 /* Clean any previous token */
1911 if (Process->Token.Object) SeDeassignPrimaryToken(Process);
1912
1913 /* Set the new token */
1914 ObReferenceObject(Token);
1915 Token->TokenInUse = TRUE;
1916 ObInitializeFastReference(&Process->Token, Token);
1917 }
1918
1919 PTOKEN
1920 STDCALL
1921 SepCreateSystemProcessToken(VOID)
1922 {
1923 NTSTATUS Status;
1924 ULONG uSize;
1925 ULONG i;
1926 ULONG uLocalSystemLength;
1927 ULONG uWorldLength;
1928 ULONG uAuthUserLength;
1929 ULONG uAdminsLength;
1930 PTOKEN AccessToken;
1931 PVOID SidArea;
1932
1933 PAGED_CODE();
1934
1935 uLocalSystemLength = RtlLengthSid(SeLocalSystemSid);
1936 uWorldLength = RtlLengthSid(SeWorldSid);
1937 uAuthUserLength = RtlLengthSid(SeAuthenticatedUserSid);
1938 uAdminsLength = RtlLengthSid(SeAliasAdminsSid);
1939
1940 /*
1941 * Initialize the token
1942 */
1943 Status = ObCreateObject(KernelMode,
1944 SepTokenObjectType,
1945 NULL,
1946 KernelMode,
1947 NULL,
1948 sizeof(TOKEN),
1949 0,
1950 0,
1951 (PVOID*)&AccessToken);
1952 if (!NT_SUCCESS(Status))
1953 {
1954 return NULL;
1955 }
1956
1957 Status = ExpAllocateLocallyUniqueId(&AccessToken->TokenId);
1958 if (!NT_SUCCESS(Status))
1959 {
1960 ObDereferenceObject(AccessToken);
1961 return NULL;
1962 }
1963
1964 Status = ExpAllocateLocallyUniqueId(&AccessToken->ModifiedId);
1965 if (!NT_SUCCESS(Status))
1966 {
1967 ObDereferenceObject(AccessToken);
1968 return NULL;
1969 }
1970
1971 Status = ExpAllocateLocallyUniqueId(&AccessToken->AuthenticationId);
1972 if (!NT_SUCCESS(Status))
1973 {
1974 ObDereferenceObject(AccessToken);
1975 return NULL;
1976 }
1977
1978 AccessToken->TokenLock = &SepTokenLock;
1979
1980 AccessToken->TokenType = TokenPrimary;
1981 AccessToken->ImpersonationLevel = SecurityDelegation;
1982 AccessToken->TokenSource.SourceIdentifier.LowPart = 0;
1983 AccessToken->TokenSource.SourceIdentifier.HighPart = 0;
1984 memcpy(AccessToken->TokenSource.SourceName, "SeMgr\0\0\0", 8);
1985 AccessToken->ExpirationTime.QuadPart = -1;
1986 AccessToken->UserAndGroupCount = 4;
1987
1988 uSize = sizeof(SID_AND_ATTRIBUTES) * AccessToken->UserAndGroupCount;
1989 uSize += uLocalSystemLength;
1990 uSize += uWorldLength;
1991 uSize += uAuthUserLength;
1992 uSize += uAdminsLength;
1993
1994 AccessToken->UserAndGroups =
1995 (PSID_AND_ATTRIBUTES)ExAllocatePoolWithTag(PagedPool,
1996 uSize,
1997 TAG('T', 'O', 'K', 'u'));
1998 SidArea = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
1999
2000 i = 0;
2001 AccessToken->UserAndGroups[i].Sid = (PSID) SidArea;
2002 AccessToken->UserAndGroups[i++].Attributes = 0;
2003 RtlCopySid(uLocalSystemLength, SidArea, SeLocalSystemSid);
2004 SidArea = (char*)SidArea + uLocalSystemLength;
2005
2006 AccessToken->DefaultOwnerIndex = i;
2007 AccessToken->UserAndGroups[i].Sid = (PSID) SidArea;
2008 AccessToken->PrimaryGroup = (PSID) SidArea;
2009 AccessToken->UserAndGroups[i++].Attributes = SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT;
2010 Status = RtlCopySid(uAdminsLength, SidArea, SeAliasAdminsSid);
2011 SidArea = (char*)SidArea + uAdminsLength;
2012
2013 AccessToken->UserAndGroups[i].Sid = (PSID) SidArea;
2014 AccessToken->UserAndGroups[i++].Attributes = SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY;
2015 RtlCopySid(uWorldLength, SidArea, SeWorldSid);
2016 SidArea = (char*)SidArea + uWorldLength;
2017
2018 AccessToken->UserAndGroups[i].Sid = (PSID) SidArea;
2019 AccessToken->UserAndGroups[i++].Attributes = SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY;
2020 RtlCopySid(uAuthUserLength, SidArea, SeAuthenticatedUserSid);
2021 SidArea = (char*)SidArea + uAuthUserLength;
2022
2023 AccessToken->PrivilegeCount = 20;
2024
2025 uSize = AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
2026 AccessToken->Privileges =
2027 (PLUID_AND_ATTRIBUTES)ExAllocatePoolWithTag(PagedPool,
2028 uSize,
2029 TAG('T', 'O', 'K', 'p'));
2030
2031 i = 0;
2032 AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
2033 AccessToken->Privileges[i++].Luid = SeTcbPrivilege;
2034
2035 AccessToken->Privileges[i].Attributes = 0;
2036 AccessToken->Privileges[i++].Luid = SeCreateTokenPrivilege;
2037
2038 AccessToken->Privileges[i].Attributes = 0;
2039 AccessToken->Privileges[i++].Luid = SeTakeOwnershipPrivilege;
2040
2041 AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
2042 AccessToken->Privileges[i++].Luid = SeCreatePagefilePrivilege;
2043
2044 AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
2045 AccessToken->Privileges[i++].Luid = SeLockMemoryPrivilege;
2046
2047 AccessToken->Privileges[i].Attributes = 0;
2048 AccessToken->Privileges[i++].Luid = SeAssignPrimaryTokenPrivilege;
2049
2050 AccessToken->Privileges[i].Attributes = 0;
2051 AccessToken->Privileges[i++].Luid = SeIncreaseQuotaPrivilege;
2052
2053 AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
2054 AccessToken->Privileges[i++].Luid = SeIncreaseBasePriorityPrivilege;
2055
2056 AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
2057 AccessToken->Privileges[i++].Luid = SeCreatePermanentPrivilege;
2058
2059 AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
2060 AccessToken->Privileges[i++].Luid = SeDebugPrivilege;
2061
2062 AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
2063 AccessToken->Privileges[i++].Luid = SeAuditPrivilege;
2064
2065 AccessToken->Privileges[i].Attributes = 0;
2066 AccessToken->Privileges[i++].Luid = SeSecurityPrivilege;
2067
2068 AccessToken->Privileges[i].Attributes = 0;
2069 AccessToken->Privileges[i++].Luid = SeSystemEnvironmentPrivilege;
2070
2071 AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
2072 AccessToken->Privileges[i++].Luid = SeChangeNotifyPrivilege;
2073
2074 AccessToken->Privileges[i].Attributes = 0;
2075 AccessToken->Privileges[i++].Luid = SeBackupPrivilege;
2076
2077 AccessToken->Privileges[i].Attributes = 0;
2078 AccessToken->Privileges[i++].Luid = SeRestorePrivilege;
2079
2080 AccessToken->Privileges[i].Attributes = 0;
2081 AccessToken->Privileges[i++].Luid = SeShutdownPrivilege;
2082
2083 AccessToken->Privileges[i].Attributes = 0;
2084 AccessToken->Privileges[i++].Luid = SeLoadDriverPrivilege;
2085
2086 AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
2087 AccessToken->Privileges[i++].Luid = SeProfileSingleProcessPrivilege;
2088
2089 AccessToken->Privileges[i].Attributes = 0;
2090 AccessToken->Privileges[i++].Luid = SeSystemtimePrivilege;
2091 #if 0
2092 AccessToken->Privileges[i].Attributes = 0;
2093 AccessToken->Privileges[i++].Luid = SeUndockPrivilege;
2094
2095 AccessToken->Privileges[i].Attributes = 0;
2096 AccessToken->Privileges[i++].Luid = SeManageVolumePrivilege;
2097 #endif
2098
2099 ASSERT(i == 20);
2100
2101 uSize = sizeof(ACL);
2102 uSize += sizeof(ACE) + uLocalSystemLength;
2103 uSize += sizeof(ACE) + uAdminsLength;
2104 uSize = (uSize & (~3)) + 8;
2105 AccessToken->DefaultDacl =
2106 (PACL) ExAllocatePoolWithTag(PagedPool,
2107 uSize,
2108 TAG('T', 'O', 'K', 'd'));
2109 Status = RtlCreateAcl(AccessToken->DefaultDacl, uSize, ACL_REVISION);
2110 if ( NT_SUCCESS(Status) )
2111 {
2112 Status = RtlAddAccessAllowedAce(AccessToken->DefaultDacl, ACL_REVISION, GENERIC_ALL, SeLocalSystemSid);
2113 }
2114
2115 if ( NT_SUCCESS(Status) )
2116 {
2117 Status = RtlAddAccessAllowedAce(AccessToken->DefaultDacl, ACL_REVISION, GENERIC_READ|GENERIC_EXECUTE|READ_CONTROL, SeAliasAdminsSid);
2118 }
2119
2120 if ( ! NT_SUCCESS(Status) )
2121 {
2122 ObDereferenceObject(AccessToken);
2123 return NULL;
2124 }
2125
2126 return AccessToken;
2127 }
2128
2129
2130 NTSTATUS STDCALL
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 PTOKEN AccessToken;
2147 LUID TokenId;
2148 LUID ModifiedId;
2149 PVOID EndMem;
2150 ULONG uLength;
2151 ULONG i;
2152 KPROCESSOR_MODE PreviousMode;
2153 ULONG nTokenPrivileges = 0;
2154 LARGE_INTEGER LocalExpirationTime = {{0}};
2155 NTSTATUS Status = STATUS_SUCCESS;
2156
2157 PAGED_CODE();
2158
2159 PreviousMode = ExGetPreviousMode();
2160
2161 if(PreviousMode != KernelMode)
2162 {
2163 _SEH_TRY
2164 {
2165 ProbeForWriteHandle(TokenHandle);
2166 ProbeForRead(AuthenticationId,
2167 sizeof(LUID),
2168 sizeof(ULONG));
2169 LocalExpirationTime = ProbeForReadLargeInteger(ExpirationTime);
2170 ProbeForRead(TokenUser,
2171 sizeof(TOKEN_USER),
2172 sizeof(ULONG));
2173 ProbeForRead(TokenGroups,
2174 sizeof(TOKEN_GROUPS),
2175 sizeof(ULONG));
2176 ProbeForRead(TokenPrivileges,
2177 sizeof(TOKEN_PRIVILEGES),
2178 sizeof(ULONG));
2179 ProbeForRead(TokenOwner,
2180 sizeof(TOKEN_OWNER),
2181 sizeof(ULONG));
2182 ProbeForRead(TokenPrimaryGroup,
2183 sizeof(TOKEN_PRIMARY_GROUP),
2184 sizeof(ULONG));
2185 ProbeForRead(TokenDefaultDacl,
2186 sizeof(TOKEN_DEFAULT_DACL),
2187 sizeof(ULONG));
2188 ProbeForRead(TokenSource,
2189 sizeof(TOKEN_SOURCE),
2190 sizeof(ULONG));
2191 nTokenPrivileges = TokenPrivileges->PrivilegeCount;
2192 }
2193 _SEH_HANDLE
2194 {
2195 Status = _SEH_GetExceptionCode();
2196 }
2197 _SEH_END;
2198
2199 if(!NT_SUCCESS(Status))
2200 {
2201 return Status;
2202 }
2203 }
2204 else
2205 {
2206 nTokenPrivileges = TokenPrivileges->PrivilegeCount;
2207 LocalExpirationTime = *ExpirationTime;
2208 }
2209
2210 Status = ZwAllocateLocallyUniqueId(&TokenId);
2211 if (!NT_SUCCESS(Status))
2212 return(Status);
2213
2214 Status = ZwAllocateLocallyUniqueId(&ModifiedId);
2215 if (!NT_SUCCESS(Status))
2216 return(Status);
2217
2218 Status = ObCreateObject(PreviousMode,
2219 SepTokenObjectType,
2220 ObjectAttributes,
2221 PreviousMode,
2222 NULL,
2223 sizeof(TOKEN),
2224 0,
2225 0,
2226 (PVOID*)&AccessToken);
2227 if (!NT_SUCCESS(Status))
2228 {
2229 DPRINT1("ObCreateObject() failed (Status %lx)\n");
2230 return(Status);
2231 }
2232
2233 AccessToken->TokenLock = &SepTokenLock;
2234
2235 RtlCopyLuid(&AccessToken->TokenSource.SourceIdentifier,
2236 &TokenSource->SourceIdentifier);
2237 memcpy(AccessToken->TokenSource.SourceName,
2238 TokenSource->SourceName,
2239 sizeof(TokenSource->SourceName));
2240
2241 RtlCopyLuid(&AccessToken->TokenId, &TokenId);
2242 RtlCopyLuid(&AccessToken->AuthenticationId, AuthenticationId);
2243 AccessToken->ExpirationTime = *ExpirationTime;
2244 RtlCopyLuid(&AccessToken->ModifiedId, &ModifiedId);
2245
2246 AccessToken->UserAndGroupCount = TokenGroups->GroupCount + 1;
2247 AccessToken->PrivilegeCount = TokenPrivileges->PrivilegeCount;
2248 AccessToken->UserAndGroups = 0;
2249 AccessToken->Privileges = 0;
2250
2251 AccessToken->TokenType = TokenType;
2252 AccessToken->ImpersonationLevel = ((PSECURITY_QUALITY_OF_SERVICE)
2253 (ObjectAttributes->SecurityQualityOfService))->ImpersonationLevel;
2254
2255 /*
2256 * Normally we would just point these members into the variable information
2257 * area; however, our ObCreateObject() call can't allocate a variable information
2258 * area, so we allocate them seperately and provide a destroy function.
2259 */
2260
2261 uLength = sizeof(SID_AND_ATTRIBUTES) * AccessToken->UserAndGroupCount;
2262 uLength += RtlLengthSid(TokenUser->User.Sid);
2263 for (i = 0; i < TokenGroups->GroupCount; i++)
2264 uLength += RtlLengthSid(TokenGroups->Groups[i].Sid);
2265
2266 AccessToken->UserAndGroups =
2267 (PSID_AND_ATTRIBUTES)ExAllocatePoolWithTag(PagedPool,
2268 uLength,
2269 TAG('T', 'O', 'K', 'u'));
2270
2271 EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
2272
2273 Status = RtlCopySidAndAttributesArray(1,
2274 &TokenUser->User,
2275 uLength,
2276 AccessToken->UserAndGroups,
2277 EndMem,
2278 &EndMem,
2279 &uLength);
2280 if (NT_SUCCESS(Status))
2281 {
2282 Status = RtlCopySidAndAttributesArray(TokenGroups->GroupCount,
2283 TokenGroups->Groups,
2284 uLength,
2285 &AccessToken->UserAndGroups[1],
2286 EndMem,
2287 &EndMem,
2288 &uLength);
2289 }
2290
2291 if (NT_SUCCESS(Status))
2292 {
2293 Status = SepFindPrimaryGroupAndDefaultOwner(
2294 AccessToken,
2295 TokenPrimaryGroup->PrimaryGroup,
2296 TokenOwner->Owner);
2297 }
2298
2299 if (NT_SUCCESS(Status))
2300 {
2301 uLength = TokenPrivileges->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
2302 AccessToken->Privileges =
2303 (PLUID_AND_ATTRIBUTES)ExAllocatePoolWithTag(PagedPool,
2304 uLength,
2305 TAG('T', 'O', 'K', 'p'));
2306
2307 if (PreviousMode != KernelMode)
2308 {
2309 _SEH_TRY
2310 {
2311 RtlCopyMemory(AccessToken->Privileges,
2312 TokenPrivileges->Privileges,
2313 nTokenPrivileges * sizeof(LUID_AND_ATTRIBUTES));
2314 }
2315 _SEH_HANDLE
2316 {
2317 Status = _SEH_GetExceptionCode();
2318 }
2319 _SEH_END;
2320 }
2321 else
2322 {
2323 RtlCopyMemory(AccessToken->Privileges,
2324 TokenPrivileges->Privileges,
2325 nTokenPrivileges * sizeof(LUID_AND_ATTRIBUTES));
2326 }
2327 }
2328
2329 if (NT_SUCCESS(Status))
2330 {
2331 AccessToken->DefaultDacl =
2332 (PACL) ExAllocatePoolWithTag(PagedPool,
2333 TokenDefaultDacl->DefaultDacl->AclSize,
2334 TAG('T', 'O', 'K', 'd'));
2335 memcpy(AccessToken->DefaultDacl,
2336 TokenDefaultDacl->DefaultDacl,
2337 TokenDefaultDacl->DefaultDacl->AclSize);
2338 }
2339
2340 Status = ObInsertObject ((PVOID)AccessToken,
2341 NULL,
2342 DesiredAccess,
2343 0,
2344 NULL,
2345 &hToken);
2346 if (!NT_SUCCESS(Status))
2347 {
2348 DPRINT1("ObInsertObject() failed (Status %lx)\n", Status);
2349 }
2350
2351 if (NT_SUCCESS(Status))
2352 {
2353 _SEH_TRY
2354 {
2355 *TokenHandle = hToken;
2356 }
2357 _SEH_HANDLE
2358 {
2359 Status = _SEH_GetExceptionCode();
2360 }
2361 _SEH_END;
2362 }
2363
2364 return Status;
2365 }
2366
2367
2368 /*
2369 * @implemented
2370 */
2371 NTSTATUS STDCALL
2372 SeQueryAuthenticationIdToken(IN PACCESS_TOKEN Token,
2373 OUT PLUID LogonId)
2374 {
2375 PAGED_CODE();
2376
2377 *LogonId = ((PTOKEN)Token)->AuthenticationId;
2378
2379 return STATUS_SUCCESS;
2380 }
2381
2382
2383 /*
2384 * @implemented
2385 */
2386 SECURITY_IMPERSONATION_LEVEL
2387 STDCALL
2388 SeTokenImpersonationLevel(IN PACCESS_TOKEN Token)
2389 {
2390 PAGED_CODE();
2391
2392 return ((PTOKEN)Token)->ImpersonationLevel;
2393 }
2394
2395
2396 /*
2397 * @implemented
2398 */
2399 TOKEN_TYPE STDCALL
2400 SeTokenType(IN PACCESS_TOKEN Token)
2401 {
2402 PAGED_CODE();
2403
2404 return ((PTOKEN)Token)->TokenType;
2405 }
2406
2407
2408 /*
2409 * @implemented
2410 */
2411 BOOLEAN
2412 STDCALL
2413 SeTokenIsAdmin(
2414 IN PACCESS_TOKEN Token
2415 )
2416 {
2417 PAGED_CODE();
2418 return (((PTOKEN)Token)->TokenFlags & TOKEN_HAS_ADMIN_GROUP) != 0;
2419 }
2420
2421 /*
2422 * @implemented
2423 */
2424 BOOLEAN
2425 STDCALL
2426 SeTokenIsRestricted(
2427 IN PACCESS_TOKEN Token
2428 )
2429 {
2430 PAGED_CODE();
2431 return (((PTOKEN)Token)->TokenFlags & TOKEN_IS_RESTRICTED) != 0;
2432 }
2433
2434 /*
2435 * @implemented
2436 */
2437 BOOLEAN
2438 STDCALL
2439 SeTokenIsWriteRestricted(
2440 IN PACCESS_TOKEN Token
2441 )
2442 {
2443 PAGED_CODE();
2444 return (((PTOKEN)Token)->TokenFlags & TOKEN_HAS_RESTORE_PRIVILEGE) != 0;
2445 }
2446
2447
2448 /*
2449 * @unimplemented
2450 */
2451 NTSTATUS
2452 STDCALL
2453 NtImpersonateAnonymousToken(
2454 IN HANDLE Thread
2455 )
2456 {
2457 UNIMPLEMENTED;
2458 return STATUS_NOT_IMPLEMENTED;
2459 }
2460
2461
2462 /*
2463 * @implemented
2464 */
2465 NTSTATUS
2466 STDCALL
2467 NtOpenThreadTokenEx(IN HANDLE ThreadHandle,
2468 IN ACCESS_MASK DesiredAccess,
2469 IN BOOLEAN OpenAsSelf,
2470 IN ULONG HandleAttributes,
2471 OUT PHANDLE TokenHandle)
2472 {
2473 PETHREAD Thread;
2474 HANDLE hToken;
2475 PTOKEN Token, NewToken, PrimaryToken;
2476 BOOLEAN CopyOnOpen, EffectiveOnly;
2477 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
2478 SE_IMPERSONATION_STATE ImpersonationState;
2479 OBJECT_ATTRIBUTES ObjectAttributes;
2480 SECURITY_DESCRIPTOR SecurityDescriptor;
2481 PACL Dacl = NULL;
2482 KPROCESSOR_MODE PreviousMode;
2483 NTSTATUS Status = STATUS_SUCCESS;
2484
2485 PAGED_CODE();
2486
2487 PreviousMode = ExGetPreviousMode();
2488
2489 if(PreviousMode != KernelMode)
2490 {
2491 _SEH_TRY
2492 {
2493 ProbeForWriteHandle(TokenHandle);
2494 }
2495 _SEH_HANDLE
2496 {
2497 Status = _SEH_GetExceptionCode();
2498 }
2499 _SEH_END;
2500
2501 if(!NT_SUCCESS(Status))
2502 {
2503 return Status;
2504 }
2505 }
2506
2507 /*
2508 * At first open the thread token for information access and verify
2509 * that the token associated with thread is valid.
2510 */
2511
2512 Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_QUERY_INFORMATION,
2513 PsThreadType, PreviousMode, (PVOID*)&Thread,
2514 NULL);
2515 if (!NT_SUCCESS(Status))
2516 {
2517 return Status;
2518 }
2519
2520 Token = PsReferenceImpersonationToken(Thread, &CopyOnOpen, &EffectiveOnly,
2521 &ImpersonationLevel);
2522 if (Token == NULL)
2523 {
2524 ObfDereferenceObject(Thread);
2525 return STATUS_NO_TOKEN;
2526 }
2527
2528 ObDereferenceObject(Thread);
2529
2530 if (ImpersonationLevel == SecurityAnonymous)
2531 {
2532 ObfDereferenceObject(Token);
2533 return STATUS_CANT_OPEN_ANONYMOUS;
2534 }
2535
2536 /*
2537 * Revert to self if OpenAsSelf is specified.
2538 */
2539
2540 if (OpenAsSelf)
2541 {
2542 PsDisableImpersonation(PsGetCurrentThread(), &ImpersonationState);
2543 }
2544
2545 if (CopyOnOpen)
2546 {
2547 Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_ALL_ACCESS,
2548 PsThreadType, PreviousMode,
2549 (PVOID*)&Thread, NULL);
2550 if (!NT_SUCCESS(Status))
2551 {
2552 ObfDereferenceObject(Token);
2553 if (OpenAsSelf)
2554 {
2555 PsRestoreImpersonation(PsGetCurrentThread(), &ImpersonationState);
2556 }
2557 return Status;
2558 }
2559
2560 PrimaryToken = PsReferencePrimaryToken(Thread->ThreadsProcess);
2561 Status = SepCreateImpersonationTokenDacl(Token, PrimaryToken, &Dacl);
2562 KEBUGCHECK(0);
2563 ObfDereferenceObject(PrimaryToken);
2564 ObfDereferenceObject(Thread);
2565 if (!NT_SUCCESS(Status))
2566 {
2567 ObfDereferenceObject(Token);
2568 if (OpenAsSelf)
2569 {
2570 PsRestoreImpersonation(PsGetCurrentThread(), &ImpersonationState);
2571 }
2572 return Status;
2573 }
2574
2575 RtlCreateSecurityDescriptor(&SecurityDescriptor,
2576 SECURITY_DESCRIPTOR_REVISION);
2577 RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl,
2578 FALSE);
2579
2580 InitializeObjectAttributes(&ObjectAttributes, NULL, HandleAttributes,
2581 NULL, &SecurityDescriptor);
2582
2583 Status = SepDuplicateToken(Token, &ObjectAttributes, EffectiveOnly,
2584 TokenImpersonation, ImpersonationLevel,
2585 KernelMode, &NewToken);
2586 ExFreePool(Dacl);
2587 if (!NT_SUCCESS(Status))
2588 {
2589 ObfDereferenceObject(Token);
2590 if (OpenAsSelf)
2591 {
2592 PsRestoreImpersonation(PsGetCurrentThread(), &ImpersonationState);
2593 }
2594 return Status;
2595 }
2596
2597 Status = ObInsertObject(NewToken, NULL, DesiredAccess, 0, NULL,
2598 &hToken);
2599
2600 }
2601 else
2602 {
2603 Status = ObOpenObjectByPointer(Token, HandleAttributes,
2604 NULL, DesiredAccess, SepTokenObjectType,
2605 PreviousMode, &hToken);
2606 }
2607
2608 ObfDereferenceObject(Token);
2609
2610 if (OpenAsSelf)
2611 {
2612 PsRestoreImpersonation(PsGetCurrentThread(), &ImpersonationState);
2613 }
2614
2615 if(NT_SUCCESS(Status))
2616 {
2617 _SEH_TRY
2618 {
2619 *TokenHandle = hToken;
2620 }
2621 _SEH_HANDLE
2622 {
2623 Status = _SEH_GetExceptionCode();
2624 }
2625 _SEH_END;
2626 }
2627
2628 return Status;
2629 }
2630
2631 /*
2632 * @implemented
2633 */
2634 NTSTATUS STDCALL
2635 NtOpenThreadToken(IN HANDLE ThreadHandle,
2636 IN ACCESS_MASK DesiredAccess,
2637 IN BOOLEAN OpenAsSelf,
2638 OUT PHANDLE TokenHandle)
2639 {
2640 return NtOpenThreadTokenEx(ThreadHandle, DesiredAccess, OpenAsSelf, 0,
2641 TokenHandle);
2642 }
2643
2644 static NTSTATUS
2645 SepCompareTokens(IN PTOKEN FirstToken,
2646 IN PTOKEN SecondToken,
2647 OUT PBOOLEAN Equal)
2648 {
2649 BOOLEAN Restricted, IsEqual = FALSE;
2650
2651 ASSERT(FirstToken != SecondToken);
2652
2653 /* FIXME: Check if every SID that is present in either token is also present in the other one */
2654
2655 Restricted = SeTokenIsRestricted(FirstToken);
2656 if (Restricted == SeTokenIsRestricted(SecondToken))
2657 {
2658 if (Restricted)
2659 {
2660 /* FIXME: Check if every SID that is restricted in either token is also restricted in the other one */
2661 }
2662
2663 /* FIXME: Check if every privilege that is present in either token is also present in the other one */
2664 }
2665
2666 *Equal = IsEqual;
2667 return STATUS_SUCCESS;
2668 }
2669
2670 /*
2671 * @unimplemented
2672 */
2673 NTSTATUS
2674 NTAPI
2675 NtCompareTokens(IN HANDLE FirstTokenHandle,
2676 IN HANDLE SecondTokenHandle,
2677 OUT PBOOLEAN Equal)
2678 {
2679 KPROCESSOR_MODE PreviousMode;
2680 PTOKEN FirstToken, SecondToken;
2681 BOOLEAN IsEqual;
2682 NTSTATUS Status = STATUS_SUCCESS;
2683
2684 PAGED_CODE();
2685
2686 PreviousMode = ExGetPreviousMode();
2687
2688 if (PreviousMode != KernelMode)
2689 {
2690 _SEH_TRY
2691 {
2692 ProbeForWriteBoolean(Equal);
2693 }
2694 _SEH_HANDLE
2695 {
2696 Status = _SEH_GetExceptionCode();
2697 }
2698 _SEH_END;
2699
2700 if (!NT_SUCCESS(Status))
2701 return Status;
2702 }
2703
2704 Status = ObReferenceObjectByHandle(FirstTokenHandle,
2705 TOKEN_QUERY,
2706 SepTokenObjectType,
2707 PreviousMode,
2708 (PVOID*)&FirstToken,
2709 NULL);
2710 if (!NT_SUCCESS(Status))
2711 return Status;
2712
2713 Status = ObReferenceObjectByHandle(SecondTokenHandle,
2714 TOKEN_QUERY,
2715 SepTokenObjectType,
2716 PreviousMode,
2717 (PVOID*)&SecondToken,
2718 NULL);
2719 if (!NT_SUCCESS(Status))
2720 {
2721 ObDereferenceObject(FirstToken);
2722 return Status;
2723 }
2724
2725 if (FirstToken != SecondToken)
2726 {
2727 Status = SepCompareTokens(FirstToken,
2728 SecondToken,
2729 &IsEqual);
2730 }
2731 else
2732 IsEqual = TRUE;
2733
2734 ObDereferenceObject(FirstToken);
2735 ObDereferenceObject(SecondToken);
2736
2737 if (NT_SUCCESS(Status))
2738 {
2739 _SEH_TRY
2740 {
2741 *Equal = IsEqual;
2742 }
2743 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
2744 {
2745 Status = _SEH_GetExceptionCode();
2746 }
2747 _SEH_END;
2748 }
2749
2750 return Status;
2751 }
2752
2753 /* EOF */