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-2023 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 * Denies access of a target object and the children objects 21 * in an object type list. 22 * 23 * @param[in,out] ObjectTypeList 24 * A pointer to an object type list where access is to be 25 * denied for the target object and its children in the 26 * hierarchy list. 27 * 28 * @param[in] ObjectTypeListLength 29 * The length of the object type list. This length represents 30 * the number of object elements in the list. 31 * 32 * @param[in] AccessMask 33 * The access mask right that is to be denied for the object. 34 * 35 * @param[in] ObjectTypeGuid 36 * A pointer to a object type GUID, that identifies the object. 37 * This GUID is used to search for the target object in the list. 38 * If this parameter is set to NULL, the function will deny access 39 * starting from the object itself in the list (aka the root). 40 */ 41 static 42 VOID 43 SepDenyAccessObjectTypeResultList( 44 _Inout_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList, 45 _In_ ULONG ObjectTypeListLength, 46 _In_ ACCESS_MASK AccessMask, 47 _In_opt_ PGUID ObjectTypeGuid) 48 { 49 ULONG ObjectTypeIndex; 50 ULONG ReturnedObjectIndex; 51 USHORT Level; 52 53 PAGED_CODE(); 54 55 DPRINT("Access rights 0x%08lx\n", AccessMask); 56 57 /* 58 * The object type of interest is the one that was supplied 59 * by the creator who made the ACE. If the object type was 60 * not supplied then we have no clear indication from where 61 * shall we start updating the access rights of objects on 62 * this list, so we have to begin from the root (aka the 63 * object itself). 64 */ 65 if (!ObjectTypeGuid) 66 { 67 DPRINT("No object type provided, updating access rights from root\n"); 68 ReturnedObjectIndex = 0; 69 goto LoopAndUpdateRightsObjects; 70 } 71 72 /* Check if that object exists in the list */ 73 if (SepObjectTypeGuidInList(ObjectTypeList, 74 ObjectTypeListLength, 75 ObjectTypeGuid, 76 &ReturnedObjectIndex)) 77 { 78 LoopAndUpdateRightsObjects: 79 /* Update the access rights of the target object */ 80 ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.DeniedAccessRights |= 81 (AccessMask & ~ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.GrantedAccessRights); 82 DPRINT("Denied rights 0x%08lx of target object at index %lu\n", 83 ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.DeniedAccessRights, ReturnedObjectIndex); 84 85 /* And update the children of the target object */ 86 for (ObjectTypeIndex = ReturnedObjectIndex + 1; 87 ObjectTypeIndex < ObjectTypeListLength; 88 ObjectTypeIndex++) 89 { 90 /* 91 * Stop looking for children objects if we hit an object that has 92 * the same level as the target object or less. 93 */ 94 Level = ObjectTypeList[ObjectTypeIndex].Level; 95 if (Level <= ObjectTypeList[ReturnedObjectIndex].Level) 96 { 97 DPRINT("We looked for all children objects, stop looking\n"); 98 break; 99 } 100 101 /* Update the access right of the child */ 102 ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.DeniedAccessRights |= 103 (AccessMask & ~ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights); 104 DPRINT("Denied rights 0x%08lx of child object at index %lu\n", 105 ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.DeniedAccessRights, ObjectTypeIndex); 106 } 107 } 108 } 109 110 /** 111 * @brief 112 * Allows access of a target object and the children objects 113 * in an object type list. 114 * 115 * @param[in,out] ObjectTypeList 116 * A pointer to an object type list where access is to be 117 * allowed for the target object and its children in the 118 * hierarchy list. 119 * 120 * @param[in] ObjectTypeListLength 121 * The length of the object type list. This length represents 122 * the number of object elements in the list. 123 * 124 * @param[in] AccessMask 125 * The access mask right that is to be allowed for the object. 126 * 127 * @param[in] ObjectTypeGuid 128 * A pointer to a object type GUID, that identifies the object. 129 * This GUID is used to search for the target object in the list. 130 * If this parameter is set to NULL, the function will allow access 131 * starting from the object itself in the list (aka the root). 132 */ 133 static 134 VOID 135 SepAllowAccessObjectTypeResultList( 136 _Inout_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList, 137 _In_ ULONG ObjectTypeListLength, 138 _In_ ACCESS_MASK AccessMask, 139 _In_opt_ PGUID ObjectTypeGuid) 140 { 141 ULONG ObjectTypeIndex; 142 ULONG ReturnedObjectIndex; 143 USHORT Level; 144 145 PAGED_CODE(); 146 147 DPRINT("Access rights 0x%08lx\n", AccessMask); 148 149 /* 150 * Begin updating the access rights from the root object 151 * (see comment in SepDenyAccessObjectTypeListMaximum). 152 */ 153 if (!ObjectTypeGuid) 154 { 155 DPRINT("No object type provided, updating access rights from root\n"); 156 ReturnedObjectIndex = 0; 157 goto LoopAndUpdateRightsObjects; 158 } 159 160 /* Check if that object exists in the list */ 161 if (SepObjectTypeGuidInList(ObjectTypeList, 162 ObjectTypeListLength, 163 ObjectTypeGuid, 164 &ReturnedObjectIndex)) 165 { 166 LoopAndUpdateRightsObjects: 167 /* Update the access rights of the target object */ 168 ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.GrantedAccessRights |= 169 (AccessMask & ~ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.DeniedAccessRights); 170 DPRINT("Granted rights 0x%08lx of target object at index %lu\n", 171 ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.GrantedAccessRights, ReturnedObjectIndex); 172 173 /* And update the children of the target object */ 174 for (ObjectTypeIndex = ReturnedObjectIndex + 1; 175 ObjectTypeIndex < ObjectTypeListLength; 176 ObjectTypeIndex++) 177 { 178 /* 179 * Stop looking for children objects if we hit an object that has 180 * the same level as the target object or less. 181 */ 182 Level = ObjectTypeList[ObjectTypeIndex].Level; 183 if (Level <= ObjectTypeList[ReturnedObjectIndex].Level) 184 { 185 break; 186 } 187 188 /* Update the access right of the child */ 189 ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights |= 190 (AccessMask & ~ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.DeniedAccessRights); 191 DPRINT("Granted rights 0x%08lx of child object at index %lu\n", 192 ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights, ObjectTypeIndex); 193 } 194 } 195 } 196 197 /** 198 * @brief 199 * Denies access of a target object in the object type 200 * list. This access is denied for the whole hierarchy 201 * in the list. 202 * 203 * @param[in,out] ObjectTypeList 204 * A pointer to an object type list where access is to be 205 * denied for the target object. This operation applies 206 * for the entire hierarchy of the object type list. 207 * 208 * @param[in] ObjectTypeListLength 209 * The length of the object type list. This length represents 210 * the number of object elements in the list. 211 * 212 * @param[in] AccessMask 213 * The access mask right that is to be denied for the object. 214 * 215 * @param[in] ObjectTypeGuid 216 * A pointer to a object type GUID, that identifies the object. 217 * This GUID is used to search for the target object in the list. 218 * If this parameter is set to NULL, the function will deny access 219 * to the object itself in the list (aka the root). 220 * 221 * @param[out] BreakOnDeny 222 * A pointer returned boolean value to the caller. The function 223 * will return TRUE if the requested remaining right is denied 224 * by the ACE, otherwise it returns FALSE. 225 */ 226 static 227 VOID 228 SepDenyAccessObjectTypeList( 229 _Inout_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList, 230 _In_ ULONG ObjectTypeListLength, 231 _In_ ACCESS_MASK AccessMask, 232 _In_opt_ PGUID ObjectTypeGuid, 233 _Out_opt_ PBOOLEAN BreakOnDeny) 234 { 235 ULONG ReturnedObjectIndex; 236 BOOLEAN MustBreak; 237 238 PAGED_CODE(); 239 240 DPRINT("Access rights 0x%08lx\n", AccessMask); 241 242 /* Assume we do not want to break at first */ 243 MustBreak = FALSE; 244 245 /* 246 * If no object type was supplied then tell the caller it has to break on 247 * searching for other ACEs if the requested remaining access right is 248 * denied by the deny ACE itself. Track down that denied right too. 249 */ 250 if (!ObjectTypeGuid) 251 { 252 if (ObjectTypeList[0].ObjectAccessRights.RemainingAccessRights & AccessMask) 253 { 254 DPRINT("Root object requests remaining access right that is denied 0x%08lx\n", AccessMask); 255 MustBreak = TRUE; 256 } 257 258 ObjectTypeList[0].ObjectAccessRights.DeniedAccessRights |= 259 (AccessMask & ~ObjectTypeList[0].ObjectAccessRights.GrantedAccessRights); 260 DPRINT("Denied rights of root object 0x%08lx\n", ObjectTypeList[0].ObjectAccessRights.DeniedAccessRights); 261 goto Quit; 262 } 263 264 /* 265 * If the object exists tell the caller it has to break down if the requested 266 * remaining access right is denied by the ACE. Track down the denied right too. 267 */ 268 if (SepObjectTypeGuidInList(ObjectTypeList, 269 ObjectTypeListLength, 270 ObjectTypeGuid, 271 &ReturnedObjectIndex)) 272 { 273 if (ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.RemainingAccessRights & AccessMask) 274 { 275 DPRINT("Object at index %lu requests remaining access right that is denied 0x%08lx\n", ReturnedObjectIndex, AccessMask); 276 MustBreak = TRUE; 277 } 278 279 ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.DeniedAccessRights |= 280 (AccessMask & ~ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.GrantedAccessRights); 281 DPRINT("Denied rights 0x%08lx of object at index %lu\n", 282 ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.DeniedAccessRights, ReturnedObjectIndex); 283 } 284 285 Quit: 286 /* Signal the caller he has to break if he wants to */ 287 if (BreakOnDeny) 288 { 289 *BreakOnDeny = MustBreak; 290 } 291 } 292 293 /** 294 * @brief 295 * Allows access of a target object in the object type 296 * list. This access is allowed for the whole hierarchy 297 * in the list. 298 * 299 * @param[in,out] ObjectTypeList 300 * A pointer to an object type list where access is to be 301 * allowed for the target object. This operation applies 302 * for the entire hierarchy of the object type list. 303 * 304 * @param[in] ObjectTypeListLength 305 * The length of the object type list. This length represents 306 * the number of object elements in the list. 307 * 308 * @param[in] AccessMask 309 * The access mask right that is to be allowed for the object. 310 * 311 * @param[in] RemoveRemainingRights 312 * If set to TRUE, the function will remove the remaining rights 313 * of a target object. It will also grant access of the said object. 314 * Otherwise if set to FALSE, the function will only grant access. 315 * 316 * @param[in] ObjectTypeGuid 317 * A pointer to a object type GUID, that identifies the object. 318 * This GUID is used to search for the target object in the list. 319 * If this parameter is set to NULL, the function will allow access 320 * to the object itself in the list (aka the root). 321 */ 322 static 323 VOID 324 SepAllowAccessObjectTypeList( 325 _Inout_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList, 326 _In_ ULONG ObjectTypeListLength, 327 _In_ ACCESS_MASK AccessMask, 328 _In_ BOOLEAN RemoveRemainingRights, 329 _In_opt_ PGUID ObjectTypeGuid) 330 { 331 ULONG ReturnedObjectIndex; 332 333 PAGED_CODE(); 334 335 DPRINT("Access rights 0x%08lx\n", AccessMask); 336 337 /* 338 * If no object type was supplied then remove the remaining rights 339 * of the object itself, the root. Track down that right to the 340 * granted rights as well. 341 */ 342 if (!ObjectTypeGuid) 343 { 344 if (RemoveRemainingRights) 345 { 346 ObjectTypeList[0].ObjectAccessRights.RemainingAccessRights &= ~AccessMask; 347 DPRINT("Remaining rights of root object 0x%08lx\n", ObjectTypeList[0].ObjectAccessRights.RemainingAccessRights); 348 } 349 350 ObjectTypeList[0].ObjectAccessRights.GrantedAccessRights |= 351 (AccessMask & ~ObjectTypeList[0].ObjectAccessRights.DeniedAccessRights); 352 DPRINT("Granted rights of root object 0x%08lx\n", ObjectTypeList[0].ObjectAccessRights.GrantedAccessRights); 353 return; 354 } 355 356 /* 357 * Grant access to the object if it exists by removing the remaining 358 * rights. Unlike the NtAccessCheckByTypeResultList variant we do not 359 * care about the children of the target object beccause NtAccessCheckByType 360 * will either grant or deny access to the entire hierarchy of the list. 361 */ 362 if (SepObjectTypeGuidInList(ObjectTypeList, 363 ObjectTypeListLength, 364 ObjectTypeGuid, 365 &ReturnedObjectIndex)) 366 { 367 /* Remove the remaining rights of that object */ 368 if (RemoveRemainingRights) 369 { 370 ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.RemainingAccessRights &= ~AccessMask; 371 DPRINT("Remaining rights of object 0x%08lx at index %lu\n", 372 ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.RemainingAccessRights, ReturnedObjectIndex); 373 } 374 375 /* And track it down to the granted access rights */ 376 ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.GrantedAccessRights |= 377 (AccessMask & ~ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.DeniedAccessRights); 378 DPRINT("Granted rights of object 0x%08lx at index %lu\n", 379 ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.GrantedAccessRights, ReturnedObjectIndex); 380 } 381 } 382 383 /** 384 * @brief 385 * Analyzes an access control entry that is present in a discretionary 386 * access control list (DACL) for access right masks of each entry with 387 * the purpose to judge whether the calling thread can be warranted 388 * access check to a certain object or not. 389 * 390 * @param[in] ActionType 391 * The type of analysis to be done against an access entry. This type 392 * influences how access rights are gathered. This can either be AccessCheckMaximum 393 * which means the algorithm will perform analysis against ACEs on behalf of the 394 * requestor that gave us the acknowledgement that he desires MAXIMUM_ALLOWED access 395 * right or AccessCheckRegular if the requestor wants a subset of access rights. 396 * 397 * @param[in] RemainingAccess 398 * The remaining access rights that have yet to be granted to the calling thread 399 * whomst requests access to a certain object. This parameter mustn't be 0 as 400 * the remaining rights are left to be addressed. This is the case if we have 401 * to address the remaining rights on a regular subset basis (the requestor 402 * didn't ask for MAXIMUM_ALLOWED). Otherwise this parameter can be 0. 403 * 404 * @param[in] Dacl 405 * The discretionary access control list to be given to this function. This DACL 406 * must have at least one ACE currently present in the list. 407 * 408 * @param[in] AccessToken 409 * A pointer to an access token, where an equality comparison check is performed if 410 * the security identifier (SID) from a ACE of a certain object is present in this 411 * token. This token represents the effective (calling thread) token of the caller. 412 * 413 * @param[in] PrimaryAccessToken 414 * A pointer to an access token, represented as an access token associated with the 415 * primary calling process. This token describes the primary security context of the 416 * main process. 417 * 418 * @param[in] IsTokenRestricted 419 * If this parameter is set to TRUE, the function considers the token pointed by 420 * AccessToken parameter argument as restricted. That is, the token has restricted 421 * SIDs therefore the function will act accordingly against that token by checking 422 * for restricted SIDs only when doing an equaility comparison check between the 423 * two identifiers. 424 * 425 * @param[in] PrincipalSelfSid 426 * A pointer to a security identifier that represents a principal. A principal 427 * identifies a user object which is associated with its own security descriptor. 428 * 429 * @param[in] GenericMapping 430 * A pointer to a generic mapping that is associated with the object in question 431 * being checked for access. If certain set of desired access rights have 432 * a generic access right, this parameter is needed to map generic rights. 433 * 434 * @param[in] ObjectTypeList 435 * A pointer to a list array of object types. If such array is provided to the 436 * function, the algorithm will perform a different approach by doing analysis 437 * against ACEs each sub-object of an object of primary level (level 0) or sub-objects 438 * of a sub-object of an object. If this parameter is NULL, the function will normally 439 * analyze the ACEs of a DACL of the target object itself. 440 * 441 * @param[in] ObjectTypeListLength 442 * The length of the object type list array, pointed by ObjectTypeList. This length in 443 * question represents the number of elements in such array. This parameter must be 0 444 * if no array list is provided. 445 * 446 * @param[in] UseResultList 447 * This parameter is to used to determine how to perform an object type access check. 448 * If set to TRUE, the function will either grant or deny access to the object and sub-objects 449 * in the hierarchy list. If set to FALSE, the function will either grant or deny access to 450 * the target that will affect the entire hierarchy of the list. This parameter is used 451 * if the access action type is AccessCheckMaximum. 452 * 453 * @param[in,out] AccessCheckRights 454 * A pointer to a structure that contains the access check rights. This function fills 455 * up this structure with remaining, granted and denied rights to the caller for 456 * access check. Henceforth, this parameter must not be NULL! 457 */ 458 static 459 VOID 460 SepAnalyzeAcesFromDacl( 461 _In_ ACCESS_CHECK_RIGHT_TYPE ActionType, 462 _In_ ACCESS_MASK RemainingAccess, 463 _In_ PACL Dacl, 464 _In_ PACCESS_TOKEN AccessToken, 465 _In_ PACCESS_TOKEN PrimaryAccessToken, 466 _In_ BOOLEAN IsTokenRestricted, 467 _In_opt_ PSID PrincipalSelfSid, 468 _In_ PGENERIC_MAPPING GenericMapping, 469 _In_opt_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList, 470 _In_ ULONG ObjectTypeListLength, 471 _In_ BOOLEAN UseResultList, 472 _Inout_ PACCESS_CHECK_RIGHTS AccessCheckRights) 473 { 474 NTSTATUS Status; 475 PACE CurrentAce; 476 ULONG AceIndex; 477 ULONG ObjectTypeIndex; 478 PSID Sid; 479 PGUID ObjectTypeGuid; 480 ACCESS_MASK Access; 481 BOOLEAN BreakOnDeny; 482 483 PAGED_CODE(); 484 485 /* These parameters are really needed */ 486 ASSERT(Dacl); 487 ASSERT(AccessToken); 488 489 /* TODO: To be removed once we support compound ACEs handling in Se */ 490 DBG_UNREFERENCED_PARAMETER(PrimaryAccessToken); 491 492 /* Determine how we should analyze the ACEs */ 493 switch (ActionType) 494 { 495 /* 496 * We got the acknowledgement the calling thread desires 497 * maximum rights (as according to MAXIMUM_ALLOWED access 498 * mask). Analyze the ACE of the given DACL. 499 */ 500 case AccessCheckMaximum: 501 { 502 /* Loop over the DACL to retrieve ACEs */ 503 for (AceIndex = 0; AceIndex < Dacl->AceCount; AceIndex++) 504 { 505 /* Obtain a ACE now */ 506 Status = RtlGetAce(Dacl, AceIndex, (PVOID*)&CurrentAce); 507 508 /* Getting this ACE is important, otherwise something is seriously wrong */ 509 ASSERT(NT_SUCCESS(Status)); 510 511 /* 512 * Now it's time to analyze it based upon the 513 * type of this ACE we're being given. 514 */ 515 if (!(CurrentAce->Header.AceFlags & INHERIT_ONLY_ACE)) 516 { 517 if (CurrentAce->Header.AceType == ACCESS_DENIED_ACE_TYPE) 518 { 519 /* Get the SID from this ACE */ 520 Sid = SepGetSidFromAce(CurrentAce); 521 ASSERT(Sid); 522 523 if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, TRUE, IsTokenRestricted)) 524 { 525 /* Get this access right from the ACE */ 526 Access = CurrentAce->AccessMask; 527 528 /* Map this access right if it has a generic mask right */ 529 if ((Access & GENERIC_ACCESS) && GenericMapping) 530 { 531 RtlMapGenericMask(&Access, GenericMapping); 532 } 533 534 /* Deny access rights that have not been granted yet */ 535 AccessCheckRights->DeniedAccessRights |= (Access & ~AccessCheckRights->GrantedAccessRights); 536 DPRINT("DeniedAccessRights 0x%08lx\n", AccessCheckRights->DeniedAccessRights); 537 } 538 } 539 else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) 540 { 541 /* Get the SID from this ACE */ 542 Sid = SepGetSidFromAce(CurrentAce); 543 ASSERT(Sid); 544 545 if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, FALSE, IsTokenRestricted)) 546 { 547 /* Get this access right from the ACE */ 548 Access = CurrentAce->AccessMask; 549 550 /* Map this access right if it has a generic mask right */ 551 if ((Access & GENERIC_ACCESS) && GenericMapping) 552 { 553 RtlMapGenericMask(&Access, GenericMapping); 554 } 555 556 /* Grant access rights that have not been denied yet */ 557 AccessCheckRights->GrantedAccessRights |= (Access & ~AccessCheckRights->DeniedAccessRights); 558 DPRINT("GrantedAccessRights 0x%08lx\n", AccessCheckRights->GrantedAccessRights); 559 } 560 } 561 else if (CurrentAce->Header.AceType == ACCESS_DENIED_OBJECT_ACE_TYPE) 562 { 563 /* Get the SID and object type from this ACE */ 564 Sid = SepGetSidFromAce(CurrentAce); 565 ObjectTypeGuid = SepGetObjectTypeGuidFromAce(CurrentAce, TRUE); 566 ASSERT(Sid); 567 568 if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, TRUE, IsTokenRestricted)) 569 { 570 /* Get this access right from the ACE */ 571 Access = CurrentAce->AccessMask; 572 573 /* Map this access right if it has a generic mask right */ 574 if ((Access & GENERIC_ACCESS) && GenericMapping) 575 { 576 RtlMapGenericMask(&Access, GenericMapping); 577 } 578 579 /* If no list was passed treat this is as ACCESS_DENIED_ACE_TYPE */ 580 if (!ObjectTypeList && !ObjectTypeListLength) 581 { 582 AccessCheckRights->DeniedAccessRights |= (Access & ~AccessCheckRights->GrantedAccessRights); 583 DPRINT("DeniedAccessRights 0x%08lx\n", AccessCheckRights->DeniedAccessRights); 584 } 585 else if (!UseResultList) 586 { 587 /* 588 * We have an object type list but the caller wants to deny access 589 * to the entire hierarchy list. Evaluate the rights of the object 590 * for the whole list. Ignore what the function tells us if we have 591 * to break on deny or not because we only want to keep track of 592 * denied rights. 593 */ 594 SepDenyAccessObjectTypeList(ObjectTypeList, 595 ObjectTypeListLength, 596 Access, 597 ObjectTypeGuid, 598 NULL); 599 } 600 else 601 { 602 /* Otherwise evaluate the access rights for each sub-object */ 603 SepDenyAccessObjectTypeResultList(ObjectTypeList, 604 ObjectTypeListLength, 605 Access, 606 ObjectTypeGuid); 607 } 608 } 609 } 610 else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_OBJECT_ACE_TYPE) 611 { 612 /* Get the SID and object type from this ACE */ 613 Sid = SepGetSidFromAce(CurrentAce); 614 ObjectTypeGuid = SepGetObjectTypeGuidFromAce(CurrentAce, FALSE); 615 ASSERT(Sid); 616 617 if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, FALSE, IsTokenRestricted)) 618 { 619 /* Get this access right from the ACE */ 620 Access = CurrentAce->AccessMask; 621 622 /* Map this access right if it has a generic mask right */ 623 if ((Access & GENERIC_ACCESS) && GenericMapping) 624 { 625 RtlMapGenericMask(&Access, GenericMapping); 626 } 627 628 /* If no list was passed treat this is as ACCESS_ALLOWED_ACE_TYPE */ 629 if (!ObjectTypeList && !ObjectTypeListLength) 630 { 631 AccessCheckRights->GrantedAccessRights |= (Access & ~AccessCheckRights->DeniedAccessRights); 632 DPRINT("GrantedAccessRights 0x%08lx\n", AccessCheckRights->GrantedAccessRights); 633 } 634 else if (!UseResultList) 635 { 636 /* 637 * We have an object type list but the caller wants to allow access 638 * to the entire hierarchy list. Evaluate the rights of the object 639 * for the whole list. 640 */ 641 SepAllowAccessObjectTypeList(ObjectTypeList, 642 ObjectTypeListLength, 643 Access, 644 FALSE, 645 ObjectTypeGuid); 646 } 647 else 648 { 649 /* Otherwise evaluate the access rights for each sub-object */ 650 SepAllowAccessObjectTypeResultList(ObjectTypeList, 651 ObjectTypeListLength, 652 Access, 653 ObjectTypeGuid); 654 } 655 } 656 } 657 else 658 { 659 DPRINT1("Unsupported ACE type 0x%lx\n", CurrentAce->Header.AceType); 660 } 661 } 662 } 663 664 /* We're done here */ 665 break; 666 } 667 668 /* 669 * We got the acknowledgement the calling thread desires 670 * only a subset of rights therefore we have to act a little 671 * different here. 672 */ 673 case AccessCheckRegular: 674 { 675 /* Cache the remaining access rights to be addressed */ 676 ASSERT(RemainingAccess != 0); 677 AccessCheckRights->RemainingAccessRights = RemainingAccess; 678 679 /* Fill the remaining rights of each object in the list if we have one */ 680 if (ObjectTypeList && (ObjectTypeListLength != 0)) 681 { 682 for (ObjectTypeIndex = 0; 683 ObjectTypeIndex < ObjectTypeListLength; 684 ObjectTypeIndex++) 685 { 686 ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.RemainingAccessRights = RemainingAccess; 687 } 688 } 689 690 /* Loop over the DACL to retrieve ACEs */ 691 for (AceIndex = 0; AceIndex < Dacl->AceCount; AceIndex++) 692 { 693 /* Obtain a ACE now */ 694 Status = RtlGetAce(Dacl, AceIndex, (PVOID*)&CurrentAce); 695 696 /* Getting this ACE is important, otherwise something is seriously wrong */ 697 ASSERT(NT_SUCCESS(Status)); 698 699 /* 700 * Now it's time to analyze it based upon the 701 * type of this ACE we're being given. 702 */ 703 if (!(CurrentAce->Header.AceFlags & INHERIT_ONLY_ACE)) 704 { 705 if (CurrentAce->Header.AceType == ACCESS_DENIED_ACE_TYPE) 706 { 707 /* Get the SID from this ACE */ 708 Sid = SepGetSidFromAce(CurrentAce); 709 ASSERT(Sid); 710 711 if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, TRUE, IsTokenRestricted)) 712 { 713 /* Get this access right from the ACE */ 714 Access = CurrentAce->AccessMask; 715 716 /* Map this access right if it has a generic mask right */ 717 if ((Access & GENERIC_ACCESS) && GenericMapping) 718 { 719 RtlMapGenericMask(&Access, GenericMapping); 720 } 721 722 /* 723 * The caller requests a right that cannot be 724 * granted. Access is implicitly denied for 725 * the calling thread. Track this access right. 726 */ 727 if (AccessCheckRights->RemainingAccessRights & Access) 728 { 729 DPRINT("Refuted access 0x%08lx\n", Access); 730 AccessCheckRights->DeniedAccessRights |= Access; 731 break; 732 } 733 } 734 } 735 else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) 736 { 737 /* Get the SID from this ACE */ 738 Sid = SepGetSidFromAce(CurrentAce); 739 ASSERT(Sid); 740 741 if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, FALSE, IsTokenRestricted)) 742 { 743 /* Get this access right from the ACE */ 744 Access = CurrentAce->AccessMask; 745 746 /* Map this access right if it has a generic mask right */ 747 if ((Access & GENERIC_ACCESS) && GenericMapping) 748 { 749 RtlMapGenericMask(&Access, GenericMapping); 750 } 751 752 /* Remove the remaining rights */ 753 DPRINT("RemainingAccessRights 0x%08lx Access 0x%08lx\n", AccessCheckRights->RemainingAccessRights, Access); 754 AccessCheckRights->RemainingAccessRights &= ~Access; 755 DPRINT("RemainingAccessRights 0x%08lx\n", AccessCheckRights->RemainingAccessRights); 756 757 /* Track the granted access right */ 758 AccessCheckRights->GrantedAccessRights |= Access; 759 } 760 } 761 else if (CurrentAce->Header.AceType == ACCESS_DENIED_OBJECT_ACE_TYPE) 762 { 763 /* Get the SID and object type from this ACE */ 764 Sid = SepGetSidFromAce(CurrentAce); 765 ObjectTypeGuid = SepGetObjectTypeGuidFromAce(CurrentAce, TRUE); 766 ASSERT(Sid); 767 768 if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, TRUE, IsTokenRestricted)) 769 { 770 /* Get this access right from the ACE */ 771 Access = CurrentAce->AccessMask; 772 773 /* Map this access right if it has a generic mask right */ 774 if ((Access & GENERIC_ACCESS) && GenericMapping) 775 { 776 RtlMapGenericMask(&Access, GenericMapping); 777 } 778 779 /* If no list was passed treat this is as ACCESS_DENIED_ACE_TYPE */ 780 if (!ObjectTypeList && !ObjectTypeListLength) 781 { 782 if (AccessCheckRights->RemainingAccessRights & Access) 783 { 784 DPRINT("Refuted access 0x%08lx\n", Access); 785 AccessCheckRights->DeniedAccessRights |= Access; 786 break; 787 } 788 } 789 else 790 { 791 /* 792 * Otherwise evaluate the rights of the object for the entire list. 793 * The function will signal us if the caller requested a right that is 794 * denied by the ACE of an object in the list. 795 */ 796 SepDenyAccessObjectTypeList(ObjectTypeList, 797 ObjectTypeListLength, 798 Access, 799 ObjectTypeGuid, 800 &BreakOnDeny); 801 802 /* We are acknowledged the caller requested a denied right */ 803 if (BreakOnDeny) 804 { 805 DPRINT("Refuted access 0x%08lx\n", Access); 806 break; 807 } 808 } 809 } 810 } 811 else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_OBJECT_ACE_TYPE) 812 { 813 /* Get the SID and object type from this ACE */ 814 Sid = SepGetSidFromAce(CurrentAce); 815 ObjectTypeGuid = SepGetObjectTypeGuidFromAce(CurrentAce, FALSE); 816 ASSERT(Sid); 817 818 if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, FALSE, IsTokenRestricted)) 819 { 820 /* Get this access right from the ACE */ 821 Access = CurrentAce->AccessMask; 822 823 /* Map this access right if it has a generic mask right */ 824 if ((Access & GENERIC_ACCESS) && GenericMapping) 825 { 826 RtlMapGenericMask(&Access, GenericMapping); 827 } 828 829 /* If no list was passed treat this is as ACCESS_ALLOWED_ACE_TYPE */ 830 if (!ObjectTypeList && !ObjectTypeListLength) 831 { 832 /* Remove the remaining rights */ 833 DPRINT("RemainingAccessRights 0x%08lx Access 0x%08lx\n", AccessCheckRights->RemainingAccessRights, Access); 834 AccessCheckRights->RemainingAccessRights &= ~Access; 835 DPRINT("RemainingAccessRights 0x%08lx\n", AccessCheckRights->RemainingAccessRights); 836 837 /* Track the granted access right */ 838 AccessCheckRights->GrantedAccessRights |= Access; 839 } 840 else 841 { 842 /* Otherwise evaluate the rights of the object for the entire list */ 843 SepAllowAccessObjectTypeList(ObjectTypeList, 844 ObjectTypeListLength, 845 Access, 846 TRUE, 847 ObjectTypeGuid); 848 } 849 } 850 } 851 else 852 { 853 DPRINT1("Unsupported ACE type 0x%lx\n", CurrentAce->Header.AceType); 854 } 855 } 856 } 857 858 /* We're done here */ 859 break; 860 } 861 862 /* We shouldn't reach here */ 863 DEFAULT_UNREACHABLE; 864 } 865 } 866 867 /** 868 * @brief 869 * Private worker function that determines whether security access rights can be 870 * givento the calling thread in order to access an object depending on the 871 * security descriptor and other security context entities, such as an owner. This 872 * function is the heart and brain of the whole access check algorithm in the kernel. 873 * 874 * @param[in] ClientAccessToken 875 * A pointer to a client (thread) access token that requests access rights 876 * of an object or subset of multiple objects. 877 * 878 * @param[in] PrimaryAccessToken 879 * A pointer to a primary access token that describes the primary security 880 * context of the main calling process. 881 * 882 * @param[in] PrincipalSelfSid 883 * A pointer to a security identifier that represents a security principal, 884 * that is, a user object associated with its security descriptor. 885 * 886 * @param[in] DesiredAccess 887 * The access rights desired by the calling thread to acquire in order to 888 * access an object. 889 * 890 * @param[in] ObjectTypeList 891 * An array list of object types to be checked against for access. The function 892 * will act accordingly in this case by checking each sub-object of an object 893 * of primary level and such. If this parameter is NULL, the function will 894 * perform a normal access check against the target object itself. 895 * 896 * @param[in] ObjectTypeListLength 897 * The length of a object type list. Such length represents the number of 898 * elements in this list. 899 * 900 * @param[in] PreviouslyGrantedAccess 901 * The access rights previously acquired in the past. If this parameter is 0, 902 * it is deemed that the calling thread hasn't acquired any rights. Access checks 903 * are more tighten in this case. 904 * 905 * @param[in] GenericMapping 906 * A pointer to a generic mapping of access rights of the target object. 907 * 908 * @param[in] AccessMode 909 * The processor request level mode. 910 * 911 * @param[in] UseResultList 912 * If set to TRUE, the function will return a list of granted access rights 913 * of each sub-object as well as status code for each. If this parameter is 914 * set to FALSE, then the function will just return only the granted access 915 * rights and status code for single object that's been target for access 916 * checks. 917 * 918 * @param[out] Privileges 919 * A pointer to a definite set of privileges that have been audited 920 * whilst doing access check procedures. Such set of privileges are 921 * optionally returned to the caller. This can be set to NULL if 922 * the caller doesn't want to obtain a set of privileges. 923 * 924 * @param[out] GrantedAccessList 925 * A list of granted access rights returned to the caller. This list 926 * can comprehend multiple elements which represent the sub-objects 927 * that have been checked or a single element which is the target 928 * object itself. 929 * 930 * @param[out] AccessStatusList 931 * A list of access status codes returned to the caller. This list 932 * can comprehend multiple elements which represent the sub-objects 933 * that have been checked or a single element which is the target 934 * object itself. 935 * 936 * @return 937 * Returns TRUE if access onto the specific object is allowed, FALSE 938 * otherwise. 939 */ 940 static 941 BOOLEAN 942 SepAccessCheckWorker( 943 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 944 _In_opt_ PACCESS_TOKEN ClientAccessToken, 945 _In_ PACCESS_TOKEN PrimaryAccessToken, 946 _In_opt_ PSID PrincipalSelfSid, 947 _In_ ACCESS_MASK DesiredAccess, 948 _In_opt_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList, 949 _In_ ULONG ObjectTypeListLength, 950 _In_ ACCESS_MASK PreviouslyGrantedAccess, 951 _In_ PGENERIC_MAPPING GenericMapping, 952 _In_ KPROCESSOR_MODE AccessMode, 953 _In_ BOOLEAN UseResultList, 954 _Out_opt_ PPRIVILEGE_SET* Privileges, 955 _Out_ PACCESS_MASK GrantedAccessList, 956 _Out_ PNTSTATUS AccessStatusList) 957 { 958 ACCESS_MASK RemainingAccess; 959 ACCESS_MASK WantedRights; 960 ACCESS_MASK MaskDesired; 961 ACCESS_MASK GrantedRights = 0; 962 ULONG ResultListIndex; 963 ULONG ObjectTypeIndex; 964 PACL Dacl; 965 BOOLEAN Present; 966 BOOLEAN Defaulted; 967 NTSTATUS Status; 968 BOOLEAN AccessIsGranted = FALSE; 969 PACCESS_TOKEN Token = NULL; 970 ACCESS_CHECK_RIGHTS AccessCheckRights = {0}; 971 972 PAGED_CODE(); 973 974 /* A security descriptor must be expected for access checks */ 975 ASSERT(SecurityDescriptor); 976 977 /* Check for no access desired */ 978 if (!DesiredAccess) 979 { 980 /* Check if we had no previous access */ 981 if (!PreviouslyGrantedAccess) 982 { 983 /* Then there's nothing to give */ 984 DPRINT1("The caller has no previously granted access gained!\n"); 985 Status = STATUS_ACCESS_DENIED; 986 goto ReturnCommonStatus; 987 } 988 989 /* Return the previous access only */ 990 Status = STATUS_SUCCESS; 991 *Privileges = NULL; 992 goto ReturnCommonStatus; 993 } 994 995 /* Map given accesses */ 996 RtlMapGenericMask(&DesiredAccess, GenericMapping); 997 if (PreviouslyGrantedAccess) 998 RtlMapGenericMask(&PreviouslyGrantedAccess, GenericMapping); 999 1000 /* Initialize remaining access rights */ 1001 RemainingAccess = DesiredAccess; 1002 1003 /* 1004 * Initialize the required rights if the caller wants to know access 1005 * for the object and each sub-object in the list. 1006 */ 1007 if (UseResultList) 1008 { 1009 if (DesiredAccess & MAXIMUM_ALLOWED) 1010 { 1011 WantedRights = (DesiredAccess | PreviouslyGrantedAccess) & ~MAXIMUM_ALLOWED; 1012 MaskDesired = ~MAXIMUM_ALLOWED; 1013 } 1014 else 1015 { 1016 WantedRights = MaskDesired = DesiredAccess | PreviouslyGrantedAccess; 1017 } 1018 } 1019 1020 /* 1021 * Obtain the token provided by the caller. Client (or also 1022 * called impersonation or thread) token takes precedence over 1023 * the primary token which is the token associated with the security 1024 * context of the main calling process. This is because it is the 1025 * client itself that requests access of an object or subset of 1026 * multiple objects. Otherwise obtain the security context of the 1027 * main process (the actual primary token). 1028 */ 1029 Token = ClientAccessToken ? ClientAccessToken : PrimaryAccessToken; 1030 1031 /* 1032 * We should at least expect a primary token 1033 * to be present if client token is not 1034 * available. 1035 */ 1036 ASSERT(Token); 1037 1038 /* 1039 * Check for ACCESS_SYSTEM_SECURITY and WRITE_OWNER access. 1040 * Write down a set of privileges that have been checked 1041 * if the caller wants it. 1042 */ 1043 Status = SePrivilegePolicyCheck(&RemainingAccess, 1044 &PreviouslyGrantedAccess, 1045 NULL, 1046 Token, 1047 Privileges, 1048 AccessMode); 1049 if (!NT_SUCCESS(Status)) 1050 { 1051 goto ReturnCommonStatus; 1052 } 1053 1054 /* Succeed if there are no more rights to grant */ 1055 if (RemainingAccess == 0) 1056 { 1057 Status = STATUS_SUCCESS; 1058 goto ReturnCommonStatus; 1059 } 1060 1061 /* 1062 * HACK: Temporary hack that checks if the caller passed an empty 1063 * generic mapping. In such cases we cannot mask out the remaining 1064 * access rights without a proper mapping so the only option we 1065 * can do is to check if the client is an administrator, 1066 * since they are powerful users. 1067 * 1068 * See CORE-18576 for information. 1069 */ 1070 if (GenericMapping->GenericRead == 0 && 1071 GenericMapping->GenericWrite == 0 && 1072 GenericMapping->GenericExecute == 0 && 1073 GenericMapping->GenericAll == 0) 1074 { 1075 if (SeTokenIsAdmin(Token)) 1076 { 1077 /* Grant him access */ 1078 PreviouslyGrantedAccess |= RemainingAccess; 1079 Status = STATUS_SUCCESS; 1080 goto ReturnCommonStatus; 1081 } 1082 1083 /* It's not an admin so bail out */ 1084 PreviouslyGrantedAccess = 0; 1085 Status = STATUS_ACCESS_DENIED; 1086 goto ReturnCommonStatus; 1087 } 1088 1089 /* Get the DACL */ 1090 Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor, 1091 &Present, 1092 &Dacl, 1093 &Defaulted); 1094 if (!NT_SUCCESS(Status)) 1095 { 1096 goto ReturnCommonStatus; 1097 } 1098 1099 /* Grant desired access if the object is unprotected */ 1100 if (Present == FALSE || Dacl == NULL) 1101 { 1102 PreviouslyGrantedAccess |= RemainingAccess; 1103 if (RemainingAccess & MAXIMUM_ALLOWED) 1104 { 1105 PreviouslyGrantedAccess &= ~MAXIMUM_ALLOWED; 1106 PreviouslyGrantedAccess |= GenericMapping->GenericAll; 1107 } 1108 1109 Status = STATUS_SUCCESS; 1110 goto ReturnCommonStatus; 1111 } 1112 1113 /* Deny access if the DACL is empty */ 1114 if (Dacl->AceCount == 0) 1115 { 1116 if (RemainingAccess == MAXIMUM_ALLOWED && PreviouslyGrantedAccess != 0) 1117 { 1118 Status = STATUS_SUCCESS; 1119 } 1120 else 1121 { 1122 DPRINT1("The DACL has no ACEs and the caller has no previously granted access!\n"); 1123 PreviouslyGrantedAccess = 0; 1124 Status = STATUS_ACCESS_DENIED; 1125 } 1126 goto ReturnCommonStatus; 1127 } 1128 1129 /* 1130 * Determine the MAXIMUM_ALLOWED access rights according to the DACL. 1131 * Or if the caller is supplying a list of object types then determine 1132 * the rights of each object on that list. 1133 */ 1134 if ((DesiredAccess & MAXIMUM_ALLOWED) || UseResultList) 1135 { 1136 /* Perform access checks against ACEs from this DACL */ 1137 SepAnalyzeAcesFromDacl(AccessCheckMaximum, 1138 0, 1139 Dacl, 1140 Token, 1141 PrimaryAccessToken, 1142 FALSE, 1143 PrincipalSelfSid, 1144 GenericMapping, 1145 ObjectTypeList, 1146 ObjectTypeListLength, 1147 UseResultList, 1148 &AccessCheckRights); 1149 1150 /* 1151 * Perform further access checks if this token 1152 * has restricted SIDs. 1153 */ 1154 if (SeTokenIsRestricted(Token)) 1155 { 1156 SepAnalyzeAcesFromDacl(AccessCheckMaximum, 1157 0, 1158 Dacl, 1159 Token, 1160 PrimaryAccessToken, 1161 TRUE, 1162 PrincipalSelfSid, 1163 GenericMapping, 1164 ObjectTypeList, 1165 ObjectTypeListLength, 1166 UseResultList, 1167 &AccessCheckRights); 1168 } 1169 1170 /* The caller did not provide an object type list, check access only for that object */ 1171 if (!ObjectTypeList && !ObjectTypeListLength) 1172 { 1173 /* Fail if some rights have not been granted */ 1174 RemainingAccess &= ~(MAXIMUM_ALLOWED | AccessCheckRights.GrantedAccessRights); 1175 if (RemainingAccess != 0) 1176 { 1177 DPRINT("Failed to grant access rights, access denied. RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n", RemainingAccess, DesiredAccess); 1178 PreviouslyGrantedAccess = 0; 1179 Status = STATUS_ACCESS_DENIED; 1180 goto ReturnCommonStatus; 1181 } 1182 1183 /* Set granted access right and access status */ 1184 PreviouslyGrantedAccess |= AccessCheckRights.GrantedAccessRights; 1185 if (PreviouslyGrantedAccess != 0) 1186 { 1187 Status = STATUS_SUCCESS; 1188 } 1189 else 1190 { 1191 DPRINT("Failed to grant access rights, access denied. PreviouslyGrantedAccess == 0 DesiredAccess = %08lx\n", DesiredAccess); 1192 Status = STATUS_ACCESS_DENIED; 1193 } 1194 1195 /* We are done here */ 1196 goto ReturnCommonStatus; 1197 } 1198 else if (!UseResultList) 1199 { 1200 /* 1201 * We have a list but the caller wants to know if access can be granted 1202 * to an object in the list. Access will either be granted or denied 1203 * to the whole hierarchy of the list. Look for every object in the list 1204 * that has granted access rights and collect them. 1205 */ 1206 for (ObjectTypeIndex = 0; 1207 ObjectTypeIndex < ObjectTypeListLength; 1208 ObjectTypeIndex++) 1209 { 1210 if (ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights != 0) 1211 { 1212 GrantedRights |= ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights; 1213 } 1214 } 1215 1216 /* Now check if acccess can be granted */ 1217 RemainingAccess &= ~(MAXIMUM_ALLOWED | GrantedRights); 1218 if (RemainingAccess != 0) 1219 { 1220 DPRINT("Failed to grant access rights to the whole object hierarchy list, access denied. RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n", 1221 RemainingAccess, DesiredAccess); 1222 PreviouslyGrantedAccess = 0; 1223 Status = STATUS_ACCESS_DENIED; 1224 goto ReturnCommonStatus; 1225 } 1226 1227 /* Set granted access right and access status */ 1228 PreviouslyGrantedAccess |= GrantedRights; 1229 if (PreviouslyGrantedAccess != 0) 1230 { 1231 Status = STATUS_SUCCESS; 1232 } 1233 else 1234 { 1235 DPRINT("Failed to grant access rights to the whole object hierarchy list, access denied. PreviouslyGrantedAccess == 0 DesiredAccess = %08lx\n", 1236 DesiredAccess); 1237 Status = STATUS_ACCESS_DENIED; 1238 } 1239 1240 /* We are done here */ 1241 goto ReturnCommonStatus; 1242 } 1243 else 1244 { 1245 /* 1246 * We have a list and the caller wants to know access for each 1247 * sub-object in the list. Report the access status and granted 1248 * rights for the object and each sub-object in the list. 1249 */ 1250 for (ObjectTypeIndex = 0; 1251 ObjectTypeIndex < ObjectTypeListLength; 1252 ObjectTypeIndex++) 1253 { 1254 /* Check if we have some rights */ 1255 GrantedRights = (ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights | PreviouslyGrantedAccess) & MaskDesired; 1256 if (GrantedRights != 0) 1257 { 1258 /* 1259 * If we still have some remaining rights to grant the ultimate 1260 * conclusion is that the caller has no access to the object itself. 1261 */ 1262 RemainingAccess = (~GrantedRights & WantedRights); 1263 if (RemainingAccess != 0) 1264 { 1265 DPRINT("Failed to grant access rights at specific object at index %lu, access denied. RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n", 1266 ObjectTypeIndex, RemainingAccess, DesiredAccess); 1267 AccessStatusList[ObjectTypeIndex] = STATUS_ACCESS_DENIED; 1268 } 1269 else 1270 { 1271 AccessStatusList[ObjectTypeIndex] = STATUS_SUCCESS; 1272 } 1273 } 1274 else 1275 { 1276 /* No access is given */ 1277 DPRINT("Failed to grant access rights at specific object at index %lu. No access is given\n", ObjectTypeIndex); 1278 AccessStatusList[ObjectTypeIndex] = STATUS_ACCESS_DENIED; 1279 } 1280 1281 /* Return the access rights to the caller */ 1282 GrantedAccessList[ObjectTypeIndex] = GrantedRights; 1283 } 1284 1285 /* 1286 * We have built a list of access statuses for each object but 1287 * we still need to figure out the common status for the 1288 * function. The same status code will be used to check if 1289 * we should report any security debug stuff once we are done. 1290 */ 1291 Status = STATUS_SUCCESS; 1292 for (ResultListIndex = 0; ResultListIndex < ObjectTypeListLength; ResultListIndex++) 1293 { 1294 /* There is at least one sub-object of which access cannot be granted */ 1295 if (AccessStatusList[ResultListIndex] == STATUS_ACCESS_DENIED) 1296 { 1297 Status = AccessStatusList[ResultListIndex]; 1298 break; 1299 } 1300 } 1301 1302 /* We are done here */ 1303 goto ReturnCommonStatus; 1304 } 1305 } 1306 1307 /* Grant rights according to the DACL */ 1308 SepAnalyzeAcesFromDacl(AccessCheckRegular, 1309 RemainingAccess, 1310 Dacl, 1311 Token, 1312 PrimaryAccessToken, 1313 FALSE, 1314 PrincipalSelfSid, 1315 GenericMapping, 1316 ObjectTypeList, 1317 ObjectTypeListLength, 1318 UseResultList, 1319 &AccessCheckRights); 1320 1321 /* The caller did not provide an object type list, check access only for that object */ 1322 if (!ObjectTypeList && !ObjectTypeListLength) 1323 { 1324 /* Fail if some rights have not been granted */ 1325 if (AccessCheckRights.RemainingAccessRights != 0) 1326 { 1327 DPRINT("Failed to grant access rights, access denied. RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n", AccessCheckRights.RemainingAccessRights, DesiredAccess); 1328 PreviouslyGrantedAccess = 0; 1329 Status = STATUS_ACCESS_DENIED; 1330 goto ReturnCommonStatus; 1331 } 1332 } 1333 else 1334 { 1335 /* 1336 * We have an object type list, look for the object of which 1337 * remaining rights are all granted. 1338 */ 1339 for (ObjectTypeIndex = 0; 1340 ObjectTypeIndex < ObjectTypeListLength; 1341 ObjectTypeIndex++) 1342 { 1343 if (ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.RemainingAccessRights == 0) 1344 { 1345 AccessIsGranted = TRUE; 1346 break; 1347 } 1348 } 1349 1350 if (!AccessIsGranted) 1351 { 1352 DPRINT("Failed to grant access rights to the whole object hierarchy list, access denied. DesiredAccess = 0x%08lx\n", DesiredAccess); 1353 PreviouslyGrantedAccess = 0; 1354 Status = STATUS_ACCESS_DENIED; 1355 goto ReturnCommonStatus; 1356 } 1357 } 1358 1359 /* 1360 * Perform further access checks if this token 1361 * has restricted SIDs. 1362 */ 1363 if (SeTokenIsRestricted(Token)) 1364 { 1365 SepAnalyzeAcesFromDacl(AccessCheckRegular, 1366 RemainingAccess, 1367 Dacl, 1368 Token, 1369 PrimaryAccessToken, 1370 TRUE, 1371 PrincipalSelfSid, 1372 GenericMapping, 1373 ObjectTypeList, 1374 ObjectTypeListLength, 1375 UseResultList, 1376 &AccessCheckRights); 1377 1378 /* The caller did not provide an object type list, check access only for that object */ 1379 if (!ObjectTypeList && !ObjectTypeListLength) 1380 { 1381 /* Fail if some rights have not been granted */ 1382 if (AccessCheckRights.RemainingAccessRights != 0) 1383 { 1384 DPRINT("Failed to grant access rights, access denied. RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n", AccessCheckRights.RemainingAccessRights, DesiredAccess); 1385 PreviouslyGrantedAccess = 0; 1386 Status = STATUS_ACCESS_DENIED; 1387 goto ReturnCommonStatus; 1388 } 1389 } 1390 else 1391 { 1392 /* 1393 * We have an object type list, look for the object of which remaining 1394 * rights are all granted. The user may have access to the requested 1395 * object but on a restricted token case the user is only granted partial 1396 * access. If access is denied to restricted SIDs, the bottom line is that 1397 * access is denied to the user. 1398 */ 1399 AccessIsGranted = FALSE; 1400 for (ObjectTypeIndex = 0; 1401 ObjectTypeIndex < ObjectTypeListLength; 1402 ObjectTypeIndex++) 1403 { 1404 if (ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.RemainingAccessRights == 0) 1405 { 1406 AccessIsGranted = TRUE; 1407 break; 1408 } 1409 } 1410 1411 if (!AccessIsGranted) 1412 { 1413 DPRINT("Failed to grant access rights to the whole object hierarchy list, access denied. DesiredAccess = 0x%08lx\n", DesiredAccess); 1414 PreviouslyGrantedAccess = 0; 1415 Status = STATUS_ACCESS_DENIED; 1416 goto ReturnCommonStatus; 1417 } 1418 } 1419 } 1420 1421 /* Set granted access rights */ 1422 PreviouslyGrantedAccess |= DesiredAccess; 1423 1424 /* Fail if no rights have been granted */ 1425 if (PreviouslyGrantedAccess == 0) 1426 { 1427 DPRINT("Failed to grant access rights, access denied. PreviouslyGrantedAccess == 0 DesiredAccess = %08lx\n", DesiredAccess); 1428 Status = STATUS_ACCESS_DENIED; 1429 goto ReturnCommonStatus; 1430 } 1431 1432 /* 1433 * If we're here then we granted all the desired 1434 * access rights the caller wanted. 1435 */ 1436 Status = STATUS_SUCCESS; 1437 1438 ReturnCommonStatus: 1439 if (!UseResultList) 1440 { 1441 *GrantedAccessList = PreviouslyGrantedAccess; 1442 *AccessStatusList = Status; 1443 } 1444 1445 #if DBG 1446 /* Dump security debug info on access denied case */ 1447 if (Status == STATUS_ACCESS_DENIED) 1448 { 1449 SepDumpSdDebugInfo(SecurityDescriptor); 1450 SepDumpTokenDebugInfo(Token); 1451 1452 if (ObjectTypeList && (ObjectTypeListLength != 0)) 1453 { 1454 SepDumpAccessAndStatusList(GrantedAccessList, 1455 AccessStatusList, 1456 UseResultList, 1457 ObjectTypeList, 1458 ObjectTypeListLength); 1459 } 1460 else 1461 { 1462 SepDumpAccessRightsStats(&AccessCheckRights); 1463 } 1464 } 1465 #endif 1466 1467 return NT_SUCCESS(Status); 1468 } 1469 1470 /** 1471 * @brief 1472 * Retrieves the length size of a set list of privileges structure. 1473 * 1474 * @param[in] PrivilegeSet 1475 * A valid set of privileges. 1476 * 1477 * @return 1478 * Returns the total length of a set of privileges. 1479 */ 1480 static 1481 ULONG 1482 SepGetPrivilegeSetLength( 1483 _In_ PPRIVILEGE_SET PrivilegeSet) 1484 { 1485 if (PrivilegeSet == NULL) 1486 return 0; 1487 1488 if (PrivilegeSet->PrivilegeCount == 0) 1489 return (ULONG)(sizeof(PRIVILEGE_SET) - sizeof(LUID_AND_ATTRIBUTES)); 1490 1491 return (ULONG)(sizeof(PRIVILEGE_SET) + 1492 (PrivilegeSet->PrivilegeCount - 1) * sizeof(LUID_AND_ATTRIBUTES)); 1493 } 1494 1495 /** 1496 * @brief 1497 * Internal function that performs a security check against the 1498 * client who requests access on a resource object. This function 1499 * is used by access check NT system calls. 1500 * 1501 * @param[in] SecurityDescriptor 1502 * A pointer to a security descriptor that identifies the security 1503 * information of an object being accessed. This function walks 1504 * through this descriptor for any ACLs and respective access 1505 * rights if access can be granted. 1506 * 1507 * @param[in] ClientToken 1508 * A handle to an access token, that identifies the client of which 1509 * requests access to the target object. 1510 * 1511 * @param[in] PrincipalSelfSid 1512 * A pointer to a principal self SID. This parameter can be NULL if 1513 * the associated object being checked for access does not represent 1514 * a principal. 1515 * 1516 * @param[in] DesiredAccess 1517 * The access right bitmask where the client wants to acquire. This 1518 * can be an OR'ed set of multiple access rights or MAXIMUM_ALLOWED 1519 * to request all of possible access rights the target object allows. 1520 * If only some rights were granted but not all the access is deemed 1521 * as denied. 1522 * 1523 * @param[in] GenericMapping 1524 * The generic mapping of access rights of an object type. 1525 * 1526 * @param[out] PrivilegeSet 1527 * A pointer to a set of privileges that were used to perform the 1528 * access check, returned to caller. This function will return no 1529 * privileges (privilege count set to 0) if no privileges were used 1530 * to accomplish the access check. This parameter must not be NULL! 1531 * 1532 * @param[in,out] PrivilegeSetLength 1533 * The total length size of a set of privileges. This length represents 1534 * the count of elements in the privilege set array. 1535 * 1536 * @param[in] ObjectTypeList 1537 * A pointer to a given object type list. If this parameter is not NULL 1538 * the function will perform an access check against the main object 1539 * and sub-objects of this list. If this parameter is NULL and 1540 * ObjectTypeListLength is 0, the function will perform a normal 1541 * access check instead. 1542 * 1543 * @param[in] ObjectTypeListLength 1544 * The length of the object type list array, pointed by ObjectTypeList. 1545 * This length in question represents the number of elements in such array. 1546 * This parameter must be 0 if no array list is provided. 1547 * 1548 * @param[in] UseResultList 1549 * If this parameter is set to TRUE, the function will return the GrantedAccess 1550 * and AccessStatus parameter as arrays of granted rights and status value for 1551 * each individual object element pointed by ObjectTypeList. 1552 * 1553 * @param[out] GrantedAccess 1554 * A pointer to granted access rights, returned to the caller. If ObjectTypeList 1555 * is not NULL this paramater is an array of granted access rights for the object 1556 * and each individual sub-object of the list. 1557 * 1558 * @param[out] AccessStatus 1559 * A pointer to a status code, returned to the caller. This status code 1560 * represents whether access is granted or denied to the client on the 1561 * target object. The difference between the status code of the function 1562 * is that code indicates whether the function has successfully completed 1563 * the access check operation. If ObjectTypeList is not NULL, this 1564 * parameter is an array of access status for the object and each individual 1565 * sub-object of the list. 1566 * 1567 * @return 1568 * Returns STATUS_SUCCESS if access check has been done without problems 1569 * and that the object can be accessed. STATUS_GENERIC_NOT_MAPPED is returned 1570 * if no generic access right is mapped. STATUS_NO_IMPERSONATION_TOKEN is returned 1571 * if the token from the handle is not an impersonation token. 1572 * STATUS_BAD_IMPERSONATION_LEVEL is returned if the token cannot be impersonated 1573 * because the current security impersonation level doesn't permit so. 1574 * STATUS_INVALID_SECURITY_DESCR is returned if the security descriptor given 1575 * to the call is not a valid one. STATUS_BUFFER_TOO_SMALL is returned if 1576 * the buffer to the captured privileges has a length that is less than the required 1577 * size of the set of privileges. STATUS_INVALID_PARAMETER is returned if the caller 1578 * did not provide an object type list but the caller wanted to invoke an object type 1579 * result list access check, or if the list is out of order or the list is invalid. 1580 * A failure NTSTATUS code is returned otherwise. 1581 * 1582 * @remarks 1583 * The function performs an access check against the object type list, 1584 * if provided, depending on the UseResultList parameter. That is, if that 1585 * parameter was set to TRUE the function will either grant or deny access 1586 * to each individual sub-object and return an array of access status and 1587 * granted rights for the corresponding object type list. Otherwise the function 1588 * will grant or deny access to the object type list hierarchy as a whole. 1589 */ 1590 static 1591 NTSTATUS 1592 SepAccessCheck( 1593 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 1594 _In_ HANDLE ClientToken, 1595 _In_opt_ PSID PrincipalSelfSid, 1596 _In_ ACCESS_MASK DesiredAccess, 1597 _In_ PGENERIC_MAPPING GenericMapping, 1598 _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet, 1599 _Inout_ PULONG PrivilegeSetLength, 1600 _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList, 1601 _In_ ULONG ObjectTypeListLength, 1602 _In_ BOOLEAN UseResultList, 1603 _Out_ PACCESS_MASK GrantedAccess, 1604 _Out_ PNTSTATUS AccessStatus) 1605 { 1606 PSECURITY_DESCRIPTOR CapturedSecurityDescriptor = NULL; 1607 POBJECT_TYPE_LIST_INTERNAL CapturedObjectTypeList = NULL; 1608 PSID CapturedPrincipalSelfSid = NULL; 1609 SECURITY_SUBJECT_CONTEXT SubjectSecurityContext; 1610 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1611 ACCESS_MASK PreviouslyGrantedAccess = 0; 1612 PPRIVILEGE_SET Privileges = NULL; 1613 ULONG CapturedPrivilegeSetLength, RequiredPrivilegeSetLength; 1614 ULONG ResultListIndex; 1615 PTOKEN Token; 1616 NTSTATUS Status; 1617 1618 PAGED_CODE(); 1619 1620 /* Check if this is kernel mode */ 1621 if (PreviousMode == KernelMode) 1622 { 1623 /* Check if kernel wants everything */ 1624 if (DesiredAccess & MAXIMUM_ALLOWED) 1625 { 1626 /* Give it */ 1627 *GrantedAccess = GenericMapping->GenericAll; 1628 *GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED); 1629 } 1630 else 1631 { 1632 /* Just give the desired access */ 1633 *GrantedAccess = DesiredAccess; 1634 } 1635 1636 /* Success */ 1637 *AccessStatus = STATUS_SUCCESS; 1638 return STATUS_SUCCESS; 1639 } 1640 1641 /* Protect probe in SEH */ 1642 _SEH2_TRY 1643 { 1644 /* Probe all pointers */ 1645 ProbeForRead(GenericMapping, sizeof(GENERIC_MAPPING), sizeof(ULONG)); 1646 ProbeForRead(PrivilegeSetLength, sizeof(ULONG), sizeof(ULONG)); 1647 ProbeForWrite(PrivilegeSet, *PrivilegeSetLength, sizeof(ULONG)); 1648 1649 /* 1650 * Probe the access and status list based on the way 1651 * we are going to fill data in. 1652 */ 1653 if (UseResultList) 1654 { 1655 /* Bail out on an empty list */ 1656 if (!ObjectTypeListLength) 1657 { 1658 DPRINT1("The object type list is empty\n"); 1659 _SEH2_YIELD(return STATUS_INVALID_PARAMETER); 1660 } 1661 1662 ProbeForWrite(GrantedAccess, sizeof(ACCESS_MASK) * ObjectTypeListLength, sizeof(ULONG)); 1663 ProbeForWrite(AccessStatus, sizeof(NTSTATUS) * ObjectTypeListLength, sizeof(ULONG)); 1664 } 1665 else 1666 { 1667 ProbeForWrite(GrantedAccess, sizeof(ACCESS_MASK), sizeof(ULONG)); 1668 ProbeForWrite(AccessStatus, sizeof(NTSTATUS), sizeof(ULONG)); 1669 } 1670 1671 /* Capture the privilege set length and the mapping */ 1672 CapturedPrivilegeSetLength = *PrivilegeSetLength; 1673 } 1674 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1675 { 1676 /* Return the exception code */ 1677 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1678 } 1679 _SEH2_END; 1680 1681 /* Check for unmapped access rights */ 1682 if (DesiredAccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL)) 1683 { 1684 DPRINT1("Some generic rights are not mapped\n"); 1685 return STATUS_GENERIC_NOT_MAPPED; 1686 } 1687 1688 /* Reference the token */ 1689 Status = ObReferenceObjectByHandle(ClientToken, 1690 TOKEN_QUERY, 1691 SeTokenObjectType, 1692 PreviousMode, 1693 (PVOID*)&Token, 1694 NULL); 1695 if (!NT_SUCCESS(Status)) 1696 { 1697 DPRINT1("Failed to reference token (Status 0x%08lx)\n", Status); 1698 return Status; 1699 } 1700 1701 /* Check token type */ 1702 if (Token->TokenType != TokenImpersonation) 1703 { 1704 DPRINT("No impersonation token\n"); 1705 ObDereferenceObject(Token); 1706 return STATUS_NO_IMPERSONATION_TOKEN; 1707 } 1708 1709 /* Check the impersonation level */ 1710 if (Token->ImpersonationLevel < SecurityIdentification) 1711 { 1712 DPRINT1("Impersonation level < SecurityIdentification\n"); 1713 ObDereferenceObject(Token); 1714 return STATUS_BAD_IMPERSONATION_LEVEL; 1715 } 1716 1717 /* Capture the object type list, the list is probed by the function itself */ 1718 Status = SeCaptureObjectTypeList(ObjectTypeList, 1719 ObjectTypeListLength, 1720 PreviousMode, 1721 &CapturedObjectTypeList); 1722 if (!NT_SUCCESS(Status)) 1723 { 1724 DPRINT1("Failed to capture the object type list (Status 0x%08lx)\n", Status); 1725 ObDereferenceObject(Token); 1726 return Status; 1727 } 1728 1729 /* Check for ACCESS_SYSTEM_SECURITY and WRITE_OWNER access */ 1730 Status = SePrivilegePolicyCheck(&DesiredAccess, 1731 &PreviouslyGrantedAccess, 1732 NULL, 1733 Token, 1734 &Privileges, 1735 PreviousMode); 1736 if (!NT_SUCCESS(Status)) 1737 { 1738 DPRINT1("SePrivilegePolicyCheck failed (Status 0x%08lx)\n", Status); 1739 SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode); 1740 ObDereferenceObject(Token); 1741 1742 /* 1743 * The caller does not have the required access to do an access check. 1744 * Propagate the access and status for the whole hierarchy of the list 1745 * or just to single target object. 1746 */ 1747 if (UseResultList) 1748 { 1749 for (ResultListIndex = 0; ResultListIndex < ObjectTypeListLength; ResultListIndex++) 1750 { 1751 AccessStatus[ResultListIndex] = Status; 1752 GrantedAccess[ResultListIndex] = 0; 1753 } 1754 } 1755 else 1756 { 1757 *AccessStatus = Status; 1758 *GrantedAccess = 0; 1759 } 1760 1761 return STATUS_SUCCESS; 1762 } 1763 1764 /* Check the size of the privilege set and return the privileges */ 1765 if (Privileges != NULL) 1766 { 1767 DPRINT("Privileges != NULL\n"); 1768 1769 /* Calculate the required privilege set buffer size */ 1770 RequiredPrivilegeSetLength = SepGetPrivilegeSetLength(Privileges); 1771 1772 /* Fail if the privilege set buffer is too small */ 1773 if (CapturedPrivilegeSetLength < RequiredPrivilegeSetLength) 1774 { 1775 SeFreePrivileges(Privileges); 1776 SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode); 1777 ObDereferenceObject(Token); 1778 *PrivilegeSetLength = RequiredPrivilegeSetLength; 1779 return STATUS_BUFFER_TOO_SMALL; 1780 } 1781 1782 /* Copy the privilege set to the caller */ 1783 RtlCopyMemory(PrivilegeSet, 1784 Privileges, 1785 RequiredPrivilegeSetLength); 1786 1787 /* Free the local privilege set */ 1788 SeFreePrivileges(Privileges); 1789 } 1790 else 1791 { 1792 DPRINT("Privileges == NULL\n"); 1793 1794 /* Fail if the privilege set buffer is too small */ 1795 if (CapturedPrivilegeSetLength < sizeof(PRIVILEGE_SET)) 1796 { 1797 SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode); 1798 ObDereferenceObject(Token); 1799 *PrivilegeSetLength = sizeof(PRIVILEGE_SET); 1800 return STATUS_BUFFER_TOO_SMALL; 1801 } 1802 1803 /* Initialize the privilege set */ 1804 PrivilegeSet->PrivilegeCount = 0; 1805 PrivilegeSet->Control = 0; 1806 } 1807 1808 /* Capture the security descriptor */ 1809 Status = SeCaptureSecurityDescriptor(SecurityDescriptor, 1810 PreviousMode, 1811 PagedPool, 1812 FALSE, 1813 &CapturedSecurityDescriptor); 1814 if (!NT_SUCCESS(Status)) 1815 { 1816 DPRINT1("Failed to capture the Security Descriptor\n"); 1817 SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode); 1818 ObDereferenceObject(Token); 1819 return Status; 1820 } 1821 1822 /* Check the captured security descriptor */ 1823 if (CapturedSecurityDescriptor == NULL) 1824 { 1825 DPRINT1("Security Descriptor is NULL\n"); 1826 SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode); 1827 ObDereferenceObject(Token); 1828 return STATUS_INVALID_SECURITY_DESCR; 1829 } 1830 1831 /* Check security descriptor for valid owner and group */ 1832 if (SepGetOwnerFromDescriptor(CapturedSecurityDescriptor) == NULL || 1833 SepGetGroupFromDescriptor(CapturedSecurityDescriptor) == NULL) 1834 { 1835 DPRINT1("Security Descriptor does not have a valid group or owner\n"); 1836 SeReleaseSecurityDescriptor(CapturedSecurityDescriptor, 1837 PreviousMode, 1838 FALSE); 1839 SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode); 1840 ObDereferenceObject(Token); 1841 return STATUS_INVALID_SECURITY_DESCR; 1842 } 1843 1844 /* Capture the principal self SID if we have one */ 1845 if (PrincipalSelfSid) 1846 { 1847 Status = SepCaptureSid(PrincipalSelfSid, 1848 PreviousMode, 1849 PagedPool, 1850 TRUE, 1851 &CapturedPrincipalSelfSid); 1852 if (!NT_SUCCESS(Status)) 1853 { 1854 DPRINT1("Failed to capture the principal self SID (Status 0x%08lx)\n", Status); 1855 SeReleaseSecurityDescriptor(CapturedSecurityDescriptor, 1856 PreviousMode, 1857 FALSE); 1858 SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode); 1859 ObDereferenceObject(Token); 1860 return Status; 1861 } 1862 } 1863 1864 /* Set up the subject context, and lock it */ 1865 SeCaptureSubjectContext(&SubjectSecurityContext); 1866 1867 /* Lock the token */ 1868 SepAcquireTokenLockShared(Token); 1869 1870 /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */ 1871 if (DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED)) 1872 { 1873 if (SepTokenIsOwner(Token, CapturedSecurityDescriptor, FALSE)) 1874 { 1875 if (DesiredAccess & MAXIMUM_ALLOWED) 1876 PreviouslyGrantedAccess |= (WRITE_DAC | READ_CONTROL); 1877 else 1878 PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL)); 1879 1880 DesiredAccess &= ~(WRITE_DAC | READ_CONTROL); 1881 } 1882 } 1883 1884 if (DesiredAccess == 0) 1885 { 1886 /* 1887 * Propagate the access and status for the whole hierarchy 1888 * of the list or just to single target object. 1889 */ 1890 if (UseResultList) 1891 { 1892 for (ResultListIndex = 0; ResultListIndex < ObjectTypeListLength; ResultListIndex++) 1893 { 1894 AccessStatus[ResultListIndex] = STATUS_SUCCESS; 1895 GrantedAccess[ResultListIndex] = PreviouslyGrantedAccess; 1896 } 1897 } 1898 else 1899 { 1900 *GrantedAccess = PreviouslyGrantedAccess; 1901 *AccessStatus = STATUS_SUCCESS; 1902 } 1903 } 1904 else 1905 { 1906 /* Now perform the access check */ 1907 SepAccessCheckWorker(CapturedSecurityDescriptor, 1908 Token, 1909 &SubjectSecurityContext.PrimaryToken, 1910 CapturedPrincipalSelfSid, 1911 DesiredAccess, 1912 CapturedObjectTypeList, 1913 ObjectTypeListLength, 1914 PreviouslyGrantedAccess, 1915 GenericMapping, 1916 PreviousMode, 1917 UseResultList, 1918 NULL, 1919 GrantedAccess, 1920 AccessStatus); 1921 } 1922 1923 /* Release subject context and unlock the token */ 1924 SeReleaseSubjectContext(&SubjectSecurityContext); 1925 SepReleaseTokenLock(Token); 1926 1927 /* Release the caputed principal self SID */ 1928 SepReleaseSid(CapturedPrincipalSelfSid, 1929 PreviousMode, 1930 TRUE); 1931 1932 /* Release the captured security descriptor */ 1933 SeReleaseSecurityDescriptor(CapturedSecurityDescriptor, 1934 PreviousMode, 1935 FALSE); 1936 1937 /* Release the object type list */ 1938 SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode); 1939 1940 /* Dereference the token */ 1941 ObDereferenceObject(Token); 1942 1943 /* Check succeeded */ 1944 return STATUS_SUCCESS; 1945 } 1946 1947 /* PUBLIC FUNCTIONS ***********************************************************/ 1948 1949 /** 1950 * @brief 1951 * Determines whether security access rights can be given to an object 1952 * depending on the security descriptor and other security context 1953 * entities, such as an owner. 1954 * 1955 * @param[in] SecurityDescriptor 1956 * Security descriptor of the object that is being accessed. 1957 * 1958 * @param[in] SubjectSecurityContext 1959 * The captured subject security context. 1960 * 1961 * @param[in] SubjectContextLocked 1962 * If set to TRUE, the caller acknowledges that the subject context 1963 * has already been locked by the caller himself. If set to FALSE, 1964 * the function locks the subject context. 1965 * 1966 * @param[in] DesiredAccess 1967 * Access right bitmask that the calling thread wants to acquire. 1968 * 1969 * @param[in] PreviouslyGrantedAccess 1970 * The access rights previously acquired in the past. 1971 * 1972 * @param[out] Privileges 1973 * The returned set of privileges. 1974 * 1975 * @param[in] GenericMapping 1976 * The generic mapping of access rights of an object type. 1977 * 1978 * @param[in] AccessMode 1979 * The processor request level mode. 1980 * 1981 * @param[out] GrantedAccess 1982 * A list of granted access rights. 1983 * 1984 * @param[out] AccessStatus 1985 * The returned status code specifying why access cannot be made 1986 * onto an object (if said access is denied in the first place). 1987 * 1988 * @return 1989 * Returns TRUE if access onto the specific object is allowed, FALSE 1990 * otherwise. 1991 */ 1992 BOOLEAN 1993 NTAPI 1994 SeAccessCheck( 1995 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 1996 _In_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext, 1997 _In_ BOOLEAN SubjectContextLocked, 1998 _In_ ACCESS_MASK DesiredAccess, 1999 _In_ ACCESS_MASK PreviouslyGrantedAccess, 2000 _Out_ PPRIVILEGE_SET* Privileges, 2001 _In_ PGENERIC_MAPPING GenericMapping, 2002 _In_ KPROCESSOR_MODE AccessMode, 2003 _Out_ PACCESS_MASK GrantedAccess, 2004 _Out_ PNTSTATUS AccessStatus) 2005 { 2006 BOOLEAN ret; 2007 2008 PAGED_CODE(); 2009 2010 /* Check if this is kernel mode */ 2011 if (AccessMode == KernelMode) 2012 { 2013 /* Check if kernel wants everything */ 2014 if (DesiredAccess & MAXIMUM_ALLOWED) 2015 { 2016 /* Give it */ 2017 *GrantedAccess = GenericMapping->GenericAll; 2018 *GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED); 2019 *GrantedAccess |= PreviouslyGrantedAccess; 2020 } 2021 else 2022 { 2023 /* Give the desired and previous access */ 2024 *GrantedAccess = DesiredAccess | PreviouslyGrantedAccess; 2025 } 2026 2027 /* Success */ 2028 *AccessStatus = STATUS_SUCCESS; 2029 return TRUE; 2030 } 2031 2032 /* Check if we didn't get an SD */ 2033 if (!SecurityDescriptor) 2034 { 2035 /* Automatic failure */ 2036 *AccessStatus = STATUS_ACCESS_DENIED; 2037 return FALSE; 2038 } 2039 2040 /* Check for invalid impersonation */ 2041 if ((SubjectSecurityContext->ClientToken) && 2042 (SubjectSecurityContext->ImpersonationLevel < SecurityImpersonation)) 2043 { 2044 *AccessStatus = STATUS_BAD_IMPERSONATION_LEVEL; 2045 return FALSE; 2046 } 2047 2048 /* Acquire the lock if needed */ 2049 if (!SubjectContextLocked) 2050 SeLockSubjectContext(SubjectSecurityContext); 2051 2052 /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */ 2053 if (DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED)) 2054 { 2055 PACCESS_TOKEN Token = SubjectSecurityContext->ClientToken ? 2056 SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken; 2057 2058 if (SepTokenIsOwner(Token, 2059 SecurityDescriptor, 2060 FALSE)) 2061 { 2062 if (DesiredAccess & MAXIMUM_ALLOWED) 2063 PreviouslyGrantedAccess |= (WRITE_DAC | READ_CONTROL); 2064 else 2065 PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL)); 2066 2067 DesiredAccess &= ~(WRITE_DAC | READ_CONTROL); 2068 } 2069 } 2070 2071 if (DesiredAccess == 0) 2072 { 2073 *GrantedAccess = PreviouslyGrantedAccess; 2074 if (PreviouslyGrantedAccess == 0) 2075 { 2076 DPRINT1("Request for zero access to an object. Denying.\n"); 2077 *AccessStatus = STATUS_ACCESS_DENIED; 2078 ret = FALSE; 2079 } 2080 else 2081 { 2082 *AccessStatus = STATUS_SUCCESS; 2083 ret = TRUE; 2084 } 2085 } 2086 else 2087 { 2088 /* Call the internal function */ 2089 ret = SepAccessCheckWorker(SecurityDescriptor, 2090 SubjectSecurityContext->ClientToken, 2091 SubjectSecurityContext->PrimaryToken, 2092 NULL, 2093 DesiredAccess, 2094 NULL, 2095 0, 2096 PreviouslyGrantedAccess, 2097 GenericMapping, 2098 AccessMode, 2099 FALSE, 2100 Privileges, 2101 GrantedAccess, 2102 AccessStatus); 2103 } 2104 2105 /* Release the lock if needed */ 2106 if (!SubjectContextLocked) 2107 SeUnlockSubjectContext(SubjectSecurityContext); 2108 2109 return ret; 2110 } 2111 2112 /** 2113 * @brief 2114 * Determines whether security access rights can be given to an object 2115 * depending on the security descriptor. Unlike the regular access check 2116 * procedure in the NT kernel, the fast traverse check is a faster way 2117 * to quickly check if access can be made into an object. 2118 * 2119 * @param[in] SecurityDescriptor 2120 * Security descriptor of the object that is being accessed. 2121 * 2122 * @param[in] AccessState 2123 * An access state to determine if the access token in the current 2124 * security context of the object is an restricted token. 2125 * 2126 * @param[in] DesiredAccess 2127 * The access right bitmask where the calling thread wants to acquire. 2128 * 2129 * @param[in] AccessMode 2130 * Process level request mode. 2131 * 2132 * @return 2133 * Returns TRUE if access onto the specific object is allowed, FALSE 2134 * otherwise. 2135 */ 2136 BOOLEAN 2137 NTAPI 2138 SeFastTraverseCheck( 2139 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 2140 _In_ PACCESS_STATE AccessState, 2141 _In_ ACCESS_MASK DesiredAccess, 2142 _In_ KPROCESSOR_MODE AccessMode) 2143 { 2144 PACL Dacl; 2145 ULONG AceIndex; 2146 PKNOWN_ACE Ace; 2147 2148 PAGED_CODE(); 2149 2150 ASSERT(AccessMode != KernelMode); 2151 2152 if (SecurityDescriptor == NULL) 2153 return FALSE; 2154 2155 /* Get DACL */ 2156 Dacl = SepGetDaclFromDescriptor(SecurityDescriptor); 2157 /* If no DACL, grant access */ 2158 if (Dacl == NULL) 2159 return TRUE; 2160 2161 /* No ACE -> Deny */ 2162 if (!Dacl->AceCount) 2163 return FALSE; 2164 2165 /* Can't perform the check on restricted token */ 2166 if (AccessState->Flags & TOKEN_IS_RESTRICTED) 2167 return FALSE; 2168 2169 /* Browse the ACEs */ 2170 for (AceIndex = 0, Ace = (PKNOWN_ACE)((ULONG_PTR)Dacl + sizeof(ACL)); 2171 AceIndex < Dacl->AceCount; 2172 AceIndex++, Ace = (PKNOWN_ACE)((ULONG_PTR)Ace + Ace->Header.AceSize)) 2173 { 2174 if (Ace->Header.AceFlags & INHERIT_ONLY_ACE) 2175 continue; 2176 2177 /* If access-allowed ACE */ 2178 if (Ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) 2179 { 2180 /* Check if all accesses are granted */ 2181 if (!(Ace->Mask & DesiredAccess)) 2182 continue; 2183 2184 /* Check SID and grant access if matching */ 2185 if (RtlEqualSid(SeWorldSid, &(Ace->SidStart))) 2186 return TRUE; 2187 } 2188 /* If access-denied ACE */ 2189 else if (Ace->Header.AceType == ACCESS_DENIED_ACE_TYPE) 2190 { 2191 /* Here, only check if it denies any access wanted and deny if so */ 2192 if (Ace->Mask & DesiredAccess) 2193 return FALSE; 2194 } 2195 } 2196 2197 /* Faulty, deny */ 2198 return FALSE; 2199 } 2200 2201 /* SYSTEM CALLS ***************************************************************/ 2202 2203 /** 2204 * @brief 2205 * Determines whether security access can be granted to a client 2206 * that requests such access on an object. 2207 * 2208 * @remarks 2209 * For more documentation details about the parameters and 2210 * overall function behavior, see SepAccessCheck. 2211 */ 2212 NTSTATUS 2213 NTAPI 2214 NtAccessCheck( 2215 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 2216 _In_ HANDLE ClientToken, 2217 _In_ ACCESS_MASK DesiredAccess, 2218 _In_ PGENERIC_MAPPING GenericMapping, 2219 _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet, 2220 _Inout_ PULONG PrivilegeSetLength, 2221 _Out_ PACCESS_MASK GrantedAccess, 2222 _Out_ PNTSTATUS AccessStatus) 2223 { 2224 PAGED_CODE(); 2225 2226 /* Invoke the internal function to do the job */ 2227 return SepAccessCheck(SecurityDescriptor, 2228 ClientToken, 2229 NULL, 2230 DesiredAccess, 2231 GenericMapping, 2232 PrivilegeSet, 2233 PrivilegeSetLength, 2234 NULL, 2235 0, 2236 FALSE, 2237 GrantedAccess, 2238 AccessStatus); 2239 } 2240 2241 /** 2242 * @brief 2243 * Determines whether security access can be granted to a client 2244 * that requests such access on the object type list. The access 2245 * is either granted or denied for the whole object hierarchy 2246 * in the list. 2247 * 2248 * @remarks 2249 * For more documentation details about the parameters and 2250 * overall function behavior, see SepAccessCheck. 2251 */ 2252 NTSTATUS 2253 NTAPI 2254 NtAccessCheckByType( 2255 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 2256 _In_opt_ PSID PrincipalSelfSid, 2257 _In_ HANDLE ClientToken, 2258 _In_ ACCESS_MASK DesiredAccess, 2259 _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList, 2260 _In_ ULONG ObjectTypeListLength, 2261 _In_ PGENERIC_MAPPING GenericMapping, 2262 _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet, 2263 _Inout_ PULONG PrivilegeSetLength, 2264 _Out_ PACCESS_MASK GrantedAccess, 2265 _Out_ PNTSTATUS AccessStatus) 2266 { 2267 PAGED_CODE(); 2268 2269 /* Invoke the internal function to do the job */ 2270 return SepAccessCheck(SecurityDescriptor, 2271 ClientToken, 2272 PrincipalSelfSid, 2273 DesiredAccess, 2274 GenericMapping, 2275 PrivilegeSet, 2276 PrivilegeSetLength, 2277 ObjectTypeList, 2278 ObjectTypeListLength, 2279 FALSE, 2280 GrantedAccess, 2281 AccessStatus); 2282 } 2283 2284 /** 2285 * @brief 2286 * Determines whether security access can be granted to a client 2287 * that requests such access on the object type list. Unlike the 2288 * NtAccessCheckByType variant, this function will grant or deny 2289 * access to each individual object and sub-object in the list. 2290 * 2291 * @remarks 2292 * For more documentation details about the parameters and 2293 * overall function behavior, see SepAccessCheck. 2294 */ 2295 NTSTATUS 2296 NTAPI 2297 NtAccessCheckByTypeResultList( 2298 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 2299 _In_opt_ PSID PrincipalSelfSid, 2300 _In_ HANDLE ClientToken, 2301 _In_ ACCESS_MASK DesiredAccess, 2302 _In_reads_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList, 2303 _In_ ULONG ObjectTypeListLength, 2304 _In_ PGENERIC_MAPPING GenericMapping, 2305 _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet, 2306 _Inout_ PULONG PrivilegeSetLength, 2307 _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccess, 2308 _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatus) 2309 { 2310 PAGED_CODE(); 2311 2312 /* Invoke the internal function to do the job */ 2313 return SepAccessCheck(SecurityDescriptor, 2314 ClientToken, 2315 PrincipalSelfSid, 2316 DesiredAccess, 2317 GenericMapping, 2318 PrivilegeSet, 2319 PrivilegeSetLength, 2320 ObjectTypeList, 2321 ObjectTypeListLength, 2322 TRUE, 2323 GrantedAccess, 2324 AccessStatus); 2325 } 2326 2327 /* EOF */ 2328