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