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 2014 Timo Kreuzer <timo.kreuzer@reactos.org> 6 * Copyright 2014 Eric Kohl 7 * Copyright 2022 George Bișoc <george.bisoc@reactos.org> 8 */ 9 10 /* INCLUDES *******************************************************************/ 11 12 #include <ntoskrnl.h> 13 #define NDEBUG 14 #include <debug.h> 15 16 /* PRIVATE FUNCTIONS **********************************************************/ 17 18 /** 19 * @brief 20 * Allocates memory for the internal access check rights 21 * data structure and initializes it for use for the kernel. 22 * The purpose of this piece of data is to track down the 23 * remaining, granted and denied access rights whilst we 24 * are doing an access check procedure. 25 * 26 * @return 27 * Returns a pointer to allocated and initialized access 28 * check rights, otherwise NULL is returned. 29 */ 30 PACCESS_CHECK_RIGHTS 31 SepInitAccessCheckRights(VOID) 32 { 33 PACCESS_CHECK_RIGHTS AccessRights; 34 35 PAGED_CODE(); 36 37 /* Allocate some pool for access check rights */ 38 AccessRights = ExAllocatePoolWithTag(PagedPool, 39 sizeof(ACCESS_CHECK_RIGHTS), 40 TAG_ACCESS_CHECK_RIGHT); 41 42 /* Bail out if we failed */ 43 if (!AccessRights) 44 { 45 return NULL; 46 } 47 48 /* Initialize the structure */ 49 AccessRights->RemainingAccessRights = 0; 50 AccessRights->GrantedAccessRights = 0; 51 AccessRights->DeniedAccessRights = 0; 52 53 return AccessRights; 54 } 55 56 /** 57 * @brief 58 * Frees an allocated access check rights from 59 * memory space after access check procedures 60 * have finished. 61 * 62 * @param[in] AccessRights 63 * A pointer to access check rights of which is 64 * to be freed from memory. 65 * 66 * @return 67 * Nothing. 68 */ 69 VOID 70 SepFreeAccessCheckRights( 71 _In_ PACCESS_CHECK_RIGHTS AccessRights) 72 { 73 PAGED_CODE(); 74 75 if (AccessRights) 76 { 77 ExFreePoolWithTag(AccessRights, TAG_ACCESS_CHECK_RIGHT); 78 } 79 } 80 81 /** 82 * @brief 83 * Analyzes an access control entry that is present in a discretionary 84 * access control list (DACL) for access right masks of each entry with 85 * the purpose to judge whether the calling thread can be warranted 86 * access check to a certain object or not. 87 * 88 * @param[in] ActionType 89 * The type of analysis to be done against an access entry. This type 90 * influences how access rights are gathered. This can either be AccessCheckMaximum 91 * which means the algorithm will perform analysis against ACEs on behalf of the 92 * requestor that gave us the acknowledgement that he desires MAXIMUM_ALLOWED access 93 * right or AccessCheckRegular if the requestor wants a subset of access rights. 94 * 95 * @param[in] Dacl 96 * The discretionary access control list to be given to this function. This DACL 97 * must have at least one ACE currently present in the list. 98 * 99 * @param[in] AccessToken 100 * A pointer to an access token, where an equality comparison check is performed if 101 * the security identifier (SID) from a ACE of a certain object is present in this 102 * token. This token represents the effective (calling thread) token of the caller. 103 * 104 * @param[in] PrimaryAccessToken 105 * A pointer to an access token, represented as an access token associated with the 106 * primary calling process. This token describes the primary security context of the 107 * main process. 108 * 109 * @param[in] IsTokenRestricted 110 * If this parameter is set to TRUE, the function considers the token pointed by 111 * AccessToken parameter argument as restricted. That is, the token has restricted 112 * SIDs therefore the function will act accordingly against that token by checking 113 * for restricted SIDs only when doing an equaility comparison check between the 114 * two identifiers. 115 * 116 * @param[in] AccessRightsAllocated 117 * If this parameter is set to TRUE, the function will not allocate the access 118 * check rights again. This is typical when we have to do additional analysis 119 * of ACEs because a token has restricted SIDs (see IsTokenRestricted parameter) 120 * of which we already initialized the access check rights pointer before. 121 * 122 * @param[in] PrincipalSelfSid 123 * A pointer to a security identifier that represents a principal. A principal 124 * identifies a user object which is associated with its own security descriptor. 125 * 126 * @param[in] GenericMapping 127 * A pointer to a generic mapping that is associated with the object in question 128 * being checked for access. If certain set of desired access rights have 129 * a generic access right, this parameter is needed to map generic rights. 130 * 131 * @param[in] ObjectTypeList 132 * A pointer to a list array of object types. If such array is provided to the 133 * function, the algorithm will perform a different approach by doing analysis 134 * against ACEs each sub-object of an object of primary level (level 0) or sub-objects 135 * of a sub-object of an object. If this parameter is NULL, the function will normally 136 * analyze the ACEs of a DACL of the target object itself. 137 * 138 * @param[in] ObjectTypeListLength 139 * The length of the object type list array, pointed by ObjectTypeList. This length in 140 * question represents the number of elements in such array. This parameter must be 0 141 * if no array list is provided. 142 * 143 * @param[in] RemainingAccess 144 * The remaining access rights that have yet to be granted to the calling thread 145 * whomst requests access to a certain object. This parameter mustn't be 0 as 146 * the remaining rights are left to be addressed. This is the case if we have 147 * to address the remaining rights on a regular subset basis (the requestor 148 * didn't ask for MAXIMUM_ALLOWED). Otherwise this parameter can be 0. 149 * 150 * @return 151 * Returns a pointer to initialized access check rights after ACE analysis 152 * has finished. This pointer contains the rights that have been acquired 153 * in order to determine if access can be granted to the calling thread. 154 * Typically this pointer contains the remaining, denied and granted rights. 155 * 156 * Otherwise NULL is returned and thus access check procedure can't any longer 157 * continue further. We have prematurely failed this access check operation 158 * at this point. 159 */ 160 PACCESS_CHECK_RIGHTS 161 SepAnalyzeAcesFromDacl( 162 _In_ ACCESS_CHECK_RIGHT_TYPE ActionType, 163 _In_ PACL Dacl, 164 _In_ PACCESS_TOKEN AccessToken, 165 _In_ PACCESS_TOKEN PrimaryAccessToken, 166 _In_ BOOLEAN IsTokenRestricted, 167 _In_ BOOLEAN AccessRightsAllocated, 168 _In_opt_ PSID PrincipalSelfSid, 169 _In_ PGENERIC_MAPPING GenericMapping, 170 _In_opt_ POBJECT_TYPE_LIST ObjectTypeList, 171 _In_ ULONG ObjectTypeListLength, 172 _In_ ACCESS_MASK RemainingAccess) 173 { 174 NTSTATUS Status; 175 PACE CurrentAce; 176 ULONG AceIndex; 177 PSID Sid; 178 ACCESS_MASK Access; 179 PACCESS_CHECK_RIGHTS AccessRights; 180 181 PAGED_CODE(); 182 183 /* These parameters are really needed */ 184 ASSERT(Dacl); 185 ASSERT(AccessToken); 186 187 /* TODO: To be removed once we support object type handling in Se */ 188 DBG_UNREFERENCED_PARAMETER(ObjectTypeList); 189 DBG_UNREFERENCED_PARAMETER(ObjectTypeListLength); 190 191 /* TODO: To be removed once we support compound ACEs handling in Se */ 192 DBG_UNREFERENCED_PARAMETER(PrimaryAccessToken); 193 194 /* 195 * Allocate memory for access check rights if 196 * we have not done it so. Otherwise just use 197 * the already allocated pointer. This is 198 * typically when we have to do additional 199 * ACEs analysis because the token has 200 * restricted SIDs so we have allocated this 201 * pointer before. 202 */ 203 if (!AccessRightsAllocated) 204 { 205 AccessRights = SepInitAccessCheckRights(); 206 if (!AccessRights) 207 { 208 DPRINT1("SepAnalyzeAcesFromDacl(): Failed to initialize the access check rights!\n"); 209 return NULL; 210 } 211 } 212 213 /* Determine how we should analyze the ACEs */ 214 switch (ActionType) 215 { 216 /* 217 * We got the acknowledgement the calling thread desires 218 * maximum rights (as according to MAXIMUM_ALLOWED access 219 * mask). Analyze the ACE of the given DACL. 220 */ 221 case AccessCheckMaximum: 222 { 223 /* Loop over the DACL to retrieve ACEs */ 224 for (AceIndex = 0; AceIndex < Dacl->AceCount; AceIndex++) 225 { 226 /* Obtain a ACE now */ 227 Status = RtlGetAce(Dacl, AceIndex, (PVOID*)&CurrentAce); 228 229 /* Getting this ACE is important, otherwise something is seriously wrong */ 230 ASSERT(NT_SUCCESS(Status)); 231 232 /* 233 * Now it's time to analyze it based upon the 234 * type of this ACE we're being given. 235 */ 236 if (!(CurrentAce->Header.AceFlags & INHERIT_ONLY_ACE)) 237 { 238 if (CurrentAce->Header.AceType == ACCESS_DENIED_ACE_TYPE) 239 { 240 /* Get the SID from this ACE */ 241 Sid = SepGetSidFromAce(ACCESS_DENIED_ACE_TYPE, CurrentAce); 242 243 if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, TRUE, IsTokenRestricted)) 244 { 245 /* Get this access right from the ACE */ 246 Access = CurrentAce->AccessMask; 247 248 /* Map this access right if it has a generic mask right */ 249 if ((Access & GENERIC_ACCESS) && GenericMapping) 250 { 251 RtlMapGenericMask(&Access, GenericMapping); 252 } 253 254 /* Deny access rights that have not been granted yet */ 255 AccessRights->DeniedAccessRights |= (Access & ~AccessRights->GrantedAccessRights); 256 DPRINT("SepAnalyzeAcesFromDacl(): DeniedAccessRights 0x%08lx\n", AccessRights->DeniedAccessRights); 257 } 258 } 259 else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) 260 { 261 /* Get the SID from this ACE */ 262 Sid = SepGetSidFromAce(ACCESS_ALLOWED_ACE_TYPE, CurrentAce); 263 264 if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, FALSE, IsTokenRestricted)) 265 { 266 /* Get this access right from the ACE */ 267 Access = CurrentAce->AccessMask; 268 269 /* Map this access right if it has a generic mask right */ 270 if ((Access & GENERIC_ACCESS) && GenericMapping) 271 { 272 RtlMapGenericMask(&Access, GenericMapping); 273 } 274 275 /* Grant access rights that have not been denied yet */ 276 AccessRights->GrantedAccessRights |= (Access & ~AccessRights->DeniedAccessRights); 277 DPRINT("SepAnalyzeAcesFromDacl(): GrantedAccessRights 0x%08lx\n", AccessRights->GrantedAccessRights); 278 } 279 } 280 else 281 { 282 DPRINT1("SepAnalyzeAcesFromDacl(): Unsupported ACE type 0x%lx\n", CurrentAce->Header.AceType); 283 } 284 } 285 } 286 287 /* We're done here */ 288 break; 289 } 290 291 /* 292 * We got the acknowledgement the calling thread desires 293 * only a subset of rights therefore we have to act a little 294 * different here. 295 */ 296 case AccessCheckRegular: 297 { 298 /* Cache the remaining access rights to be addressed */ 299 AccessRights->RemainingAccessRights = RemainingAccess; 300 301 /* Loop over the DACL to retrieve ACEs */ 302 for (AceIndex = 0; AceIndex < Dacl->AceCount; AceIndex++) 303 { 304 /* Obtain a ACE now */ 305 Status = RtlGetAce(Dacl, AceIndex, (PVOID*)&CurrentAce); 306 307 /* Getting this ACE is important, otherwise something is seriously wrong */ 308 ASSERT(NT_SUCCESS(Status)); 309 310 /* 311 * Now it's time to analyze it based upon the 312 * type of this ACE we're being given. 313 */ 314 if (!(CurrentAce->Header.AceFlags & INHERIT_ONLY_ACE)) 315 { 316 if (CurrentAce->Header.AceType == ACCESS_DENIED_ACE_TYPE) 317 { 318 /* Get the SID from this ACE */ 319 Sid = SepGetSidFromAce(ACCESS_DENIED_ACE_TYPE, CurrentAce); 320 321 if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, TRUE, IsTokenRestricted)) 322 { 323 /* Get this access right from the ACE */ 324 Access = CurrentAce->AccessMask; 325 326 /* Map this access right if it has a generic mask right */ 327 if ((Access & GENERIC_ACCESS) && GenericMapping) 328 { 329 RtlMapGenericMask(&Access, GenericMapping); 330 } 331 332 /* 333 * The caller requests a right that cannot be 334 * granted. Access is implicitly denied for 335 * the calling thread. Track this access right. 336 */ 337 if (AccessRights->RemainingAccessRights & Access) 338 { 339 DPRINT("SepAnalyzeAcesFromDacl(): Refuted access 0x%08lx\n", Access); 340 AccessRights->DeniedAccessRights |= Access; 341 break; 342 } 343 } 344 } 345 else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) 346 { 347 /* Get the SID from this ACE */ 348 Sid = SepGetSidFromAce(ACCESS_ALLOWED_ACE_TYPE, CurrentAce); 349 350 if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, FALSE, IsTokenRestricted)) 351 { 352 /* Get this access right from the ACE */ 353 Access = CurrentAce->AccessMask; 354 355 /* Map this access right if it has a generic mask right */ 356 if ((Access & GENERIC_ACCESS) && GenericMapping) 357 { 358 RtlMapGenericMask(&Access, GenericMapping); 359 } 360 361 /* Remove granted rights */ 362 DPRINT("SepAnalyzeAcesFromDacl(): RemainingAccessRights 0x%08lx Access 0x%08lx\n", AccessRights->RemainingAccessRights, Access); 363 AccessRights->RemainingAccessRights &= ~Access; 364 DPRINT("SepAnalyzeAcesFromDacl(): RemainingAccessRights 0x%08lx\n", AccessRights->RemainingAccessRights); 365 366 /* Track the granted access right */ 367 AccessRights->GrantedAccessRights |= Access; 368 } 369 } 370 else 371 { 372 DPRINT1("SepAnalyzeAcesFromDacl(): Unsupported ACE type 0x%lx\n", CurrentAce->Header.AceType); 373 } 374 } 375 } 376 377 /* We're done here */ 378 break; 379 } 380 381 /* We shouldn't reach here */ 382 DEFAULT_UNREACHABLE; 383 } 384 385 /* Return the access rights that we've got */ 386 return AccessRights; 387 } 388 389 /** 390 * @brief 391 * Private function that determines whether security access rights can be given 392 * to the calling thread in order to access an object depending on the security 393 * descriptor and other security context entities, such as an owner. This 394 * function is the heart and brain of the whole access check algorithm in 395 * the kernel. 396 * 397 * @param[in] ClientAccessToken 398 * A pointer to a client (thread) access token that requests access rights 399 * of an object or subset of multiple objects. 400 * 401 * @param[in] PrimaryAccessToken 402 * A pointer to a primary access token that describes the primary security 403 * context of the main calling process. 404 * 405 * @param[in] PrincipalSelfSid 406 * A pointer to a security identifier that represents a security principal, 407 * that is, a user object associated with its security descriptor. 408 * 409 * @param[in] DesiredAccess 410 * The access rights desired by the calling thread to acquire in order to 411 * access an object. 412 * 413 * @param[in] ObjectTypeList 414 * An array list of object types to be checked against for access. The function 415 * will act accordingly in this case by checking each sub-object of an object 416 * of primary level and such. If this parameter is NULL, the function will 417 * perform a normal access check against the target object itself. 418 * 419 * @param[in] ObjectTypeListLength 420 * The length of a object type list. Such length represents the number of 421 * elements in this list. 422 * 423 * @param[in] PreviouslyGrantedAccess 424 * The access rights previously acquired in the past. If this parameter is 0, 425 * it is deemed that the calling thread hasn't acquired any rights. Access checks 426 * are more tighten in this case. 427 * 428 * @param[in] GenericMapping 429 * A pointer to a generic mapping of access rights of the target object. 430 * 431 * @param[in] AccessMode 432 * The processor request level mode. 433 * 434 * @param[in] UseResultList 435 * If set to TRUE, the function will return a list of granted access rights 436 * of each sub-object as well as status code for each. If this parameter is 437 * set to FALSE, then the function will just return only the granted access 438 * rights and status code for single object that's been target for access 439 * checks. 440 * 441 * @param[out] Privileges 442 * A pointer to a definite set of privileges that have been audited 443 * whilst doing access check procedures. Such set of privileges are 444 * optionally returned to the caller. This can be set to NULL if 445 * the caller doesn't want to obtain a set of privileges. 446 * 447 * @param[out] GrantedAccessList 448 * A list of granted access rights returned to the caller. This list 449 * can comprehend multiple elements which represent the sub-objects 450 * that have been checked or a single element which is the target 451 * object itself. 452 * 453 * @param[out] AccessStatusList 454 * A list of access status codes returned to the caller. This list 455 * can comprehend multiple elements which represent the sub-objects 456 * that have been checked or a single element which is the target 457 * object itself. 458 * 459 * @return 460 * Returns TRUE if access onto the specific object is allowed, FALSE 461 * otherwise. 462 */ 463 BOOLEAN 464 NTAPI 465 SepAccessCheck( 466 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 467 _In_opt_ PACCESS_TOKEN ClientAccessToken, 468 _In_ PACCESS_TOKEN PrimaryAccessToken, 469 _In_opt_ PSID PrincipalSelfSid, 470 _In_ ACCESS_MASK DesiredAccess, 471 _In_opt_ POBJECT_TYPE_LIST ObjectTypeList, 472 _In_ ULONG ObjectTypeListLength, 473 _In_ ACCESS_MASK PreviouslyGrantedAccess, 474 _In_ PGENERIC_MAPPING GenericMapping, 475 _In_ KPROCESSOR_MODE AccessMode, 476 _In_ BOOLEAN UseResultList, 477 _Out_opt_ PPRIVILEGE_SET* Privileges, 478 _Out_ PACCESS_MASK GrantedAccessList, 479 _Out_ PNTSTATUS AccessStatusList) 480 { 481 ACCESS_MASK RemainingAccess; 482 PACCESS_CHECK_RIGHTS AccessCheckRights; 483 PACCESS_TOKEN Token; 484 ULONG ResultListLength; 485 ULONG ResultListIndex; 486 PACL Dacl; 487 BOOLEAN Present; 488 BOOLEAN Defaulted; 489 NTSTATUS Status; 490 491 PAGED_CODE(); 492 493 /* A security descriptor must be expected for access checks */ 494 ASSERT(SecurityDescriptor); 495 496 /* Assume no access check rights first */ 497 AccessCheckRights = NULL; 498 499 /* Check for no access desired */ 500 if (!DesiredAccess) 501 { 502 /* Check if we had no previous access */ 503 if (!PreviouslyGrantedAccess) 504 { 505 /* Then there's nothing to give */ 506 DPRINT1("SepAccessCheck(): The caller has no previously granted access gained!\n"); 507 Status = STATUS_ACCESS_DENIED; 508 goto ReturnCommonStatus; 509 } 510 511 /* Return the previous access only */ 512 Status = STATUS_SUCCESS; 513 *Privileges = NULL; 514 goto ReturnCommonStatus; 515 } 516 517 /* Map given accesses */ 518 RtlMapGenericMask(&DesiredAccess, GenericMapping); 519 if (PreviouslyGrantedAccess) 520 RtlMapGenericMask(&PreviouslyGrantedAccess, GenericMapping); 521 522 /* Initialize remaining access rights */ 523 RemainingAccess = DesiredAccess; 524 525 /* 526 * Obtain the token provided by the caller. Client (or also 527 * called impersonation or thread) token takes precedence over 528 * the primary token which is the token associated with the security 529 * context of the main calling process. This is because it is the 530 * client itself that requests access of an object or subset of 531 * multiple objects. Otherwise obtain the security context of the 532 * main process (the actual primary token). 533 */ 534 Token = ClientAccessToken ? ClientAccessToken : PrimaryAccessToken; 535 536 /* 537 * We should at least expect a primary token 538 * to be present if client token is not 539 * available. 540 */ 541 ASSERT(Token); 542 543 /* 544 * Check for ACCESS_SYSTEM_SECURITY and WRITE_OWNER access. 545 * Write down a set of privileges that have been checked 546 * if the caller wants it. 547 */ 548 Status = SePrivilegePolicyCheck(&RemainingAccess, 549 &PreviouslyGrantedAccess, 550 NULL, 551 Token, 552 Privileges, 553 AccessMode); 554 if (!NT_SUCCESS(Status)) 555 { 556 goto ReturnCommonStatus; 557 } 558 559 /* Succeed if there are no more rights to grant */ 560 if (RemainingAccess == 0) 561 { 562 Status = STATUS_SUCCESS; 563 goto ReturnCommonStatus; 564 } 565 566 /* Get the DACL */ 567 Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor, 568 &Present, 569 &Dacl, 570 &Defaulted); 571 if (!NT_SUCCESS(Status)) 572 { 573 goto ReturnCommonStatus; 574 } 575 576 /* Grant desired access if the object is unprotected */ 577 if (Present == FALSE || Dacl == NULL) 578 { 579 PreviouslyGrantedAccess |= RemainingAccess; 580 if (RemainingAccess & MAXIMUM_ALLOWED) 581 { 582 PreviouslyGrantedAccess &= ~MAXIMUM_ALLOWED; 583 PreviouslyGrantedAccess |= GenericMapping->GenericAll; 584 } 585 586 Status = STATUS_SUCCESS; 587 goto ReturnCommonStatus; 588 } 589 590 /* Deny access if the DACL is empty */ 591 if (Dacl->AceCount == 0) 592 { 593 if (RemainingAccess == MAXIMUM_ALLOWED && PreviouslyGrantedAccess != 0) 594 { 595 Status = STATUS_SUCCESS; 596 } 597 else 598 { 599 DPRINT1("SepAccessCheck(): The DACL has no ACEs and the caller has no previously granted access!\n"); 600 PreviouslyGrantedAccess = 0; 601 Status = STATUS_ACCESS_DENIED; 602 } 603 goto ReturnCommonStatus; 604 } 605 606 /* Determine the MAXIMUM_ALLOWED access rights according to the DACL */ 607 if (DesiredAccess & MAXIMUM_ALLOWED) 608 { 609 /* Perform access checks against ACEs from this DACL */ 610 AccessCheckRights = SepAnalyzeAcesFromDacl(AccessCheckMaximum, 611 Dacl, 612 Token, 613 PrimaryAccessToken, 614 FALSE, 615 FALSE, 616 PrincipalSelfSid, 617 GenericMapping, 618 ObjectTypeList, 619 ObjectTypeListLength, 620 0); 621 622 /* 623 * Getting the access check rights is very 624 * important as we have to do access checks 625 * depending on the kind of rights we get. 626 * Fail prematurely if we can't... 627 */ 628 if (!AccessCheckRights) 629 { 630 DPRINT1("SepAccessCheck(): Failed to obtain access check rights!\n"); 631 Status = STATUS_INSUFFICIENT_RESOURCES; 632 PreviouslyGrantedAccess = 0; 633 goto ReturnCommonStatus; 634 } 635 636 /* 637 * Perform further access checks if this token 638 * has restricted SIDs. 639 */ 640 if (SeTokenIsRestricted(Token)) 641 { 642 AccessCheckRights = SepAnalyzeAcesFromDacl(AccessCheckMaximum, 643 Dacl, 644 Token, 645 PrimaryAccessToken, 646 TRUE, 647 TRUE, 648 PrincipalSelfSid, 649 GenericMapping, 650 ObjectTypeList, 651 ObjectTypeListLength, 652 0); 653 } 654 655 /* Fail if some rights have not been granted */ 656 RemainingAccess &= ~(MAXIMUM_ALLOWED | AccessCheckRights->GrantedAccessRights); 657 if (RemainingAccess != 0) 658 { 659 DPRINT1("SepAccessCheck(): Failed to grant access rights. RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n", RemainingAccess, DesiredAccess); 660 PreviouslyGrantedAccess = 0; 661 Status = STATUS_ACCESS_DENIED; 662 goto ReturnCommonStatus; 663 } 664 665 /* Set granted access right and access status */ 666 PreviouslyGrantedAccess |= AccessCheckRights->GrantedAccessRights; 667 if (PreviouslyGrantedAccess != 0) 668 { 669 Status = STATUS_SUCCESS; 670 } 671 else 672 { 673 DPRINT1("SepAccessCheck(): Failed to grant access rights. PreviouslyGrantedAccess == 0 DesiredAccess = %08lx\n", DesiredAccess); 674 Status = STATUS_ACCESS_DENIED; 675 } 676 677 /* We have successfully granted all the rights */ 678 goto ReturnCommonStatus; 679 } 680 681 /* Grant rights according to the DACL */ 682 AccessCheckRights = SepAnalyzeAcesFromDacl(AccessCheckRegular, 683 Dacl, 684 Token, 685 PrimaryAccessToken, 686 FALSE, 687 FALSE, 688 PrincipalSelfSid, 689 GenericMapping, 690 ObjectTypeList, 691 ObjectTypeListLength, 692 RemainingAccess); 693 694 /* 695 * Getting the access check rights is very 696 * important as we have to do access checks 697 * depending on the kind of rights we get. 698 * Fail prematurely if we can't... 699 */ 700 if (!AccessCheckRights) 701 { 702 DPRINT1("SepAccessCheck(): Failed to obtain access check rights!\n"); 703 Status = STATUS_INSUFFICIENT_RESOURCES; 704 PreviouslyGrantedAccess = 0; 705 goto ReturnCommonStatus; 706 } 707 708 /* Fail if some rights have not been granted */ 709 if (AccessCheckRights->RemainingAccessRights != 0) 710 { 711 DPRINT1("SepAccessCheck(): Failed to grant access rights. RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n", AccessCheckRights->RemainingAccessRights, DesiredAccess); 712 PreviouslyGrantedAccess = 0; 713 Status = STATUS_ACCESS_DENIED; 714 goto ReturnCommonStatus; 715 } 716 717 /* 718 * Perform further access checks if this token 719 * has restricted SIDs. 720 */ 721 if (SeTokenIsRestricted(Token)) 722 { 723 AccessCheckRights = SepAnalyzeAcesFromDacl(AccessCheckRegular, 724 Dacl, 725 Token, 726 PrimaryAccessToken, 727 TRUE, 728 TRUE, 729 PrincipalSelfSid, 730 GenericMapping, 731 ObjectTypeList, 732 ObjectTypeListLength, 733 RemainingAccess); 734 735 /* Fail if some rights have not been granted */ 736 if (AccessCheckRights->RemainingAccessRights != 0) 737 { 738 DPRINT1("SepAccessCheck(): Failed to grant access rights. RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n", AccessCheckRights->RemainingAccessRights, DesiredAccess); 739 PreviouslyGrantedAccess = 0; 740 Status = STATUS_ACCESS_DENIED; 741 goto ReturnCommonStatus; 742 } 743 } 744 745 /* Set granted access rights */ 746 PreviouslyGrantedAccess |= DesiredAccess; 747 748 /* Fail if no rights have been granted */ 749 if (PreviouslyGrantedAccess == 0) 750 { 751 DPRINT1("SepAccessCheck(): Failed to grant access rights. PreviouslyGrantedAccess == 0 DesiredAccess = %08lx\n", DesiredAccess); 752 Status = STATUS_ACCESS_DENIED; 753 goto ReturnCommonStatus; 754 } 755 756 /* 757 * If we're here then we granted all the desired 758 * access rights the caller wanted. 759 */ 760 Status = STATUS_SUCCESS; 761 762 ReturnCommonStatus: 763 ResultListLength = UseResultList ? ObjectTypeListLength : 1; 764 for (ResultListIndex = 0; ResultListIndex < ResultListLength; ResultListIndex++) 765 { 766 GrantedAccessList[ResultListIndex] = PreviouslyGrantedAccess; 767 AccessStatusList[ResultListIndex] = Status; 768 } 769 770 /* Free the allocated access check rights */ 771 SepFreeAccessCheckRights(AccessCheckRights); 772 AccessCheckRights = NULL; 773 774 return NT_SUCCESS(Status); 775 } 776 777 /** 778 * @brief 779 * Retrieves the main user from a security descriptor. 780 * 781 * @param[in] SecurityDescriptor 782 * A valid allocated security descriptor structure where the owner 783 * is to be retrieved. 784 * 785 * @return 786 * Returns a SID that represents the main user (owner). 787 */ 788 static PSID 789 SepGetSDOwner( 790 _In_ PSECURITY_DESCRIPTOR _SecurityDescriptor) 791 { 792 PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor; 793 PSID Owner; 794 795 if (SecurityDescriptor->Control & SE_SELF_RELATIVE) 796 Owner = (PSID)((ULONG_PTR)SecurityDescriptor->Owner + 797 (ULONG_PTR)SecurityDescriptor); 798 else 799 Owner = (PSID)SecurityDescriptor->Owner; 800 801 return Owner; 802 } 803 804 /** 805 * @brief 806 * Retrieves the group from a security descriptor. 807 * 808 * @param[in] SecurityDescriptor 809 * A valid allocated security descriptor structure where the group 810 * is to be retrieved. 811 * 812 * @return 813 * Returns a SID that represents a group. 814 */ 815 static PSID 816 SepGetSDGroup( 817 _In_ PSECURITY_DESCRIPTOR _SecurityDescriptor) 818 { 819 PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor; 820 PSID Group; 821 822 if (SecurityDescriptor->Control & SE_SELF_RELATIVE) 823 Group = (PSID)((ULONG_PTR)SecurityDescriptor->Group + 824 (ULONG_PTR)SecurityDescriptor); 825 else 826 Group = (PSID)SecurityDescriptor->Group; 827 828 return Group; 829 } 830 831 /** 832 * @brief 833 * Retrieves the length size of a set list of privileges structure. 834 * 835 * @param[in] PrivilegeSet 836 * A valid set of privileges. 837 * 838 * @return 839 * Returns the total length of a set of privileges. 840 */ 841 static 842 ULONG 843 SepGetPrivilegeSetLength( 844 _In_ PPRIVILEGE_SET PrivilegeSet) 845 { 846 if (PrivilegeSet == NULL) 847 return 0; 848 849 if (PrivilegeSet->PrivilegeCount == 0) 850 return (ULONG)(sizeof(PRIVILEGE_SET) - sizeof(LUID_AND_ATTRIBUTES)); 851 852 return (ULONG)(sizeof(PRIVILEGE_SET) + 853 (PrivilegeSet->PrivilegeCount - 1) * sizeof(LUID_AND_ATTRIBUTES)); 854 } 855 856 /* PUBLIC FUNCTIONS ***********************************************************/ 857 858 /** 859 * @brief 860 * Determines whether security access rights can be given to an object 861 * depending on the security descriptor and other security context 862 * entities, such as an owner. 863 * 864 * @param[in] SecurityDescriptor 865 * Security descriptor of the object that is being accessed. 866 * 867 * @param[in] SubjectSecurityContext 868 * The captured subject security context. 869 * 870 * @param[in] SubjectContextLocked 871 * If set to TRUE, the caller acknowledges that the subject context 872 * has already been locked by the caller himself. If set to FALSE, 873 * the function locks the subject context. 874 * 875 * @param[in] DesiredAccess 876 * Access right bitmask that the calling thread wants to acquire. 877 * 878 * @param[in] PreviouslyGrantedAccess 879 * The access rights previously acquired in the past. 880 * 881 * @param[out] Privileges 882 * The returned set of privileges. 883 * 884 * @param[in] GenericMapping 885 * The generic mapping of access rights of an object type. 886 * 887 * @param[in] AccessMode 888 * The processor request level mode. 889 * 890 * @param[out] GrantedAccess 891 * A list of granted access rights. 892 * 893 * @param[out] AccessStatus 894 * The returned status code specifying why access cannot be made 895 * onto an object (if said access is denied in the first place). 896 * 897 * @return 898 * Returns TRUE if access onto the specific object is allowed, FALSE 899 * otherwise. 900 */ 901 BOOLEAN 902 NTAPI 903 SeAccessCheck( 904 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 905 _In_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext, 906 _In_ BOOLEAN SubjectContextLocked, 907 _In_ ACCESS_MASK DesiredAccess, 908 _In_ ACCESS_MASK PreviouslyGrantedAccess, 909 _Out_ PPRIVILEGE_SET* Privileges, 910 _In_ PGENERIC_MAPPING GenericMapping, 911 _In_ KPROCESSOR_MODE AccessMode, 912 _Out_ PACCESS_MASK GrantedAccess, 913 _Out_ PNTSTATUS AccessStatus) 914 { 915 BOOLEAN ret; 916 917 PAGED_CODE(); 918 919 /* Check if this is kernel mode */ 920 if (AccessMode == KernelMode) 921 { 922 /* Check if kernel wants everything */ 923 if (DesiredAccess & MAXIMUM_ALLOWED) 924 { 925 /* Give it */ 926 *GrantedAccess = GenericMapping->GenericAll; 927 *GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED); 928 *GrantedAccess |= PreviouslyGrantedAccess; 929 } 930 else 931 { 932 /* Give the desired and previous access */ 933 *GrantedAccess = DesiredAccess | PreviouslyGrantedAccess; 934 } 935 936 /* Success */ 937 *AccessStatus = STATUS_SUCCESS; 938 return TRUE; 939 } 940 941 /* Check if we didn't get an SD */ 942 if (!SecurityDescriptor) 943 { 944 /* Automatic failure */ 945 *AccessStatus = STATUS_ACCESS_DENIED; 946 return FALSE; 947 } 948 949 /* Check for invalid impersonation */ 950 if ((SubjectSecurityContext->ClientToken) && 951 (SubjectSecurityContext->ImpersonationLevel < SecurityImpersonation)) 952 { 953 *AccessStatus = STATUS_BAD_IMPERSONATION_LEVEL; 954 return FALSE; 955 } 956 957 /* Acquire the lock if needed */ 958 if (!SubjectContextLocked) 959 SeLockSubjectContext(SubjectSecurityContext); 960 961 /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */ 962 if (DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED)) 963 { 964 PACCESS_TOKEN Token = SubjectSecurityContext->ClientToken ? 965 SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken; 966 967 if (SepTokenIsOwner(Token, 968 SecurityDescriptor, 969 FALSE)) 970 { 971 if (DesiredAccess & MAXIMUM_ALLOWED) 972 PreviouslyGrantedAccess |= (WRITE_DAC | READ_CONTROL); 973 else 974 PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL)); 975 976 DesiredAccess &= ~(WRITE_DAC | READ_CONTROL); 977 } 978 } 979 980 if (DesiredAccess == 0) 981 { 982 *GrantedAccess = PreviouslyGrantedAccess; 983 if (PreviouslyGrantedAccess == 0) 984 { 985 DPRINT1("Request for zero access to an object. Denying.\n"); 986 *AccessStatus = STATUS_ACCESS_DENIED; 987 ret = FALSE; 988 } 989 else 990 { 991 *AccessStatus = STATUS_SUCCESS; 992 ret = TRUE; 993 } 994 } 995 else 996 { 997 /* Call the internal function */ 998 ret = SepAccessCheck(SecurityDescriptor, 999 SubjectSecurityContext->ClientToken, 1000 SubjectSecurityContext->PrimaryToken, 1001 NULL, 1002 DesiredAccess, 1003 NULL, 1004 0, 1005 PreviouslyGrantedAccess, 1006 GenericMapping, 1007 AccessMode, 1008 FALSE, 1009 Privileges, 1010 GrantedAccess, 1011 AccessStatus); 1012 } 1013 1014 /* Release the lock if needed */ 1015 if (!SubjectContextLocked) 1016 SeUnlockSubjectContext(SubjectSecurityContext); 1017 1018 return ret; 1019 } 1020 1021 /** 1022 * @brief 1023 * Determines whether security access rights can be given to an object 1024 * depending on the security descriptor. Unlike the regular access check 1025 * procedure in the NT kernel, the fast traverse check is a faster way 1026 * to quickly check if access can be made into an object. 1027 * 1028 * @param[in] SecurityDescriptor 1029 * Security descriptor of the object that is being accessed. 1030 * 1031 * @param[in] AccessState 1032 * An access state to determine if the access token in the current 1033 * security context of the object is an restricted token. 1034 * 1035 * @param[in] DesiredAccess 1036 * The access right bitmask where the calling thread wants to acquire. 1037 * 1038 * @param[in] AccessMode 1039 * Process level request mode. 1040 * 1041 * @return 1042 * Returns TRUE if access onto the specific object is allowed, FALSE 1043 * otherwise. 1044 */ 1045 BOOLEAN 1046 NTAPI 1047 SeFastTraverseCheck( 1048 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 1049 _In_ PACCESS_STATE AccessState, 1050 _In_ ACCESS_MASK DesiredAccess, 1051 _In_ KPROCESSOR_MODE AccessMode) 1052 { 1053 PACL Dacl; 1054 ULONG AceIndex; 1055 PKNOWN_ACE Ace; 1056 1057 PAGED_CODE(); 1058 1059 ASSERT(AccessMode != KernelMode); 1060 1061 if (SecurityDescriptor == NULL) 1062 return FALSE; 1063 1064 /* Get DACL */ 1065 Dacl = SepGetDaclFromDescriptor(SecurityDescriptor); 1066 /* If no DACL, grant access */ 1067 if (Dacl == NULL) 1068 return TRUE; 1069 1070 /* No ACE -> Deny */ 1071 if (!Dacl->AceCount) 1072 return FALSE; 1073 1074 /* Can't perform the check on restricted token */ 1075 if (AccessState->Flags & TOKEN_IS_RESTRICTED) 1076 return FALSE; 1077 1078 /* Browse the ACEs */ 1079 for (AceIndex = 0, Ace = (PKNOWN_ACE)((ULONG_PTR)Dacl + sizeof(ACL)); 1080 AceIndex < Dacl->AceCount; 1081 AceIndex++, Ace = (PKNOWN_ACE)((ULONG_PTR)Ace + Ace->Header.AceSize)) 1082 { 1083 if (Ace->Header.AceFlags & INHERIT_ONLY_ACE) 1084 continue; 1085 1086 /* If access-allowed ACE */ 1087 if (Ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) 1088 { 1089 /* Check if all accesses are granted */ 1090 if (!(Ace->Mask & DesiredAccess)) 1091 continue; 1092 1093 /* Check SID and grant access if matching */ 1094 if (RtlEqualSid(SeWorldSid, &(Ace->SidStart))) 1095 return TRUE; 1096 } 1097 /* If access-denied ACE */ 1098 else if (Ace->Header.AceType == ACCESS_DENIED_ACE_TYPE) 1099 { 1100 /* Here, only check if it denies any access wanted and deny if so */ 1101 if (Ace->Mask & DesiredAccess) 1102 return FALSE; 1103 } 1104 } 1105 1106 /* Faulty, deny */ 1107 return FALSE; 1108 } 1109 1110 /* SYSTEM CALLS ***************************************************************/ 1111 1112 /** 1113 * @brief 1114 * Determines whether security access rights can be given to an object 1115 * depending on the security descriptor and a valid handle to an access 1116 * token. 1117 * 1118 * @param[in] SecurityDescriptor 1119 * Security descriptor of the object that is being accessed. 1120 * 1121 * @param[in] TokenHandle 1122 * A handle to a token. 1123 * 1124 * @param[in] DesiredAccess 1125 * The access right bitmask where the calling thread wants to acquire. 1126 * 1127 * @param[in] GenericMapping 1128 * The generic mapping of access rights of an object type. 1129 * 1130 * @param[out] PrivilegeSet 1131 * The returned set of privileges. 1132 * 1133 * @param[in,out] PrivilegeSetLength 1134 * The total length size of a set of privileges. 1135 * 1136 * @param[out] GrantedAccess 1137 * A list of granted access rights. 1138 * 1139 * @param[out] AccessStatus 1140 * The returned status code specifying why access cannot be made 1141 * onto an object (if said access is denied in the first place). 1142 * 1143 * @return 1144 * Returns STATUS_SUCCESS if access check has been done without problems 1145 * and that the object can be accessed. STATUS_GENERIC_NOT_MAPPED is returned 1146 * if no generic access right is mapped. STATUS_NO_IMPERSONATION_TOKEN is returned 1147 * if the token from the handle is not an impersonation token. 1148 * STATUS_BAD_IMPERSONATION_LEVEL is returned if the token cannot be impersonated 1149 * because the current security impersonation level doesn't permit so. 1150 * STATUS_INVALID_SECURITY_DESCR is returned if the security descriptor given 1151 * to the call is not a valid one. STATUS_BUFFER_TOO_SMALL is returned if 1152 * the buffer to the captured privileges has a length that is less than the required 1153 * size of the set of privileges. A failure NTSTATUS code is returned otherwise. 1154 */ 1155 NTSTATUS 1156 NTAPI 1157 NtAccessCheck( 1158 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 1159 _In_ HANDLE TokenHandle, 1160 _In_ ACCESS_MASK DesiredAccess, 1161 _In_ PGENERIC_MAPPING GenericMapping, 1162 _Out_opt_ PPRIVILEGE_SET PrivilegeSet, 1163 _Inout_ PULONG PrivilegeSetLength, 1164 _Out_ PACCESS_MASK GrantedAccess, 1165 _Out_ PNTSTATUS AccessStatus) 1166 { 1167 PSECURITY_DESCRIPTOR CapturedSecurityDescriptor = NULL; 1168 SECURITY_SUBJECT_CONTEXT SubjectSecurityContext; 1169 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1170 ACCESS_MASK PreviouslyGrantedAccess = 0; 1171 PPRIVILEGE_SET Privileges = NULL; 1172 ULONG CapturedPrivilegeSetLength, RequiredPrivilegeSetLength; 1173 PTOKEN Token; 1174 NTSTATUS Status; 1175 1176 PAGED_CODE(); 1177 1178 /* Check if this is kernel mode */ 1179 if (PreviousMode == KernelMode) 1180 { 1181 /* Check if kernel wants everything */ 1182 if (DesiredAccess & MAXIMUM_ALLOWED) 1183 { 1184 /* Give it */ 1185 *GrantedAccess = GenericMapping->GenericAll; 1186 *GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED); 1187 } 1188 else 1189 { 1190 /* Just give the desired access */ 1191 *GrantedAccess = DesiredAccess; 1192 } 1193 1194 /* Success */ 1195 *AccessStatus = STATUS_SUCCESS; 1196 return STATUS_SUCCESS; 1197 } 1198 1199 /* Protect probe in SEH */ 1200 _SEH2_TRY 1201 { 1202 /* Probe all pointers */ 1203 ProbeForRead(GenericMapping, sizeof(GENERIC_MAPPING), sizeof(ULONG)); 1204 ProbeForRead(PrivilegeSetLength, sizeof(ULONG), sizeof(ULONG)); 1205 ProbeForWrite(PrivilegeSet, *PrivilegeSetLength, sizeof(ULONG)); 1206 ProbeForWrite(GrantedAccess, sizeof(ACCESS_MASK), sizeof(ULONG)); 1207 ProbeForWrite(AccessStatus, sizeof(NTSTATUS), sizeof(ULONG)); 1208 1209 /* Capture the privilege set length and the mapping */ 1210 CapturedPrivilegeSetLength = *PrivilegeSetLength; 1211 } 1212 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1213 { 1214 /* Return the exception code */ 1215 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1216 } 1217 _SEH2_END; 1218 1219 /* Check for unmapped access rights */ 1220 if (DesiredAccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL)) 1221 return STATUS_GENERIC_NOT_MAPPED; 1222 1223 /* Reference the token */ 1224 Status = ObReferenceObjectByHandle(TokenHandle, 1225 TOKEN_QUERY, 1226 SeTokenObjectType, 1227 PreviousMode, 1228 (PVOID*)&Token, 1229 NULL); 1230 if (!NT_SUCCESS(Status)) 1231 { 1232 DPRINT("Failed to reference token (Status %lx)\n", Status); 1233 return Status; 1234 } 1235 1236 /* Check token type */ 1237 if (Token->TokenType != TokenImpersonation) 1238 { 1239 DPRINT("No impersonation token\n"); 1240 ObDereferenceObject(Token); 1241 return STATUS_NO_IMPERSONATION_TOKEN; 1242 } 1243 1244 /* Check the impersonation level */ 1245 if (Token->ImpersonationLevel < SecurityIdentification) 1246 { 1247 DPRINT("Impersonation level < SecurityIdentification\n"); 1248 ObDereferenceObject(Token); 1249 return STATUS_BAD_IMPERSONATION_LEVEL; 1250 } 1251 1252 /* Check for ACCESS_SYSTEM_SECURITY and WRITE_OWNER access */ 1253 Status = SePrivilegePolicyCheck(&DesiredAccess, 1254 &PreviouslyGrantedAccess, 1255 NULL, 1256 Token, 1257 &Privileges, 1258 PreviousMode); 1259 if (!NT_SUCCESS(Status)) 1260 { 1261 DPRINT("SePrivilegePolicyCheck failed (Status 0x%08lx)\n", Status); 1262 ObDereferenceObject(Token); 1263 *AccessStatus = Status; 1264 *GrantedAccess = 0; 1265 return STATUS_SUCCESS; 1266 } 1267 1268 /* Check the size of the privilege set and return the privileges */ 1269 if (Privileges != NULL) 1270 { 1271 DPRINT("Privileges != NULL\n"); 1272 1273 /* Calculate the required privilege set buffer size */ 1274 RequiredPrivilegeSetLength = SepGetPrivilegeSetLength(Privileges); 1275 1276 /* Fail if the privilege set buffer is too small */ 1277 if (CapturedPrivilegeSetLength < RequiredPrivilegeSetLength) 1278 { 1279 ObDereferenceObject(Token); 1280 SeFreePrivileges(Privileges); 1281 *PrivilegeSetLength = RequiredPrivilegeSetLength; 1282 return STATUS_BUFFER_TOO_SMALL; 1283 } 1284 1285 /* Copy the privilege set to the caller */ 1286 RtlCopyMemory(PrivilegeSet, 1287 Privileges, 1288 RequiredPrivilegeSetLength); 1289 1290 /* Free the local privilege set */ 1291 SeFreePrivileges(Privileges); 1292 } 1293 else 1294 { 1295 DPRINT("Privileges == NULL\n"); 1296 1297 /* Fail if the privilege set buffer is too small */ 1298 if (CapturedPrivilegeSetLength < sizeof(PRIVILEGE_SET)) 1299 { 1300 ObDereferenceObject(Token); 1301 *PrivilegeSetLength = sizeof(PRIVILEGE_SET); 1302 return STATUS_BUFFER_TOO_SMALL; 1303 } 1304 1305 /* Initialize the privilege set */ 1306 PrivilegeSet->PrivilegeCount = 0; 1307 PrivilegeSet->Control = 0; 1308 } 1309 1310 /* Capture the security descriptor */ 1311 Status = SeCaptureSecurityDescriptor(SecurityDescriptor, 1312 PreviousMode, 1313 PagedPool, 1314 FALSE, 1315 &CapturedSecurityDescriptor); 1316 if (!NT_SUCCESS(Status)) 1317 { 1318 DPRINT("Failed to capture the Security Descriptor\n"); 1319 ObDereferenceObject(Token); 1320 return Status; 1321 } 1322 1323 /* Check the captured security descriptor */ 1324 if (CapturedSecurityDescriptor == NULL) 1325 { 1326 DPRINT("Security Descriptor is NULL\n"); 1327 ObDereferenceObject(Token); 1328 return STATUS_INVALID_SECURITY_DESCR; 1329 } 1330 1331 /* Check security descriptor for valid owner and group */ 1332 if (SepGetSDOwner(CapturedSecurityDescriptor) == NULL || 1333 SepGetSDGroup(CapturedSecurityDescriptor) == NULL) 1334 { 1335 DPRINT("Security Descriptor does not have a valid group or owner\n"); 1336 SeReleaseSecurityDescriptor(CapturedSecurityDescriptor, 1337 PreviousMode, 1338 FALSE); 1339 ObDereferenceObject(Token); 1340 return STATUS_INVALID_SECURITY_DESCR; 1341 } 1342 1343 /* Set up the subject context, and lock it */ 1344 SeCaptureSubjectContext(&SubjectSecurityContext); 1345 1346 /* Lock the token */ 1347 SepAcquireTokenLockShared(Token); 1348 1349 /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */ 1350 if (DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED)) 1351 { 1352 if (SepTokenIsOwner(Token, CapturedSecurityDescriptor, FALSE)) 1353 { 1354 if (DesiredAccess & MAXIMUM_ALLOWED) 1355 PreviouslyGrantedAccess |= (WRITE_DAC | READ_CONTROL); 1356 else 1357 PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL)); 1358 1359 DesiredAccess &= ~(WRITE_DAC | READ_CONTROL); 1360 } 1361 } 1362 1363 if (DesiredAccess == 0) 1364 { 1365 *GrantedAccess = PreviouslyGrantedAccess; 1366 *AccessStatus = STATUS_SUCCESS; 1367 } 1368 else 1369 { 1370 /* Now perform the access check */ 1371 SepAccessCheck(CapturedSecurityDescriptor, 1372 Token, 1373 &SubjectSecurityContext.PrimaryToken, 1374 NULL, 1375 DesiredAccess, 1376 NULL, 1377 0, 1378 PreviouslyGrantedAccess, 1379 GenericMapping, 1380 PreviousMode, 1381 FALSE, 1382 NULL, 1383 GrantedAccess, 1384 AccessStatus); 1385 } 1386 1387 /* Release subject context and unlock the token */ 1388 SeReleaseSubjectContext(&SubjectSecurityContext); 1389 SepReleaseTokenLock(Token); 1390 1391 /* Release the captured security descriptor */ 1392 SeReleaseSecurityDescriptor(CapturedSecurityDescriptor, 1393 PreviousMode, 1394 FALSE); 1395 1396 /* Dereference the token */ 1397 ObDereferenceObject(Token); 1398 1399 /* Check succeeded */ 1400 return STATUS_SUCCESS; 1401 } 1402 1403 /** 1404 * @brief 1405 * Determines whether security access could be granted or not on 1406 * an object by the requestor who wants such access through type. 1407 * 1408 * @param[in] SecurityDescriptor 1409 * A security descriptor with information data for auditing. 1410 * 1411 * @param[in] PrincipalSelfSid 1412 * A principal self user SID. 1413 * 1414 * @param[in] ClientToken 1415 * A client access token. 1416 * 1417 * @param[in] DesiredAccess 1418 * The desired access masks rights requested by the caller. 1419 * 1420 * @param[in] ObjectTypeList 1421 * A list of object types. 1422 * 1423 * @param[in] ObjectTypeLength 1424 * The length size of the list. 1425 * 1426 * @param[in] GenericMapping 1427 * The generic mapping list of access masks rights. 1428 * 1429 * @param[in] PrivilegeSet 1430 * An array set of privileges. 1431 * 1432 * @param[in,out] PrivilegeSetLength 1433 * The length size of the array set of privileges. 1434 * 1435 * @param[out] GrantedAccess 1436 * The returned granted access rights. 1437 * 1438 * @param[out] AccessStatus 1439 * The returned NTSTATUS code indicating the final results 1440 * of auditing. 1441 * 1442 * @return 1443 * To be added... 1444 */ 1445 NTSTATUS 1446 NTAPI 1447 NtAccessCheckByType( 1448 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 1449 _In_ PSID PrincipalSelfSid, 1450 _In_ HANDLE ClientToken, 1451 _In_ ACCESS_MASK DesiredAccess, 1452 _In_ POBJECT_TYPE_LIST ObjectTypeList, 1453 _In_ ULONG ObjectTypeLength, 1454 _In_ PGENERIC_MAPPING GenericMapping, 1455 _In_ PPRIVILEGE_SET PrivilegeSet, 1456 _Inout_ PULONG PrivilegeSetLength, 1457 _Out_ PACCESS_MASK GrantedAccess, 1458 _Out_ PNTSTATUS AccessStatus) 1459 { 1460 UNIMPLEMENTED; 1461 return STATUS_NOT_IMPLEMENTED; 1462 } 1463 1464 /** 1465 * @brief 1466 * Determines whether security access could be granted or not on 1467 * an object by the requestor who wants such access through 1468 * type list. 1469 * 1470 * @param[in] SecurityDescriptor 1471 * A security descriptor with information data for auditing. 1472 * 1473 * @param[in] PrincipalSelfSid 1474 * A principal self user SID. 1475 * 1476 * @param[in] ClientToken 1477 * A client access token. 1478 * 1479 * @param[in] DesiredAccess 1480 * The desired access masks rights requested by the caller. 1481 * 1482 * @param[in] ObjectTypeList 1483 * A list of object types. 1484 * 1485 * @param[in] ObjectTypeLength 1486 * The length size of the list. 1487 * 1488 * @param[in] GenericMapping 1489 * The generic mapping list of access masks rights. 1490 * 1491 * @param[in] PrivilegeSet 1492 * An array set of privileges. 1493 * 1494 * @param[in,out] PrivilegeSetLength 1495 * The length size of the array set of privileges. 1496 * 1497 * @param[out] GrantedAccess 1498 * The returned granted access rights. 1499 * 1500 * @param[out] AccessStatus 1501 * The returned NTSTATUS code indicating the final results 1502 * of auditing. 1503 * 1504 * @return 1505 * To be added... 1506 */ 1507 NTSTATUS 1508 NTAPI 1509 NtAccessCheckByTypeResultList( 1510 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 1511 _In_ PSID PrincipalSelfSid, 1512 _In_ HANDLE ClientToken, 1513 _In_ ACCESS_MASK DesiredAccess, 1514 _In_ POBJECT_TYPE_LIST ObjectTypeList, 1515 _In_ ULONG ObjectTypeLength, 1516 _In_ PGENERIC_MAPPING GenericMapping, 1517 _In_ PPRIVILEGE_SET PrivilegeSet, 1518 _Inout_ PULONG PrivilegeSetLength, 1519 _Out_ PACCESS_MASK GrantedAccess, 1520 _Out_ PNTSTATUS AccessStatus) 1521 { 1522 UNIMPLEMENTED; 1523 return STATUS_NOT_IMPLEMENTED; 1524 } 1525 1526 /* EOF */ 1527