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