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