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