1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Access control lists (ACLs) implementation 5 * COPYRIGHT: Copyright David Welch <welch@cwcom.net> 6 */ 7 8 /* INCLUDES *******************************************************************/ 9 10 #include <ntoskrnl.h> 11 #define NDEBUG 12 #include <debug.h> 13 14 /* GLOBALS ********************************************************************/ 15 16 PACL SePublicDefaultDacl = NULL; 17 PACL SeSystemDefaultDacl = NULL; 18 PACL SePublicDefaultUnrestrictedDacl = NULL; 19 PACL SePublicOpenDacl = NULL; 20 PACL SePublicOpenUnrestrictedDacl = NULL; 21 PACL SeUnrestrictedDacl = NULL; 22 PACL SeSystemAnonymousLogonDacl = NULL; 23 24 /* FUNCTIONS ******************************************************************/ 25 26 /** 27 * @brief 28 * Initializes known discretionary access control lists in the system upon 29 * kernel and Executive initialization procedure. 30 * 31 * @return 32 * Returns TRUE if all the DACLs have been successfully initialized, 33 * FALSE otherwise. 34 */ 35 CODE_SEG("INIT") 36 BOOLEAN 37 NTAPI 38 SepInitDACLs(VOID) 39 { 40 ULONG AclLength; 41 42 /* create PublicDefaultDacl */ 43 AclLength = sizeof(ACL) + 44 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) + 45 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) + 46 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)); 47 48 SePublicDefaultDacl = ExAllocatePoolWithTag(PagedPool, 49 AclLength, 50 TAG_ACL); 51 if (SePublicDefaultDacl == NULL) 52 return FALSE; 53 54 RtlCreateAcl(SePublicDefaultDacl, 55 AclLength, 56 ACL_REVISION); 57 58 RtlAddAccessAllowedAce(SePublicDefaultDacl, 59 ACL_REVISION, 60 GENERIC_EXECUTE, 61 SeWorldSid); 62 63 RtlAddAccessAllowedAce(SePublicDefaultDacl, 64 ACL_REVISION, 65 GENERIC_ALL, 66 SeLocalSystemSid); 67 68 RtlAddAccessAllowedAce(SePublicDefaultDacl, 69 ACL_REVISION, 70 GENERIC_ALL, 71 SeAliasAdminsSid); 72 73 /* create PublicDefaultUnrestrictedDacl */ 74 AclLength = sizeof(ACL) + 75 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) + 76 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) + 77 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)) + 78 (sizeof(ACE) + RtlLengthSid(SeRestrictedCodeSid)); 79 80 SePublicDefaultUnrestrictedDacl = ExAllocatePoolWithTag(PagedPool, 81 AclLength, 82 TAG_ACL); 83 if (SePublicDefaultUnrestrictedDacl == NULL) 84 return FALSE; 85 86 RtlCreateAcl(SePublicDefaultUnrestrictedDacl, 87 AclLength, 88 ACL_REVISION); 89 90 RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl, 91 ACL_REVISION, 92 GENERIC_EXECUTE, 93 SeWorldSid); 94 95 RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl, 96 ACL_REVISION, 97 GENERIC_ALL, 98 SeLocalSystemSid); 99 100 RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl, 101 ACL_REVISION, 102 GENERIC_ALL, 103 SeAliasAdminsSid); 104 105 RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl, 106 ACL_REVISION, 107 GENERIC_READ | GENERIC_EXECUTE | READ_CONTROL, 108 SeRestrictedCodeSid); 109 110 /* create PublicOpenDacl */ 111 AclLength = sizeof(ACL) + 112 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) + 113 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) + 114 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)); 115 116 SePublicOpenDacl = ExAllocatePoolWithTag(PagedPool, 117 AclLength, 118 TAG_ACL); 119 if (SePublicOpenDacl == NULL) 120 return FALSE; 121 122 RtlCreateAcl(SePublicOpenDacl, 123 AclLength, 124 ACL_REVISION); 125 126 RtlAddAccessAllowedAce(SePublicOpenDacl, 127 ACL_REVISION, 128 GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE, 129 SeWorldSid); 130 131 RtlAddAccessAllowedAce(SePublicOpenDacl, 132 ACL_REVISION, 133 GENERIC_ALL, 134 SeLocalSystemSid); 135 136 RtlAddAccessAllowedAce(SePublicOpenDacl, 137 ACL_REVISION, 138 GENERIC_ALL, 139 SeAliasAdminsSid); 140 141 /* create PublicOpenUnrestrictedDacl */ 142 AclLength = sizeof(ACL) + 143 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) + 144 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) + 145 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)) + 146 (sizeof(ACE) + RtlLengthSid(SeRestrictedCodeSid)); 147 148 SePublicOpenUnrestrictedDacl = ExAllocatePoolWithTag(PagedPool, 149 AclLength, 150 TAG_ACL); 151 if (SePublicOpenUnrestrictedDacl == NULL) 152 return FALSE; 153 154 RtlCreateAcl(SePublicOpenUnrestrictedDacl, 155 AclLength, 156 ACL_REVISION); 157 158 RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl, 159 ACL_REVISION, 160 GENERIC_ALL, 161 SeWorldSid); 162 163 RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl, 164 ACL_REVISION, 165 GENERIC_ALL, 166 SeLocalSystemSid); 167 168 RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl, 169 ACL_REVISION, 170 GENERIC_ALL, 171 SeAliasAdminsSid); 172 173 RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl, 174 ACL_REVISION, 175 GENERIC_READ | GENERIC_EXECUTE, 176 SeRestrictedCodeSid); 177 178 /* create SystemDefaultDacl */ 179 AclLength = sizeof(ACL) + 180 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) + 181 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)); 182 183 SeSystemDefaultDacl = ExAllocatePoolWithTag(PagedPool, 184 AclLength, 185 TAG_ACL); 186 if (SeSystemDefaultDacl == NULL) 187 return FALSE; 188 189 RtlCreateAcl(SeSystemDefaultDacl, 190 AclLength, 191 ACL_REVISION); 192 193 RtlAddAccessAllowedAce(SeSystemDefaultDacl, 194 ACL_REVISION, 195 GENERIC_ALL, 196 SeLocalSystemSid); 197 198 RtlAddAccessAllowedAce(SeSystemDefaultDacl, 199 ACL_REVISION, 200 GENERIC_READ | GENERIC_EXECUTE | READ_CONTROL, 201 SeAliasAdminsSid); 202 203 /* create UnrestrictedDacl */ 204 AclLength = sizeof(ACL) + 205 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) + 206 (sizeof(ACE) + RtlLengthSid(SeRestrictedCodeSid)); 207 208 SeUnrestrictedDacl = ExAllocatePoolWithTag(PagedPool, 209 AclLength, 210 TAG_ACL); 211 if (SeUnrestrictedDacl == NULL) 212 return FALSE; 213 214 RtlCreateAcl(SeUnrestrictedDacl, 215 AclLength, 216 ACL_REVISION); 217 218 RtlAddAccessAllowedAce(SeUnrestrictedDacl, 219 ACL_REVISION, 220 GENERIC_ALL, 221 SeWorldSid); 222 223 RtlAddAccessAllowedAce(SeUnrestrictedDacl, 224 ACL_REVISION, 225 GENERIC_READ | GENERIC_EXECUTE, 226 SeRestrictedCodeSid); 227 228 /* create SystemAnonymousLogonDacl */ 229 AclLength = sizeof(ACL) + 230 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) + 231 (sizeof(ACE) + RtlLengthSid(SeAnonymousLogonSid)); 232 233 SeSystemAnonymousLogonDacl = ExAllocatePoolWithTag(PagedPool, 234 AclLength, 235 TAG_ACL); 236 if (SeSystemAnonymousLogonDacl == NULL) 237 return FALSE; 238 239 RtlCreateAcl(SeSystemAnonymousLogonDacl, 240 AclLength, 241 ACL_REVISION); 242 243 RtlAddAccessAllowedAce(SeSystemAnonymousLogonDacl, 244 ACL_REVISION, 245 GENERIC_ALL, 246 SeWorldSid); 247 248 RtlAddAccessAllowedAce(SeSystemAnonymousLogonDacl, 249 ACL_REVISION, 250 GENERIC_ALL, 251 SeAnonymousLogonSid); 252 253 return TRUE; 254 } 255 256 /** 257 * @brief 258 * Allocates a discretionary access control list based on certain properties 259 * of a regular and primary access tokens. 260 * 261 * @param[in] Token 262 * An access token. 263 * 264 * @param[in] PrimaryToken 265 * A primary access token. 266 * 267 * @param[out] Dacl 268 * The returned allocated DACL. 269 * 270 * @return 271 * Returns STATUS_SUCCESS if DACL creation from tokens has completed 272 * successfully. STATUS_INSUFFICIENT_RESOURCES is returned if DACL 273 * allocation from memory pool fails otherwise. 274 */ 275 NTSTATUS 276 NTAPI 277 SepCreateImpersonationTokenDacl( 278 _In_ PTOKEN Token, 279 _In_ PTOKEN PrimaryToken, 280 _Out_ PACL* Dacl) 281 { 282 ULONG AclLength; 283 PACL TokenDacl; 284 285 PAGED_CODE(); 286 287 *Dacl = NULL; 288 289 AclLength = sizeof(ACL) + 290 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)) + 291 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) + 292 (sizeof(ACE) + RtlLengthSid(SeRestrictedCodeSid)) + 293 (sizeof(ACE) + RtlLengthSid(Token->UserAndGroups->Sid)) + 294 (sizeof(ACE) + RtlLengthSid(PrimaryToken->UserAndGroups->Sid)); 295 296 TokenDacl = ExAllocatePoolWithTag(PagedPool, AclLength, TAG_ACL); 297 if (TokenDacl == NULL) 298 { 299 return STATUS_INSUFFICIENT_RESOURCES; 300 } 301 302 RtlCreateAcl(TokenDacl, AclLength, ACL_REVISION); 303 RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL, 304 Token->UserAndGroups->Sid); 305 RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL, 306 PrimaryToken->UserAndGroups->Sid); 307 RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL, 308 SeAliasAdminsSid); 309 RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL, 310 SeLocalSystemSid); 311 312 if (Token->RestrictedSids != NULL || PrimaryToken->RestrictedSids != NULL) 313 { 314 RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL, 315 SeRestrictedCodeSid); 316 } 317 318 *Dacl = TokenDacl; 319 320 return STATUS_SUCCESS; 321 } 322 323 /** 324 * @brief 325 * Captures an access control list from an already valid input ACL. 326 * 327 * @param[in] InputAcl 328 * A valid ACL. 329 * 330 * @param[in] AccessMode 331 * Processor level access mode. The processor mode determines how 332 * the input arguments are probed. 333 * 334 * @param[in] PoolType 335 * Pool type for new captured ACL for creation. The pool type determines 336 * in which memory pool the ACL data should reside. 337 * 338 * @param[in] CaptureIfKernel 339 * If set to TRUE and the processor access mode being KernelMode, we are 340 * capturing an ACL directly in the kernel. Otherwise we are capturing 341 * within a kernel mode driver. 342 * 343 * @param[out] CapturedAcl 344 * The returned and allocated captured ACL. 345 * 346 * @return 347 * Returns STATUS_SUCCESS if the ACL has been successfully captured. 348 * STATUS_INSUFFICIENT_RESOURCES is returned otherwise. 349 */ 350 NTSTATUS 351 NTAPI 352 SepCaptureAcl( 353 _In_ PACL InputAcl, 354 _In_ KPROCESSOR_MODE AccessMode, 355 _In_ POOL_TYPE PoolType, 356 _In_ BOOLEAN CaptureIfKernel, 357 _Out_ PACL *CapturedAcl) 358 { 359 PACL NewAcl; 360 ULONG AclSize; 361 362 PAGED_CODE(); 363 364 /* If in kernel mode and we do not capture, just 365 * return the given ACL and don't validate it. */ 366 if ((AccessMode == KernelMode) && !CaptureIfKernel) 367 { 368 *CapturedAcl = InputAcl; 369 return STATUS_SUCCESS; 370 } 371 372 /* Otherwise, capture and validate the ACL, depending on the access mode */ 373 if (AccessMode != KernelMode) 374 { 375 _SEH2_TRY 376 { 377 ProbeForRead(InputAcl, 378 sizeof(ACL), 379 sizeof(ULONG)); 380 AclSize = InputAcl->AclSize; 381 ProbeForRead(InputAcl, 382 AclSize, 383 sizeof(ULONG)); 384 } 385 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 386 { 387 /* Return the exception code */ 388 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 389 } 390 _SEH2_END; 391 392 /* Validate the minimal size an ACL can have */ 393 if (AclSize < sizeof(ACL)) 394 return STATUS_INVALID_ACL; 395 396 NewAcl = ExAllocatePoolWithTag(PoolType, 397 AclSize, 398 TAG_ACL); 399 if (!NewAcl) 400 return STATUS_INSUFFICIENT_RESOURCES; 401 402 _SEH2_TRY 403 { 404 RtlCopyMemory(NewAcl, InputAcl, AclSize); 405 } 406 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 407 { 408 /* Free the ACL and return the exception code */ 409 ExFreePoolWithTag(NewAcl, TAG_ACL); 410 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 411 } 412 _SEH2_END; 413 } 414 else 415 { 416 AclSize = InputAcl->AclSize; 417 418 /* Validate the minimal size an ACL can have */ 419 if (AclSize < sizeof(ACL)) 420 return STATUS_INVALID_ACL; 421 422 NewAcl = ExAllocatePoolWithTag(PoolType, 423 AclSize, 424 TAG_ACL); 425 if (!NewAcl) 426 return STATUS_INSUFFICIENT_RESOURCES; 427 428 RtlCopyMemory(NewAcl, InputAcl, AclSize); 429 } 430 431 /* Validate the captured ACL */ 432 if (!RtlValidAcl(NewAcl)) 433 { 434 /* Free the ACL and fail */ 435 ExFreePoolWithTag(NewAcl, TAG_ACL); 436 return STATUS_INVALID_ACL; 437 } 438 439 /* It's valid, return it */ 440 *CapturedAcl = NewAcl; 441 return STATUS_SUCCESS; 442 } 443 444 /** 445 * @brief 446 * Releases (frees) a captured ACL from the memory pool. 447 * 448 * @param[in] CapturedAcl 449 * A valid captured ACL to free. 450 * 451 * @param[in] AccessMode 452 * Processor level access mode. 453 * 454 * @param[in] CaptureIfKernel 455 * If set to TRUE and the processor access mode being KernelMode, we're 456 * releasing an ACL directly in the kernel. Otherwise we're releasing 457 * within a kernel mode driver. 458 * 459 * @return 460 * Nothing. 461 */ 462 VOID 463 NTAPI 464 SepReleaseAcl( 465 _In_ PACL CapturedAcl, 466 _In_ KPROCESSOR_MODE AccessMode, 467 _In_ BOOLEAN CaptureIfKernel) 468 { 469 PAGED_CODE(); 470 471 if (CapturedAcl != NULL && 472 (AccessMode != KernelMode || 473 (AccessMode == KernelMode && CaptureIfKernel))) 474 { 475 ExFreePoolWithTag(CapturedAcl, TAG_ACL); 476 } 477 } 478 479 /** 480 * @brief 481 * Determines if a certain ACE can or cannot be propagated based on 482 * ACE inheritation flags and whatnot. 483 * 484 * @param[in] AceFlags 485 * Bit flags of an ACE to perform propagation checks. 486 * 487 * @param[out] NewAceFlags 488 * New ACE bit blags based on the specific ACE flags of the first 489 * argument parameter. 490 * 491 * @param[in] IsInherited 492 * If set to TRUE, an ACE is deemed as directly inherited from another 493 * instance. In that case we're allowed to propagate. 494 * 495 * @param[in] IsDirectoryObject 496 * If set to TRUE, an object directly inherits this ACE so we can propagate 497 * it. 498 * 499 * @return 500 * Returns TRUE if an ACE can be propagated, FALSE otherwise. 501 */ 502 BOOLEAN 503 SepShouldPropagateAce( 504 _In_ UCHAR AceFlags, 505 _Out_ PUCHAR NewAceFlags, 506 _In_ BOOLEAN IsInherited, 507 _In_ BOOLEAN IsDirectoryObject) 508 { 509 if (!IsInherited) 510 { 511 *NewAceFlags = AceFlags; 512 return TRUE; 513 } 514 515 if (!IsDirectoryObject) 516 { 517 if (AceFlags & OBJECT_INHERIT_ACE) 518 { 519 *NewAceFlags = AceFlags & ~VALID_INHERIT_FLAGS; 520 return TRUE; 521 } 522 return FALSE; 523 } 524 525 if (AceFlags & NO_PROPAGATE_INHERIT_ACE) 526 { 527 if (AceFlags & CONTAINER_INHERIT_ACE) 528 { 529 *NewAceFlags = AceFlags & ~VALID_INHERIT_FLAGS; 530 return TRUE; 531 } 532 return FALSE; 533 } 534 535 if (AceFlags & CONTAINER_INHERIT_ACE) 536 { 537 *NewAceFlags = CONTAINER_INHERIT_ACE | (AceFlags & OBJECT_INHERIT_ACE) | (AceFlags & ~VALID_INHERIT_FLAGS); 538 return TRUE; 539 } 540 541 if (AceFlags & OBJECT_INHERIT_ACE) 542 { 543 *NewAceFlags = INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE | (AceFlags & ~VALID_INHERIT_FLAGS); 544 return TRUE; 545 } 546 547 return FALSE; 548 } 549 550 /** 551 * @brief 552 * Propagates (copies) an access control list. 553 * 554 * @param[out] AclDest 555 * The destination parameter with propagated ACL. 556 * 557 * @param[in,out] AclLength 558 * The length of the ACL that we propagate. 559 * 560 * @param[in] AclSource 561 * The source instance of a valid ACL. 562 * 563 * @param[in] Owner 564 * A SID that represents the main user that identifies the ACL. 565 * 566 * @param[in] Group 567 * A SID that represents a group that identifies the ACL. 568 * 569 * @param[in] IsInherited 570 * If set to TRUE, that means the ACL is directly inherited. 571 * 572 * @param[in] IsDirectoryObject 573 * If set to TRUE, that means the ACL is directly inherited because 574 * of the object that inherits it. 575 * 576 * @param[in] GenericMapping 577 * Generic mapping of access rights to map only certain effective 578 * ACEs. 579 * 580 * @return 581 * Returns STATUS_SUCCESS if ACL has been propagated successfully. 582 * STATUS_BUFFER_TOO_SMALL is returned if the ACL length is not greater 583 * than the maximum written size of the buffer for ACL propagation 584 * otherwise. 585 */ 586 NTSTATUS 587 SepPropagateAcl( 588 _Out_writes_bytes_opt_(AclLength) PACL AclDest, 589 _Inout_ PULONG AclLength, 590 _In_reads_bytes_(AclSource->AclSize) PACL AclSource, 591 _In_ PSID Owner, 592 _In_ PSID Group, 593 _In_ BOOLEAN IsInherited, 594 _In_ BOOLEAN IsDirectoryObject, 595 _In_ PGENERIC_MAPPING GenericMapping) 596 { 597 ACCESS_MASK Mask; 598 PACCESS_ALLOWED_ACE AceSource; 599 PACCESS_ALLOWED_ACE AceDest; 600 PUCHAR CurrentDest; 601 PUCHAR CurrentSource; 602 ULONG i; 603 ULONG Written; 604 UCHAR AceFlags; 605 USHORT AceSize; 606 USHORT AceCount = 0; 607 PSID Sid; 608 BOOLEAN WriteTwoAces; 609 610 ASSERT(RtlValidAcl(AclSource)); 611 ASSERT(AclSource->AclSize % sizeof(ULONG) == 0); 612 ASSERT(AclSource->Sbz1 == 0); 613 ASSERT(AclSource->Sbz2 == 0); 614 615 Written = 0; 616 if (*AclLength >= Written + sizeof(ACL)) 617 { 618 RtlCopyMemory(AclDest, 619 AclSource, 620 sizeof(ACL)); 621 } 622 Written += sizeof(ACL); 623 624 CurrentDest = (PUCHAR)(AclDest + 1); 625 CurrentSource = (PUCHAR)(AclSource + 1); 626 for (i = 0; i < AclSource->AceCount; i++) 627 { 628 ASSERT((ULONG_PTR)CurrentDest % sizeof(ULONG) == 0); 629 ASSERT((ULONG_PTR)CurrentSource % sizeof(ULONG) == 0); 630 AceDest = (PACCESS_ALLOWED_ACE)CurrentDest; 631 AceSource = (PACCESS_ALLOWED_ACE)CurrentSource; 632 633 if (AceSource->Header.AceType > ACCESS_MAX_MS_V2_ACE_TYPE) 634 { 635 /* FIXME: handle object & compound ACEs */ 636 AceSize = AceSource->Header.AceSize; 637 638 if (*AclLength >= Written + AceSize) 639 { 640 RtlCopyMemory(AceDest, AceSource, AceSize); 641 } 642 CurrentDest += AceSize; 643 CurrentSource += AceSize; 644 Written += AceSize; 645 AceCount++; 646 continue; 647 } 648 649 /* These all have the same structure */ 650 ASSERT(AceSource->Header.AceType == ACCESS_ALLOWED_ACE_TYPE || 651 AceSource->Header.AceType == ACCESS_DENIED_ACE_TYPE || 652 AceSource->Header.AceType == SYSTEM_AUDIT_ACE_TYPE || 653 AceSource->Header.AceType == SYSTEM_ALARM_ACE_TYPE); 654 655 ASSERT(AceSource->Header.AceSize % sizeof(ULONG) == 0); 656 ASSERT(AceSource->Header.AceSize >= sizeof(*AceSource)); 657 if (!SepShouldPropagateAce(AceSource->Header.AceFlags, 658 &AceFlags, 659 IsInherited, 660 IsDirectoryObject)) 661 { 662 CurrentSource += AceSource->Header.AceSize; 663 continue; 664 } 665 666 /* FIXME: filter out duplicate ACEs */ 667 AceSize = AceSource->Header.AceSize; 668 Mask = AceSource->Mask; 669 Sid = (PSID)&AceSource->SidStart; 670 ASSERT(AceSize >= FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(Sid)); 671 672 WriteTwoAces = FALSE; 673 /* Map effective ACE to specific rights */ 674 if (!(AceFlags & INHERIT_ONLY_ACE)) 675 { 676 RtlMapGenericMask(&Mask, GenericMapping); 677 Mask &= GenericMapping->GenericAll; 678 679 if (IsInherited) 680 { 681 if (RtlEqualSid(Sid, SeCreatorOwnerSid)) 682 Sid = Owner; 683 else if (RtlEqualSid(Sid, SeCreatorGroupSid)) 684 Sid = Group; 685 AceSize = FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(Sid); 686 687 /* 688 * A generic container ACE becomes two ACEs: 689 * - a specific effective ACE with no inheritance flags 690 * - an inherit-only ACE that keeps the generic rights 691 */ 692 if (IsDirectoryObject && 693 (AceFlags & CONTAINER_INHERIT_ACE) && 694 (Mask != AceSource->Mask || Sid != (PSID)&AceSource->SidStart)) 695 { 696 WriteTwoAces = TRUE; 697 } 698 } 699 } 700 701 while (1) 702 { 703 if (*AclLength >= Written + AceSize) 704 { 705 AceDest->Header.AceType = AceSource->Header.AceType; 706 AceDest->Header.AceFlags = WriteTwoAces ? AceFlags & ~VALID_INHERIT_FLAGS 707 : AceFlags; 708 AceDest->Header.AceSize = AceSize; 709 AceDest->Mask = Mask; 710 RtlCopySid(AceSize - FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart), 711 (PSID)&AceDest->SidStart, 712 Sid); 713 } 714 Written += AceSize; 715 716 AceCount++; 717 CurrentDest += AceSize; 718 719 if (!WriteTwoAces) 720 break; 721 722 /* Second ACE keeps all the generics from the source ACE */ 723 WriteTwoAces = FALSE; 724 AceDest = (PACCESS_ALLOWED_ACE)CurrentDest; 725 AceSize = AceSource->Header.AceSize; 726 Mask = AceSource->Mask; 727 Sid = (PSID)&AceSource->SidStart; 728 AceFlags |= INHERIT_ONLY_ACE; 729 } 730 731 CurrentSource += AceSource->Header.AceSize; 732 } 733 734 if (*AclLength >= sizeof(ACL)) 735 { 736 AclDest->AceCount = AceCount; 737 AclDest->AclSize = Written; 738 } 739 740 if (Written > *AclLength) 741 { 742 *AclLength = Written; 743 return STATUS_BUFFER_TOO_SMALL; 744 } 745 *AclLength = Written; 746 return STATUS_SUCCESS; 747 } 748 749 /** 750 * @brief 751 * Selects an ACL and returns it to the caller. 752 * 753 * @param[in] ExplicitAcl 754 * If specified, the specified ACL to the call will be 755 * the selected ACL for the caller. 756 * 757 * @param[in] ExplicitPresent 758 * If set to TRUE and with specific ACL filled to the call, the 759 * function will immediately return the specific ACL as the selected 760 * ACL for the caller. 761 * 762 * @param[in] ExplicitDefaulted 763 * If set to FALSE and with specific ACL filled to the call, the ACL 764 * is not a default ACL. Otherwise it's a default ACL that we cannot 765 * select it as is. 766 * 767 * @param[in] ParentAcl 768 * If specified, the parent ACL will be used to determine the exact ACL 769 * length to check if the ACL in question is not empty. If the list 770 * is not empty then the function will select such ACL to the caller. 771 * 772 * @param[in] DefaultAcl 773 * If specified, the default ACL will be the selected one for the caller. 774 * 775 * @param[out] AclLength 776 * The size length of an ACL. 777 * 778 * @param[in] Owner 779 * A SID that represents the main user that identifies the ACL. 780 * 781 * @param[in] Group 782 * A SID that represents a group that identifies the ACL. 783 * 784 * @param[out] AclPresent 785 * The returned boolean value, indicating if the ACL that we want to select 786 * does actually exist. 787 * 788 * @param[out] IsInherited 789 * The returned boolean value, indicating if the ACL we want to select it 790 * is actually inherited or not. 791 * 792 * @param[in] IsDirectoryObject 793 * If set to TRUE, the object inherits this ACL. 794 * 795 * @param[in] GenericMapping 796 * Generic mapping of access rights to map only certain effective 797 * ACEs of an ACL that we want to select it. 798 * 799 * @return 800 * Returns the selected access control list (ACL) to the caller, 801 * NULL otherwise. 802 */ 803 PACL 804 SepSelectAcl( 805 _In_opt_ PACL ExplicitAcl, 806 _In_ BOOLEAN ExplicitPresent, 807 _In_ BOOLEAN ExplicitDefaulted, 808 _In_opt_ PACL ParentAcl, 809 _In_opt_ PACL DefaultAcl, 810 _Out_ PULONG AclLength, 811 _In_ PSID Owner, 812 _In_ PSID Group, 813 _Out_ PBOOLEAN AclPresent, 814 _Out_ PBOOLEAN IsInherited, 815 _In_ BOOLEAN IsDirectoryObject, 816 _In_ PGENERIC_MAPPING GenericMapping) 817 { 818 PACL Acl; 819 NTSTATUS Status; 820 821 *AclPresent = TRUE; 822 if (ExplicitPresent && !ExplicitDefaulted) 823 { 824 Acl = ExplicitAcl; 825 } 826 else 827 { 828 if (ParentAcl) 829 { 830 *IsInherited = TRUE; 831 *AclLength = 0; 832 Status = SepPropagateAcl(NULL, 833 AclLength, 834 ParentAcl, 835 Owner, 836 Group, 837 *IsInherited, 838 IsDirectoryObject, 839 GenericMapping); 840 ASSERT(Status == STATUS_BUFFER_TOO_SMALL); 841 842 /* Use the parent ACL only if it's not empty */ 843 if (*AclLength != sizeof(ACL)) 844 return ParentAcl; 845 } 846 847 if (ExplicitPresent) 848 { 849 Acl = ExplicitAcl; 850 } 851 else if (DefaultAcl) 852 { 853 Acl = DefaultAcl; 854 } 855 else 856 { 857 *AclPresent = FALSE; 858 Acl = NULL; 859 } 860 } 861 862 *IsInherited = FALSE; 863 *AclLength = 0; 864 if (Acl) 865 { 866 /* Get the length */ 867 Status = SepPropagateAcl(NULL, 868 AclLength, 869 Acl, 870 Owner, 871 Group, 872 *IsInherited, 873 IsDirectoryObject, 874 GenericMapping); 875 ASSERT(Status == STATUS_BUFFER_TOO_SMALL); 876 } 877 return Acl; 878 } 879 880 /* EOF */ 881