1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Security access check control implementation 5 * COPYRIGHT: Copyright Timo Kreuzer <timo.kreuzer@reactos.org> 6 * Copyright Eric Kohl 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 /* GLOBALS ********************************************************************/ 16 17 18 /* PRIVATE FUNCTIONS **********************************************************/ 19 20 /** 21 * @brief 22 * Private function that determines whether security access rights can be given 23 * to an object depending on the security descriptor and other security context 24 * entities, such as an owner. 25 * 26 * @param[in] SecurityDescriptor 27 * Security descriptor of the object that is being accessed. 28 * 29 * @param[in] SubjectSecurityContext 30 * The captured subject security context. 31 * 32 * @param[in] DesiredAccess 33 * Access right bitmask that the calling thread wants to acquire. 34 * 35 * @param[in] ObjectTypeListLength 36 * The length of a object type list. 37 * 38 * @param[in] PreviouslyGrantedAccess 39 * The access rights previously acquired in the past. 40 * 41 * @param[out] Privileges 42 * The returned set of privileges. 43 * 44 * @param[in] GenericMapping 45 * The generic mapping of access rights of an object type. 46 * 47 * @param[in] AccessMode 48 * The processor request level mode. 49 * 50 * @param[out] GrantedAccessList 51 * A list of granted access rights. 52 * 53 * @param[out] AccessStatusList 54 * The returned status code specifying why access cannot be made 55 * onto an object (if said access is denied in the first place). 56 * 57 * @param[in] UseResultList 58 * If set to TRUE, the function will return complete lists of 59 * access status codes and granted access rights. 60 * 61 * @return 62 * Returns TRUE if access onto the specific object is allowed, FALSE 63 * otherwise. 64 * 65 * @remarks 66 * The function is currently incomplete! 67 */ 68 BOOLEAN NTAPI 69 SepAccessCheck( 70 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 71 _In_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext, 72 _In_ ACCESS_MASK DesiredAccess, 73 _In_ POBJECT_TYPE_LIST ObjectTypeList, 74 _In_ ULONG ObjectTypeListLength, 75 _In_ ACCESS_MASK PreviouslyGrantedAccess, 76 _Out_ PPRIVILEGE_SET* Privileges, 77 _In_ PGENERIC_MAPPING GenericMapping, 78 _In_ KPROCESSOR_MODE AccessMode, 79 _Out_ PACCESS_MASK GrantedAccessList, 80 _Out_ PNTSTATUS AccessStatusList, 81 _In_ BOOLEAN UseResultList) 82 { 83 ACCESS_MASK RemainingAccess; 84 ACCESS_MASK TempAccess; 85 ACCESS_MASK TempGrantedAccess = 0; 86 ACCESS_MASK TempDeniedAccess = 0; 87 PACCESS_TOKEN Token; 88 ULONG i, ResultListLength; 89 PACL Dacl; 90 BOOLEAN Present; 91 BOOLEAN Defaulted; 92 PACE CurrentAce; 93 PSID Sid; 94 NTSTATUS Status; 95 PAGED_CODE(); 96 97 DPRINT("SepAccessCheck()\n"); 98 99 /* Check for no access desired */ 100 if (!DesiredAccess) 101 { 102 /* Check if we had no previous access */ 103 if (!PreviouslyGrantedAccess) 104 { 105 /* Then there's nothing to give */ 106 Status = STATUS_ACCESS_DENIED; 107 goto ReturnCommonStatus; 108 } 109 110 /* Return the previous access only */ 111 Status = STATUS_SUCCESS; 112 *Privileges = NULL; 113 goto ReturnCommonStatus; 114 } 115 116 /* Map given accesses */ 117 RtlMapGenericMask(&DesiredAccess, GenericMapping); 118 if (PreviouslyGrantedAccess) 119 RtlMapGenericMask(&PreviouslyGrantedAccess, GenericMapping); 120 121 /* Initialize remaining access rights */ 122 RemainingAccess = DesiredAccess; 123 124 Token = SubjectSecurityContext->ClientToken ? 125 SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken; 126 127 /* Check for ACCESS_SYSTEM_SECURITY and WRITE_OWNER access */ 128 Status = SePrivilegePolicyCheck(&RemainingAccess, 129 &PreviouslyGrantedAccess, 130 NULL, 131 Token, 132 NULL, 133 UserMode); 134 if (!NT_SUCCESS(Status)) 135 { 136 goto ReturnCommonStatus; 137 } 138 139 /* Succeed if there are no more rights to grant */ 140 if (RemainingAccess == 0) 141 { 142 Status = STATUS_SUCCESS; 143 goto ReturnCommonStatus; 144 } 145 146 /* Get the DACL */ 147 Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor, 148 &Present, 149 &Dacl, 150 &Defaulted); 151 if (!NT_SUCCESS(Status)) 152 { 153 goto ReturnCommonStatus; 154 } 155 156 /* RULE 1: Grant desired access if the object is unprotected */ 157 if (Present == FALSE || Dacl == NULL) 158 { 159 PreviouslyGrantedAccess |= RemainingAccess; 160 if (RemainingAccess & MAXIMUM_ALLOWED) 161 { 162 PreviouslyGrantedAccess &= ~MAXIMUM_ALLOWED; 163 PreviouslyGrantedAccess |= GenericMapping->GenericAll; 164 } 165 166 Status = STATUS_SUCCESS; 167 goto ReturnCommonStatus; 168 } 169 170 /* Deny access if the DACL is empty */ 171 if (Dacl->AceCount == 0) 172 { 173 if (RemainingAccess == MAXIMUM_ALLOWED && PreviouslyGrantedAccess != 0) 174 { 175 Status = STATUS_SUCCESS; 176 } 177 else 178 { 179 PreviouslyGrantedAccess = 0; 180 Status = STATUS_ACCESS_DENIED; 181 } 182 goto ReturnCommonStatus; 183 } 184 185 /* Determine the MAXIMUM_ALLOWED access rights according to the DACL */ 186 if (DesiredAccess & MAXIMUM_ALLOWED) 187 { 188 CurrentAce = (PACE)(Dacl + 1); 189 for (i = 0; i < Dacl->AceCount; i++) 190 { 191 if (!(CurrentAce->Header.AceFlags & INHERIT_ONLY_ACE)) 192 { 193 Sid = (PSID)(CurrentAce + 1); 194 if (CurrentAce->Header.AceType == ACCESS_DENIED_ACE_TYPE) 195 { 196 if (SepSidInToken(Token, Sid)) 197 { 198 /* Map access rights from the ACE */ 199 TempAccess = CurrentAce->AccessMask; 200 RtlMapGenericMask(&TempAccess, GenericMapping); 201 202 /* Deny access rights that have not been granted yet */ 203 TempDeniedAccess |= (TempAccess & ~TempGrantedAccess); 204 } 205 } 206 else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) 207 { 208 if (SepSidInToken(Token, Sid)) 209 { 210 /* Map access rights from the ACE */ 211 TempAccess = CurrentAce->AccessMask; 212 RtlMapGenericMask(&TempAccess, GenericMapping); 213 214 /* Grant access rights that have not been denied yet */ 215 TempGrantedAccess |= (TempAccess & ~TempDeniedAccess); 216 } 217 } 218 else 219 { 220 DPRINT1("Unsupported ACE type 0x%lx\n", CurrentAce->Header.AceType); 221 } 222 } 223 224 /* Get the next ACE */ 225 CurrentAce = (PACE)((ULONG_PTR)CurrentAce + CurrentAce->Header.AceSize); 226 } 227 228 /* Fail if some rights have not been granted */ 229 RemainingAccess &= ~(MAXIMUM_ALLOWED | TempGrantedAccess); 230 if (RemainingAccess != 0) 231 { 232 PreviouslyGrantedAccess = 0; 233 Status = STATUS_ACCESS_DENIED; 234 goto ReturnCommonStatus; 235 } 236 237 /* Set granted access right and access status */ 238 PreviouslyGrantedAccess |= TempGrantedAccess; 239 if (PreviouslyGrantedAccess != 0) 240 { 241 Status = STATUS_SUCCESS; 242 } 243 else 244 { 245 Status = STATUS_ACCESS_DENIED; 246 } 247 goto ReturnCommonStatus; 248 } 249 250 /* RULE 4: Grant rights according to the DACL */ 251 CurrentAce = (PACE)(Dacl + 1); 252 for (i = 0; i < Dacl->AceCount; i++) 253 { 254 if (!(CurrentAce->Header.AceFlags & INHERIT_ONLY_ACE)) 255 { 256 Sid = (PSID)(CurrentAce + 1); 257 if (CurrentAce->Header.AceType == ACCESS_DENIED_ACE_TYPE) 258 { 259 if (SepSidInToken(Token, Sid)) 260 { 261 /* Map access rights from the ACE */ 262 TempAccess = CurrentAce->AccessMask; 263 RtlMapGenericMask(&TempAccess, GenericMapping); 264 265 /* Leave if a remaining right must be denied */ 266 if (RemainingAccess & TempAccess) 267 break; 268 } 269 } 270 else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) 271 { 272 if (SepSidInToken(Token, Sid)) 273 { 274 /* Map access rights from the ACE */ 275 TempAccess = CurrentAce->AccessMask; 276 DPRINT("TempAccess 0x%08lx\n", TempAccess); 277 RtlMapGenericMask(&TempAccess, GenericMapping); 278 279 /* Remove granted rights */ 280 DPRINT("RemainingAccess 0x%08lx TempAccess 0x%08lx\n", RemainingAccess, TempAccess); 281 RemainingAccess &= ~TempAccess; 282 DPRINT("RemainingAccess 0x%08lx\n", RemainingAccess); 283 } 284 } 285 else 286 { 287 DPRINT1("Unsupported ACE type 0x%lx\n", CurrentAce->Header.AceType); 288 } 289 } 290 291 /* Get the next ACE */ 292 CurrentAce = (PACE)((ULONG_PTR)CurrentAce + CurrentAce->Header.AceSize); 293 } 294 295 DPRINT("DesiredAccess %08lx\nPreviouslyGrantedAccess %08lx\nRemainingAccess %08lx\n", 296 DesiredAccess, PreviouslyGrantedAccess, RemainingAccess); 297 298 /* Fail if some rights have not been granted */ 299 if (RemainingAccess != 0) 300 { 301 DPRINT("HACK: RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n", RemainingAccess, DesiredAccess); 302 #if 0 303 /* HACK HACK HACK */ 304 Status = STATUS_ACCESS_DENIED; 305 goto ReturnCommonStatus; 306 #endif 307 } 308 309 /* Set granted access rights */ 310 PreviouslyGrantedAccess |= DesiredAccess; 311 312 /* Fail if no rights have been granted */ 313 if (PreviouslyGrantedAccess == 0) 314 { 315 DPRINT1("PreviouslyGrantedAccess == 0 DesiredAccess = %08lx\n", DesiredAccess); 316 Status = STATUS_ACCESS_DENIED; 317 goto ReturnCommonStatus; 318 } 319 320 Status = STATUS_SUCCESS; 321 goto ReturnCommonStatus; 322 323 ReturnCommonStatus: 324 ResultListLength = UseResultList ? ObjectTypeListLength : 1; 325 for (i = 0; i < ResultListLength; i++) 326 { 327 GrantedAccessList[i] = PreviouslyGrantedAccess; 328 AccessStatusList[i] = Status; 329 } 330 331 return NT_SUCCESS(Status); 332 } 333 334 /** 335 * @brief 336 * Retrieves the main user from a security descriptor. 337 * 338 * @param[in] SecurityDescriptor 339 * A valid allocated security descriptor structure where the owner 340 * is to be retrieved. 341 * 342 * @return 343 * Returns a SID that represents the main user (owner). 344 */ 345 static PSID 346 SepGetSDOwner( 347 _In_ PSECURITY_DESCRIPTOR _SecurityDescriptor) 348 { 349 PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor; 350 PSID Owner; 351 352 if (SecurityDescriptor->Control & SE_SELF_RELATIVE) 353 Owner = (PSID)((ULONG_PTR)SecurityDescriptor->Owner + 354 (ULONG_PTR)SecurityDescriptor); 355 else 356 Owner = (PSID)SecurityDescriptor->Owner; 357 358 return Owner; 359 } 360 361 /** 362 * @brief 363 * Retrieves the group from a security descriptor. 364 * 365 * @param[in] SecurityDescriptor 366 * A valid allocated security descriptor structure where the group 367 * is to be retrieved. 368 * 369 * @return 370 * Returns a SID that represents a group. 371 */ 372 static PSID 373 SepGetSDGroup( 374 _In_ PSECURITY_DESCRIPTOR _SecurityDescriptor) 375 { 376 PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor; 377 PSID Group; 378 379 if (SecurityDescriptor->Control & SE_SELF_RELATIVE) 380 Group = (PSID)((ULONG_PTR)SecurityDescriptor->Group + 381 (ULONG_PTR)SecurityDescriptor); 382 else 383 Group = (PSID)SecurityDescriptor->Group; 384 385 return Group; 386 } 387 388 /** 389 * @brief 390 * Retrieves the length size of a set list of privileges structure. 391 * 392 * @param[in] PrivilegeSet 393 * A valid set of privileges. 394 * 395 * @return 396 * Returns the total length of a set of privileges. 397 */ 398 static 399 ULONG 400 SepGetPrivilegeSetLength( 401 _In_ PPRIVILEGE_SET PrivilegeSet) 402 { 403 if (PrivilegeSet == NULL) 404 return 0; 405 406 if (PrivilegeSet->PrivilegeCount == 0) 407 return (ULONG)(sizeof(PRIVILEGE_SET) - sizeof(LUID_AND_ATTRIBUTES)); 408 409 return (ULONG)(sizeof(PRIVILEGE_SET) + 410 (PrivilegeSet->PrivilegeCount - 1) * sizeof(LUID_AND_ATTRIBUTES)); 411 } 412 413 /* PUBLIC FUNCTIONS ***********************************************************/ 414 415 /** 416 * @brief 417 * Determines whether security access rights can be given to an object 418 * depending on the security descriptor and other security context 419 * entities, such as an owner. 420 * 421 * @param[in] SecurityDescriptor 422 * Security descriptor of the object that is being accessed. 423 * 424 * @param[in] SubjectSecurityContext 425 * The captured subject security context. 426 * 427 * @param[in] SubjectContextLocked 428 * If set to TRUE, a lock must be acquired for the security subject 429 * context. 430 * 431 * @param[in] DesiredAccess 432 * Access right bitmask that the calling thread wants to acquire. 433 * 434 * @param[in] PreviouslyGrantedAccess 435 * The access rights previously acquired in the past. 436 * 437 * @param[out] Privileges 438 * The returned set of privileges. 439 * 440 * @param[in] GenericMapping 441 * The generic mapping of access rights of an object type. 442 * 443 * @param[in] AccessMode 444 * The processor request level mode. 445 * 446 * @param[out] GrantedAccess 447 * A list of granted access rights. 448 * 449 * @param[out] AccessStatus 450 * The returned status code specifying why access cannot be made 451 * onto an object (if said access is denied in the first place). 452 * 453 * @return 454 * Returns TRUE if access onto the specific object is allowed, FALSE 455 * otherwise. 456 */ 457 BOOLEAN 458 NTAPI 459 SeAccessCheck( 460 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 461 _In_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext, 462 _In_ BOOLEAN SubjectContextLocked, 463 _In_ ACCESS_MASK DesiredAccess, 464 _In_ ACCESS_MASK PreviouslyGrantedAccess, 465 _Out_ PPRIVILEGE_SET* Privileges, 466 _In_ PGENERIC_MAPPING GenericMapping, 467 _In_ KPROCESSOR_MODE AccessMode, 468 _Out_ PACCESS_MASK GrantedAccess, 469 _Out_ PNTSTATUS AccessStatus) 470 { 471 BOOLEAN ret; 472 473 PAGED_CODE(); 474 475 /* Check if this is kernel mode */ 476 if (AccessMode == KernelMode) 477 { 478 /* Check if kernel wants everything */ 479 if (DesiredAccess & MAXIMUM_ALLOWED) 480 { 481 /* Give it */ 482 *GrantedAccess = GenericMapping->GenericAll; 483 *GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED); 484 *GrantedAccess |= PreviouslyGrantedAccess; 485 } 486 else 487 { 488 /* Give the desired and previous access */ 489 *GrantedAccess = DesiredAccess | PreviouslyGrantedAccess; 490 } 491 492 /* Success */ 493 *AccessStatus = STATUS_SUCCESS; 494 return TRUE; 495 } 496 497 /* Check if we didn't get an SD */ 498 if (!SecurityDescriptor) 499 { 500 /* Automatic failure */ 501 *AccessStatus = STATUS_ACCESS_DENIED; 502 return FALSE; 503 } 504 505 /* Check for invalid impersonation */ 506 if ((SubjectSecurityContext->ClientToken) && 507 (SubjectSecurityContext->ImpersonationLevel < SecurityImpersonation)) 508 { 509 *AccessStatus = STATUS_BAD_IMPERSONATION_LEVEL; 510 return FALSE; 511 } 512 513 /* Acquire the lock if needed */ 514 if (!SubjectContextLocked) 515 SeLockSubjectContext(SubjectSecurityContext); 516 517 /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */ 518 if (DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED)) 519 { 520 PACCESS_TOKEN Token = SubjectSecurityContext->ClientToken ? 521 SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken; 522 523 if (SepTokenIsOwner(Token, 524 SecurityDescriptor, 525 FALSE)) 526 { 527 if (DesiredAccess & MAXIMUM_ALLOWED) 528 PreviouslyGrantedAccess |= (WRITE_DAC | READ_CONTROL); 529 else 530 PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL)); 531 532 DesiredAccess &= ~(WRITE_DAC | READ_CONTROL); 533 } 534 } 535 536 if (DesiredAccess == 0) 537 { 538 *GrantedAccess = PreviouslyGrantedAccess; 539 if (PreviouslyGrantedAccess == 0) 540 { 541 DPRINT1("Request for zero access to an object. Denying.\n"); 542 *AccessStatus = STATUS_ACCESS_DENIED; 543 ret = FALSE; 544 } 545 else 546 { 547 *AccessStatus = STATUS_SUCCESS; 548 ret = TRUE; 549 } 550 } 551 else 552 { 553 /* Call the internal function */ 554 ret = SepAccessCheck(SecurityDescriptor, 555 SubjectSecurityContext, 556 DesiredAccess, 557 NULL, 558 0, 559 PreviouslyGrantedAccess, 560 Privileges, 561 GenericMapping, 562 AccessMode, 563 GrantedAccess, 564 AccessStatus, 565 FALSE); 566 } 567 568 /* Release the lock if needed */ 569 if (!SubjectContextLocked) 570 SeUnlockSubjectContext(SubjectSecurityContext); 571 572 return ret; 573 } 574 575 /** 576 * @brief 577 * Determines whether security access rights can be given to an object 578 * depending on the security descriptor. Unlike the regular access check 579 * procedure in the NT kernel, the fast traverse check is a faster way 580 * to quickly check if access can be made into an object. 581 * 582 * @param[in] SecurityDescriptor 583 * Security descriptor of the object that is being accessed. 584 * 585 * @param[in] AccessState 586 * An access state to determine if the access token in the current 587 * security context of the object is an restricted token. 588 * 589 * @param[in] DesiredAccess 590 * The access right bitmask where the calling thread wants to acquire. 591 * 592 * @param[in] AccessMode 593 * Process level request mode. 594 * 595 * @return 596 * Returns TRUE if access onto the specific object is allowed, FALSE 597 * otherwise. 598 */ 599 BOOLEAN 600 NTAPI 601 SeFastTraverseCheck( 602 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 603 _In_ PACCESS_STATE AccessState, 604 _In_ ACCESS_MASK DesiredAccess, 605 _In_ KPROCESSOR_MODE AccessMode) 606 { 607 PACL Dacl; 608 ULONG AceIndex; 609 PKNOWN_ACE Ace; 610 611 PAGED_CODE(); 612 613 ASSERT(AccessMode != KernelMode); 614 615 if (SecurityDescriptor == NULL) 616 return FALSE; 617 618 /* Get DACL */ 619 Dacl = SepGetDaclFromDescriptor(SecurityDescriptor); 620 /* If no DACL, grant access */ 621 if (Dacl == NULL) 622 return TRUE; 623 624 /* No ACE -> Deny */ 625 if (!Dacl->AceCount) 626 return FALSE; 627 628 /* Can't perform the check on restricted token */ 629 if (AccessState->Flags & TOKEN_IS_RESTRICTED) 630 return FALSE; 631 632 /* Browse the ACEs */ 633 for (AceIndex = 0, Ace = (PKNOWN_ACE)((ULONG_PTR)Dacl + sizeof(ACL)); 634 AceIndex < Dacl->AceCount; 635 AceIndex++, Ace = (PKNOWN_ACE)((ULONG_PTR)Ace + Ace->Header.AceSize)) 636 { 637 if (Ace->Header.AceFlags & INHERIT_ONLY_ACE) 638 continue; 639 640 /* If access-allowed ACE */ 641 if (Ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) 642 { 643 /* Check if all accesses are granted */ 644 if (!(Ace->Mask & DesiredAccess)) 645 continue; 646 647 /* Check SID and grant access if matching */ 648 if (RtlEqualSid(SeWorldSid, &(Ace->SidStart))) 649 return TRUE; 650 } 651 /* If access-denied ACE */ 652 else if (Ace->Header.AceType == ACCESS_DENIED_ACE_TYPE) 653 { 654 /* Here, only check if it denies any access wanted and deny if so */ 655 if (Ace->Mask & DesiredAccess) 656 return FALSE; 657 } 658 } 659 660 /* Faulty, deny */ 661 return FALSE; 662 } 663 664 /* SYSTEM CALLS ***************************************************************/ 665 666 /** 667 * @brief 668 * Determines whether security access rights can be given to an object 669 * depending on the security descriptor and a valid handle to an access 670 * token. 671 * 672 * @param[in] SecurityDescriptor 673 * Security descriptor of the object that is being accessed. 674 * 675 * @param[in] TokenHandle 676 * A handle to a token. 677 * 678 * @param[in] DesiredAccess 679 * The access right bitmask where the calling thread wants to acquire. 680 * 681 * @param[in] GenericMapping 682 * The generic mapping of access rights of an object type. 683 * 684 * @param[out] PrivilegeSet 685 * The returned set of privileges. 686 * 687 * @param[in,out] PrivilegeSetLength 688 * The total length size of a set of privileges. 689 * 690 * @param[out] GrantedAccess 691 * A list of granted access rights. 692 * 693 * @param[out] AccessStatus 694 * The returned status code specifying why access cannot be made 695 * onto an object (if said access is denied in the first place). 696 * 697 * @return 698 * Returns STATUS_SUCCESS if access check has been done without problems 699 * and that the object can be accessed. STATUS_GENERIC_NOT_MAPPED is returned 700 * if no generic access right is mapped. STATUS_NO_IMPERSONATION_TOKEN is returned 701 * if the token from the handle is not an impersonation token. 702 * STATUS_BAD_IMPERSONATION_LEVEL is returned if the token cannot be impersonated 703 * because the current security impersonation level doesn't permit so. 704 * STATUS_INVALID_SECURITY_DESCR is returned if the security descriptor given 705 * to the call is not a valid one. STATUS_BUFFER_TOO_SMALL is returned if 706 * the buffer to the captured privileges has a length that is less than the required 707 * size of the set of privileges. A failure NTSTATUS code is returned otherwise. 708 */ 709 NTSTATUS 710 NTAPI 711 NtAccessCheck( 712 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 713 _In_ HANDLE TokenHandle, 714 _In_ ACCESS_MASK DesiredAccess, 715 _In_ PGENERIC_MAPPING GenericMapping, 716 _Out_opt_ PPRIVILEGE_SET PrivilegeSet, 717 _Inout_ PULONG PrivilegeSetLength, 718 _Out_ PACCESS_MASK GrantedAccess, 719 _Out_ PNTSTATUS AccessStatus) 720 { 721 PSECURITY_DESCRIPTOR CapturedSecurityDescriptor = NULL; 722 SECURITY_SUBJECT_CONTEXT SubjectSecurityContext; 723 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 724 ACCESS_MASK PreviouslyGrantedAccess = 0; 725 PPRIVILEGE_SET Privileges = NULL; 726 ULONG CapturedPrivilegeSetLength, RequiredPrivilegeSetLength; 727 PTOKEN Token; 728 NTSTATUS Status; 729 PAGED_CODE(); 730 731 /* Check if this is kernel mode */ 732 if (PreviousMode == KernelMode) 733 { 734 /* Check if kernel wants everything */ 735 if (DesiredAccess & MAXIMUM_ALLOWED) 736 { 737 /* Give it */ 738 *GrantedAccess = GenericMapping->GenericAll; 739 *GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED); 740 } 741 else 742 { 743 /* Just give the desired access */ 744 *GrantedAccess = DesiredAccess; 745 } 746 747 /* Success */ 748 *AccessStatus = STATUS_SUCCESS; 749 return STATUS_SUCCESS; 750 } 751 752 /* Protect probe in SEH */ 753 _SEH2_TRY 754 { 755 /* Probe all pointers */ 756 ProbeForRead(GenericMapping, sizeof(GENERIC_MAPPING), sizeof(ULONG)); 757 ProbeForRead(PrivilegeSetLength, sizeof(ULONG), sizeof(ULONG)); 758 ProbeForWrite(PrivilegeSet, *PrivilegeSetLength, sizeof(ULONG)); 759 ProbeForWrite(GrantedAccess, sizeof(ACCESS_MASK), sizeof(ULONG)); 760 ProbeForWrite(AccessStatus, sizeof(NTSTATUS), sizeof(ULONG)); 761 762 /* Capture the privilege set length and the mapping */ 763 CapturedPrivilegeSetLength = *PrivilegeSetLength; 764 } 765 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 766 { 767 /* Return the exception code */ 768 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 769 } 770 _SEH2_END; 771 772 /* Check for unmapped access rights */ 773 if (DesiredAccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL)) 774 return STATUS_GENERIC_NOT_MAPPED; 775 776 /* Reference the token */ 777 Status = ObReferenceObjectByHandle(TokenHandle, 778 TOKEN_QUERY, 779 SeTokenObjectType, 780 PreviousMode, 781 (PVOID*)&Token, 782 NULL); 783 if (!NT_SUCCESS(Status)) 784 { 785 DPRINT("Failed to reference token (Status %lx)\n", Status); 786 return Status; 787 } 788 789 /* Check token type */ 790 if (Token->TokenType != TokenImpersonation) 791 { 792 DPRINT("No impersonation token\n"); 793 ObDereferenceObject(Token); 794 return STATUS_NO_IMPERSONATION_TOKEN; 795 } 796 797 /* Check the impersonation level */ 798 if (Token->ImpersonationLevel < SecurityIdentification) 799 { 800 DPRINT("Impersonation level < SecurityIdentification\n"); 801 ObDereferenceObject(Token); 802 return STATUS_BAD_IMPERSONATION_LEVEL; 803 } 804 805 /* Check for ACCESS_SYSTEM_SECURITY and WRITE_OWNER access */ 806 Status = SePrivilegePolicyCheck(&DesiredAccess, 807 &PreviouslyGrantedAccess, 808 NULL, 809 Token, 810 &Privileges, 811 PreviousMode); 812 if (!NT_SUCCESS(Status)) 813 { 814 DPRINT("SePrivilegePolicyCheck failed (Status 0x%08lx)\n", Status); 815 ObDereferenceObject(Token); 816 *AccessStatus = Status; 817 *GrantedAccess = 0; 818 return STATUS_SUCCESS; 819 } 820 821 /* Check the size of the privilege set and return the privileges */ 822 if (Privileges != NULL) 823 { 824 DPRINT("Privileges != NULL\n"); 825 826 /* Calculate the required privilege set buffer size */ 827 RequiredPrivilegeSetLength = SepGetPrivilegeSetLength(Privileges); 828 829 /* Fail if the privilege set buffer is too small */ 830 if (CapturedPrivilegeSetLength < RequiredPrivilegeSetLength) 831 { 832 ObDereferenceObject(Token); 833 SeFreePrivileges(Privileges); 834 *PrivilegeSetLength = RequiredPrivilegeSetLength; 835 return STATUS_BUFFER_TOO_SMALL; 836 } 837 838 /* Copy the privilege set to the caller */ 839 RtlCopyMemory(PrivilegeSet, 840 Privileges, 841 RequiredPrivilegeSetLength); 842 843 /* Free the local privilege set */ 844 SeFreePrivileges(Privileges); 845 } 846 else 847 { 848 DPRINT("Privileges == NULL\n"); 849 850 /* Fail if the privilege set buffer is too small */ 851 if (CapturedPrivilegeSetLength < sizeof(PRIVILEGE_SET)) 852 { 853 ObDereferenceObject(Token); 854 *PrivilegeSetLength = sizeof(PRIVILEGE_SET); 855 return STATUS_BUFFER_TOO_SMALL; 856 } 857 858 /* Initialize the privilege set */ 859 PrivilegeSet->PrivilegeCount = 0; 860 PrivilegeSet->Control = 0; 861 } 862 863 /* Capture the security descriptor */ 864 Status = SeCaptureSecurityDescriptor(SecurityDescriptor, 865 PreviousMode, 866 PagedPool, 867 FALSE, 868 &CapturedSecurityDescriptor); 869 if (!NT_SUCCESS(Status)) 870 { 871 DPRINT("Failed to capture the Security Descriptor\n"); 872 ObDereferenceObject(Token); 873 return Status; 874 } 875 876 /* Check the captured security descriptor */ 877 if (CapturedSecurityDescriptor == NULL) 878 { 879 DPRINT("Security Descriptor is NULL\n"); 880 ObDereferenceObject(Token); 881 return STATUS_INVALID_SECURITY_DESCR; 882 } 883 884 /* Check security descriptor for valid owner and group */ 885 if (SepGetSDOwner(SecurityDescriptor) == NULL || // FIXME: use CapturedSecurityDescriptor 886 SepGetSDGroup(SecurityDescriptor) == NULL) // FIXME: use CapturedSecurityDescriptor 887 { 888 DPRINT("Security Descriptor does not have a valid group or owner\n"); 889 SeReleaseSecurityDescriptor(CapturedSecurityDescriptor, 890 PreviousMode, 891 FALSE); 892 ObDereferenceObject(Token); 893 return STATUS_INVALID_SECURITY_DESCR; 894 } 895 896 /* Set up the subject context, and lock it */ 897 SeCaptureSubjectContext(&SubjectSecurityContext); 898 899 /* Lock the token */ 900 SepAcquireTokenLockShared(Token); 901 902 /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */ 903 if (DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED)) 904 { 905 if (SepTokenIsOwner(Token, SecurityDescriptor, FALSE)) // FIXME: use CapturedSecurityDescriptor 906 { 907 if (DesiredAccess & MAXIMUM_ALLOWED) 908 PreviouslyGrantedAccess |= (WRITE_DAC | READ_CONTROL); 909 else 910 PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL)); 911 912 DesiredAccess &= ~(WRITE_DAC | READ_CONTROL); 913 } 914 } 915 916 if (DesiredAccess == 0) 917 { 918 *GrantedAccess = PreviouslyGrantedAccess; 919 *AccessStatus = STATUS_SUCCESS; 920 } 921 else 922 { 923 /* Now perform the access check */ 924 SepAccessCheck(SecurityDescriptor, // FIXME: use CapturedSecurityDescriptor 925 &SubjectSecurityContext, 926 DesiredAccess, 927 NULL, 928 0, 929 PreviouslyGrantedAccess, 930 &PrivilegeSet, //FIXME 931 GenericMapping, 932 PreviousMode, 933 GrantedAccess, 934 AccessStatus, 935 FALSE); 936 } 937 938 /* Release subject context and unlock the token */ 939 SeReleaseSubjectContext(&SubjectSecurityContext); 940 SepReleaseTokenLock(Token); 941 942 /* Release the captured security descriptor */ 943 SeReleaseSecurityDescriptor(CapturedSecurityDescriptor, 944 PreviousMode, 945 FALSE); 946 947 /* Dereference the token */ 948 ObDereferenceObject(Token); 949 950 /* Check succeeded */ 951 return STATUS_SUCCESS; 952 } 953 954 /** 955 * @brief 956 * Determines whether security access could be granted or not on 957 * an object by the requestor who wants such access through type. 958 * 959 * @param[in] SecurityDescriptor 960 * A security descriptor with information data for auditing. 961 * 962 * @param[in] PrincipalSelfSid 963 * A principal self user SID. 964 * 965 * @param[in] ClientToken 966 * A client access token. 967 * 968 * @param[in] DesiredAccess 969 * The desired access masks rights requested by the caller. 970 * 971 * @param[in] ObjectTypeList 972 * A list of object types. 973 * 974 * @param[in] ObjectTypeLength 975 * The length size of the list. 976 * 977 * @param[in] GenericMapping 978 * The generic mapping list of access masks rights. 979 * 980 * @param[in] PrivilegeSet 981 * An array set of privileges. 982 * 983 * @param[in,out] PrivilegeSetLength 984 * The length size of the array set of privileges. 985 * 986 * @param[out] GrantedAccess 987 * The returned granted access rights. 988 * 989 * @param[out] AccessStatus 990 * The returned NTSTATUS code indicating the final results 991 * of auditing. 992 * 993 * @return 994 * To be added... 995 */ 996 NTSTATUS 997 NTAPI 998 NtAccessCheckByType( 999 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 1000 _In_ PSID PrincipalSelfSid, 1001 _In_ HANDLE ClientToken, 1002 _In_ ACCESS_MASK DesiredAccess, 1003 _In_ POBJECT_TYPE_LIST ObjectTypeList, 1004 _In_ ULONG ObjectTypeLength, 1005 _In_ PGENERIC_MAPPING GenericMapping, 1006 _In_ PPRIVILEGE_SET PrivilegeSet, 1007 _Inout_ PULONG PrivilegeSetLength, 1008 _Out_ PACCESS_MASK GrantedAccess, 1009 _Out_ PNTSTATUS AccessStatus) 1010 { 1011 UNIMPLEMENTED; 1012 return STATUS_NOT_IMPLEMENTED; 1013 } 1014 1015 /** 1016 * @brief 1017 * Determines whether security access could be granted or not on 1018 * an object by the requestor who wants such access through 1019 * type list. 1020 * 1021 * @param[in] SecurityDescriptor 1022 * A security descriptor with information data for auditing. 1023 * 1024 * @param[in] PrincipalSelfSid 1025 * A principal self user SID. 1026 * 1027 * @param[in] ClientToken 1028 * A client access token. 1029 * 1030 * @param[in] DesiredAccess 1031 * The desired access masks rights requested by the caller. 1032 * 1033 * @param[in] ObjectTypeList 1034 * A list of object types. 1035 * 1036 * @param[in] ObjectTypeLength 1037 * The length size of the list. 1038 * 1039 * @param[in] GenericMapping 1040 * The generic mapping list of access masks rights. 1041 * 1042 * @param[in] PrivilegeSet 1043 * An array set of privileges. 1044 * 1045 * @param[in,out] PrivilegeSetLength 1046 * The length size of the array set of privileges. 1047 * 1048 * @param[out] GrantedAccess 1049 * The returned granted access rights. 1050 * 1051 * @param[out] AccessStatus 1052 * The returned NTSTATUS code indicating the final results 1053 * of auditing. 1054 * 1055 * @return 1056 * To be added... 1057 */ 1058 NTSTATUS 1059 NTAPI 1060 NtAccessCheckByTypeResultList( 1061 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 1062 _In_ PSID PrincipalSelfSid, 1063 _In_ HANDLE ClientToken, 1064 _In_ ACCESS_MASK DesiredAccess, 1065 _In_ POBJECT_TYPE_LIST ObjectTypeList, 1066 _In_ ULONG ObjectTypeLength, 1067 _In_ PGENERIC_MAPPING GenericMapping, 1068 _In_ PPRIVILEGE_SET PrivilegeSet, 1069 _Inout_ PULONG PrivilegeSetLength, 1070 _Out_ PACCESS_MASK GrantedAccess, 1071 _Out_ PNTSTATUS AccessStatus) 1072 { 1073 UNIMPLEMENTED; 1074 return STATUS_NOT_IMPLEMENTED; 1075 } 1076 1077 /* EOF */ 1078