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 #include <ntlsa.h> 21 22 typedef struct _TOKEN_AUDIT_POLICY_INFORMATION 23 { 24 ULONG PolicyCount; 25 struct 26 { 27 ULONG Category; 28 UCHAR Value; 29 } Policies[1]; 30 } TOKEN_AUDIT_POLICY_INFORMATION, *PTOKEN_AUDIT_POLICY_INFORMATION; 31 32 /* GLOBALS ********************************************************************/ 33 34 POBJECT_TYPE SeTokenObjectType = NULL; 35 ERESOURCE SepTokenLock; // FIXME: Global lock! 36 37 TOKEN_SOURCE SeSystemTokenSource = {"*SYSTEM*", {0}}; 38 LUID SeSystemAuthenticationId = SYSTEM_LUID; 39 LUID SeAnonymousAuthenticationId = ANONYMOUS_LOGON_LUID; 40 41 static GENERIC_MAPPING SepTokenMapping = { 42 TOKEN_READ, 43 TOKEN_WRITE, 44 TOKEN_EXECUTE, 45 TOKEN_ALL_ACCESS 46 }; 47 48 static const INFORMATION_CLASS_INFO SeTokenInformationClass[] = { 49 50 /* Class 0 not used, blame MS! */ 51 ICI_SQ_SAME( 0, 0, 0), 52 53 /* TokenUser */ 54 ICI_SQ_SAME( sizeof(TOKEN_USER), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ), 55 /* TokenGroups */ 56 ICI_SQ_SAME( sizeof(TOKEN_GROUPS), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ), 57 /* TokenPrivileges */ 58 ICI_SQ_SAME( sizeof(TOKEN_PRIVILEGES), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ), 59 /* TokenOwner */ 60 ICI_SQ_SAME( sizeof(TOKEN_OWNER), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET | ICIF_SET_SIZE_VARIABLE ), 61 /* TokenPrimaryGroup */ 62 ICI_SQ_SAME( sizeof(TOKEN_PRIMARY_GROUP), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET | ICIF_SET_SIZE_VARIABLE ), 63 /* TokenDefaultDacl */ 64 ICI_SQ_SAME( sizeof(TOKEN_DEFAULT_DACL), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET | ICIF_SET_SIZE_VARIABLE ), 65 /* TokenSource */ 66 ICI_SQ_SAME( sizeof(TOKEN_SOURCE), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ), 67 /* TokenType */ 68 ICI_SQ_SAME( sizeof(TOKEN_TYPE), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ), 69 /* TokenImpersonationLevel */ 70 ICI_SQ_SAME( sizeof(SECURITY_IMPERSONATION_LEVEL), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ), 71 /* TokenStatistics */ 72 ICI_SQ_SAME( sizeof(TOKEN_STATISTICS), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ), 73 /* TokenRestrictedSids */ 74 ICI_SQ_SAME( sizeof(TOKEN_GROUPS), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ), 75 /* TokenSessionId */ 76 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), 77 /* TokenGroupsAndPrivileges */ 78 ICI_SQ_SAME( sizeof(TOKEN_GROUPS_AND_PRIVILEGES), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ), 79 /* TokenSessionReference */ 80 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_SET | ICIF_QUERY_SIZE_VARIABLE ), 81 /* TokenSandBoxInert */ 82 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ), 83 /* TokenAuditPolicy */ 84 ICI_SQ_SAME( /* FIXME */0, sizeof(ULONG), ICIF_QUERY | ICIF_SET | ICIF_QUERY_SIZE_VARIABLE ), 85 /* TokenOrigin */ 86 ICI_SQ_SAME( sizeof(TOKEN_ORIGIN), sizeof(ULONG), ICIF_QUERY | ICIF_SET | ICIF_QUERY_SIZE_VARIABLE ), 87 }; 88 89 /* FUNCTIONS *****************************************************************/ 90 91 static NTSTATUS 92 SepCompareTokens(IN PTOKEN FirstToken, 93 IN PTOKEN SecondToken, 94 OUT PBOOLEAN Equal) 95 { 96 BOOLEAN Restricted, IsEqual = FALSE; 97 98 ASSERT(FirstToken != SecondToken); 99 100 /* Lock the tokens */ 101 SepAcquireTokenLockShared(FirstToken); 102 SepAcquireTokenLockShared(SecondToken); 103 104 /* FIXME: Check if every SID that is present in either token is also present in the other one */ 105 106 Restricted = SeTokenIsRestricted(FirstToken); 107 if (Restricted == SeTokenIsRestricted(SecondToken)) 108 { 109 if (Restricted) 110 { 111 /* FIXME: Check if every SID that is restricted in either token is also restricted in the other one */ 112 } 113 114 /* FIXME: Check if every privilege that is present in either token is also present in the other one */ 115 DPRINT1("FIXME: Pretending tokens are equal!\n"); 116 IsEqual = TRUE; 117 } 118 119 /* Unlock the tokens */ 120 SepReleaseTokenLock(SecondToken); 121 SepReleaseTokenLock(FirstToken); 122 123 *Equal = IsEqual; 124 return STATUS_SUCCESS; 125 } 126 127 static 128 VOID 129 SepUpdateSinglePrivilegeFlagToken( 130 _Inout_ PTOKEN Token, 131 _In_ ULONG Index) 132 { 133 ULONG TokenFlag; 134 ASSERT(Index < Token->PrivilegeCount); 135 136 /* The high part of all values we are interested in is 0 */ 137 if (Token->Privileges[Index].Luid.HighPart != 0) 138 { 139 return; 140 } 141 142 /* Check for certain privileges to update flags */ 143 if (Token->Privileges[Index].Luid.LowPart == SE_CHANGE_NOTIFY_PRIVILEGE) 144 { 145 TokenFlag = TOKEN_HAS_TRAVERSE_PRIVILEGE; 146 } 147 else if (Token->Privileges[Index].Luid.LowPart == SE_BACKUP_PRIVILEGE) 148 { 149 TokenFlag = TOKEN_HAS_BACKUP_PRIVILEGE; 150 } 151 else if (Token->Privileges[Index].Luid.LowPart == SE_RESTORE_PRIVILEGE) 152 { 153 TokenFlag = TOKEN_HAS_RESTORE_PRIVILEGE; 154 } 155 else if (Token->Privileges[Index].Luid.LowPart == SE_IMPERSONATE_PRIVILEGE) 156 { 157 TokenFlag = TOKEN_HAS_IMPERSONATE_PRIVILEGE; 158 } 159 else 160 { 161 /* Nothing to do */ 162 return; 163 } 164 165 /* Check if the specified privilege is enabled */ 166 if (Token->Privileges[Index].Attributes & SE_PRIVILEGE_ENABLED) 167 { 168 /* It is enabled, so set the flag */ 169 Token->TokenFlags |= TokenFlag; 170 } 171 else 172 { 173 /* Is is disabled, so remove the flag */ 174 Token->TokenFlags &= ~TokenFlag; 175 } 176 } 177 178 static 179 VOID 180 SepUpdatePrivilegeFlagsToken( 181 _Inout_ PTOKEN Token) 182 { 183 ULONG i; 184 185 /* Loop all privileges */ 186 for (i = 0; i < Token->PrivilegeCount; i++) 187 { 188 /* Updates the flags dor this privilege */ 189 SepUpdateSinglePrivilegeFlagToken(Token, i); 190 } 191 } 192 193 static 194 VOID 195 SepRemovePrivilegeToken( 196 _Inout_ PTOKEN Token, 197 _In_ ULONG Index) 198 { 199 ULONG MoveCount; 200 ASSERT(Index < Token->PrivilegeCount); 201 202 /* Calculate the number of trailing privileges */ 203 MoveCount = Token->PrivilegeCount - Index - 1; 204 if (MoveCount != 0) 205 { 206 /* Move them one location ahead */ 207 RtlMoveMemory(&Token->Privileges[Index], 208 &Token->Privileges[Index + 1], 209 MoveCount * sizeof(LUID_AND_ATTRIBUTES)); 210 } 211 212 /* Update privilege count */ 213 Token->PrivilegeCount--; 214 } 215 216 VOID 217 NTAPI 218 SepFreeProxyData(PVOID ProxyData) 219 { 220 UNIMPLEMENTED; 221 } 222 223 NTSTATUS 224 NTAPI 225 SepCopyProxyData(PVOID* Dest, 226 PVOID Src) 227 { 228 UNIMPLEMENTED; 229 return STATUS_NOT_IMPLEMENTED; 230 } 231 232 NTSTATUS 233 NTAPI 234 SeExchangePrimaryToken( 235 _In_ PEPROCESS Process, 236 _In_ PACCESS_TOKEN NewAccessToken, 237 _Out_ PACCESS_TOKEN* OldAccessToken) 238 { 239 PTOKEN OldToken; 240 PTOKEN NewToken = (PTOKEN)NewAccessToken; 241 242 PAGED_CODE(); 243 244 if (NewToken->TokenType != TokenPrimary) 245 return STATUS_BAD_TOKEN_TYPE; 246 247 if (NewToken->TokenInUse) 248 { 249 BOOLEAN IsEqual; 250 NTSTATUS Status; 251 252 /* Maybe we're trying to set the same token */ 253 OldToken = PsReferencePrimaryToken(Process); 254 if (OldToken == NewToken) 255 { 256 /* So it's a nop. */ 257 *OldAccessToken = OldToken; 258 return STATUS_SUCCESS; 259 } 260 261 Status = SepCompareTokens(OldToken, NewToken, &IsEqual); 262 if (!NT_SUCCESS(Status)) 263 { 264 PsDereferencePrimaryToken(OldToken); 265 *OldAccessToken = NULL; 266 return Status; 267 } 268 269 if (!IsEqual) 270 { 271 PsDereferencePrimaryToken(OldToken); 272 *OldAccessToken = NULL; 273 return STATUS_TOKEN_ALREADY_IN_USE; 274 } 275 /* Silently return STATUS_SUCCESS but do not set the new token, 276 * as it's already in use elsewhere. */ 277 *OldAccessToken = OldToken; 278 return STATUS_SUCCESS; 279 } 280 281 /* Lock the new token */ 282 SepAcquireTokenLockExclusive(NewToken); 283 284 /* Mark new token in use */ 285 NewToken->TokenInUse = TRUE; 286 287 // TODO: Set a correct SessionId for NewToken 288 289 /* Unlock the new token */ 290 SepReleaseTokenLock(NewToken); 291 292 /* Reference the new token */ 293 ObReferenceObject(NewToken); 294 295 /* Replace the old with the new */ 296 OldToken = ObFastReplaceObject(&Process->Token, NewToken); 297 298 /* Lock the old token */ 299 SepAcquireTokenLockExclusive(OldToken); 300 301 /* Mark the old token as free */ 302 OldToken->TokenInUse = FALSE; 303 304 /* Unlock the old token */ 305 SepReleaseTokenLock(OldToken); 306 307 *OldAccessToken = (PACCESS_TOKEN)OldToken; 308 return STATUS_SUCCESS; 309 } 310 311 VOID 312 NTAPI 313 SeDeassignPrimaryToken(PEPROCESS Process) 314 { 315 PTOKEN OldToken; 316 317 /* Remove the Token */ 318 OldToken = ObFastReplaceObject(&Process->Token, NULL); 319 320 /* Mark the Old Token as free */ 321 OldToken->TokenInUse = FALSE; 322 323 /* Dereference the Token */ 324 ObDereferenceObject(OldToken); 325 } 326 327 static ULONG 328 RtlLengthSidAndAttributes(ULONG Count, 329 PSID_AND_ATTRIBUTES Src) 330 { 331 ULONG i; 332 ULONG uLength; 333 334 PAGED_CODE(); 335 336 uLength = Count * sizeof(SID_AND_ATTRIBUTES); 337 for (i = 0; i < Count; i++) 338 uLength += RtlLengthSid(Src[i].Sid); 339 340 return uLength; 341 } 342 343 344 static NTSTATUS 345 SepFindPrimaryGroupAndDefaultOwner( 346 _In_ PTOKEN Token, 347 _In_ PSID PrimaryGroup, 348 _In_opt_ PSID DefaultOwner, 349 _Out_opt_ PULONG PrimaryGroupIndex, 350 _Out_opt_ PULONG DefaultOwnerIndex) 351 { 352 ULONG i; 353 354 /* We should return at least a search result */ 355 if (!PrimaryGroupIndex && !DefaultOwnerIndex) 356 return STATUS_INVALID_PARAMETER; 357 358 if (PrimaryGroupIndex) 359 { 360 /* Initialize with an invalid index */ 361 // Token->PrimaryGroup = NULL; 362 *PrimaryGroupIndex = Token->UserAndGroupCount; 363 } 364 365 if (DefaultOwnerIndex) 366 { 367 if (DefaultOwner) 368 { 369 /* An owner is specified: check whether this is actually the user */ 370 if (RtlEqualSid(Token->UserAndGroups[0].Sid, DefaultOwner)) 371 { 372 /* 373 * It's the user (first element in array): set it 374 * as the owner and stop the search for it. 375 */ 376 *DefaultOwnerIndex = 0; 377 DefaultOwnerIndex = NULL; 378 } 379 else 380 { 381 /* An owner is specified: initialize with an invalid index */ 382 *DefaultOwnerIndex = Token->UserAndGroupCount; 383 } 384 } 385 else 386 { 387 /* 388 * No owner specified: set the user (first element in array) 389 * as the owner and stop the search for it. 390 */ 391 *DefaultOwnerIndex = 0; 392 DefaultOwnerIndex = NULL; 393 } 394 } 395 396 /* Validate and set the primary group and default owner indices */ 397 for (i = 0; i < Token->UserAndGroupCount; i++) 398 { 399 /* Stop the search if we have found what we searched for */ 400 if (!PrimaryGroupIndex && !DefaultOwnerIndex) 401 break; 402 403 if (DefaultOwnerIndex && DefaultOwner && 404 RtlEqualSid(Token->UserAndGroups[i].Sid, DefaultOwner) && 405 (Token->UserAndGroups[i].Attributes & SE_GROUP_OWNER)) 406 { 407 /* Owner is found, stop the search for it */ 408 *DefaultOwnerIndex = i; 409 DefaultOwnerIndex = NULL; 410 } 411 412 if (PrimaryGroupIndex && 413 RtlEqualSid(Token->UserAndGroups[i].Sid, PrimaryGroup)) 414 { 415 /* Primary group is found, stop the search for it */ 416 // Token->PrimaryGroup = Token->UserAndGroups[i].Sid; 417 *PrimaryGroupIndex = i; 418 PrimaryGroupIndex = NULL; 419 } 420 } 421 422 if (DefaultOwnerIndex) 423 { 424 if (*DefaultOwnerIndex == Token->UserAndGroupCount) 425 return STATUS_INVALID_OWNER; 426 } 427 428 if (PrimaryGroupIndex) 429 { 430 if (*PrimaryGroupIndex == Token->UserAndGroupCount) 431 // if (Token->PrimaryGroup == NULL) 432 return STATUS_INVALID_PRIMARY_GROUP; 433 } 434 435 return STATUS_SUCCESS; 436 } 437 438 439 NTSTATUS 440 NTAPI 441 SepDuplicateToken( 442 _In_ PTOKEN Token, 443 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, 444 _In_ BOOLEAN EffectiveOnly, 445 _In_ TOKEN_TYPE TokenType, 446 _In_ SECURITY_IMPERSONATION_LEVEL Level, 447 _In_ KPROCESSOR_MODE PreviousMode, 448 _Out_ PTOKEN* NewAccessToken) 449 { 450 NTSTATUS Status; 451 PTOKEN AccessToken; 452 PVOID EndMem; 453 ULONG VariableLength; 454 ULONG TotalSize; 455 456 PAGED_CODE(); 457 458 /* Compute how much size we need to allocate for the token */ 459 VariableLength = Token->VariableLength; 460 TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength; 461 462 Status = ObCreateObject(PreviousMode, 463 SeTokenObjectType, 464 ObjectAttributes, 465 PreviousMode, 466 NULL, 467 TotalSize, 468 0, 469 0, 470 (PVOID*)&AccessToken); 471 if (!NT_SUCCESS(Status)) 472 { 473 DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status); 474 return Status; 475 } 476 477 /* Zero out the buffer and initialize the token */ 478 RtlZeroMemory(AccessToken, TotalSize); 479 480 ExAllocateLocallyUniqueId(&AccessToken->TokenId); 481 482 AccessToken->TokenType = TokenType; 483 AccessToken->ImpersonationLevel = Level; 484 485 AccessToken->TokenLock = &SepTokenLock; // FIXME: Global lock! 486 487 /* Copy the immutable fields */ 488 RtlCopyLuid(&AccessToken->TokenSource.SourceIdentifier, 489 &Token->TokenSource.SourceIdentifier); 490 RtlCopyMemory(AccessToken->TokenSource.SourceName, 491 Token->TokenSource.SourceName, 492 sizeof(Token->TokenSource.SourceName)); 493 494 AccessToken->AuthenticationId = Token->AuthenticationId; 495 AccessToken->ParentTokenId = Token->ParentTokenId; 496 AccessToken->ExpirationTime = Token->ExpirationTime; 497 AccessToken->OriginatingLogonSession = Token->OriginatingLogonSession; 498 499 500 /* Lock the source token and copy the mutable fields */ 501 SepAcquireTokenLockExclusive(Token); 502 503 AccessToken->SessionId = Token->SessionId; 504 RtlCopyLuid(&AccessToken->ModifiedId, &Token->ModifiedId); 505 506 AccessToken->TokenFlags = Token->TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED; 507 508 /* Copy and reference the logon session */ 509 // RtlCopyLuid(&AccessToken->AuthenticationId, &Token->AuthenticationId); 510 Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId); 511 if (!NT_SUCCESS(Status)) 512 { 513 /* No logon session could be found, bail out */ 514 DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n", Status); 515 /* Set the flag for proper cleanup by the delete procedure */ 516 AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED; 517 goto Quit; 518 } 519 520 /* Assign the data that reside in the TOKEN's variable information area */ 521 AccessToken->VariableLength = VariableLength; 522 EndMem = (PVOID)&AccessToken->VariablePart; 523 524 /* Copy the privileges */ 525 AccessToken->PrivilegeCount = 0; 526 AccessToken->Privileges = NULL; 527 if (Token->Privileges && (Token->PrivilegeCount > 0)) 528 { 529 ULONG PrivilegesLength = Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES); 530 PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID)); 531 532 ASSERT(VariableLength >= PrivilegesLength); 533 534 AccessToken->PrivilegeCount = Token->PrivilegeCount; 535 AccessToken->Privileges = EndMem; 536 EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength); 537 VariableLength -= PrivilegesLength; 538 539 RtlCopyMemory(AccessToken->Privileges, 540 Token->Privileges, 541 AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)); 542 } 543 544 /* Copy the user and groups */ 545 AccessToken->UserAndGroupCount = 0; 546 AccessToken->UserAndGroups = NULL; 547 if (Token->UserAndGroups && (Token->UserAndGroupCount > 0)) 548 { 549 AccessToken->UserAndGroupCount = Token->UserAndGroupCount; 550 AccessToken->UserAndGroups = EndMem; 551 EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount]; 552 VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups); 553 554 Status = RtlCopySidAndAttributesArray(AccessToken->UserAndGroupCount, 555 Token->UserAndGroups, 556 VariableLength, 557 AccessToken->UserAndGroups, 558 EndMem, 559 &EndMem, 560 &VariableLength); 561 if (!NT_SUCCESS(Status)) 562 { 563 DPRINT1("RtlCopySidAndAttributesArray(UserAndGroups) failed (Status 0x%lx)\n", Status); 564 goto Quit; 565 } 566 } 567 568 #if 1 569 { 570 ULONG PrimaryGroupIndex; 571 572 /* Find the token primary group */ 573 Status = SepFindPrimaryGroupAndDefaultOwner(AccessToken, 574 Token->PrimaryGroup, 575 NULL, 576 &PrimaryGroupIndex, 577 NULL); 578 if (!NT_SUCCESS(Status)) 579 { 580 DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n", Status); 581 goto Quit; 582 } 583 AccessToken->PrimaryGroup = AccessToken->UserAndGroups[PrimaryGroupIndex].Sid; 584 } 585 #else 586 AccessToken->PrimaryGroup = (PVOID)((ULONG_PTR)AccessToken + (ULONG_PTR)Token->PrimaryGroup - (ULONG_PTR)Token->UserAndGroups); 587 #endif 588 AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex; 589 590 /* Copy the restricted SIDs */ 591 AccessToken->RestrictedSidCount = 0; 592 AccessToken->RestrictedSids = NULL; 593 if (Token->RestrictedSids && (Token->RestrictedSidCount > 0)) 594 { 595 AccessToken->RestrictedSidCount = Token->RestrictedSidCount; 596 AccessToken->RestrictedSids = EndMem; 597 EndMem = &AccessToken->RestrictedSids[AccessToken->RestrictedSidCount]; 598 VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->RestrictedSids); 599 600 Status = RtlCopySidAndAttributesArray(AccessToken->RestrictedSidCount, 601 Token->RestrictedSids, 602 VariableLength, 603 AccessToken->RestrictedSids, 604 EndMem, 605 &EndMem, 606 &VariableLength); 607 if (!NT_SUCCESS(Status)) 608 { 609 DPRINT1("RtlCopySidAndAttributesArray(RestrictedSids) failed (Status 0x%lx)\n", Status); 610 goto Quit; 611 } 612 } 613 614 615 // 616 // FIXME: Implement the "EffectiveOnly" option, that removes all 617 // the disabled parts (privileges and groups) of the token. 618 // 619 620 621 // 622 // NOTE: So far our dynamic area only contains 623 // the default dacl, so this makes the following 624 // code pretty simple. The day where it stores 625 // other data, the code will require adaptations. 626 // 627 628 /* Now allocate the TOKEN's dynamic information area and set the data */ 629 AccessToken->DynamicAvailable = 0; // Unused memory in the dynamic area. 630 AccessToken->DynamicPart = NULL; 631 if (Token->DynamicPart && Token->DefaultDacl) 632 { 633 AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool, 634 Token->DefaultDacl->AclSize, 635 TAG_TOKEN_DYNAMIC); 636 if (AccessToken->DynamicPart == NULL) 637 { 638 Status = STATUS_INSUFFICIENT_RESOURCES; 639 goto Quit; 640 } 641 EndMem = (PVOID)AccessToken->DynamicPart; 642 643 AccessToken->DefaultDacl = EndMem; 644 645 RtlCopyMemory(AccessToken->DefaultDacl, 646 Token->DefaultDacl, 647 Token->DefaultDacl->AclSize); 648 } 649 650 /* Unlock the source token */ 651 SepReleaseTokenLock(Token); 652 653 /* Return the token */ 654 *NewAccessToken = AccessToken; 655 Status = STATUS_SUCCESS; 656 657 Quit: 658 if (!NT_SUCCESS(Status)) 659 { 660 /* Unlock the source token */ 661 SepReleaseTokenLock(Token); 662 663 /* Dereference the token, the delete procedure will clean it up */ 664 ObDereferenceObject(AccessToken); 665 } 666 667 return Status; 668 } 669 670 NTSTATUS 671 NTAPI 672 SeSubProcessToken(IN PTOKEN ParentToken, 673 OUT PTOKEN *Token, 674 IN BOOLEAN InUse, 675 IN ULONG SessionId) 676 { 677 PTOKEN NewToken; 678 OBJECT_ATTRIBUTES ObjectAttributes; 679 NTSTATUS Status; 680 681 /* Initialize the attributes and duplicate it */ 682 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); 683 Status = SepDuplicateToken(ParentToken, 684 &ObjectAttributes, 685 FALSE, 686 TokenPrimary, 687 ParentToken->ImpersonationLevel, 688 KernelMode, 689 &NewToken); 690 if (NT_SUCCESS(Status)) 691 { 692 /* Insert it */ 693 Status = ObInsertObject(NewToken, 694 NULL, 695 0, 696 0, 697 NULL, 698 NULL); 699 if (NT_SUCCESS(Status)) 700 { 701 /* Set the session ID */ 702 NewToken->SessionId = SessionId; 703 NewToken->TokenInUse = InUse; 704 705 /* Return the token */ 706 *Token = NewToken; 707 } 708 } 709 710 /* Return status */ 711 return Status; 712 } 713 714 NTSTATUS 715 NTAPI 716 SeIsTokenChild(IN PTOKEN Token, 717 OUT PBOOLEAN IsChild) 718 { 719 PTOKEN ProcessToken; 720 LUID ProcessTokenId, CallerParentId; 721 722 /* Assume failure */ 723 *IsChild = FALSE; 724 725 /* Reference the process token */ 726 ProcessToken = PsReferencePrimaryToken(PsGetCurrentProcess()); 727 if (!ProcessToken) 728 return STATUS_UNSUCCESSFUL; 729 730 /* Get its token ID */ 731 ProcessTokenId = ProcessToken->TokenId; 732 733 /* Dereference the token */ 734 ObFastDereferenceObject(&PsGetCurrentProcess()->Token, ProcessToken); 735 736 /* Get our parent token ID */ 737 CallerParentId = Token->ParentTokenId; 738 739 /* Compare the token IDs */ 740 if (RtlEqualLuid(&CallerParentId, &ProcessTokenId)) 741 *IsChild = TRUE; 742 743 /* Return success */ 744 return STATUS_SUCCESS; 745 } 746 747 NTSTATUS 748 NTAPI 749 SeIsTokenSibling(IN PTOKEN Token, 750 OUT PBOOLEAN IsSibling) 751 { 752 PTOKEN ProcessToken; 753 LUID ProcessParentId, ProcessAuthId; 754 LUID CallerParentId, CallerAuthId; 755 756 /* Assume failure */ 757 *IsSibling = FALSE; 758 759 /* Reference the process token */ 760 ProcessToken = PsReferencePrimaryToken(PsGetCurrentProcess()); 761 if (!ProcessToken) 762 return STATUS_UNSUCCESSFUL; 763 764 /* Get its parent and authentication IDs */ 765 ProcessParentId = ProcessToken->ParentTokenId; 766 ProcessAuthId = ProcessToken->AuthenticationId; 767 768 /* Dereference the token */ 769 ObFastDereferenceObject(&PsGetCurrentProcess()->Token, ProcessToken); 770 771 /* Get our parent and authentication IDs */ 772 CallerParentId = Token->ParentTokenId; 773 CallerAuthId = Token->AuthenticationId; 774 775 /* Compare the token IDs */ 776 if (RtlEqualLuid(&CallerParentId, &ProcessParentId) && 777 RtlEqualLuid(&CallerAuthId, &ProcessAuthId)) 778 { 779 *IsSibling = TRUE; 780 } 781 782 /* Return success */ 783 return STATUS_SUCCESS; 784 } 785 786 NTSTATUS 787 NTAPI 788 SeCopyClientToken(IN PACCESS_TOKEN Token, 789 IN SECURITY_IMPERSONATION_LEVEL Level, 790 IN KPROCESSOR_MODE PreviousMode, 791 OUT PACCESS_TOKEN* NewToken) 792 { 793 NTSTATUS Status; 794 OBJECT_ATTRIBUTES ObjectAttributes; 795 796 PAGED_CODE(); 797 798 InitializeObjectAttributes(&ObjectAttributes, 799 NULL, 800 0, 801 NULL, 802 NULL); 803 804 Status = SepDuplicateToken(Token, 805 &ObjectAttributes, 806 FALSE, 807 TokenImpersonation, 808 Level, 809 PreviousMode, 810 (PTOKEN*)NewToken); 811 812 return Status; 813 } 814 815 VOID 816 NTAPI 817 SepDeleteToken(PVOID ObjectBody) 818 { 819 PTOKEN AccessToken = (PTOKEN)ObjectBody; 820 821 DPRINT("SepDeleteToken()\n"); 822 823 /* Dereference the logon session */ 824 if ((AccessToken->TokenFlags & TOKEN_SESSION_NOT_REFERENCED) == 0) 825 SepRmDereferenceLogonSession(&AccessToken->AuthenticationId); 826 827 /* Delete the dynamic information area */ 828 if (AccessToken->DynamicPart) 829 ExFreePoolWithTag(AccessToken->DynamicPart, TAG_TOKEN_DYNAMIC); 830 } 831 832 833 VOID 834 INIT_FUNCTION 835 NTAPI 836 SepInitializeTokenImplementation(VOID) 837 { 838 UNICODE_STRING Name; 839 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; 840 841 ExInitializeResource(&SepTokenLock); // FIXME: Global lock! 842 843 DPRINT("Creating Token Object Type\n"); 844 845 /* Initialize the Token type */ 846 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); 847 RtlInitUnicodeString(&Name, L"Token"); 848 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); 849 ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK; 850 ObjectTypeInitializer.SecurityRequired = TRUE; 851 ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(TOKEN); 852 ObjectTypeInitializer.GenericMapping = SepTokenMapping; 853 ObjectTypeInitializer.PoolType = PagedPool; 854 ObjectTypeInitializer.ValidAccessMask = TOKEN_ALL_ACCESS; 855 ObjectTypeInitializer.UseDefaultObject = TRUE; 856 ObjectTypeInitializer.DeleteProcedure = SepDeleteToken; 857 ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &SeTokenObjectType); 858 } 859 860 VOID 861 NTAPI 862 SeAssignPrimaryToken(IN PEPROCESS Process, 863 IN PTOKEN Token) 864 { 865 PAGED_CODE(); 866 867 /* Sanity checks */ 868 ASSERT(Token->TokenType == TokenPrimary); 869 ASSERT(!Token->TokenInUse); 870 871 /* Clean any previous token */ 872 if (Process->Token.Object) SeDeassignPrimaryToken(Process); 873 874 /* Set the new token */ 875 ObReferenceObject(Token); 876 Token->TokenInUse = TRUE; 877 ObInitializeFastReference(&Process->Token, Token); 878 } 879 880 NTSTATUS 881 NTAPI 882 SepCreateToken( 883 _Out_ PHANDLE TokenHandle, 884 _In_ KPROCESSOR_MODE PreviousMode, 885 _In_ ACCESS_MASK DesiredAccess, 886 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, 887 _In_ TOKEN_TYPE TokenType, 888 _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, 889 _In_ PLUID AuthenticationId, 890 _In_ PLARGE_INTEGER ExpirationTime, 891 _In_ PSID_AND_ATTRIBUTES User, 892 _In_ ULONG GroupCount, 893 _In_ PSID_AND_ATTRIBUTES Groups, 894 _In_ ULONG GroupsLength, 895 _In_ ULONG PrivilegeCount, 896 _In_ PLUID_AND_ATTRIBUTES Privileges, 897 _In_opt_ PSID Owner, 898 _In_ PSID PrimaryGroup, 899 _In_opt_ PACL DefaultDacl, 900 _In_ PTOKEN_SOURCE TokenSource, 901 _In_ BOOLEAN SystemToken) 902 { 903 NTSTATUS Status; 904 PTOKEN AccessToken; 905 ULONG TokenFlags = 0; 906 ULONG PrimaryGroupIndex, DefaultOwnerIndex; 907 LUID TokenId; 908 LUID ModifiedId; 909 PVOID EndMem; 910 ULONG PrivilegesLength; 911 ULONG UserGroupsLength; 912 ULONG VariableLength; 913 ULONG TotalSize; 914 ULONG i; 915 916 PAGED_CODE(); 917 918 /* Loop all groups */ 919 for (i = 0; i < GroupCount; i++) 920 { 921 /* Check for mandatory groups */ 922 if (Groups[i].Attributes & SE_GROUP_MANDATORY) 923 { 924 /* Force them to be enabled */ 925 Groups[i].Attributes |= (SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT); 926 } 927 928 /* Check of the group is an admin group */ 929 if (RtlEqualSid(SeAliasAdminsSid, Groups[i].Sid)) 930 { 931 /* Remember this so we can optimize queries later */ 932 TokenFlags |= TOKEN_HAS_ADMIN_GROUP; 933 } 934 } 935 936 /* Allocate unique IDs for the token */ 937 ExAllocateLocallyUniqueId(&TokenId); 938 ExAllocateLocallyUniqueId(&ModifiedId); 939 940 /* Compute how much size we need to allocate for the token */ 941 942 /* Privileges size */ 943 PrivilegesLength = PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES); 944 PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID)); 945 946 /* User and groups size */ 947 UserGroupsLength = (1 + GroupCount) * sizeof(SID_AND_ATTRIBUTES); 948 UserGroupsLength += RtlLengthSid(User->Sid); 949 for (i = 0; i < GroupCount; i++) 950 { 951 UserGroupsLength += RtlLengthSid(Groups[i].Sid); 952 } 953 UserGroupsLength = ALIGN_UP_BY(UserGroupsLength, sizeof(PVOID)); 954 955 /* Add the additional groups array length */ 956 UserGroupsLength += ALIGN_UP_BY(GroupsLength, sizeof(PVOID)); 957 958 VariableLength = PrivilegesLength + UserGroupsLength; 959 TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength; 960 961 Status = ObCreateObject(PreviousMode, 962 SeTokenObjectType, 963 ObjectAttributes, 964 PreviousMode, 965 NULL, 966 TotalSize, 967 0, 968 0, 969 (PVOID*)&AccessToken); 970 if (!NT_SUCCESS(Status)) 971 { 972 DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status); 973 return Status; 974 } 975 976 /* Zero out the buffer and initialize the token */ 977 RtlZeroMemory(AccessToken, TotalSize); 978 979 RtlCopyLuid(&AccessToken->TokenId, &TokenId); 980 981 AccessToken->TokenType = TokenType; 982 AccessToken->ImpersonationLevel = ImpersonationLevel; 983 984 AccessToken->TokenLock = &SepTokenLock; // FIXME: Global lock! 985 986 RtlCopyLuid(&AccessToken->TokenSource.SourceIdentifier, 987 &TokenSource->SourceIdentifier); 988 RtlCopyMemory(AccessToken->TokenSource.SourceName, 989 TokenSource->SourceName, 990 sizeof(TokenSource->SourceName)); 991 992 AccessToken->ExpirationTime = *ExpirationTime; 993 RtlCopyLuid(&AccessToken->ModifiedId, &ModifiedId); 994 995 AccessToken->TokenFlags = TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED; 996 997 /* Copy and reference the logon session */ 998 RtlCopyLuid(&AccessToken->AuthenticationId, AuthenticationId); 999 Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId); 1000 if (!NT_SUCCESS(Status)) 1001 { 1002 /* No logon session could be found, bail out */ 1003 DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n", Status); 1004 /* Set the flag for proper cleanup by the delete procedure */ 1005 AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED; 1006 goto Quit; 1007 } 1008 1009 /* Assign the data that reside in the TOKEN's variable information area */ 1010 AccessToken->VariableLength = VariableLength; 1011 EndMem = (PVOID)&AccessToken->VariablePart; 1012 1013 /* Copy the privileges */ 1014 AccessToken->PrivilegeCount = PrivilegeCount; 1015 AccessToken->Privileges = NULL; 1016 if (PrivilegeCount > 0) 1017 { 1018 AccessToken->Privileges = EndMem; 1019 EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength); 1020 VariableLength -= PrivilegesLength; 1021 1022 if (PreviousMode != KernelMode) 1023 { 1024 _SEH2_TRY 1025 { 1026 RtlCopyMemory(AccessToken->Privileges, 1027 Privileges, 1028 PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)); 1029 } 1030 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1031 { 1032 Status = _SEH2_GetExceptionCode(); 1033 } 1034 _SEH2_END; 1035 } 1036 else 1037 { 1038 RtlCopyMemory(AccessToken->Privileges, 1039 Privileges, 1040 PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)); 1041 } 1042 1043 if (!NT_SUCCESS(Status)) 1044 goto Quit; 1045 } 1046 1047 /* Update the privilege flags */ 1048 SepUpdatePrivilegeFlagsToken(AccessToken); 1049 1050 /* Copy the user and groups */ 1051 AccessToken->UserAndGroupCount = 1 + GroupCount; 1052 AccessToken->UserAndGroups = EndMem; 1053 EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount]; 1054 VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups); 1055 1056 Status = RtlCopySidAndAttributesArray(1, 1057 User, 1058 VariableLength, 1059 &AccessToken->UserAndGroups[0], 1060 EndMem, 1061 &EndMem, 1062 &VariableLength); 1063 if (!NT_SUCCESS(Status)) 1064 goto Quit; 1065 1066 Status = RtlCopySidAndAttributesArray(GroupCount, 1067 Groups, 1068 VariableLength, 1069 &AccessToken->UserAndGroups[1], 1070 EndMem, 1071 &EndMem, 1072 &VariableLength); 1073 if (!NT_SUCCESS(Status)) 1074 goto Quit; 1075 1076 /* Find the token primary group and default owner */ 1077 Status = SepFindPrimaryGroupAndDefaultOwner(AccessToken, 1078 PrimaryGroup, 1079 Owner, 1080 &PrimaryGroupIndex, 1081 &DefaultOwnerIndex); 1082 if (!NT_SUCCESS(Status)) 1083 { 1084 DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n", Status); 1085 goto Quit; 1086 } 1087 1088 AccessToken->PrimaryGroup = AccessToken->UserAndGroups[PrimaryGroupIndex].Sid; 1089 AccessToken->DefaultOwnerIndex = DefaultOwnerIndex; 1090 1091 /* Now allocate the TOKEN's dynamic information area and set the data */ 1092 AccessToken->DynamicAvailable = 0; // Unused memory in the dynamic area. 1093 AccessToken->DynamicPart = NULL; 1094 if (DefaultDacl != NULL) 1095 { 1096 AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool, 1097 DefaultDacl->AclSize, 1098 TAG_TOKEN_DYNAMIC); 1099 if (AccessToken->DynamicPart == NULL) 1100 { 1101 Status = STATUS_INSUFFICIENT_RESOURCES; 1102 goto Quit; 1103 } 1104 EndMem = (PVOID)AccessToken->DynamicPart; 1105 1106 AccessToken->DefaultDacl = EndMem; 1107 1108 RtlCopyMemory(AccessToken->DefaultDacl, 1109 DefaultDacl, 1110 DefaultDacl->AclSize); 1111 } 1112 1113 /* Insert the token only if it's not the system token, otherwise return it directly */ 1114 if (!SystemToken) 1115 { 1116 Status = ObInsertObject(AccessToken, 1117 NULL, 1118 DesiredAccess, 1119 0, 1120 NULL, 1121 TokenHandle); 1122 if (!NT_SUCCESS(Status)) 1123 { 1124 DPRINT1("ObInsertObject() failed (Status 0x%lx)\n", Status); 1125 } 1126 } 1127 else 1128 { 1129 /* Return pointer instead of handle */ 1130 *TokenHandle = (HANDLE)AccessToken; 1131 } 1132 1133 Quit: 1134 if (!NT_SUCCESS(Status)) 1135 { 1136 /* Dereference the token, the delete procedure will clean it up */ 1137 ObDereferenceObject(AccessToken); 1138 } 1139 1140 return Status; 1141 } 1142 1143 PTOKEN 1144 NTAPI 1145 SepCreateSystemProcessToken(VOID) 1146 { 1147 LUID_AND_ATTRIBUTES Privileges[25]; 1148 ULONG GroupAttributes, OwnerAttributes; 1149 SID_AND_ATTRIBUTES Groups[32]; 1150 LARGE_INTEGER Expiration; 1151 SID_AND_ATTRIBUTES UserSid; 1152 ULONG GroupsLength; 1153 PSID PrimaryGroup; 1154 OBJECT_ATTRIBUTES ObjectAttributes; 1155 PSID Owner; 1156 ULONG i; 1157 PTOKEN Token; 1158 NTSTATUS Status; 1159 1160 /* Don't ever expire */ 1161 Expiration.QuadPart = -1; 1162 1163 /* All groups mandatory and enabled */ 1164 GroupAttributes = SE_GROUP_ENABLED | SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT; 1165 OwnerAttributes = SE_GROUP_ENABLED | SE_GROUP_OWNER | SE_GROUP_ENABLED_BY_DEFAULT; 1166 1167 /* User is Local System */ 1168 UserSid.Sid = SeLocalSystemSid; 1169 UserSid.Attributes = 0; 1170 1171 /* Primary group is Local System */ 1172 PrimaryGroup = SeLocalSystemSid; 1173 1174 /* Owner is Administrators */ 1175 Owner = SeAliasAdminsSid; 1176 1177 /* Groups are Administrators, World, and Authenticated Users */ 1178 Groups[0].Sid = SeAliasAdminsSid; 1179 Groups[0].Attributes = OwnerAttributes; 1180 Groups[1].Sid = SeWorldSid; 1181 Groups[1].Attributes = GroupAttributes; 1182 Groups[2].Sid = SeAuthenticatedUsersSid; 1183 Groups[2].Attributes = GroupAttributes; 1184 GroupsLength = sizeof(SID_AND_ATTRIBUTES) + 1185 SeLengthSid(Groups[0].Sid) + 1186 SeLengthSid(Groups[1].Sid) + 1187 SeLengthSid(Groups[2].Sid); 1188 ASSERT(GroupsLength <= sizeof(Groups)); 1189 1190 /* Setup the privileges */ 1191 i = 0; 1192 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 1193 Privileges[i++].Luid = SeTcbPrivilege; 1194 1195 Privileges[i].Attributes = 0; 1196 Privileges[i++].Luid = SeCreateTokenPrivilege; 1197 1198 Privileges[i].Attributes = 0; 1199 Privileges[i++].Luid = SeTakeOwnershipPrivilege; 1200 1201 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 1202 Privileges[i++].Luid = SeCreatePagefilePrivilege; 1203 1204 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 1205 Privileges[i++].Luid = SeLockMemoryPrivilege; 1206 1207 Privileges[i].Attributes = 0; 1208 Privileges[i++].Luid = SeAssignPrimaryTokenPrivilege; 1209 1210 Privileges[i].Attributes = 0; 1211 Privileges[i++].Luid = SeIncreaseQuotaPrivilege; 1212 1213 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 1214 Privileges[i++].Luid = SeIncreaseBasePriorityPrivilege; 1215 1216 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 1217 Privileges[i++].Luid = SeCreatePermanentPrivilege; 1218 1219 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 1220 Privileges[i++].Luid = SeDebugPrivilege; 1221 1222 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 1223 Privileges[i++].Luid = SeAuditPrivilege; 1224 1225 Privileges[i].Attributes = 0; 1226 Privileges[i++].Luid = SeSecurityPrivilege; 1227 1228 Privileges[i].Attributes = 0; 1229 Privileges[i++].Luid = SeSystemEnvironmentPrivilege; 1230 1231 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 1232 Privileges[i++].Luid = SeChangeNotifyPrivilege; 1233 1234 Privileges[i].Attributes = 0; 1235 Privileges[i++].Luid = SeBackupPrivilege; 1236 1237 Privileges[i].Attributes = 0; 1238 Privileges[i++].Luid = SeRestorePrivilege; 1239 1240 Privileges[i].Attributes = 0; 1241 Privileges[i++].Luid = SeShutdownPrivilege; 1242 1243 Privileges[i].Attributes = 0; 1244 Privileges[i++].Luid = SeLoadDriverPrivilege; 1245 1246 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 1247 Privileges[i++].Luid = SeProfileSingleProcessPrivilege; 1248 1249 Privileges[i].Attributes = 0; 1250 Privileges[i++].Luid = SeSystemtimePrivilege; 1251 ASSERT(i == 20); 1252 1253 /* Setup the object attributes */ 1254 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); 1255 ASSERT(SeSystemDefaultDacl != NULL); 1256 1257 /* Create the token */ 1258 Status = SepCreateToken((PHANDLE)&Token, 1259 KernelMode, 1260 0, 1261 &ObjectAttributes, 1262 TokenPrimary, 1263 SecurityAnonymous, 1264 &SeSystemAuthenticationId, 1265 &Expiration, 1266 &UserSid, 1267 3, 1268 Groups, 1269 GroupsLength, 1270 20, 1271 Privileges, 1272 Owner, 1273 PrimaryGroup, 1274 SeSystemDefaultDacl, 1275 &SeSystemTokenSource, 1276 TRUE); 1277 ASSERT(Status == STATUS_SUCCESS); 1278 1279 /* Return the token */ 1280 return Token; 1281 } 1282 1283 /* PUBLIC FUNCTIONS ***********************************************************/ 1284 1285 /* 1286 * @unimplemented 1287 */ 1288 NTSTATUS 1289 NTAPI 1290 SeFilterToken(IN PACCESS_TOKEN ExistingToken, 1291 IN ULONG Flags, 1292 IN PTOKEN_GROUPS SidsToDisable OPTIONAL, 1293 IN PTOKEN_PRIVILEGES PrivilegesToDelete OPTIONAL, 1294 IN PTOKEN_GROUPS RestrictedSids OPTIONAL, 1295 OUT PACCESS_TOKEN * FilteredToken) 1296 { 1297 UNIMPLEMENTED; 1298 return STATUS_NOT_IMPLEMENTED; 1299 } 1300 1301 /* 1302 * @implemented 1303 * 1304 * NOTE: SeQueryInformationToken is just NtQueryInformationToken without all 1305 * the bells and whistles needed for user-mode buffer access protection. 1306 */ 1307 NTSTATUS 1308 NTAPI 1309 SeQueryInformationToken(IN PACCESS_TOKEN AccessToken, 1310 IN TOKEN_INFORMATION_CLASS TokenInformationClass, 1311 OUT PVOID *TokenInformation) 1312 { 1313 NTSTATUS Status; 1314 PTOKEN Token = (PTOKEN)AccessToken; 1315 ULONG RequiredLength; 1316 union 1317 { 1318 PSID PSid; 1319 ULONG Ulong; 1320 } Unused; 1321 1322 PAGED_CODE(); 1323 1324 if (TokenInformationClass >= MaxTokenInfoClass) 1325 { 1326 DPRINT1("SeQueryInformationToken(%d) invalid information class\n", TokenInformationClass); 1327 return STATUS_INVALID_INFO_CLASS; 1328 } 1329 1330 // TODO: Lock the token 1331 1332 switch (TokenInformationClass) 1333 { 1334 case TokenUser: 1335 { 1336 PTOKEN_USER tu; 1337 1338 DPRINT("SeQueryInformationToken(TokenUser)\n"); 1339 RequiredLength = sizeof(TOKEN_USER) + 1340 RtlLengthSid(Token->UserAndGroups[0].Sid); 1341 1342 /* Allocate the output buffer */ 1343 tu = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 1344 if (tu == NULL) 1345 { 1346 Status = STATUS_INSUFFICIENT_RESOURCES; 1347 break; 1348 } 1349 1350 Status = RtlCopySidAndAttributesArray(1, 1351 &Token->UserAndGroups[0], 1352 RequiredLength - sizeof(TOKEN_USER), 1353 &tu->User, 1354 (PSID)(tu + 1), 1355 &Unused.PSid, 1356 &Unused.Ulong); 1357 1358 /* Return the structure */ 1359 *TokenInformation = tu; 1360 Status = STATUS_SUCCESS; 1361 break; 1362 } 1363 1364 case TokenGroups: 1365 { 1366 PTOKEN_GROUPS tg; 1367 ULONG SidLen; 1368 PSID Sid; 1369 1370 DPRINT("SeQueryInformationToken(TokenGroups)\n"); 1371 RequiredLength = sizeof(tg->GroupCount) + 1372 RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]); 1373 1374 SidLen = RequiredLength - sizeof(tg->GroupCount) - 1375 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES)); 1376 1377 /* Allocate the output buffer */ 1378 tg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 1379 if (tg == NULL) 1380 { 1381 Status = STATUS_INSUFFICIENT_RESOURCES; 1382 break; 1383 } 1384 1385 Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) + 1386 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES))); 1387 1388 tg->GroupCount = Token->UserAndGroupCount - 1; 1389 Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1, 1390 &Token->UserAndGroups[1], 1391 SidLen, 1392 &tg->Groups[0], 1393 Sid, 1394 &Unused.PSid, 1395 &Unused.Ulong); 1396 1397 /* Return the structure */ 1398 *TokenInformation = tg; 1399 Status = STATUS_SUCCESS; 1400 break; 1401 } 1402 1403 case TokenPrivileges: 1404 { 1405 PTOKEN_PRIVILEGES tp; 1406 1407 DPRINT("SeQueryInformationToken(TokenPrivileges)\n"); 1408 RequiredLength = sizeof(tp->PrivilegeCount) + 1409 (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)); 1410 1411 /* Allocate the output buffer */ 1412 tp = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 1413 if (tp == NULL) 1414 { 1415 Status = STATUS_INSUFFICIENT_RESOURCES; 1416 break; 1417 } 1418 1419 tp->PrivilegeCount = Token->PrivilegeCount; 1420 RtlCopyLuidAndAttributesArray(Token->PrivilegeCount, 1421 Token->Privileges, 1422 &tp->Privileges[0]); 1423 1424 /* Return the structure */ 1425 *TokenInformation = tp; 1426 Status = STATUS_SUCCESS; 1427 break; 1428 } 1429 1430 case TokenOwner: 1431 { 1432 PTOKEN_OWNER to; 1433 ULONG SidLen; 1434 1435 DPRINT("SeQueryInformationToken(TokenOwner)\n"); 1436 SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid); 1437 RequiredLength = sizeof(TOKEN_OWNER) + SidLen; 1438 1439 /* Allocate the output buffer */ 1440 to = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 1441 if (to == NULL) 1442 { 1443 Status = STATUS_INSUFFICIENT_RESOURCES; 1444 break; 1445 } 1446 1447 to->Owner = (PSID)(to + 1); 1448 Status = RtlCopySid(SidLen, 1449 to->Owner, 1450 Token->UserAndGroups[Token->DefaultOwnerIndex].Sid); 1451 1452 /* Return the structure */ 1453 *TokenInformation = to; 1454 Status = STATUS_SUCCESS; 1455 break; 1456 } 1457 1458 case TokenPrimaryGroup: 1459 { 1460 PTOKEN_PRIMARY_GROUP tpg; 1461 ULONG SidLen; 1462 1463 DPRINT("SeQueryInformationToken(TokenPrimaryGroup)\n"); 1464 SidLen = RtlLengthSid(Token->PrimaryGroup); 1465 RequiredLength = sizeof(TOKEN_PRIMARY_GROUP) + SidLen; 1466 1467 /* Allocate the output buffer */ 1468 tpg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 1469 if (tpg == NULL) 1470 { 1471 Status = STATUS_INSUFFICIENT_RESOURCES; 1472 break; 1473 } 1474 1475 tpg->PrimaryGroup = (PSID)(tpg + 1); 1476 Status = RtlCopySid(SidLen, 1477 tpg->PrimaryGroup, 1478 Token->PrimaryGroup); 1479 1480 /* Return the structure */ 1481 *TokenInformation = tpg; 1482 Status = STATUS_SUCCESS; 1483 break; 1484 } 1485 1486 case TokenDefaultDacl: 1487 { 1488 PTOKEN_DEFAULT_DACL tdd; 1489 1490 DPRINT("SeQueryInformationToken(TokenDefaultDacl)\n"); 1491 RequiredLength = sizeof(TOKEN_DEFAULT_DACL); 1492 1493 if (Token->DefaultDacl != NULL) 1494 RequiredLength += Token->DefaultDacl->AclSize; 1495 1496 /* Allocate the output buffer */ 1497 tdd = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 1498 if (tdd == NULL) 1499 { 1500 Status = STATUS_INSUFFICIENT_RESOURCES; 1501 break; 1502 } 1503 1504 if (Token->DefaultDacl != NULL) 1505 { 1506 tdd->DefaultDacl = (PACL)(tdd + 1); 1507 RtlCopyMemory(tdd->DefaultDacl, 1508 Token->DefaultDacl, 1509 Token->DefaultDacl->AclSize); 1510 } 1511 else 1512 { 1513 tdd->DefaultDacl = NULL; 1514 } 1515 1516 /* Return the structure */ 1517 *TokenInformation = tdd; 1518 Status = STATUS_SUCCESS; 1519 break; 1520 } 1521 1522 case TokenSource: 1523 { 1524 PTOKEN_SOURCE ts; 1525 1526 DPRINT("SeQueryInformationToken(TokenSource)\n"); 1527 RequiredLength = sizeof(TOKEN_SOURCE); 1528 1529 /* Allocate the output buffer */ 1530 ts = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 1531 if (ts == NULL) 1532 { 1533 Status = STATUS_INSUFFICIENT_RESOURCES; 1534 break; 1535 } 1536 1537 *ts = Token->TokenSource; 1538 1539 /* Return the structure */ 1540 *TokenInformation = ts; 1541 Status = STATUS_SUCCESS; 1542 break; 1543 } 1544 1545 case TokenType: 1546 { 1547 PTOKEN_TYPE tt; 1548 1549 DPRINT("SeQueryInformationToken(TokenType)\n"); 1550 RequiredLength = sizeof(TOKEN_TYPE); 1551 1552 /* Allocate the output buffer */ 1553 tt = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 1554 if (tt == NULL) 1555 { 1556 Status = STATUS_INSUFFICIENT_RESOURCES; 1557 break; 1558 } 1559 1560 *tt = Token->TokenType; 1561 1562 /* Return the structure */ 1563 *TokenInformation = tt; 1564 Status = STATUS_SUCCESS; 1565 break; 1566 } 1567 1568 case TokenImpersonationLevel: 1569 { 1570 PSECURITY_IMPERSONATION_LEVEL sil; 1571 1572 DPRINT("SeQueryInformationToken(TokenImpersonationLevel)\n"); 1573 RequiredLength = sizeof(SECURITY_IMPERSONATION_LEVEL); 1574 1575 /* Fail if the token is not an impersonation token */ 1576 if (Token->TokenType != TokenImpersonation) 1577 { 1578 Status = STATUS_INVALID_INFO_CLASS; 1579 break; 1580 } 1581 1582 /* Allocate the output buffer */ 1583 sil = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 1584 if (sil == NULL) 1585 { 1586 Status = STATUS_INSUFFICIENT_RESOURCES; 1587 break; 1588 } 1589 1590 *sil = Token->ImpersonationLevel; 1591 1592 /* Return the structure */ 1593 *TokenInformation = sil; 1594 Status = STATUS_SUCCESS; 1595 break; 1596 } 1597 1598 case TokenStatistics: 1599 { 1600 PTOKEN_STATISTICS ts; 1601 1602 DPRINT("SeQueryInformationToken(TokenStatistics)\n"); 1603 RequiredLength = sizeof(TOKEN_STATISTICS); 1604 1605 /* Allocate the output buffer */ 1606 ts = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 1607 if (ts == NULL) 1608 { 1609 Status = STATUS_INSUFFICIENT_RESOURCES; 1610 break; 1611 } 1612 1613 ts->TokenId = Token->TokenId; 1614 ts->AuthenticationId = Token->AuthenticationId; 1615 ts->ExpirationTime = Token->ExpirationTime; 1616 ts->TokenType = Token->TokenType; 1617 ts->ImpersonationLevel = Token->ImpersonationLevel; 1618 ts->DynamicCharged = Token->DynamicCharged; 1619 ts->DynamicAvailable = Token->DynamicAvailable; 1620 ts->GroupCount = Token->UserAndGroupCount - 1; 1621 ts->PrivilegeCount = Token->PrivilegeCount; 1622 ts->ModifiedId = Token->ModifiedId; 1623 1624 /* Return the structure */ 1625 *TokenInformation = ts; 1626 Status = STATUS_SUCCESS; 1627 break; 1628 } 1629 1630 /* 1631 * The following 4 cases are only implemented in NtQueryInformationToken 1632 */ 1633 #if 0 1634 1635 case TokenOrigin: 1636 { 1637 PTOKEN_ORIGIN to; 1638 1639 DPRINT("SeQueryInformationToken(TokenOrigin)\n"); 1640 RequiredLength = sizeof(TOKEN_ORIGIN); 1641 1642 /* Allocate the output buffer */ 1643 to = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 1644 if (to == NULL) 1645 { 1646 Status = STATUS_INSUFFICIENT_RESOURCES; 1647 break; 1648 } 1649 1650 RtlCopyLuid(&to->OriginatingLogonSession, 1651 &Token->AuthenticationId); 1652 1653 /* Return the structure */ 1654 *TokenInformation = to; 1655 Status = STATUS_SUCCESS; 1656 break; 1657 } 1658 1659 case TokenGroupsAndPrivileges: 1660 DPRINT1("SeQueryInformationToken(TokenGroupsAndPrivileges) not implemented\n"); 1661 Status = STATUS_NOT_IMPLEMENTED; 1662 break; 1663 1664 case TokenRestrictedSids: 1665 { 1666 PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation; 1667 ULONG SidLen; 1668 PSID Sid; 1669 1670 DPRINT("SeQueryInformationToken(TokenRestrictedSids)\n"); 1671 RequiredLength = sizeof(tg->GroupCount) + 1672 RtlLengthSidAndAttributes(Token->RestrictedSidCount, Token->RestrictedSids); 1673 1674 SidLen = RequiredLength - sizeof(tg->GroupCount) - 1675 (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)); 1676 1677 /* Allocate the output buffer */ 1678 tg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 1679 if (tg == NULL) 1680 { 1681 Status = STATUS_INSUFFICIENT_RESOURCES; 1682 break; 1683 } 1684 1685 Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) + 1686 (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES))); 1687 1688 tg->GroupCount = Token->RestrictedSidCount; 1689 Status = RtlCopySidAndAttributesArray(Token->RestrictedSidCount, 1690 Token->RestrictedSids, 1691 SidLen, 1692 &tg->Groups[0], 1693 Sid, 1694 &Unused.PSid, 1695 &Unused.Ulong); 1696 1697 /* Return the structure */ 1698 *TokenInformation = tg; 1699 Status = STATUS_SUCCESS; 1700 break; 1701 } 1702 1703 case TokenSandBoxInert: 1704 DPRINT1("SeQueryInformationToken(TokenSandboxInert) not implemented\n"); 1705 Status = STATUS_NOT_IMPLEMENTED; 1706 break; 1707 1708 #endif 1709 1710 case TokenSessionId: 1711 { 1712 DPRINT("SeQueryInformationToken(TokenSessionId)\n"); 1713 Status = SeQuerySessionIdToken(Token, (PULONG)TokenInformation); 1714 break; 1715 } 1716 1717 default: 1718 DPRINT1("SeQueryInformationToken(%d) invalid information class\n", TokenInformationClass); 1719 Status = STATUS_INVALID_INFO_CLASS; 1720 break; 1721 } 1722 1723 return Status; 1724 } 1725 1726 /* 1727 * @implemented 1728 */ 1729 NTSTATUS 1730 NTAPI 1731 SeQuerySessionIdToken(IN PACCESS_TOKEN Token, 1732 IN PULONG pSessionId) 1733 { 1734 PAGED_CODE(); 1735 1736 /* Lock the token */ 1737 SepAcquireTokenLockShared(Token); 1738 1739 *pSessionId = ((PTOKEN)Token)->SessionId; 1740 1741 /* Unlock the token */ 1742 SepReleaseTokenLock(Token); 1743 1744 return STATUS_SUCCESS; 1745 } 1746 1747 /* 1748 * @implemented 1749 */ 1750 NTSTATUS 1751 NTAPI 1752 SeQueryAuthenticationIdToken(IN PACCESS_TOKEN Token, 1753 OUT PLUID LogonId) 1754 { 1755 PAGED_CODE(); 1756 1757 *LogonId = ((PTOKEN)Token)->AuthenticationId; 1758 1759 return STATUS_SUCCESS; 1760 } 1761 1762 1763 /* 1764 * @implemented 1765 */ 1766 SECURITY_IMPERSONATION_LEVEL 1767 NTAPI 1768 SeTokenImpersonationLevel(IN PACCESS_TOKEN Token) 1769 { 1770 PAGED_CODE(); 1771 1772 return ((PTOKEN)Token)->ImpersonationLevel; 1773 } 1774 1775 1776 /* 1777 * @implemented 1778 */ 1779 TOKEN_TYPE NTAPI 1780 SeTokenType(IN PACCESS_TOKEN Token) 1781 { 1782 PAGED_CODE(); 1783 1784 return ((PTOKEN)Token)->TokenType; 1785 } 1786 1787 1788 /* 1789 * @implemented 1790 */ 1791 BOOLEAN 1792 NTAPI 1793 SeTokenIsAdmin(IN PACCESS_TOKEN Token) 1794 { 1795 PAGED_CODE(); 1796 1797 // NOTE: Win7+ instead really checks the list of groups in the token 1798 // (since TOKEN_HAS_ADMIN_GROUP == TOKEN_WRITE_RESTRICTED ...) 1799 return (((PTOKEN)Token)->TokenFlags & TOKEN_HAS_ADMIN_GROUP) != 0; 1800 } 1801 1802 /* 1803 * @implemented 1804 */ 1805 BOOLEAN 1806 NTAPI 1807 SeTokenIsRestricted(IN PACCESS_TOKEN Token) 1808 { 1809 PAGED_CODE(); 1810 1811 return (((PTOKEN)Token)->TokenFlags & TOKEN_IS_RESTRICTED) != 0; 1812 } 1813 1814 /* 1815 * @implemented 1816 * @note First introduced in NT 5.1 SP2 x86 (5.1.2600.2622), absent in NT 5.2, 1817 * then finally re-introduced in Vista+. 1818 */ 1819 BOOLEAN 1820 NTAPI 1821 SeTokenIsWriteRestricted(IN PACCESS_TOKEN Token) 1822 { 1823 PAGED_CODE(); 1824 1825 // NOTE: NT 5.1 SP2 x86 checks the SE_BACKUP_PRIVILEGES_CHECKED flag 1826 // while Vista+ checks the TOKEN_WRITE_RESTRICTED flag as one expects. 1827 return (((PTOKEN)Token)->TokenFlags & SE_BACKUP_PRIVILEGES_CHECKED) != 0; 1828 } 1829 1830 /* SYSTEM CALLS ***************************************************************/ 1831 1832 /* 1833 * @implemented 1834 */ 1835 _Must_inspect_result_ 1836 __kernel_entry 1837 NTSTATUS 1838 NTAPI 1839 NtQueryInformationToken( 1840 _In_ HANDLE TokenHandle, 1841 _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, 1842 _Out_writes_bytes_to_opt_(TokenInformationLength, *ReturnLength) 1843 PVOID TokenInformation, 1844 _In_ ULONG TokenInformationLength, 1845 _Out_ PULONG ReturnLength) 1846 { 1847 NTSTATUS Status; 1848 KPROCESSOR_MODE PreviousMode; 1849 PTOKEN Token; 1850 ULONG RequiredLength; 1851 union 1852 { 1853 PSID PSid; 1854 ULONG Ulong; 1855 } Unused; 1856 1857 PAGED_CODE(); 1858 1859 PreviousMode = ExGetPreviousMode(); 1860 1861 /* Check buffers and class validity */ 1862 Status = DefaultQueryInfoBufferCheck(TokenInformationClass, 1863 SeTokenInformationClass, 1864 RTL_NUMBER_OF(SeTokenInformationClass), 1865 TokenInformation, 1866 TokenInformationLength, 1867 ReturnLength, 1868 NULL, 1869 PreviousMode); 1870 if (!NT_SUCCESS(Status)) 1871 { 1872 DPRINT("NtQueryInformationToken() failed, Status: 0x%x\n", Status); 1873 return Status; 1874 } 1875 1876 Status = ObReferenceObjectByHandle(TokenHandle, 1877 (TokenInformationClass == TokenSource) ? TOKEN_QUERY_SOURCE : TOKEN_QUERY, 1878 SeTokenObjectType, 1879 PreviousMode, 1880 (PVOID*)&Token, 1881 NULL); 1882 if (NT_SUCCESS(Status)) 1883 { 1884 /* Lock the token */ 1885 SepAcquireTokenLockShared(Token); 1886 1887 switch (TokenInformationClass) 1888 { 1889 case TokenUser: 1890 { 1891 PTOKEN_USER tu = (PTOKEN_USER)TokenInformation; 1892 1893 DPRINT("NtQueryInformationToken(TokenUser)\n"); 1894 RequiredLength = sizeof(TOKEN_USER) + 1895 RtlLengthSid(Token->UserAndGroups[0].Sid); 1896 1897 _SEH2_TRY 1898 { 1899 if (TokenInformationLength >= RequiredLength) 1900 { 1901 Status = RtlCopySidAndAttributesArray(1, 1902 &Token->UserAndGroups[0], 1903 RequiredLength - sizeof(TOKEN_USER), 1904 &tu->User, 1905 (PSID)(tu + 1), 1906 &Unused.PSid, 1907 &Unused.Ulong); 1908 } 1909 else 1910 { 1911 Status = STATUS_BUFFER_TOO_SMALL; 1912 } 1913 1914 if (ReturnLength != NULL) 1915 { 1916 *ReturnLength = RequiredLength; 1917 } 1918 } 1919 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1920 { 1921 Status = _SEH2_GetExceptionCode(); 1922 } 1923 _SEH2_END; 1924 1925 break; 1926 } 1927 1928 case TokenGroups: 1929 { 1930 PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation; 1931 1932 DPRINT("NtQueryInformationToken(TokenGroups)\n"); 1933 RequiredLength = sizeof(tg->GroupCount) + 1934 RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]); 1935 1936 _SEH2_TRY 1937 { 1938 if (TokenInformationLength >= RequiredLength) 1939 { 1940 ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) - 1941 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES)); 1942 PSID Sid = (PSID_AND_ATTRIBUTES)((ULONG_PTR)tg + sizeof(tg->GroupCount) + 1943 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES))); 1944 1945 tg->GroupCount = Token->UserAndGroupCount - 1; 1946 Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1, 1947 &Token->UserAndGroups[1], 1948 SidLen, 1949 &tg->Groups[0], 1950 Sid, 1951 &Unused.PSid, 1952 &Unused.Ulong); 1953 } 1954 else 1955 { 1956 Status = STATUS_BUFFER_TOO_SMALL; 1957 } 1958 1959 if (ReturnLength != NULL) 1960 { 1961 *ReturnLength = RequiredLength; 1962 } 1963 } 1964 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1965 { 1966 Status = _SEH2_GetExceptionCode(); 1967 } 1968 _SEH2_END; 1969 1970 break; 1971 } 1972 1973 case TokenPrivileges: 1974 { 1975 PTOKEN_PRIVILEGES tp = (PTOKEN_PRIVILEGES)TokenInformation; 1976 1977 DPRINT("NtQueryInformationToken(TokenPrivileges)\n"); 1978 RequiredLength = sizeof(tp->PrivilegeCount) + 1979 (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)); 1980 1981 _SEH2_TRY 1982 { 1983 if (TokenInformationLength >= RequiredLength) 1984 { 1985 tp->PrivilegeCount = Token->PrivilegeCount; 1986 RtlCopyLuidAndAttributesArray(Token->PrivilegeCount, 1987 Token->Privileges, 1988 &tp->Privileges[0]); 1989 } 1990 else 1991 { 1992 Status = STATUS_BUFFER_TOO_SMALL; 1993 } 1994 1995 if (ReturnLength != NULL) 1996 { 1997 *ReturnLength = RequiredLength; 1998 } 1999 } 2000 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2001 { 2002 Status = _SEH2_GetExceptionCode(); 2003 } 2004 _SEH2_END; 2005 2006 break; 2007 } 2008 2009 case TokenOwner: 2010 { 2011 PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation; 2012 ULONG SidLen; 2013 2014 DPRINT("NtQueryInformationToken(TokenOwner)\n"); 2015 SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid); 2016 RequiredLength = sizeof(TOKEN_OWNER) + SidLen; 2017 2018 _SEH2_TRY 2019 { 2020 if (TokenInformationLength >= RequiredLength) 2021 { 2022 to->Owner = (PSID)(to + 1); 2023 Status = RtlCopySid(SidLen, 2024 to->Owner, 2025 Token->UserAndGroups[Token->DefaultOwnerIndex].Sid); 2026 } 2027 else 2028 { 2029 Status = STATUS_BUFFER_TOO_SMALL; 2030 } 2031 2032 if (ReturnLength != NULL) 2033 { 2034 *ReturnLength = RequiredLength; 2035 } 2036 } 2037 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2038 { 2039 Status = _SEH2_GetExceptionCode(); 2040 } 2041 _SEH2_END; 2042 2043 break; 2044 } 2045 2046 case TokenPrimaryGroup: 2047 { 2048 PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation; 2049 ULONG SidLen; 2050 2051 DPRINT("NtQueryInformationToken(TokenPrimaryGroup)\n"); 2052 SidLen = RtlLengthSid(Token->PrimaryGroup); 2053 RequiredLength = sizeof(TOKEN_PRIMARY_GROUP) + SidLen; 2054 2055 _SEH2_TRY 2056 { 2057 if (TokenInformationLength >= RequiredLength) 2058 { 2059 tpg->PrimaryGroup = (PSID)(tpg + 1); 2060 Status = RtlCopySid(SidLen, 2061 tpg->PrimaryGroup, 2062 Token->PrimaryGroup); 2063 } 2064 else 2065 { 2066 Status = STATUS_BUFFER_TOO_SMALL; 2067 } 2068 2069 if (ReturnLength != NULL) 2070 { 2071 *ReturnLength = RequiredLength; 2072 } 2073 } 2074 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2075 { 2076 Status = _SEH2_GetExceptionCode(); 2077 } 2078 _SEH2_END; 2079 2080 break; 2081 } 2082 2083 case TokenDefaultDacl: 2084 { 2085 PTOKEN_DEFAULT_DACL tdd = (PTOKEN_DEFAULT_DACL)TokenInformation; 2086 2087 DPRINT("NtQueryInformationToken(TokenDefaultDacl)\n"); 2088 RequiredLength = sizeof(TOKEN_DEFAULT_DACL); 2089 2090 if (Token->DefaultDacl != NULL) 2091 RequiredLength += Token->DefaultDacl->AclSize; 2092 2093 _SEH2_TRY 2094 { 2095 if (TokenInformationLength >= RequiredLength) 2096 { 2097 if (Token->DefaultDacl != NULL) 2098 { 2099 tdd->DefaultDacl = (PACL)(tdd + 1); 2100 RtlCopyMemory(tdd->DefaultDacl, 2101 Token->DefaultDacl, 2102 Token->DefaultDacl->AclSize); 2103 } 2104 else 2105 { 2106 tdd->DefaultDacl = NULL; 2107 } 2108 } 2109 else 2110 { 2111 Status = STATUS_BUFFER_TOO_SMALL; 2112 } 2113 2114 if (ReturnLength != NULL) 2115 { 2116 *ReturnLength = RequiredLength; 2117 } 2118 } 2119 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2120 { 2121 Status = _SEH2_GetExceptionCode(); 2122 } 2123 _SEH2_END; 2124 2125 break; 2126 } 2127 2128 case TokenSource: 2129 { 2130 PTOKEN_SOURCE ts = (PTOKEN_SOURCE)TokenInformation; 2131 2132 DPRINT("NtQueryInformationToken(TokenSource)\n"); 2133 RequiredLength = sizeof(TOKEN_SOURCE); 2134 2135 _SEH2_TRY 2136 { 2137 if (TokenInformationLength >= RequiredLength) 2138 { 2139 *ts = Token->TokenSource; 2140 } 2141 else 2142 { 2143 Status = STATUS_BUFFER_TOO_SMALL; 2144 } 2145 2146 if (ReturnLength != NULL) 2147 { 2148 *ReturnLength = RequiredLength; 2149 } 2150 } 2151 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2152 { 2153 Status = _SEH2_GetExceptionCode(); 2154 } 2155 _SEH2_END; 2156 2157 break; 2158 } 2159 2160 case TokenType: 2161 { 2162 PTOKEN_TYPE tt = (PTOKEN_TYPE)TokenInformation; 2163 2164 DPRINT("NtQueryInformationToken(TokenType)\n"); 2165 RequiredLength = sizeof(TOKEN_TYPE); 2166 2167 _SEH2_TRY 2168 { 2169 if (TokenInformationLength >= RequiredLength) 2170 { 2171 *tt = Token->TokenType; 2172 } 2173 else 2174 { 2175 Status = STATUS_BUFFER_TOO_SMALL; 2176 } 2177 2178 if (ReturnLength != NULL) 2179 { 2180 *ReturnLength = RequiredLength; 2181 } 2182 } 2183 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2184 { 2185 Status = _SEH2_GetExceptionCode(); 2186 } 2187 _SEH2_END; 2188 2189 break; 2190 } 2191 2192 case TokenImpersonationLevel: 2193 { 2194 PSECURITY_IMPERSONATION_LEVEL sil = (PSECURITY_IMPERSONATION_LEVEL)TokenInformation; 2195 2196 DPRINT("NtQueryInformationToken(TokenImpersonationLevel)\n"); 2197 2198 /* Fail if the token is not an impersonation token */ 2199 if (Token->TokenType != TokenImpersonation) 2200 { 2201 Status = STATUS_INVALID_INFO_CLASS; 2202 break; 2203 } 2204 2205 RequiredLength = sizeof(SECURITY_IMPERSONATION_LEVEL); 2206 2207 _SEH2_TRY 2208 { 2209 if (TokenInformationLength >= RequiredLength) 2210 { 2211 *sil = Token->ImpersonationLevel; 2212 } 2213 else 2214 { 2215 Status = STATUS_BUFFER_TOO_SMALL; 2216 } 2217 2218 if (ReturnLength != NULL) 2219 { 2220 *ReturnLength = RequiredLength; 2221 } 2222 } 2223 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2224 { 2225 Status = _SEH2_GetExceptionCode(); 2226 } 2227 _SEH2_END; 2228 2229 break; 2230 } 2231 2232 case TokenStatistics: 2233 { 2234 PTOKEN_STATISTICS ts = (PTOKEN_STATISTICS)TokenInformation; 2235 2236 DPRINT("NtQueryInformationToken(TokenStatistics)\n"); 2237 RequiredLength = sizeof(TOKEN_STATISTICS); 2238 2239 _SEH2_TRY 2240 { 2241 if (TokenInformationLength >= RequiredLength) 2242 { 2243 ts->TokenId = Token->TokenId; 2244 ts->AuthenticationId = Token->AuthenticationId; 2245 ts->ExpirationTime = Token->ExpirationTime; 2246 ts->TokenType = Token->TokenType; 2247 ts->ImpersonationLevel = Token->ImpersonationLevel; 2248 ts->DynamicCharged = Token->DynamicCharged; 2249 ts->DynamicAvailable = Token->DynamicAvailable; 2250 ts->GroupCount = Token->UserAndGroupCount - 1; 2251 ts->PrivilegeCount = Token->PrivilegeCount; 2252 ts->ModifiedId = Token->ModifiedId; 2253 } 2254 else 2255 { 2256 Status = STATUS_BUFFER_TOO_SMALL; 2257 } 2258 2259 if (ReturnLength != NULL) 2260 { 2261 *ReturnLength = RequiredLength; 2262 } 2263 } 2264 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2265 { 2266 Status = _SEH2_GetExceptionCode(); 2267 } 2268 _SEH2_END; 2269 2270 break; 2271 } 2272 2273 case TokenOrigin: 2274 { 2275 PTOKEN_ORIGIN to = (PTOKEN_ORIGIN)TokenInformation; 2276 2277 DPRINT("NtQueryInformationToken(TokenOrigin)\n"); 2278 RequiredLength = sizeof(TOKEN_ORIGIN); 2279 2280 _SEH2_TRY 2281 { 2282 if (TokenInformationLength >= RequiredLength) 2283 { 2284 RtlCopyLuid(&to->OriginatingLogonSession, 2285 &Token->AuthenticationId); 2286 } 2287 else 2288 { 2289 Status = STATUS_BUFFER_TOO_SMALL; 2290 } 2291 2292 if (ReturnLength != NULL) 2293 { 2294 *ReturnLength = RequiredLength; 2295 } 2296 } 2297 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2298 { 2299 Status = _SEH2_GetExceptionCode(); 2300 } 2301 _SEH2_END; 2302 2303 break; 2304 } 2305 2306 case TokenGroupsAndPrivileges: 2307 DPRINT1("NtQueryInformationToken(TokenGroupsAndPrivileges) not implemented\n"); 2308 Status = STATUS_NOT_IMPLEMENTED; 2309 break; 2310 2311 case TokenRestrictedSids: 2312 { 2313 PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation; 2314 2315 DPRINT("NtQueryInformationToken(TokenRestrictedSids)\n"); 2316 RequiredLength = sizeof(tg->GroupCount) + 2317 RtlLengthSidAndAttributes(Token->RestrictedSidCount, Token->RestrictedSids); 2318 2319 _SEH2_TRY 2320 { 2321 if (TokenInformationLength >= RequiredLength) 2322 { 2323 ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) - 2324 (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)); 2325 PSID Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) + 2326 (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES))); 2327 2328 tg->GroupCount = Token->RestrictedSidCount; 2329 Status = RtlCopySidAndAttributesArray(Token->RestrictedSidCount, 2330 Token->RestrictedSids, 2331 SidLen, 2332 &tg->Groups[0], 2333 Sid, 2334 &Unused.PSid, 2335 &Unused.Ulong); 2336 } 2337 else 2338 { 2339 Status = STATUS_BUFFER_TOO_SMALL; 2340 } 2341 2342 if (ReturnLength != NULL) 2343 { 2344 *ReturnLength = RequiredLength; 2345 } 2346 } 2347 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2348 { 2349 Status = _SEH2_GetExceptionCode(); 2350 } 2351 _SEH2_END; 2352 2353 break; 2354 } 2355 2356 case TokenSandBoxInert: 2357 DPRINT1("NtQueryInformationToken(TokenSandboxInert) not implemented\n"); 2358 Status = STATUS_NOT_IMPLEMENTED; 2359 break; 2360 2361 case TokenSessionId: 2362 { 2363 ULONG SessionId = 0; 2364 2365 DPRINT("NtQueryInformationToken(TokenSessionId)\n"); 2366 2367 Status = SeQuerySessionIdToken(Token, &SessionId); 2368 if (NT_SUCCESS(Status)) 2369 { 2370 _SEH2_TRY 2371 { 2372 /* Buffer size was already verified, no need to check here again */ 2373 *(PULONG)TokenInformation = SessionId; 2374 2375 if (ReturnLength != NULL) 2376 { 2377 *ReturnLength = sizeof(ULONG); 2378 } 2379 } 2380 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2381 { 2382 Status = _SEH2_GetExceptionCode(); 2383 } 2384 _SEH2_END; 2385 } 2386 2387 break; 2388 } 2389 2390 default: 2391 DPRINT1("NtQueryInformationToken(%d) invalid information class\n", TokenInformationClass); 2392 Status = STATUS_INVALID_INFO_CLASS; 2393 break; 2394 } 2395 2396 /* Unlock and dereference the token */ 2397 SepReleaseTokenLock(Token); 2398 ObDereferenceObject(Token); 2399 } 2400 2401 return Status; 2402 } 2403 2404 2405 /* 2406 * NtSetTokenInformation: Partly implemented. 2407 * Unimplemented: 2408 * TokenOrigin, TokenDefaultDacl 2409 */ 2410 _Must_inspect_result_ 2411 __kernel_entry 2412 NTSTATUS 2413 NTAPI 2414 NtSetInformationToken( 2415 _In_ HANDLE TokenHandle, 2416 _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, 2417 _In_reads_bytes_(TokenInformationLength) PVOID TokenInformation, 2418 _In_ ULONG TokenInformationLength) 2419 { 2420 NTSTATUS Status; 2421 PTOKEN Token; 2422 KPROCESSOR_MODE PreviousMode; 2423 ULONG NeededAccess = TOKEN_ADJUST_DEFAULT; 2424 2425 PAGED_CODE(); 2426 2427 PreviousMode = ExGetPreviousMode(); 2428 2429 Status = DefaultSetInfoBufferCheck(TokenInformationClass, 2430 SeTokenInformationClass, 2431 RTL_NUMBER_OF(SeTokenInformationClass), 2432 TokenInformation, 2433 TokenInformationLength, 2434 PreviousMode); 2435 if (!NT_SUCCESS(Status)) 2436 { 2437 /* Invalid buffers */ 2438 DPRINT("NtSetInformationToken() failed, Status: 0x%x\n", Status); 2439 return Status; 2440 } 2441 2442 if (TokenInformationClass == TokenSessionId) 2443 { 2444 NeededAccess |= TOKEN_ADJUST_SESSIONID; 2445 } 2446 2447 Status = ObReferenceObjectByHandle(TokenHandle, 2448 NeededAccess, 2449 SeTokenObjectType, 2450 PreviousMode, 2451 (PVOID*)&Token, 2452 NULL); 2453 if (NT_SUCCESS(Status)) 2454 { 2455 switch (TokenInformationClass) 2456 { 2457 case TokenOwner: 2458 { 2459 if (TokenInformationLength >= sizeof(TOKEN_OWNER)) 2460 { 2461 PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation; 2462 PSID InputSid = NULL, CapturedSid; 2463 ULONG DefaultOwnerIndex; 2464 2465 _SEH2_TRY 2466 { 2467 InputSid = to->Owner; 2468 } 2469 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2470 { 2471 Status = _SEH2_GetExceptionCode(); 2472 _SEH2_YIELD(goto Cleanup); 2473 } 2474 _SEH2_END; 2475 2476 Status = SepCaptureSid(InputSid, 2477 PreviousMode, 2478 PagedPool, 2479 FALSE, 2480 &CapturedSid); 2481 if (NT_SUCCESS(Status)) 2482 { 2483 /* Lock the token */ 2484 SepAcquireTokenLockExclusive(Token); 2485 2486 /* Find the owner amongst the existing token user and groups */ 2487 Status = SepFindPrimaryGroupAndDefaultOwner(Token, 2488 NULL, 2489 CapturedSid, 2490 NULL, 2491 &DefaultOwnerIndex); 2492 if (NT_SUCCESS(Status)) 2493 { 2494 /* Found it */ 2495 Token->DefaultOwnerIndex = DefaultOwnerIndex; 2496 ExAllocateLocallyUniqueId(&Token->ModifiedId); 2497 } 2498 2499 /* Unlock the token */ 2500 SepReleaseTokenLock(Token); 2501 2502 SepReleaseSid(CapturedSid, 2503 PreviousMode, 2504 FALSE); 2505 } 2506 } 2507 else 2508 { 2509 Status = STATUS_INFO_LENGTH_MISMATCH; 2510 } 2511 break; 2512 } 2513 2514 case TokenPrimaryGroup: 2515 { 2516 if (TokenInformationLength >= sizeof(TOKEN_PRIMARY_GROUP)) 2517 { 2518 PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation; 2519 PSID InputSid = NULL, CapturedSid; 2520 ULONG PrimaryGroupIndex; 2521 2522 _SEH2_TRY 2523 { 2524 InputSid = tpg->PrimaryGroup; 2525 } 2526 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2527 { 2528 Status = _SEH2_GetExceptionCode(); 2529 _SEH2_YIELD(goto Cleanup); 2530 } 2531 _SEH2_END; 2532 2533 Status = SepCaptureSid(InputSid, 2534 PreviousMode, 2535 PagedPool, 2536 FALSE, 2537 &CapturedSid); 2538 if (NT_SUCCESS(Status)) 2539 { 2540 /* Lock the token */ 2541 SepAcquireTokenLockExclusive(Token); 2542 2543 /* Find the primary group amongst the existing token user and groups */ 2544 Status = SepFindPrimaryGroupAndDefaultOwner(Token, 2545 CapturedSid, 2546 NULL, 2547 &PrimaryGroupIndex, 2548 NULL); 2549 if (NT_SUCCESS(Status)) 2550 { 2551 /* Found it */ 2552 Token->PrimaryGroup = Token->UserAndGroups[PrimaryGroupIndex].Sid; 2553 ExAllocateLocallyUniqueId(&Token->ModifiedId); 2554 } 2555 2556 /* Unlock the token */ 2557 SepReleaseTokenLock(Token); 2558 2559 SepReleaseSid(CapturedSid, 2560 PreviousMode, 2561 FALSE); 2562 } 2563 } 2564 else 2565 { 2566 Status = STATUS_INFO_LENGTH_MISMATCH; 2567 } 2568 break; 2569 } 2570 2571 case TokenDefaultDacl: 2572 { 2573 if (TokenInformationLength >= sizeof(TOKEN_DEFAULT_DACL)) 2574 { 2575 PTOKEN_DEFAULT_DACL tdd = (PTOKEN_DEFAULT_DACL)TokenInformation; 2576 PACL InputAcl = NULL; 2577 2578 _SEH2_TRY 2579 { 2580 InputAcl = tdd->DefaultDacl; 2581 } 2582 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2583 { 2584 Status = _SEH2_GetExceptionCode(); 2585 _SEH2_YIELD(goto Cleanup); 2586 } 2587 _SEH2_END; 2588 2589 if (InputAcl != NULL) 2590 { 2591 PACL CapturedAcl; 2592 2593 /* Capture and copy the dacl */ 2594 Status = SepCaptureAcl(InputAcl, 2595 PreviousMode, 2596 PagedPool, 2597 TRUE, 2598 &CapturedAcl); 2599 if (NT_SUCCESS(Status)) 2600 { 2601 ULONG DynamicLength; 2602 2603 /* Lock the token */ 2604 SepAcquireTokenLockExclusive(Token); 2605 2606 // 2607 // NOTE: So far our dynamic area only contains 2608 // the default dacl, so this makes the following 2609 // code pretty simple. The day where it stores 2610 // other data, the code will require adaptations. 2611 // 2612 2613 DynamicLength = Token->DynamicAvailable; 2614 // Add here any other data length present in the dynamic area... 2615 if (Token->DefaultDacl) 2616 DynamicLength += Token->DefaultDacl->AclSize; 2617 2618 /* Reallocate the dynamic area if it is too small */ 2619 Status = STATUS_SUCCESS; 2620 if ((DynamicLength < CapturedAcl->AclSize) || 2621 (Token->DynamicPart == NULL)) 2622 { 2623 PVOID NewDynamicPart; 2624 2625 NewDynamicPart = ExAllocatePoolWithTag(PagedPool, 2626 CapturedAcl->AclSize, 2627 TAG_TOKEN_DYNAMIC); 2628 if (NewDynamicPart == NULL) 2629 { 2630 Status = STATUS_INSUFFICIENT_RESOURCES; 2631 } 2632 else 2633 { 2634 if (Token->DynamicPart != NULL) 2635 { 2636 // RtlCopyMemory(NewDynamicPart, Token->DynamicPart, DynamicLength); 2637 ExFreePoolWithTag(Token->DynamicPart, TAG_TOKEN_DYNAMIC); 2638 } 2639 Token->DynamicPart = NewDynamicPart; 2640 Token->DynamicAvailable = 0; 2641 } 2642 } 2643 else 2644 { 2645 Token->DynamicAvailable = DynamicLength - CapturedAcl->AclSize; 2646 } 2647 2648 if (NT_SUCCESS(Status)) 2649 { 2650 /* Set the new dacl */ 2651 Token->DefaultDacl = (PVOID)Token->DynamicPart; 2652 RtlCopyMemory(Token->DefaultDacl, 2653 CapturedAcl, 2654 CapturedAcl->AclSize); 2655 2656 ExAllocateLocallyUniqueId(&Token->ModifiedId); 2657 } 2658 2659 /* Unlock the token */ 2660 SepReleaseTokenLock(Token); 2661 2662 ExFreePoolWithTag(CapturedAcl, TAG_ACL); 2663 } 2664 } 2665 else 2666 { 2667 /* Lock the token */ 2668 SepAcquireTokenLockExclusive(Token); 2669 2670 /* Clear the default dacl if present */ 2671 if (Token->DefaultDacl != NULL) 2672 { 2673 Token->DynamicAvailable += Token->DefaultDacl->AclSize; 2674 RtlZeroMemory(Token->DefaultDacl, Token->DefaultDacl->AclSize); 2675 Token->DefaultDacl = NULL; 2676 2677 ExAllocateLocallyUniqueId(&Token->ModifiedId); 2678 } 2679 2680 /* Unlock the token */ 2681 SepReleaseTokenLock(Token); 2682 } 2683 } 2684 else 2685 { 2686 Status = STATUS_INFO_LENGTH_MISMATCH; 2687 } 2688 break; 2689 } 2690 2691 case TokenSessionId: 2692 { 2693 ULONG SessionId = 0; 2694 2695 _SEH2_TRY 2696 { 2697 /* Buffer size was already verified, no need to check here again */ 2698 SessionId = *(PULONG)TokenInformation; 2699 } 2700 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2701 { 2702 Status = _SEH2_GetExceptionCode(); 2703 _SEH2_YIELD(goto Cleanup); 2704 } 2705 _SEH2_END; 2706 2707 /* Check for TCB privilege */ 2708 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 2709 { 2710 Status = STATUS_PRIVILEGE_NOT_HELD; 2711 break; 2712 } 2713 2714 /* Lock the token */ 2715 SepAcquireTokenLockExclusive(Token); 2716 2717 Token->SessionId = SessionId; 2718 ExAllocateLocallyUniqueId(&Token->ModifiedId); 2719 2720 /* Unlock the token */ 2721 SepReleaseTokenLock(Token); 2722 2723 break; 2724 } 2725 2726 case TokenSessionReference: 2727 { 2728 ULONG SessionReference; 2729 2730 _SEH2_TRY 2731 { 2732 /* Buffer size was already verified, no need to check here again */ 2733 SessionReference = *(PULONG)TokenInformation; 2734 } 2735 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2736 { 2737 Status = _SEH2_GetExceptionCode(); 2738 _SEH2_YIELD(goto Cleanup); 2739 } 2740 _SEH2_END; 2741 2742 /* Check for TCB privilege */ 2743 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 2744 { 2745 Status = STATUS_PRIVILEGE_NOT_HELD; 2746 goto Cleanup; 2747 } 2748 2749 /* Check if it is 0 */ 2750 if (SessionReference == 0) 2751 { 2752 ULONG OldTokenFlags; 2753 2754 /* Lock the token */ 2755 SepAcquireTokenLockExclusive(Token); 2756 2757 /* Atomically set the flag in the token */ 2758 OldTokenFlags = RtlInterlockedSetBits(&Token->TokenFlags, 2759 TOKEN_SESSION_NOT_REFERENCED); 2760 /* 2761 * If the flag was already set, do not dereference again 2762 * the logon session. Use SessionReference as an indicator 2763 * to know whether to really dereference the session. 2764 */ 2765 if (OldTokenFlags == Token->TokenFlags) 2766 SessionReference = ULONG_MAX; 2767 2768 /* Unlock the token */ 2769 SepReleaseTokenLock(Token); 2770 } 2771 2772 /* Dereference the logon session if needed */ 2773 if (SessionReference == 0) 2774 SepRmDereferenceLogonSession(&Token->AuthenticationId); 2775 2776 break; 2777 } 2778 2779 case TokenAuditPolicy: 2780 { 2781 PTOKEN_AUDIT_POLICY_INFORMATION PolicyInformation = 2782 (PTOKEN_AUDIT_POLICY_INFORMATION)TokenInformation; 2783 SEP_AUDIT_POLICY AuditPolicy; 2784 ULONG i; 2785 2786 _SEH2_TRY 2787 { 2788 ProbeForRead(PolicyInformation, 2789 FIELD_OFFSET(TOKEN_AUDIT_POLICY_INFORMATION, 2790 Policies[PolicyInformation->PolicyCount]), 2791 sizeof(ULONG)); 2792 2793 /* Loop all policies in the structure */ 2794 for (i = 0; i < PolicyInformation->PolicyCount; i++) 2795 { 2796 /* Set the corresponding bits in the packed structure */ 2797 switch (PolicyInformation->Policies[i].Category) 2798 { 2799 case AuditCategorySystem: 2800 AuditPolicy.PolicyElements.System = PolicyInformation->Policies[i].Value; 2801 break; 2802 2803 case AuditCategoryLogon: 2804 AuditPolicy.PolicyElements.Logon = PolicyInformation->Policies[i].Value; 2805 break; 2806 2807 case AuditCategoryObjectAccess: 2808 AuditPolicy.PolicyElements.ObjectAccess = PolicyInformation->Policies[i].Value; 2809 break; 2810 2811 case AuditCategoryPrivilegeUse: 2812 AuditPolicy.PolicyElements.PrivilegeUse = PolicyInformation->Policies[i].Value; 2813 break; 2814 2815 case AuditCategoryDetailedTracking: 2816 AuditPolicy.PolicyElements.DetailedTracking = PolicyInformation->Policies[i].Value; 2817 break; 2818 2819 case AuditCategoryPolicyChange: 2820 AuditPolicy.PolicyElements.PolicyChange = PolicyInformation->Policies[i].Value; 2821 break; 2822 2823 case AuditCategoryAccountManagement: 2824 AuditPolicy.PolicyElements.AccountManagement = PolicyInformation->Policies[i].Value; 2825 break; 2826 2827 case AuditCategoryDirectoryServiceAccess: 2828 AuditPolicy.PolicyElements.DirectoryServiceAccess = PolicyInformation->Policies[i].Value; 2829 break; 2830 2831 case AuditCategoryAccountLogon: 2832 AuditPolicy.PolicyElements.AccountLogon = PolicyInformation->Policies[i].Value; 2833 break; 2834 } 2835 } 2836 } 2837 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2838 { 2839 Status = _SEH2_GetExceptionCode(); 2840 _SEH2_YIELD(goto Cleanup); 2841 } 2842 _SEH2_END; 2843 2844 /* Check for TCB privilege */ 2845 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 2846 { 2847 Status = STATUS_PRIVILEGE_NOT_HELD; 2848 break; 2849 } 2850 2851 /* Lock the token */ 2852 SepAcquireTokenLockExclusive(Token); 2853 2854 /* Set the new audit policy */ 2855 Token->AuditPolicy = AuditPolicy; 2856 ExAllocateLocallyUniqueId(&Token->ModifiedId); 2857 2858 /* Unlock the token */ 2859 SepReleaseTokenLock(Token); 2860 2861 break; 2862 } 2863 2864 case TokenOrigin: 2865 { 2866 TOKEN_ORIGIN TokenOrigin; 2867 2868 _SEH2_TRY 2869 { 2870 /* Copy the token origin */ 2871 TokenOrigin = *(PTOKEN_ORIGIN)TokenInformation; 2872 } 2873 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2874 { 2875 Status = _SEH2_GetExceptionCode(); 2876 _SEH2_YIELD(goto Cleanup); 2877 } 2878 _SEH2_END; 2879 2880 /* Check for TCB privilege */ 2881 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 2882 { 2883 Status = STATUS_PRIVILEGE_NOT_HELD; 2884 break; 2885 } 2886 2887 /* Lock the token */ 2888 SepAcquireTokenLockExclusive(Token); 2889 2890 /* Check if there is no token origin set yet */ 2891 if (RtlIsZeroLuid(&Token->OriginatingLogonSession)) 2892 { 2893 /* Set the token origin */ 2894 Token->OriginatingLogonSession = 2895 TokenOrigin.OriginatingLogonSession; 2896 2897 ExAllocateLocallyUniqueId(&Token->ModifiedId); 2898 } 2899 2900 /* Unlock the token */ 2901 SepReleaseTokenLock(Token); 2902 2903 break; 2904 } 2905 2906 default: 2907 { 2908 DPRINT1("Invalid TokenInformationClass: 0x%lx\n", 2909 TokenInformationClass); 2910 Status = STATUS_INVALID_INFO_CLASS; 2911 break; 2912 } 2913 } 2914 Cleanup: 2915 ObDereferenceObject(Token); 2916 } 2917 2918 if (!NT_SUCCESS(Status)) 2919 { 2920 DPRINT1("NtSetInformationToken failed with Status 0x%lx\n", Status); 2921 } 2922 2923 return Status; 2924 } 2925 2926 2927 /* 2928 * @implemented 2929 * 2930 * NOTE: Some sources claim 4th param is ImpersonationLevel, but on W2K 2931 * this is certainly NOT true, although I can't say for sure that EffectiveOnly 2932 * is correct either. -Gunnar 2933 * This is true. EffectiveOnly overrides SQOS.EffectiveOnly. - IAI 2934 * NOTE for readers: http://hex.pp.ua/nt/NtDuplicateToken.php is therefore 2935 * wrong in that regard, while MSDN documentation is correct. 2936 */ 2937 _Must_inspect_result_ 2938 __kernel_entry 2939 NTSTATUS 2940 NTAPI 2941 NtDuplicateToken( 2942 _In_ HANDLE ExistingTokenHandle, 2943 _In_ ACCESS_MASK DesiredAccess, 2944 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, 2945 _In_ BOOLEAN EffectiveOnly, 2946 _In_ TOKEN_TYPE TokenType, 2947 _Out_ PHANDLE NewTokenHandle) 2948 { 2949 KPROCESSOR_MODE PreviousMode; 2950 HANDLE hToken; 2951 PTOKEN Token; 2952 PTOKEN NewToken; 2953 PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService; 2954 BOOLEAN QoSPresent; 2955 OBJECT_HANDLE_INFORMATION HandleInformation; 2956 NTSTATUS Status; 2957 2958 PAGED_CODE(); 2959 2960 if (TokenType != TokenImpersonation && 2961 TokenType != TokenPrimary) 2962 { 2963 return STATUS_INVALID_PARAMETER; 2964 } 2965 2966 PreviousMode = KeGetPreviousMode(); 2967 2968 if (PreviousMode != KernelMode) 2969 { 2970 _SEH2_TRY 2971 { 2972 ProbeForWriteHandle(NewTokenHandle); 2973 } 2974 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2975 { 2976 /* Return the exception code */ 2977 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2978 } 2979 _SEH2_END; 2980 } 2981 2982 Status = SepCaptureSecurityQualityOfService(ObjectAttributes, 2983 PreviousMode, 2984 PagedPool, 2985 FALSE, 2986 &CapturedSecurityQualityOfService, 2987 &QoSPresent); 2988 if (!NT_SUCCESS(Status)) 2989 { 2990 DPRINT1("NtDuplicateToken() failed to capture QoS! Status: 0x%x\n", Status); 2991 return Status; 2992 } 2993 2994 Status = ObReferenceObjectByHandle(ExistingTokenHandle, 2995 TOKEN_DUPLICATE, 2996 SeTokenObjectType, 2997 PreviousMode, 2998 (PVOID*)&Token, 2999 &HandleInformation); 3000 if (!NT_SUCCESS(Status)) 3001 { 3002 DPRINT1("Failed to reference token (Status 0x%lx)\n", Status); 3003 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService, 3004 PreviousMode, 3005 FALSE); 3006 return Status; 3007 } 3008 3009 /* 3010 * Fail, if the original token is an impersonation token and the caller 3011 * tries to raise the impersonation level of the new token above the 3012 * impersonation level of the original token. 3013 */ 3014 if (Token->TokenType == TokenImpersonation) 3015 { 3016 if (QoSPresent && 3017 CapturedSecurityQualityOfService->ImpersonationLevel >Token->ImpersonationLevel) 3018 { 3019 ObDereferenceObject(Token); 3020 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService, 3021 PreviousMode, 3022 FALSE); 3023 return STATUS_BAD_IMPERSONATION_LEVEL; 3024 } 3025 } 3026 3027 /* 3028 * Fail, if a primary token is to be created from an impersonation token 3029 * and and the impersonation level of the impersonation token is below SecurityImpersonation. 3030 */ 3031 if (Token->TokenType == TokenImpersonation && 3032 TokenType == TokenPrimary && 3033 Token->ImpersonationLevel < SecurityImpersonation) 3034 { 3035 ObDereferenceObject(Token); 3036 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService, 3037 PreviousMode, 3038 FALSE); 3039 return STATUS_BAD_IMPERSONATION_LEVEL; 3040 } 3041 3042 Status = SepDuplicateToken(Token, 3043 ObjectAttributes, 3044 EffectiveOnly, 3045 TokenType, 3046 (QoSPresent ? CapturedSecurityQualityOfService->ImpersonationLevel : SecurityAnonymous), 3047 PreviousMode, 3048 &NewToken); 3049 3050 ObDereferenceObject(Token); 3051 3052 if (NT_SUCCESS(Status)) 3053 { 3054 Status = ObInsertObject(NewToken, 3055 NULL, 3056 (DesiredAccess ? DesiredAccess : HandleInformation.GrantedAccess), 3057 0, 3058 NULL, 3059 &hToken); 3060 if (NT_SUCCESS(Status)) 3061 { 3062 _SEH2_TRY 3063 { 3064 *NewTokenHandle = hToken; 3065 } 3066 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3067 { 3068 Status = _SEH2_GetExceptionCode(); 3069 } 3070 _SEH2_END; 3071 } 3072 } 3073 3074 /* Free the captured structure */ 3075 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService, 3076 PreviousMode, 3077 FALSE); 3078 3079 return Status; 3080 } 3081 3082 NTSTATUS NTAPI 3083 NtAdjustGroupsToken(IN HANDLE TokenHandle, 3084 IN BOOLEAN ResetToDefault, 3085 IN PTOKEN_GROUPS NewState, 3086 IN ULONG BufferLength, 3087 OUT PTOKEN_GROUPS PreviousState OPTIONAL, 3088 OUT PULONG ReturnLength) 3089 { 3090 UNIMPLEMENTED; 3091 return STATUS_NOT_IMPLEMENTED; 3092 } 3093 3094 3095 static 3096 NTSTATUS 3097 SepAdjustPrivileges( 3098 _Inout_ PTOKEN Token, 3099 _In_ BOOLEAN DisableAllPrivileges, 3100 _In_opt_ PLUID_AND_ATTRIBUTES NewState, 3101 _In_ ULONG NewStateCount, 3102 _Out_opt_ PTOKEN_PRIVILEGES PreviousState, 3103 _In_ BOOLEAN ApplyChanges, 3104 _Out_ PULONG ChangedPrivileges, 3105 _Out_ PBOOLEAN ChangesMade) 3106 { 3107 ULONG i, j, PrivilegeCount, ChangeCount, NewAttributes; 3108 3109 /* Count the found privileges and those that need to be changed */ 3110 PrivilegeCount = 0; 3111 ChangeCount = 0; 3112 *ChangesMade = FALSE; 3113 3114 /* Loop all privileges in the token */ 3115 for (i = 0; i < Token->PrivilegeCount; i++) 3116 { 3117 /* Shall all of them be disabled? */ 3118 if (DisableAllPrivileges) 3119 { 3120 /* The new attributes are the old ones, but disabled */ 3121 NewAttributes = Token->Privileges[i].Attributes & ~SE_PRIVILEGE_ENABLED; 3122 } 3123 else 3124 { 3125 /* Otherwise loop all provided privileges */ 3126 for (j = 0; j < NewStateCount; j++) 3127 { 3128 /* Check if this is the LUID we are looking for */ 3129 if (RtlEqualLuid(&Token->Privileges[i].Luid, &NewState[j].Luid)) 3130 { 3131 DPRINT("Found privilege\n"); 3132 3133 /* Copy SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED */ 3134 NewAttributes = NewState[j].Attributes; 3135 NewAttributes &= (SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED); 3136 NewAttributes |= Token->Privileges[i].Attributes & ~SE_PRIVILEGE_ENABLED; 3137 3138 /* Stop looking */ 3139 break; 3140 } 3141 } 3142 3143 /* Check if we didn't find the privilege */ 3144 if (j == NewStateCount) 3145 { 3146 /* Continue with the token's next privilege */ 3147 continue; 3148 } 3149 } 3150 3151 /* We found a privilege, count it */ 3152 PrivilegeCount++; 3153 3154 /* Does the privilege need to be changed? */ 3155 if (Token->Privileges[i].Attributes != NewAttributes) 3156 { 3157 /* Does the caller want the old privileges? */ 3158 if (PreviousState != NULL) 3159 { 3160 /* Copy the old privilege */ 3161 PreviousState->Privileges[ChangeCount] = Token->Privileges[i]; 3162 } 3163 3164 /* Does the caller want to apply the changes? */ 3165 if (ApplyChanges) 3166 { 3167 /* Shall we remove the privilege? */ 3168 if (NewAttributes & SE_PRIVILEGE_REMOVED) 3169 { 3170 /* Set the token as disabled and update flags for it */ 3171 Token->Privileges[i].Attributes &= ~SE_PRIVILEGE_ENABLED; 3172 SepUpdateSinglePrivilegeFlagToken(Token, i); 3173 3174 /* Remove the privilege */ 3175 SepRemovePrivilegeToken(Token, i); 3176 3177 *ChangesMade = TRUE; 3178 3179 /* Fix the running index and continue with next one */ 3180 i--; 3181 continue; 3182 } 3183 3184 /* Set the new attributes and update flags */ 3185 Token->Privileges[i].Attributes = NewAttributes; 3186 SepUpdateSinglePrivilegeFlagToken(Token, i); 3187 *ChangesMade = TRUE; 3188 } 3189 3190 /* Increment the change count */ 3191 ChangeCount++; 3192 } 3193 } 3194 3195 /* Set the number of saved privileges */ 3196 if (PreviousState != NULL) 3197 PreviousState->PrivilegeCount = ChangeCount; 3198 3199 /* Return the number of changed privileges */ 3200 *ChangedPrivileges = ChangeCount; 3201 3202 /* Check if we missed some */ 3203 if (!DisableAllPrivileges && (PrivilegeCount < NewStateCount)) 3204 { 3205 return STATUS_NOT_ALL_ASSIGNED; 3206 } 3207 3208 return STATUS_SUCCESS; 3209 } 3210 3211 3212 /* 3213 * @implemented 3214 */ 3215 _Must_inspect_result_ 3216 __kernel_entry 3217 NTSTATUS 3218 NTAPI 3219 NtAdjustPrivilegesToken( 3220 _In_ HANDLE TokenHandle, 3221 _In_ BOOLEAN DisableAllPrivileges, 3222 _In_opt_ PTOKEN_PRIVILEGES NewState, 3223 _In_ ULONG BufferLength, 3224 _Out_writes_bytes_to_opt_(BufferLength,*ReturnLength) 3225 PTOKEN_PRIVILEGES PreviousState, 3226 _When_(PreviousState!=NULL, _Out_) PULONG ReturnLength) 3227 { 3228 NTSTATUS Status; 3229 KPROCESSOR_MODE PreviousMode; 3230 PTOKEN Token; 3231 PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL; 3232 ULONG CapturedCount = 0; 3233 ULONG CapturedLength = 0; 3234 ULONG NewStateSize = 0; 3235 ULONG ChangeCount; 3236 ULONG RequiredLength; 3237 BOOLEAN ChangesMade = FALSE; 3238 3239 PAGED_CODE(); 3240 3241 DPRINT("NtAdjustPrivilegesToken() called\n"); 3242 3243 /* Fail, if we do not disable all privileges but NewState is NULL */ 3244 if (DisableAllPrivileges == FALSE && NewState == NULL) 3245 return STATUS_INVALID_PARAMETER; 3246 3247 PreviousMode = KeGetPreviousMode(); 3248 if (PreviousMode != KernelMode) 3249 { 3250 _SEH2_TRY 3251 { 3252 /* Probe NewState */ 3253 if (DisableAllPrivileges == FALSE) 3254 { 3255 /* First probe the header */ 3256 ProbeForRead(NewState, sizeof(TOKEN_PRIVILEGES), sizeof(ULONG)); 3257 3258 CapturedCount = NewState->PrivilegeCount; 3259 NewStateSize = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[CapturedCount]); 3260 3261 ProbeForRead(NewState, NewStateSize, sizeof(ULONG)); 3262 } 3263 3264 /* Probe PreviousState and ReturnLength */ 3265 if (PreviousState != NULL) 3266 { 3267 ProbeForWrite(PreviousState, BufferLength, sizeof(ULONG)); 3268 ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG)); 3269 } 3270 } 3271 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3272 { 3273 /* Return the exception code */ 3274 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3275 } 3276 _SEH2_END; 3277 } 3278 else 3279 { 3280 /* This is kernel mode, we trust the caller */ 3281 if (DisableAllPrivileges == FALSE) 3282 CapturedCount = NewState->PrivilegeCount; 3283 } 3284 3285 /* Do we need to capture the new state? */ 3286 if (DisableAllPrivileges == FALSE) 3287 { 3288 _SEH2_TRY 3289 { 3290 /* Capture the new state array of privileges */ 3291 Status = SeCaptureLuidAndAttributesArray(NewState->Privileges, 3292 CapturedCount, 3293 PreviousMode, 3294 NULL, 3295 0, 3296 PagedPool, 3297 TRUE, 3298 &CapturedPrivileges, 3299 &CapturedLength); 3300 } 3301 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3302 { 3303 /* Return the exception code */ 3304 Status = _SEH2_GetExceptionCode(); 3305 } 3306 _SEH2_END; 3307 3308 if (!NT_SUCCESS(Status)) 3309 return Status; 3310 } 3311 3312 /* Reference the token */ 3313 Status = ObReferenceObjectByHandle(TokenHandle, 3314 TOKEN_ADJUST_PRIVILEGES | (PreviousState != NULL ? TOKEN_QUERY : 0), 3315 SeTokenObjectType, 3316 PreviousMode, 3317 (PVOID*)&Token, 3318 NULL); 3319 if (!NT_SUCCESS(Status)) 3320 { 3321 DPRINT1("Failed to reference token (Status 0x%lx)\n", Status); 3322 3323 /* Release the captured privileges */ 3324 if (CapturedPrivileges != NULL) 3325 { 3326 SeReleaseLuidAndAttributesArray(CapturedPrivileges, 3327 PreviousMode, 3328 TRUE); 3329 } 3330 3331 return Status; 3332 } 3333 3334 /* Lock the token */ 3335 SepAcquireTokenLockExclusive(Token); 3336 3337 /* Count the privileges that need to be changed, do not apply them yet */ 3338 Status = SepAdjustPrivileges(Token, 3339 DisableAllPrivileges, 3340 CapturedPrivileges, 3341 CapturedCount, 3342 NULL, 3343 FALSE, 3344 &ChangeCount, 3345 &ChangesMade); 3346 3347 /* Check if the caller asked for the previous state */ 3348 if (PreviousState != NULL) 3349 { 3350 /* Calculate the required length */ 3351 RequiredLength = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[ChangeCount]); 3352 3353 /* Try to return the required buffer length */ 3354 _SEH2_TRY 3355 { 3356 *ReturnLength = RequiredLength; 3357 } 3358 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3359 { 3360 /* Do cleanup and return the exception code */ 3361 Status = _SEH2_GetExceptionCode(); 3362 _SEH2_YIELD(goto Cleanup); 3363 } 3364 _SEH2_END; 3365 3366 /* Fail, if the buffer length is smaller than the required length */ 3367 if (BufferLength < RequiredLength) 3368 { 3369 Status = STATUS_BUFFER_TOO_SMALL; 3370 goto Cleanup; 3371 } 3372 } 3373 3374 /* Now enter SEH, since we might return the old privileges */ 3375 _SEH2_TRY 3376 { 3377 /* This time apply the changes */ 3378 Status = SepAdjustPrivileges(Token, 3379 DisableAllPrivileges, 3380 CapturedPrivileges, 3381 CapturedCount, 3382 PreviousState, 3383 TRUE, 3384 &ChangeCount, 3385 &ChangesMade); 3386 } 3387 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3388 { 3389 /* Do cleanup and return the exception code */ 3390 Status = _SEH2_GetExceptionCode(); 3391 ChangesMade = TRUE; // Force write. 3392 _SEH2_YIELD(goto Cleanup); 3393 } 3394 _SEH2_END; 3395 3396 Cleanup: 3397 /* Touch the token if we made changes */ 3398 if (ChangesMade) 3399 ExAllocateLocallyUniqueId(&Token->ModifiedId); 3400 3401 /* Unlock and dereference the token */ 3402 SepReleaseTokenLock(Token); 3403 ObDereferenceObject(Token); 3404 3405 /* Release the captured privileges */ 3406 if (CapturedPrivileges != NULL) 3407 { 3408 SeReleaseLuidAndAttributesArray(CapturedPrivileges, 3409 PreviousMode, 3410 TRUE); 3411 } 3412 3413 DPRINT ("NtAdjustPrivilegesToken() done\n"); 3414 return Status; 3415 } 3416 3417 __kernel_entry 3418 NTSTATUS 3419 NTAPI 3420 NtCreateToken( 3421 _Out_ PHANDLE TokenHandle, 3422 _In_ ACCESS_MASK DesiredAccess, 3423 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, 3424 _In_ TOKEN_TYPE TokenType, 3425 _In_ PLUID AuthenticationId, 3426 _In_ PLARGE_INTEGER ExpirationTime, 3427 _In_ PTOKEN_USER TokenUser, 3428 _In_ PTOKEN_GROUPS TokenGroups, 3429 _In_ PTOKEN_PRIVILEGES TokenPrivileges, 3430 _In_opt_ PTOKEN_OWNER TokenOwner, 3431 _In_ PTOKEN_PRIMARY_GROUP TokenPrimaryGroup, 3432 _In_opt_ PTOKEN_DEFAULT_DACL TokenDefaultDacl, 3433 _In_ PTOKEN_SOURCE TokenSource) 3434 { 3435 HANDLE hToken; 3436 KPROCESSOR_MODE PreviousMode; 3437 ULONG PrivilegeCount, GroupCount; 3438 PSID OwnerSid, PrimaryGroupSid; 3439 PACL DefaultDacl; 3440 LARGE_INTEGER LocalExpirationTime = {{0, 0}}; 3441 LUID LocalAuthenticationId; 3442 TOKEN_SOURCE LocalTokenSource; 3443 SECURITY_QUALITY_OF_SERVICE LocalSecurityQos; 3444 PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL; 3445 PSID_AND_ATTRIBUTES CapturedUser = NULL; 3446 PSID_AND_ATTRIBUTES CapturedGroups = NULL; 3447 PSID CapturedOwnerSid = NULL; 3448 PSID CapturedPrimaryGroupSid = NULL; 3449 PACL CapturedDefaultDacl = NULL; 3450 ULONG PrivilegesLength, UserLength, GroupsLength; 3451 NTSTATUS Status; 3452 3453 PAGED_CODE(); 3454 3455 PreviousMode = ExGetPreviousMode(); 3456 3457 if (PreviousMode != KernelMode) 3458 { 3459 _SEH2_TRY 3460 { 3461 ProbeForWriteHandle(TokenHandle); 3462 3463 if (ObjectAttributes != NULL) 3464 { 3465 ProbeForRead(ObjectAttributes, 3466 sizeof(OBJECT_ATTRIBUTES), 3467 sizeof(ULONG)); 3468 LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService; 3469 } 3470 3471 ProbeForRead(AuthenticationId, 3472 sizeof(LUID), 3473 sizeof(ULONG)); 3474 LocalAuthenticationId = *AuthenticationId; 3475 3476 LocalExpirationTime = ProbeForReadLargeInteger(ExpirationTime); 3477 3478 ProbeForRead(TokenUser, 3479 sizeof(TOKEN_USER), 3480 sizeof(ULONG)); 3481 3482 ProbeForRead(TokenGroups, 3483 sizeof(TOKEN_GROUPS), 3484 sizeof(ULONG)); 3485 GroupCount = TokenGroups->GroupCount; 3486 3487 ProbeForRead(TokenPrivileges, 3488 sizeof(TOKEN_PRIVILEGES), 3489 sizeof(ULONG)); 3490 PrivilegeCount = TokenPrivileges->PrivilegeCount; 3491 3492 if (TokenOwner != NULL) 3493 { 3494 ProbeForRead(TokenOwner, 3495 sizeof(TOKEN_OWNER), 3496 sizeof(ULONG)); 3497 OwnerSid = TokenOwner->Owner; 3498 } 3499 else 3500 { 3501 OwnerSid = NULL; 3502 } 3503 3504 ProbeForRead(TokenPrimaryGroup, 3505 sizeof(TOKEN_PRIMARY_GROUP), 3506 sizeof(ULONG)); 3507 PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup; 3508 3509 if (TokenDefaultDacl != NULL) 3510 { 3511 ProbeForRead(TokenDefaultDacl, 3512 sizeof(TOKEN_DEFAULT_DACL), 3513 sizeof(ULONG)); 3514 DefaultDacl = TokenDefaultDacl->DefaultDacl; 3515 } 3516 else 3517 { 3518 DefaultDacl = NULL; 3519 } 3520 3521 ProbeForRead(TokenSource, 3522 sizeof(TOKEN_SOURCE), 3523 sizeof(ULONG)); 3524 LocalTokenSource = *TokenSource; 3525 } 3526 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3527 { 3528 /* Return the exception code */ 3529 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3530 } 3531 _SEH2_END; 3532 } 3533 else 3534 { 3535 if (ObjectAttributes != NULL) 3536 LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService; 3537 LocalAuthenticationId = *AuthenticationId; 3538 LocalExpirationTime = *ExpirationTime; 3539 GroupCount = TokenGroups->GroupCount; 3540 PrivilegeCount = TokenPrivileges->PrivilegeCount; 3541 OwnerSid = TokenOwner ? TokenOwner->Owner : NULL; 3542 PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup; 3543 DefaultDacl = TokenDefaultDacl ? TokenDefaultDacl->DefaultDacl : NULL; 3544 LocalTokenSource = *TokenSource; 3545 } 3546 3547 /* Check token type */ 3548 if ((TokenType < TokenPrimary) || 3549 (TokenType > TokenImpersonation)) 3550 { 3551 return STATUS_BAD_TOKEN_TYPE; 3552 } 3553 3554 /* Check for token creation privilege */ 3555 if (!SeSinglePrivilegeCheck(SeCreateTokenPrivilege, PreviousMode)) 3556 { 3557 return STATUS_PRIVILEGE_NOT_HELD; 3558 } 3559 3560 /* Capture the user SID and attributes */ 3561 Status = SeCaptureSidAndAttributesArray(&TokenUser->User, 3562 1, 3563 PreviousMode, 3564 NULL, 3565 0, 3566 PagedPool, 3567 FALSE, 3568 &CapturedUser, 3569 &UserLength); 3570 if (!NT_SUCCESS(Status)) 3571 { 3572 goto Cleanup; 3573 } 3574 3575 /* Capture the groups SID and attributes array */ 3576 Status = SeCaptureSidAndAttributesArray(&TokenGroups->Groups[0], 3577 GroupCount, 3578 PreviousMode, 3579 NULL, 3580 0, 3581 PagedPool, 3582 FALSE, 3583 &CapturedGroups, 3584 &GroupsLength); 3585 if (!NT_SUCCESS(Status)) 3586 { 3587 goto Cleanup; 3588 } 3589 3590 /* Capture privileges */ 3591 Status = SeCaptureLuidAndAttributesArray(&TokenPrivileges->Privileges[0], 3592 PrivilegeCount, 3593 PreviousMode, 3594 NULL, 3595 0, 3596 PagedPool, 3597 FALSE, 3598 &CapturedPrivileges, 3599 &PrivilegesLength); 3600 if (!NT_SUCCESS(Status)) 3601 { 3602 goto Cleanup; 3603 } 3604 3605 /* Capture the token owner SID */ 3606 if (TokenOwner != NULL) 3607 { 3608 Status = SepCaptureSid(OwnerSid, 3609 PreviousMode, 3610 PagedPool, 3611 FALSE, 3612 &CapturedOwnerSid); 3613 if (!NT_SUCCESS(Status)) 3614 { 3615 goto Cleanup; 3616 } 3617 } 3618 3619 /* Capture the token primary group SID */ 3620 Status = SepCaptureSid(PrimaryGroupSid, 3621 PreviousMode, 3622 PagedPool, 3623 FALSE, 3624 &CapturedPrimaryGroupSid); 3625 if (!NT_SUCCESS(Status)) 3626 { 3627 goto Cleanup; 3628 } 3629 3630 /* Capture DefaultDacl */ 3631 if (DefaultDacl != NULL) 3632 { 3633 Status = SepCaptureAcl(DefaultDacl, 3634 PreviousMode, 3635 NonPagedPool, 3636 FALSE, 3637 &CapturedDefaultDacl); 3638 if (!NT_SUCCESS(Status)) 3639 { 3640 goto Cleanup; 3641 } 3642 } 3643 3644 /* Call the internal function */ 3645 Status = SepCreateToken(&hToken, 3646 PreviousMode, 3647 DesiredAccess, 3648 ObjectAttributes, 3649 TokenType, 3650 LocalSecurityQos.ImpersonationLevel, 3651 &LocalAuthenticationId, 3652 &LocalExpirationTime, 3653 CapturedUser, 3654 GroupCount, 3655 CapturedGroups, 3656 0, // FIXME: Should capture 3657 PrivilegeCount, 3658 CapturedPrivileges, 3659 CapturedOwnerSid, 3660 CapturedPrimaryGroupSid, 3661 CapturedDefaultDacl, 3662 &LocalTokenSource, 3663 FALSE); 3664 if (NT_SUCCESS(Status)) 3665 { 3666 _SEH2_TRY 3667 { 3668 *TokenHandle = hToken; 3669 } 3670 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3671 { 3672 Status = _SEH2_GetExceptionCode(); 3673 } 3674 _SEH2_END; 3675 } 3676 3677 Cleanup: 3678 3679 /* Release what we captured */ 3680 SeReleaseSidAndAttributesArray(CapturedUser, PreviousMode, FALSE); 3681 SeReleaseSidAndAttributesArray(CapturedGroups, PreviousMode, FALSE); 3682 SeReleaseLuidAndAttributesArray(CapturedPrivileges, PreviousMode, FALSE); 3683 SepReleaseSid(CapturedOwnerSid, PreviousMode, FALSE); 3684 SepReleaseSid(CapturedPrimaryGroupSid, PreviousMode, FALSE); 3685 SepReleaseAcl(CapturedDefaultDacl, PreviousMode, FALSE); 3686 3687 return Status; 3688 } 3689 3690 /* 3691 * @implemented 3692 */ 3693 NTSTATUS 3694 NTAPI 3695 NtOpenThreadTokenEx(IN HANDLE ThreadHandle, 3696 IN ACCESS_MASK DesiredAccess, 3697 IN BOOLEAN OpenAsSelf, 3698 IN ULONG HandleAttributes, 3699 OUT PHANDLE TokenHandle) 3700 { 3701 PETHREAD Thread, NewThread; 3702 HANDLE hToken; 3703 PTOKEN Token, NewToken = NULL, PrimaryToken; 3704 BOOLEAN CopyOnOpen, EffectiveOnly; 3705 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; 3706 SE_IMPERSONATION_STATE ImpersonationState; 3707 OBJECT_ATTRIBUTES ObjectAttributes; 3708 SECURITY_DESCRIPTOR SecurityDescriptor; 3709 PACL Dacl = NULL; 3710 KPROCESSOR_MODE PreviousMode; 3711 NTSTATUS Status; 3712 BOOLEAN RestoreImpersonation = FALSE; 3713 3714 PAGED_CODE(); 3715 3716 PreviousMode = ExGetPreviousMode(); 3717 3718 if (PreviousMode != KernelMode) 3719 { 3720 _SEH2_TRY 3721 { 3722 ProbeForWriteHandle(TokenHandle); 3723 } 3724 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3725 { 3726 /* Return the exception code */ 3727 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3728 } 3729 _SEH2_END; 3730 } 3731 3732 /* Validate object attributes */ 3733 HandleAttributes = ObpValidateAttributes(HandleAttributes, PreviousMode); 3734 3735 /* 3736 * At first open the thread token for information access and verify 3737 * that the token associated with thread is valid. 3738 */ 3739 3740 Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_QUERY_INFORMATION, 3741 PsThreadType, PreviousMode, (PVOID*)&Thread, 3742 NULL); 3743 if (!NT_SUCCESS(Status)) 3744 { 3745 return Status; 3746 } 3747 3748 Token = PsReferenceImpersonationToken(Thread, &CopyOnOpen, &EffectiveOnly, 3749 &ImpersonationLevel); 3750 if (Token == NULL) 3751 { 3752 ObDereferenceObject(Thread); 3753 return STATUS_NO_TOKEN; 3754 } 3755 3756 if (ImpersonationLevel == SecurityAnonymous) 3757 { 3758 PsDereferenceImpersonationToken(Token); 3759 ObDereferenceObject(Thread); 3760 return STATUS_CANT_OPEN_ANONYMOUS; 3761 } 3762 3763 /* 3764 * Revert to self if OpenAsSelf is specified. 3765 */ 3766 3767 if (OpenAsSelf) 3768 { 3769 RestoreImpersonation = PsDisableImpersonation(PsGetCurrentThread(), 3770 &ImpersonationState); 3771 } 3772 3773 if (CopyOnOpen) 3774 { 3775 Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_ALL_ACCESS, 3776 PsThreadType, KernelMode, 3777 (PVOID*)&NewThread, NULL); 3778 if (NT_SUCCESS(Status)) 3779 { 3780 PrimaryToken = PsReferencePrimaryToken(NewThread->ThreadsProcess); 3781 3782 Status = SepCreateImpersonationTokenDacl(Token, PrimaryToken, &Dacl); 3783 3784 ObFastDereferenceObject(&NewThread->ThreadsProcess->Token, PrimaryToken); 3785 3786 if (NT_SUCCESS(Status)) 3787 { 3788 if (Dacl) 3789 { 3790 RtlCreateSecurityDescriptor(&SecurityDescriptor, 3791 SECURITY_DESCRIPTOR_REVISION); 3792 RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl, 3793 FALSE); 3794 } 3795 3796 InitializeObjectAttributes(&ObjectAttributes, NULL, HandleAttributes, 3797 NULL, Dacl ? &SecurityDescriptor : NULL); 3798 3799 Status = SepDuplicateToken(Token, &ObjectAttributes, EffectiveOnly, 3800 TokenImpersonation, ImpersonationLevel, 3801 KernelMode, &NewToken); 3802 if (NT_SUCCESS(Status)) 3803 { 3804 ObReferenceObject(NewToken); 3805 Status = ObInsertObject(NewToken, NULL, DesiredAccess, 0, NULL, 3806 &hToken); 3807 } 3808 } 3809 } 3810 } 3811 else 3812 { 3813 Status = ObOpenObjectByPointer(Token, HandleAttributes, 3814 NULL, DesiredAccess, SeTokenObjectType, 3815 PreviousMode, &hToken); 3816 } 3817 3818 if (Dacl) ExFreePoolWithTag(Dacl, TAG_ACL); 3819 3820 if (RestoreImpersonation) 3821 { 3822 PsRestoreImpersonation(PsGetCurrentThread(), &ImpersonationState); 3823 } 3824 3825 ObDereferenceObject(Token); 3826 3827 if (NT_SUCCESS(Status) && CopyOnOpen) 3828 { 3829 PsImpersonateClient(Thread, NewToken, FALSE, EffectiveOnly, ImpersonationLevel); 3830 } 3831 3832 if (NewToken) ObDereferenceObject(NewToken); 3833 3834 if (CopyOnOpen && NewThread) ObDereferenceObject(NewThread); 3835 3836 ObDereferenceObject(Thread); 3837 3838 if (NT_SUCCESS(Status)) 3839 { 3840 _SEH2_TRY 3841 { 3842 *TokenHandle = hToken; 3843 } 3844 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3845 { 3846 Status = _SEH2_GetExceptionCode(); 3847 } 3848 _SEH2_END; 3849 } 3850 3851 return Status; 3852 } 3853 3854 /* 3855 * @implemented 3856 */ 3857 NTSTATUS NTAPI 3858 NtOpenThreadToken(IN HANDLE ThreadHandle, 3859 IN ACCESS_MASK DesiredAccess, 3860 IN BOOLEAN OpenAsSelf, 3861 OUT PHANDLE TokenHandle) 3862 { 3863 return NtOpenThreadTokenEx(ThreadHandle, DesiredAccess, OpenAsSelf, 0, 3864 TokenHandle); 3865 } 3866 3867 /* 3868 * @unimplemented 3869 */ 3870 NTSTATUS 3871 NTAPI 3872 NtCompareTokens(IN HANDLE FirstTokenHandle, 3873 IN HANDLE SecondTokenHandle, 3874 OUT PBOOLEAN Equal) 3875 { 3876 KPROCESSOR_MODE PreviousMode; 3877 PTOKEN FirstToken, SecondToken; 3878 BOOLEAN IsEqual; 3879 NTSTATUS Status; 3880 3881 PAGED_CODE(); 3882 3883 PreviousMode = ExGetPreviousMode(); 3884 3885 if (PreviousMode != KernelMode) 3886 { 3887 _SEH2_TRY 3888 { 3889 ProbeForWriteBoolean(Equal); 3890 } 3891 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3892 { 3893 /* Return the exception code */ 3894 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3895 } 3896 _SEH2_END; 3897 } 3898 3899 Status = ObReferenceObjectByHandle(FirstTokenHandle, 3900 TOKEN_QUERY, 3901 SeTokenObjectType, 3902 PreviousMode, 3903 (PVOID*)&FirstToken, 3904 NULL); 3905 if (!NT_SUCCESS(Status)) 3906 return Status; 3907 3908 Status = ObReferenceObjectByHandle(SecondTokenHandle, 3909 TOKEN_QUERY, 3910 SeTokenObjectType, 3911 PreviousMode, 3912 (PVOID*)&SecondToken, 3913 NULL); 3914 if (!NT_SUCCESS(Status)) 3915 { 3916 ObDereferenceObject(FirstToken); 3917 return Status; 3918 } 3919 3920 if (FirstToken != SecondToken) 3921 { 3922 Status = SepCompareTokens(FirstToken, 3923 SecondToken, 3924 &IsEqual); 3925 } 3926 else 3927 { 3928 IsEqual = TRUE; 3929 } 3930 3931 ObDereferenceObject(SecondToken); 3932 ObDereferenceObject(FirstToken); 3933 3934 if (NT_SUCCESS(Status)) 3935 { 3936 _SEH2_TRY 3937 { 3938 *Equal = IsEqual; 3939 } 3940 _SEH2_EXCEPT(ExSystemExceptionFilter()) 3941 { 3942 Status = _SEH2_GetExceptionCode(); 3943 } 3944 _SEH2_END; 3945 } 3946 3947 return Status; 3948 } 3949 3950 NTSTATUS 3951 NTAPI 3952 NtFilterToken(IN HANDLE ExistingTokenHandle, 3953 IN ULONG Flags, 3954 IN PTOKEN_GROUPS SidsToDisable OPTIONAL, 3955 IN PTOKEN_PRIVILEGES PrivilegesToDelete OPTIONAL, 3956 IN PTOKEN_GROUPS RestrictedSids OPTIONAL, 3957 OUT PHANDLE NewTokenHandle) 3958 { 3959 UNIMPLEMENTED; 3960 return STATUS_NOT_IMPLEMENTED; 3961 } 3962 3963 /* 3964 * @unimplemented 3965 */ 3966 NTSTATUS 3967 NTAPI 3968 NtImpersonateAnonymousToken(IN HANDLE Thread) 3969 { 3970 UNIMPLEMENTED; 3971 return STATUS_NOT_IMPLEMENTED; 3972 } 3973 3974 /* EOF */ 3975