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