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 ULONG ResultListLength; 483 ULONG ResultListIndex; 484 PACL Dacl; 485 BOOLEAN Present; 486 BOOLEAN Defaulted; 487 NTSTATUS Status; 488 PACCESS_TOKEN Token = NULL; 489 PACCESS_CHECK_RIGHTS AccessCheckRights = NULL; 490 491 PAGED_CODE(); 492 493 /* A security descriptor must be expected for access checks */ 494 ASSERT(SecurityDescriptor); 495 496 /* Check for no access desired */ 497 if (!DesiredAccess) 498 { 499 /* Check if we had no previous access */ 500 if (!PreviouslyGrantedAccess) 501 { 502 /* Then there's nothing to give */ 503 DPRINT1("SepAccessCheck(): The caller has no previously granted access gained!\n"); 504 Status = STATUS_ACCESS_DENIED; 505 goto ReturnCommonStatus; 506 } 507 508 /* Return the previous access only */ 509 Status = STATUS_SUCCESS; 510 *Privileges = NULL; 511 goto ReturnCommonStatus; 512 } 513 514 /* Map given accesses */ 515 RtlMapGenericMask(&DesiredAccess, GenericMapping); 516 if (PreviouslyGrantedAccess) 517 RtlMapGenericMask(&PreviouslyGrantedAccess, GenericMapping); 518 519 /* Initialize remaining access rights */ 520 RemainingAccess = DesiredAccess; 521 522 /* 523 * Obtain the token provided by the caller. Client (or also 524 * called impersonation or thread) token takes precedence over 525 * the primary token which is the token associated with the security 526 * context of the main calling process. This is because it is the 527 * client itself that requests access of an object or subset of 528 * multiple objects. Otherwise obtain the security context of the 529 * main process (the actual primary token). 530 */ 531 Token = ClientAccessToken ? ClientAccessToken : PrimaryAccessToken; 532 533 /* 534 * We should at least expect a primary token 535 * to be present if client token is not 536 * available. 537 */ 538 ASSERT(Token); 539 540 /* 541 * Check for ACCESS_SYSTEM_SECURITY and WRITE_OWNER access. 542 * Write down a set of privileges that have been checked 543 * if the caller wants it. 544 */ 545 Status = SePrivilegePolicyCheck(&RemainingAccess, 546 &PreviouslyGrantedAccess, 547 NULL, 548 Token, 549 Privileges, 550 AccessMode); 551 if (!NT_SUCCESS(Status)) 552 { 553 goto ReturnCommonStatus; 554 } 555 556 /* Succeed if there are no more rights to grant */ 557 if (RemainingAccess == 0) 558 { 559 Status = STATUS_SUCCESS; 560 goto ReturnCommonStatus; 561 } 562 563 /* Get the DACL */ 564 Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor, 565 &Present, 566 &Dacl, 567 &Defaulted); 568 if (!NT_SUCCESS(Status)) 569 { 570 goto ReturnCommonStatus; 571 } 572 573 /* Grant desired access if the object is unprotected */ 574 if (Present == FALSE || Dacl == NULL) 575 { 576 PreviouslyGrantedAccess |= RemainingAccess; 577 if (RemainingAccess & MAXIMUM_ALLOWED) 578 { 579 PreviouslyGrantedAccess &= ~MAXIMUM_ALLOWED; 580 PreviouslyGrantedAccess |= GenericMapping->GenericAll; 581 } 582 583 Status = STATUS_SUCCESS; 584 goto ReturnCommonStatus; 585 } 586 587 /* Deny access if the DACL is empty */ 588 if (Dacl->AceCount == 0) 589 { 590 if (RemainingAccess == MAXIMUM_ALLOWED && PreviouslyGrantedAccess != 0) 591 { 592 Status = STATUS_SUCCESS; 593 } 594 else 595 { 596 DPRINT1("SepAccessCheck(): The DACL has no ACEs and the caller has no previously granted access!\n"); 597 PreviouslyGrantedAccess = 0; 598 Status = STATUS_ACCESS_DENIED; 599 } 600 goto ReturnCommonStatus; 601 } 602 603 /* Determine the MAXIMUM_ALLOWED access rights according to the DACL */ 604 if (DesiredAccess & MAXIMUM_ALLOWED) 605 { 606 /* Perform access checks against ACEs from this DACL */ 607 AccessCheckRights = SepAnalyzeAcesFromDacl(AccessCheckMaximum, 608 Dacl, 609 Token, 610 PrimaryAccessToken, 611 FALSE, 612 FALSE, 613 PrincipalSelfSid, 614 GenericMapping, 615 ObjectTypeList, 616 ObjectTypeListLength, 617 0); 618 619 /* 620 * Getting the access check rights is very 621 * important as we have to do access checks 622 * depending on the kind of rights we get. 623 * Fail prematurely if we can't... 624 */ 625 if (!AccessCheckRights) 626 { 627 DPRINT1("SepAccessCheck(): Failed to obtain access check rights!\n"); 628 Status = STATUS_INSUFFICIENT_RESOURCES; 629 PreviouslyGrantedAccess = 0; 630 goto ReturnCommonStatus; 631 } 632 633 /* 634 * Perform further access checks if this token 635 * has restricted SIDs. 636 */ 637 if (SeTokenIsRestricted(Token)) 638 { 639 AccessCheckRights = SepAnalyzeAcesFromDacl(AccessCheckMaximum, 640 Dacl, 641 Token, 642 PrimaryAccessToken, 643 TRUE, 644 TRUE, 645 PrincipalSelfSid, 646 GenericMapping, 647 ObjectTypeList, 648 ObjectTypeListLength, 649 0); 650 } 651 652 /* Fail if some rights have not been granted */ 653 RemainingAccess &= ~(MAXIMUM_ALLOWED | AccessCheckRights->GrantedAccessRights); 654 if (RemainingAccess != 0) 655 { 656 DPRINT1("SepAccessCheck(): Failed to grant access rights. RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n", RemainingAccess, DesiredAccess); 657 PreviouslyGrantedAccess = 0; 658 Status = STATUS_ACCESS_DENIED; 659 goto ReturnCommonStatus; 660 } 661 662 /* Set granted access right and access status */ 663 PreviouslyGrantedAccess |= AccessCheckRights->GrantedAccessRights; 664 if (PreviouslyGrantedAccess != 0) 665 { 666 Status = STATUS_SUCCESS; 667 } 668 else 669 { 670 DPRINT1("SepAccessCheck(): Failed to grant access rights. PreviouslyGrantedAccess == 0 DesiredAccess = %08lx\n", DesiredAccess); 671 Status = STATUS_ACCESS_DENIED; 672 } 673 674 /* We have successfully granted all the rights */ 675 goto ReturnCommonStatus; 676 } 677 678 /* Grant rights according to the DACL */ 679 AccessCheckRights = SepAnalyzeAcesFromDacl(AccessCheckRegular, 680 Dacl, 681 Token, 682 PrimaryAccessToken, 683 FALSE, 684 FALSE, 685 PrincipalSelfSid, 686 GenericMapping, 687 ObjectTypeList, 688 ObjectTypeListLength, 689 RemainingAccess); 690 691 /* 692 * Getting the access check rights is very 693 * important as we have to do access checks 694 * depending on the kind of rights we get. 695 * Fail prematurely if we can't... 696 */ 697 if (!AccessCheckRights) 698 { 699 DPRINT1("SepAccessCheck(): Failed to obtain access check rights!\n"); 700 Status = STATUS_INSUFFICIENT_RESOURCES; 701 PreviouslyGrantedAccess = 0; 702 goto ReturnCommonStatus; 703 } 704 705 /* Fail if some rights have not been granted */ 706 if (AccessCheckRights->RemainingAccessRights != 0) 707 { 708 DPRINT1("SepAccessCheck(): Failed to grant access rights. RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n", AccessCheckRights->RemainingAccessRights, DesiredAccess); 709 PreviouslyGrantedAccess = 0; 710 Status = STATUS_ACCESS_DENIED; 711 goto ReturnCommonStatus; 712 } 713 714 /* 715 * Perform further access checks if this token 716 * has restricted SIDs. 717 */ 718 if (SeTokenIsRestricted(Token)) 719 { 720 AccessCheckRights = SepAnalyzeAcesFromDacl(AccessCheckRegular, 721 Dacl, 722 Token, 723 PrimaryAccessToken, 724 TRUE, 725 TRUE, 726 PrincipalSelfSid, 727 GenericMapping, 728 ObjectTypeList, 729 ObjectTypeListLength, 730 RemainingAccess); 731 732 /* Fail if some rights have not been granted */ 733 if (AccessCheckRights->RemainingAccessRights != 0) 734 { 735 DPRINT1("SepAccessCheck(): Failed to grant access rights. RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n", AccessCheckRights->RemainingAccessRights, DesiredAccess); 736 PreviouslyGrantedAccess = 0; 737 Status = STATUS_ACCESS_DENIED; 738 goto ReturnCommonStatus; 739 } 740 } 741 742 /* Set granted access rights */ 743 PreviouslyGrantedAccess |= DesiredAccess; 744 745 /* Fail if no rights have been granted */ 746 if (PreviouslyGrantedAccess == 0) 747 { 748 DPRINT1("SepAccessCheck(): Failed to grant access rights. PreviouslyGrantedAccess == 0 DesiredAccess = %08lx\n", DesiredAccess); 749 Status = STATUS_ACCESS_DENIED; 750 goto ReturnCommonStatus; 751 } 752 753 /* 754 * If we're here then we granted all the desired 755 * access rights the caller wanted. 756 */ 757 Status = STATUS_SUCCESS; 758 759 ReturnCommonStatus: 760 ResultListLength = UseResultList ? ObjectTypeListLength : 1; 761 for (ResultListIndex = 0; ResultListIndex < ResultListLength; ResultListIndex++) 762 { 763 GrantedAccessList[ResultListIndex] = PreviouslyGrantedAccess; 764 AccessStatusList[ResultListIndex] = Status; 765 } 766 767 #if DBG 768 /* Dump security debug info on access denied case */ 769 if (Status == STATUS_ACCESS_DENIED) 770 { 771 SepDumpSdDebugInfo(SecurityDescriptor); 772 SepDumpTokenDebugInfo(Token); 773 SepDumpAccessRightsStats(AccessCheckRights); 774 } 775 #endif 776 777 /* Free the allocated access check rights */ 778 SepFreeAccessCheckRights(AccessCheckRights); 779 AccessCheckRights = NULL; 780 781 return NT_SUCCESS(Status); 782 } 783 784 /** 785 * @brief 786 * Retrieves the main user from a security descriptor. 787 * 788 * @param[in] SecurityDescriptor 789 * A valid allocated security descriptor structure where the owner 790 * is to be retrieved. 791 * 792 * @return 793 * Returns a SID that represents the main user (owner). 794 */ 795 static PSID 796 SepGetSDOwner( 797 _In_ PSECURITY_DESCRIPTOR _SecurityDescriptor) 798 { 799 PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor; 800 PSID Owner; 801 802 if (SecurityDescriptor->Control & SE_SELF_RELATIVE) 803 Owner = (PSID)((ULONG_PTR)SecurityDescriptor->Owner + 804 (ULONG_PTR)SecurityDescriptor); 805 else 806 Owner = (PSID)SecurityDescriptor->Owner; 807 808 return Owner; 809 } 810 811 /** 812 * @brief 813 * Retrieves the group from a security descriptor. 814 * 815 * @param[in] SecurityDescriptor 816 * A valid allocated security descriptor structure where the group 817 * is to be retrieved. 818 * 819 * @return 820 * Returns a SID that represents a group. 821 */ 822 static PSID 823 SepGetSDGroup( 824 _In_ PSECURITY_DESCRIPTOR _SecurityDescriptor) 825 { 826 PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor; 827 PSID Group; 828 829 if (SecurityDescriptor->Control & SE_SELF_RELATIVE) 830 Group = (PSID)((ULONG_PTR)SecurityDescriptor->Group + 831 (ULONG_PTR)SecurityDescriptor); 832 else 833 Group = (PSID)SecurityDescriptor->Group; 834 835 return Group; 836 } 837 838 /** 839 * @brief 840 * Retrieves the length size of a set list of privileges structure. 841 * 842 * @param[in] PrivilegeSet 843 * A valid set of privileges. 844 * 845 * @return 846 * Returns the total length of a set of privileges. 847 */ 848 static 849 ULONG 850 SepGetPrivilegeSetLength( 851 _In_ PPRIVILEGE_SET PrivilegeSet) 852 { 853 if (PrivilegeSet == NULL) 854 return 0; 855 856 if (PrivilegeSet->PrivilegeCount == 0) 857 return (ULONG)(sizeof(PRIVILEGE_SET) - sizeof(LUID_AND_ATTRIBUTES)); 858 859 return (ULONG)(sizeof(PRIVILEGE_SET) + 860 (PrivilegeSet->PrivilegeCount - 1) * sizeof(LUID_AND_ATTRIBUTES)); 861 } 862 863 /* PUBLIC FUNCTIONS ***********************************************************/ 864 865 /** 866 * @brief 867 * Determines whether security access rights can be given to an object 868 * depending on the security descriptor and other security context 869 * entities, such as an owner. 870 * 871 * @param[in] SecurityDescriptor 872 * Security descriptor of the object that is being accessed. 873 * 874 * @param[in] SubjectSecurityContext 875 * The captured subject security context. 876 * 877 * @param[in] SubjectContextLocked 878 * If set to TRUE, the caller acknowledges that the subject context 879 * has already been locked by the caller himself. If set to FALSE, 880 * the function locks the subject context. 881 * 882 * @param[in] DesiredAccess 883 * Access right bitmask that the calling thread wants to acquire. 884 * 885 * @param[in] PreviouslyGrantedAccess 886 * The access rights previously acquired in the past. 887 * 888 * @param[out] Privileges 889 * The returned set of privileges. 890 * 891 * @param[in] GenericMapping 892 * The generic mapping of access rights of an object type. 893 * 894 * @param[in] AccessMode 895 * The processor request level mode. 896 * 897 * @param[out] GrantedAccess 898 * A list of granted access rights. 899 * 900 * @param[out] AccessStatus 901 * The returned status code specifying why access cannot be made 902 * onto an object (if said access is denied in the first place). 903 * 904 * @return 905 * Returns TRUE if access onto the specific object is allowed, FALSE 906 * otherwise. 907 */ 908 BOOLEAN 909 NTAPI 910 SeAccessCheck( 911 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 912 _In_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext, 913 _In_ BOOLEAN SubjectContextLocked, 914 _In_ ACCESS_MASK DesiredAccess, 915 _In_ ACCESS_MASK PreviouslyGrantedAccess, 916 _Out_ PPRIVILEGE_SET* Privileges, 917 _In_ PGENERIC_MAPPING GenericMapping, 918 _In_ KPROCESSOR_MODE AccessMode, 919 _Out_ PACCESS_MASK GrantedAccess, 920 _Out_ PNTSTATUS AccessStatus) 921 { 922 BOOLEAN ret; 923 924 PAGED_CODE(); 925 926 /* Check if this is kernel mode */ 927 if (AccessMode == KernelMode) 928 { 929 /* Check if kernel wants everything */ 930 if (DesiredAccess & MAXIMUM_ALLOWED) 931 { 932 /* Give it */ 933 *GrantedAccess = GenericMapping->GenericAll; 934 *GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED); 935 *GrantedAccess |= PreviouslyGrantedAccess; 936 } 937 else 938 { 939 /* Give the desired and previous access */ 940 *GrantedAccess = DesiredAccess | PreviouslyGrantedAccess; 941 } 942 943 /* Success */ 944 *AccessStatus = STATUS_SUCCESS; 945 return TRUE; 946 } 947 948 /* Check if we didn't get an SD */ 949 if (!SecurityDescriptor) 950 { 951 /* Automatic failure */ 952 *AccessStatus = STATUS_ACCESS_DENIED; 953 return FALSE; 954 } 955 956 /* Check for invalid impersonation */ 957 if ((SubjectSecurityContext->ClientToken) && 958 (SubjectSecurityContext->ImpersonationLevel < SecurityImpersonation)) 959 { 960 *AccessStatus = STATUS_BAD_IMPERSONATION_LEVEL; 961 return FALSE; 962 } 963 964 /* Acquire the lock if needed */ 965 if (!SubjectContextLocked) 966 SeLockSubjectContext(SubjectSecurityContext); 967 968 /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */ 969 if (DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED)) 970 { 971 PACCESS_TOKEN Token = SubjectSecurityContext->ClientToken ? 972 SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken; 973 974 if (SepTokenIsOwner(Token, 975 SecurityDescriptor, 976 FALSE)) 977 { 978 if (DesiredAccess & MAXIMUM_ALLOWED) 979 PreviouslyGrantedAccess |= (WRITE_DAC | READ_CONTROL); 980 else 981 PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL)); 982 983 DesiredAccess &= ~(WRITE_DAC | READ_CONTROL); 984 } 985 } 986 987 if (DesiredAccess == 0) 988 { 989 *GrantedAccess = PreviouslyGrantedAccess; 990 if (PreviouslyGrantedAccess == 0) 991 { 992 DPRINT1("Request for zero access to an object. Denying.\n"); 993 *AccessStatus = STATUS_ACCESS_DENIED; 994 ret = FALSE; 995 } 996 else 997 { 998 *AccessStatus = STATUS_SUCCESS; 999 ret = TRUE; 1000 } 1001 } 1002 else 1003 { 1004 /* Call the internal function */ 1005 ret = SepAccessCheck(SecurityDescriptor, 1006 SubjectSecurityContext->ClientToken, 1007 SubjectSecurityContext->PrimaryToken, 1008 NULL, 1009 DesiredAccess, 1010 NULL, 1011 0, 1012 PreviouslyGrantedAccess, 1013 GenericMapping, 1014 AccessMode, 1015 FALSE, 1016 Privileges, 1017 GrantedAccess, 1018 AccessStatus); 1019 } 1020 1021 /* Release the lock if needed */ 1022 if (!SubjectContextLocked) 1023 SeUnlockSubjectContext(SubjectSecurityContext); 1024 1025 return ret; 1026 } 1027 1028 /** 1029 * @brief 1030 * Determines whether security access rights can be given to an object 1031 * depending on the security descriptor. Unlike the regular access check 1032 * procedure in the NT kernel, the fast traverse check is a faster way 1033 * to quickly check if access can be made into an object. 1034 * 1035 * @param[in] SecurityDescriptor 1036 * Security descriptor of the object that is being accessed. 1037 * 1038 * @param[in] AccessState 1039 * An access state to determine if the access token in the current 1040 * security context of the object is an restricted token. 1041 * 1042 * @param[in] DesiredAccess 1043 * The access right bitmask where the calling thread wants to acquire. 1044 * 1045 * @param[in] AccessMode 1046 * Process level request mode. 1047 * 1048 * @return 1049 * Returns TRUE if access onto the specific object is allowed, FALSE 1050 * otherwise. 1051 */ 1052 BOOLEAN 1053 NTAPI 1054 SeFastTraverseCheck( 1055 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 1056 _In_ PACCESS_STATE AccessState, 1057 _In_ ACCESS_MASK DesiredAccess, 1058 _In_ KPROCESSOR_MODE AccessMode) 1059 { 1060 PACL Dacl; 1061 ULONG AceIndex; 1062 PKNOWN_ACE Ace; 1063 1064 PAGED_CODE(); 1065 1066 ASSERT(AccessMode != KernelMode); 1067 1068 if (SecurityDescriptor == NULL) 1069 return FALSE; 1070 1071 /* Get DACL */ 1072 Dacl = SepGetDaclFromDescriptor(SecurityDescriptor); 1073 /* If no DACL, grant access */ 1074 if (Dacl == NULL) 1075 return TRUE; 1076 1077 /* No ACE -> Deny */ 1078 if (!Dacl->AceCount) 1079 return FALSE; 1080 1081 /* Can't perform the check on restricted token */ 1082 if (AccessState->Flags & TOKEN_IS_RESTRICTED) 1083 return FALSE; 1084 1085 /* Browse the ACEs */ 1086 for (AceIndex = 0, Ace = (PKNOWN_ACE)((ULONG_PTR)Dacl + sizeof(ACL)); 1087 AceIndex < Dacl->AceCount; 1088 AceIndex++, Ace = (PKNOWN_ACE)((ULONG_PTR)Ace + Ace->Header.AceSize)) 1089 { 1090 if (Ace->Header.AceFlags & INHERIT_ONLY_ACE) 1091 continue; 1092 1093 /* If access-allowed ACE */ 1094 if (Ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) 1095 { 1096 /* Check if all accesses are granted */ 1097 if (!(Ace->Mask & DesiredAccess)) 1098 continue; 1099 1100 /* Check SID and grant access if matching */ 1101 if (RtlEqualSid(SeWorldSid, &(Ace->SidStart))) 1102 return TRUE; 1103 } 1104 /* If access-denied ACE */ 1105 else if (Ace->Header.AceType == ACCESS_DENIED_ACE_TYPE) 1106 { 1107 /* Here, only check if it denies any access wanted and deny if so */ 1108 if (Ace->Mask & DesiredAccess) 1109 return FALSE; 1110 } 1111 } 1112 1113 /* Faulty, deny */ 1114 return FALSE; 1115 } 1116 1117 /* SYSTEM CALLS ***************************************************************/ 1118 1119 /** 1120 * @brief 1121 * Determines whether security access rights can be given to an object 1122 * depending on the security descriptor and a valid handle to an access 1123 * token. 1124 * 1125 * @param[in] SecurityDescriptor 1126 * Security descriptor of the object that is being accessed. 1127 * 1128 * @param[in] TokenHandle 1129 * A handle to a token. 1130 * 1131 * @param[in] DesiredAccess 1132 * The access right bitmask where the calling thread wants to acquire. 1133 * 1134 * @param[in] GenericMapping 1135 * The generic mapping of access rights of an object type. 1136 * 1137 * @param[out] PrivilegeSet 1138 * The returned set of privileges. 1139 * 1140 * @param[in,out] PrivilegeSetLength 1141 * The total length size of a set of privileges. 1142 * 1143 * @param[out] GrantedAccess 1144 * A list of granted access rights. 1145 * 1146 * @param[out] AccessStatus 1147 * The returned status code specifying why access cannot be made 1148 * onto an object (if said access is denied in the first place). 1149 * 1150 * @return 1151 * Returns STATUS_SUCCESS if access check has been done without problems 1152 * and that the object can be accessed. STATUS_GENERIC_NOT_MAPPED is returned 1153 * if no generic access right is mapped. STATUS_NO_IMPERSONATION_TOKEN is returned 1154 * if the token from the handle is not an impersonation token. 1155 * STATUS_BAD_IMPERSONATION_LEVEL is returned if the token cannot be impersonated 1156 * because the current security impersonation level doesn't permit so. 1157 * STATUS_INVALID_SECURITY_DESCR is returned if the security descriptor given 1158 * to the call is not a valid one. STATUS_BUFFER_TOO_SMALL is returned if 1159 * the buffer to the captured privileges has a length that is less than the required 1160 * size of the set of privileges. A failure NTSTATUS code is returned otherwise. 1161 */ 1162 NTSTATUS 1163 NTAPI 1164 NtAccessCheck( 1165 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 1166 _In_ HANDLE TokenHandle, 1167 _In_ ACCESS_MASK DesiredAccess, 1168 _In_ PGENERIC_MAPPING GenericMapping, 1169 _Out_opt_ PPRIVILEGE_SET PrivilegeSet, 1170 _Inout_ PULONG PrivilegeSetLength, 1171 _Out_ PACCESS_MASK GrantedAccess, 1172 _Out_ PNTSTATUS AccessStatus) 1173 { 1174 PSECURITY_DESCRIPTOR CapturedSecurityDescriptor = NULL; 1175 SECURITY_SUBJECT_CONTEXT SubjectSecurityContext; 1176 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1177 ACCESS_MASK PreviouslyGrantedAccess = 0; 1178 PPRIVILEGE_SET Privileges = NULL; 1179 ULONG CapturedPrivilegeSetLength, RequiredPrivilegeSetLength; 1180 PTOKEN Token; 1181 NTSTATUS Status; 1182 1183 PAGED_CODE(); 1184 1185 /* Check if this is kernel mode */ 1186 if (PreviousMode == KernelMode) 1187 { 1188 /* Check if kernel wants everything */ 1189 if (DesiredAccess & MAXIMUM_ALLOWED) 1190 { 1191 /* Give it */ 1192 *GrantedAccess = GenericMapping->GenericAll; 1193 *GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED); 1194 } 1195 else 1196 { 1197 /* Just give the desired access */ 1198 *GrantedAccess = DesiredAccess; 1199 } 1200 1201 /* Success */ 1202 *AccessStatus = STATUS_SUCCESS; 1203 return STATUS_SUCCESS; 1204 } 1205 1206 /* Protect probe in SEH */ 1207 _SEH2_TRY 1208 { 1209 /* Probe all pointers */ 1210 ProbeForRead(GenericMapping, sizeof(GENERIC_MAPPING), sizeof(ULONG)); 1211 ProbeForRead(PrivilegeSetLength, sizeof(ULONG), sizeof(ULONG)); 1212 ProbeForWrite(PrivilegeSet, *PrivilegeSetLength, sizeof(ULONG)); 1213 ProbeForWrite(GrantedAccess, sizeof(ACCESS_MASK), sizeof(ULONG)); 1214 ProbeForWrite(AccessStatus, sizeof(NTSTATUS), sizeof(ULONG)); 1215 1216 /* Capture the privilege set length and the mapping */ 1217 CapturedPrivilegeSetLength = *PrivilegeSetLength; 1218 } 1219 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1220 { 1221 /* Return the exception code */ 1222 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1223 } 1224 _SEH2_END; 1225 1226 /* Check for unmapped access rights */ 1227 if (DesiredAccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL)) 1228 return STATUS_GENERIC_NOT_MAPPED; 1229 1230 /* Reference the token */ 1231 Status = ObReferenceObjectByHandle(TokenHandle, 1232 TOKEN_QUERY, 1233 SeTokenObjectType, 1234 PreviousMode, 1235 (PVOID*)&Token, 1236 NULL); 1237 if (!NT_SUCCESS(Status)) 1238 { 1239 DPRINT("Failed to reference token (Status %lx)\n", Status); 1240 return Status; 1241 } 1242 1243 /* Check token type */ 1244 if (Token->TokenType != TokenImpersonation) 1245 { 1246 DPRINT("No impersonation token\n"); 1247 ObDereferenceObject(Token); 1248 return STATUS_NO_IMPERSONATION_TOKEN; 1249 } 1250 1251 /* Check the impersonation level */ 1252 if (Token->ImpersonationLevel < SecurityIdentification) 1253 { 1254 DPRINT("Impersonation level < SecurityIdentification\n"); 1255 ObDereferenceObject(Token); 1256 return STATUS_BAD_IMPERSONATION_LEVEL; 1257 } 1258 1259 /* Check for ACCESS_SYSTEM_SECURITY and WRITE_OWNER access */ 1260 Status = SePrivilegePolicyCheck(&DesiredAccess, 1261 &PreviouslyGrantedAccess, 1262 NULL, 1263 Token, 1264 &Privileges, 1265 PreviousMode); 1266 if (!NT_SUCCESS(Status)) 1267 { 1268 DPRINT("SePrivilegePolicyCheck failed (Status 0x%08lx)\n", Status); 1269 ObDereferenceObject(Token); 1270 *AccessStatus = Status; 1271 *GrantedAccess = 0; 1272 return STATUS_SUCCESS; 1273 } 1274 1275 /* Check the size of the privilege set and return the privileges */ 1276 if (Privileges != NULL) 1277 { 1278 DPRINT("Privileges != NULL\n"); 1279 1280 /* Calculate the required privilege set buffer size */ 1281 RequiredPrivilegeSetLength = SepGetPrivilegeSetLength(Privileges); 1282 1283 /* Fail if the privilege set buffer is too small */ 1284 if (CapturedPrivilegeSetLength < RequiredPrivilegeSetLength) 1285 { 1286 ObDereferenceObject(Token); 1287 SeFreePrivileges(Privileges); 1288 *PrivilegeSetLength = RequiredPrivilegeSetLength; 1289 return STATUS_BUFFER_TOO_SMALL; 1290 } 1291 1292 /* Copy the privilege set to the caller */ 1293 RtlCopyMemory(PrivilegeSet, 1294 Privileges, 1295 RequiredPrivilegeSetLength); 1296 1297 /* Free the local privilege set */ 1298 SeFreePrivileges(Privileges); 1299 } 1300 else 1301 { 1302 DPRINT("Privileges == NULL\n"); 1303 1304 /* Fail if the privilege set buffer is too small */ 1305 if (CapturedPrivilegeSetLength < sizeof(PRIVILEGE_SET)) 1306 { 1307 ObDereferenceObject(Token); 1308 *PrivilegeSetLength = sizeof(PRIVILEGE_SET); 1309 return STATUS_BUFFER_TOO_SMALL; 1310 } 1311 1312 /* Initialize the privilege set */ 1313 PrivilegeSet->PrivilegeCount = 0; 1314 PrivilegeSet->Control = 0; 1315 } 1316 1317 /* Capture the security descriptor */ 1318 Status = SeCaptureSecurityDescriptor(SecurityDescriptor, 1319 PreviousMode, 1320 PagedPool, 1321 FALSE, 1322 &CapturedSecurityDescriptor); 1323 if (!NT_SUCCESS(Status)) 1324 { 1325 DPRINT("Failed to capture the Security Descriptor\n"); 1326 ObDereferenceObject(Token); 1327 return Status; 1328 } 1329 1330 /* Check the captured security descriptor */ 1331 if (CapturedSecurityDescriptor == NULL) 1332 { 1333 DPRINT("Security Descriptor is NULL\n"); 1334 ObDereferenceObject(Token); 1335 return STATUS_INVALID_SECURITY_DESCR; 1336 } 1337 1338 /* Check security descriptor for valid owner and group */ 1339 if (SepGetSDOwner(CapturedSecurityDescriptor) == NULL || 1340 SepGetSDGroup(CapturedSecurityDescriptor) == NULL) 1341 { 1342 DPRINT("Security Descriptor does not have a valid group or owner\n"); 1343 SeReleaseSecurityDescriptor(CapturedSecurityDescriptor, 1344 PreviousMode, 1345 FALSE); 1346 ObDereferenceObject(Token); 1347 return STATUS_INVALID_SECURITY_DESCR; 1348 } 1349 1350 /* Set up the subject context, and lock it */ 1351 SeCaptureSubjectContext(&SubjectSecurityContext); 1352 1353 /* Lock the token */ 1354 SepAcquireTokenLockShared(Token); 1355 1356 /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */ 1357 if (DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED)) 1358 { 1359 if (SepTokenIsOwner(Token, CapturedSecurityDescriptor, FALSE)) 1360 { 1361 if (DesiredAccess & MAXIMUM_ALLOWED) 1362 PreviouslyGrantedAccess |= (WRITE_DAC | READ_CONTROL); 1363 else 1364 PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL)); 1365 1366 DesiredAccess &= ~(WRITE_DAC | READ_CONTROL); 1367 } 1368 } 1369 1370 if (DesiredAccess == 0) 1371 { 1372 *GrantedAccess = PreviouslyGrantedAccess; 1373 *AccessStatus = STATUS_SUCCESS; 1374 } 1375 else 1376 { 1377 /* Now perform the access check */ 1378 SepAccessCheck(CapturedSecurityDescriptor, 1379 Token, 1380 &SubjectSecurityContext.PrimaryToken, 1381 NULL, 1382 DesiredAccess, 1383 NULL, 1384 0, 1385 PreviouslyGrantedAccess, 1386 GenericMapping, 1387 PreviousMode, 1388 FALSE, 1389 NULL, 1390 GrantedAccess, 1391 AccessStatus); 1392 } 1393 1394 /* Release subject context and unlock the token */ 1395 SeReleaseSubjectContext(&SubjectSecurityContext); 1396 SepReleaseTokenLock(Token); 1397 1398 /* Release the captured security descriptor */ 1399 SeReleaseSecurityDescriptor(CapturedSecurityDescriptor, 1400 PreviousMode, 1401 FALSE); 1402 1403 /* Dereference the token */ 1404 ObDereferenceObject(Token); 1405 1406 /* Check succeeded */ 1407 return STATUS_SUCCESS; 1408 } 1409 1410 /** 1411 * @brief 1412 * Determines whether security access could be granted or not on 1413 * an object by the requestor who wants such access through type. 1414 * 1415 * @param[in] SecurityDescriptor 1416 * A security descriptor with information data for auditing. 1417 * 1418 * @param[in] PrincipalSelfSid 1419 * A principal self user SID. 1420 * 1421 * @param[in] ClientToken 1422 * A client access token. 1423 * 1424 * @param[in] DesiredAccess 1425 * The desired access masks rights requested by the caller. 1426 * 1427 * @param[in] ObjectTypeList 1428 * A list of object types. 1429 * 1430 * @param[in] ObjectTypeLength 1431 * The length size of the list. 1432 * 1433 * @param[in] GenericMapping 1434 * The generic mapping list of access masks rights. 1435 * 1436 * @param[in] PrivilegeSet 1437 * An array set of privileges. 1438 * 1439 * @param[in,out] PrivilegeSetLength 1440 * The length size of the array set of privileges. 1441 * 1442 * @param[out] GrantedAccess 1443 * The returned granted access rights. 1444 * 1445 * @param[out] AccessStatus 1446 * The returned NTSTATUS code indicating the final results 1447 * of auditing. 1448 * 1449 * @return 1450 * To be added... 1451 */ 1452 NTSTATUS 1453 NTAPI 1454 NtAccessCheckByType( 1455 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 1456 _In_ PSID PrincipalSelfSid, 1457 _In_ HANDLE ClientToken, 1458 _In_ ACCESS_MASK DesiredAccess, 1459 _In_ POBJECT_TYPE_LIST ObjectTypeList, 1460 _In_ ULONG ObjectTypeLength, 1461 _In_ PGENERIC_MAPPING GenericMapping, 1462 _In_ PPRIVILEGE_SET PrivilegeSet, 1463 _Inout_ PULONG PrivilegeSetLength, 1464 _Out_ PACCESS_MASK GrantedAccess, 1465 _Out_ PNTSTATUS AccessStatus) 1466 { 1467 UNIMPLEMENTED; 1468 return STATUS_NOT_IMPLEMENTED; 1469 } 1470 1471 /** 1472 * @brief 1473 * Determines whether security access could be granted or not on 1474 * an object by the requestor who wants such access through 1475 * type list. 1476 * 1477 * @param[in] SecurityDescriptor 1478 * A security descriptor with information data for auditing. 1479 * 1480 * @param[in] PrincipalSelfSid 1481 * A principal self user SID. 1482 * 1483 * @param[in] ClientToken 1484 * A client access token. 1485 * 1486 * @param[in] DesiredAccess 1487 * The desired access masks rights requested by the caller. 1488 * 1489 * @param[in] ObjectTypeList 1490 * A list of object types. 1491 * 1492 * @param[in] ObjectTypeLength 1493 * The length size of the list. 1494 * 1495 * @param[in] GenericMapping 1496 * The generic mapping list of access masks rights. 1497 * 1498 * @param[in] PrivilegeSet 1499 * An array set of privileges. 1500 * 1501 * @param[in,out] PrivilegeSetLength 1502 * The length size of the array set of privileges. 1503 * 1504 * @param[out] GrantedAccess 1505 * The returned granted access rights. 1506 * 1507 * @param[out] AccessStatus 1508 * The returned NTSTATUS code indicating the final results 1509 * of auditing. 1510 * 1511 * @return 1512 * To be added... 1513 */ 1514 NTSTATUS 1515 NTAPI 1516 NtAccessCheckByTypeResultList( 1517 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 1518 _In_ PSID PrincipalSelfSid, 1519 _In_ HANDLE ClientToken, 1520 _In_ ACCESS_MASK DesiredAccess, 1521 _In_ POBJECT_TYPE_LIST ObjectTypeList, 1522 _In_ ULONG ObjectTypeLength, 1523 _In_ PGENERIC_MAPPING GenericMapping, 1524 _In_ PPRIVILEGE_SET PrivilegeSet, 1525 _Inout_ PULONG PrivilegeSetLength, 1526 _Out_ PACCESS_MASK GrantedAccess, 1527 _Out_ PNTSTATUS AccessStatus) 1528 { 1529 UNIMPLEMENTED; 1530 return STATUS_NOT_IMPLEMENTED; 1531 } 1532 1533 /* EOF */ 1534