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 * are the input arguments probed. 333 * 334 * @param[in] PoolType 335 * Pool type for new captured ACL for creation. The pool type determines 336 * how the ACL data should reside in the pool memory. 337 * 338 * @param[in] CaptureIfKernel 339 * If set to TRUE and the processor access mode being KernelMode, we're 340 * capturing an ACL directly in the kernel. Otherwise we're 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 = 0; 361 NTSTATUS Status = STATUS_SUCCESS; 362 363 PAGED_CODE(); 364 365 if (AccessMode != KernelMode) 366 { 367 _SEH2_TRY 368 { 369 ProbeForRead(InputAcl, 370 sizeof(ACL), 371 sizeof(ULONG)); 372 AclSize = InputAcl->AclSize; 373 ProbeForRead(InputAcl, 374 AclSize, 375 sizeof(ULONG)); 376 } 377 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 378 { 379 /* Return the exception code */ 380 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 381 } 382 _SEH2_END; 383 384 NewAcl = ExAllocatePoolWithTag(PoolType, 385 AclSize, 386 TAG_ACL); 387 if (NewAcl != NULL) 388 { 389 _SEH2_TRY 390 { 391 RtlCopyMemory(NewAcl, 392 InputAcl, 393 AclSize); 394 395 *CapturedAcl = NewAcl; 396 } 397 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 398 { 399 /* Free the ACL and return the exception code */ 400 ExFreePoolWithTag(NewAcl, TAG_ACL); 401 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 402 } 403 _SEH2_END; 404 } 405 else 406 { 407 Status = STATUS_INSUFFICIENT_RESOURCES; 408 } 409 } 410 else if (!CaptureIfKernel) 411 { 412 *CapturedAcl = InputAcl; 413 } 414 else 415 { 416 AclSize = InputAcl->AclSize; 417 418 NewAcl = ExAllocatePoolWithTag(PoolType, 419 AclSize, 420 TAG_ACL); 421 422 if (NewAcl != NULL) 423 { 424 RtlCopyMemory(NewAcl, 425 InputAcl, 426 AclSize); 427 428 *CapturedAcl = NewAcl; 429 } 430 else 431 { 432 Status = STATUS_INSUFFICIENT_RESOURCES; 433 } 434 } 435 436 return Status; 437 } 438 439 /** 440 * @brief 441 * Releases (frees) a captured ACL from the memory pool. 442 * 443 * @param[in] CapturedAcl 444 * A valid captured ACL to free. 445 * 446 * @param[in] AccessMode 447 * Processor level access mode. 448 * 449 * @param[in] CaptureIfKernel 450 * If set to TRUE and the processor access mode being KernelMode, we're 451 * releasing an ACL directly in the kernel. Otherwise we're releasing 452 * within a kernel mode driver. 453 * 454 * @return 455 * Nothing. 456 */ 457 VOID 458 NTAPI 459 SepReleaseAcl( 460 _In_ PACL CapturedAcl, 461 _In_ KPROCESSOR_MODE AccessMode, 462 _In_ BOOLEAN CaptureIfKernel) 463 { 464 PAGED_CODE(); 465 466 if (CapturedAcl != NULL && 467 (AccessMode != KernelMode || 468 (AccessMode == KernelMode && CaptureIfKernel))) 469 { 470 ExFreePoolWithTag(CapturedAcl, TAG_ACL); 471 } 472 } 473 474 /** 475 * @brief 476 * Determines if a certain ACE can or cannot be propagated based on 477 * ACE inheritation flags and whatnot. 478 * 479 * @param[in] AceFlags 480 * Bit flags of an ACE to perform propagation checks. 481 * 482 * @param[out] NewAceFlags 483 * New ACE bit blags based on the specific ACE flags of the first 484 * argument parameter. 485 * 486 * @param[in] IsInherited 487 * If set to TRUE, an ACE is deemed as directly inherited from another 488 * instance. In that case we're allowed to propagate. 489 * 490 * @param[in] IsDirectoryObject 491 * If set to TRUE, an object directly inherits this ACE so we can propagate 492 * it. 493 * 494 * @return 495 * Returns TRUE if an ACE can be propagated, FALSE otherwise. 496 */ 497 BOOLEAN 498 SepShouldPropagateAce( 499 _In_ UCHAR AceFlags, 500 _Out_ PUCHAR NewAceFlags, 501 _In_ BOOLEAN IsInherited, 502 _In_ BOOLEAN IsDirectoryObject) 503 { 504 if (!IsInherited) 505 { 506 *NewAceFlags = AceFlags; 507 return TRUE; 508 } 509 510 if (!IsDirectoryObject) 511 { 512 if (AceFlags & OBJECT_INHERIT_ACE) 513 { 514 *NewAceFlags = AceFlags & ~VALID_INHERIT_FLAGS; 515 return TRUE; 516 } 517 return FALSE; 518 } 519 520 if (AceFlags & NO_PROPAGATE_INHERIT_ACE) 521 { 522 if (AceFlags & CONTAINER_INHERIT_ACE) 523 { 524 *NewAceFlags = AceFlags & ~VALID_INHERIT_FLAGS; 525 return TRUE; 526 } 527 return FALSE; 528 } 529 530 if (AceFlags & CONTAINER_INHERIT_ACE) 531 { 532 *NewAceFlags = CONTAINER_INHERIT_ACE | (AceFlags & OBJECT_INHERIT_ACE) | (AceFlags & ~VALID_INHERIT_FLAGS); 533 return TRUE; 534 } 535 536 if (AceFlags & OBJECT_INHERIT_ACE) 537 { 538 *NewAceFlags = INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE | (AceFlags & ~VALID_INHERIT_FLAGS); 539 return TRUE; 540 } 541 542 return FALSE; 543 } 544 545 /** 546 * @brief 547 * Propagates (copies) an access control list. 548 * 549 * @param[out] AclDest 550 * The destination parameter with propagated ACL. 551 * 552 * @param[in,out] AclLength 553 * The length of the ACL that we propagate. 554 * 555 * @param[in] AclSource 556 * The source instance of a valid ACL. 557 * 558 * @param[in] Owner 559 * A SID that represents the main user that identifies the ACL. 560 * 561 * @param[in] Group 562 * A SID that represents a group that identifies the ACL. 563 * 564 * @param[in] IsInherited 565 * If set to TRUE, that means the ACL is directly inherited. 566 * 567 * @param[in] IsDirectoryObject 568 * If set to TRUE, that means the ACL is directly inherited because 569 * of the object that inherits it. 570 * 571 * @param[in] GenericMapping 572 * Generic mapping of access rights to map only certain effective 573 * ACEs. 574 * 575 * @return 576 * Returns STATUS_SUCCESS if ACL has been propagated successfully. 577 * STATUS_BUFFER_TOO_SMALL is returned if the ACL length is not greater 578 * than the maximum written size of the buffer for ACL propagation 579 * otherwise. 580 */ 581 NTSTATUS 582 SepPropagateAcl( 583 _Out_writes_bytes_opt_(AclLength) PACL AclDest, 584 _Inout_ PULONG AclLength, 585 _In_reads_bytes_(AclSource->AclSize) PACL AclSource, 586 _In_ PSID Owner, 587 _In_ PSID Group, 588 _In_ BOOLEAN IsInherited, 589 _In_ BOOLEAN IsDirectoryObject, 590 _In_ PGENERIC_MAPPING GenericMapping) 591 { 592 ACCESS_MASK Mask; 593 PACCESS_ALLOWED_ACE AceSource; 594 PACCESS_ALLOWED_ACE AceDest; 595 PUCHAR CurrentDest; 596 PUCHAR CurrentSource; 597 ULONG i; 598 ULONG Written; 599 UCHAR AceFlags; 600 USHORT AceSize; 601 USHORT AceCount = 0; 602 PSID Sid; 603 BOOLEAN WriteTwoAces; 604 605 ASSERT(RtlValidAcl(AclSource)); 606 ASSERT(AclSource->AclSize % sizeof(ULONG) == 0); 607 ASSERT(AclSource->Sbz1 == 0); 608 ASSERT(AclSource->Sbz2 == 0); 609 610 Written = 0; 611 if (*AclLength >= Written + sizeof(ACL)) 612 { 613 RtlCopyMemory(AclDest, 614 AclSource, 615 sizeof(ACL)); 616 } 617 Written += sizeof(ACL); 618 619 CurrentDest = (PUCHAR)(AclDest + 1); 620 CurrentSource = (PUCHAR)(AclSource + 1); 621 for (i = 0; i < AclSource->AceCount; i++) 622 { 623 ASSERT((ULONG_PTR)CurrentDest % sizeof(ULONG) == 0); 624 ASSERT((ULONG_PTR)CurrentSource % sizeof(ULONG) == 0); 625 AceDest = (PACCESS_ALLOWED_ACE)CurrentDest; 626 AceSource = (PACCESS_ALLOWED_ACE)CurrentSource; 627 628 if (AceSource->Header.AceType > ACCESS_MAX_MS_V2_ACE_TYPE) 629 { 630 /* FIXME: handle object & compound ACEs */ 631 AceSize = AceSource->Header.AceSize; 632 633 if (*AclLength >= Written + AceSize) 634 { 635 RtlCopyMemory(AceDest, AceSource, AceSize); 636 } 637 CurrentDest += AceSize; 638 CurrentSource += AceSize; 639 Written += AceSize; 640 AceCount++; 641 continue; 642 } 643 644 /* These all have the same structure */ 645 ASSERT(AceSource->Header.AceType == ACCESS_ALLOWED_ACE_TYPE || 646 AceSource->Header.AceType == ACCESS_DENIED_ACE_TYPE || 647 AceSource->Header.AceType == SYSTEM_AUDIT_ACE_TYPE || 648 AceSource->Header.AceType == SYSTEM_ALARM_ACE_TYPE); 649 650 ASSERT(AceSource->Header.AceSize % sizeof(ULONG) == 0); 651 ASSERT(AceSource->Header.AceSize >= sizeof(*AceSource)); 652 if (!SepShouldPropagateAce(AceSource->Header.AceFlags, 653 &AceFlags, 654 IsInherited, 655 IsDirectoryObject)) 656 { 657 CurrentSource += AceSource->Header.AceSize; 658 continue; 659 } 660 661 /* FIXME: filter out duplicate ACEs */ 662 AceSize = AceSource->Header.AceSize; 663 Mask = AceSource->Mask; 664 Sid = (PSID)&AceSource->SidStart; 665 ASSERT(AceSize >= FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(Sid)); 666 667 WriteTwoAces = FALSE; 668 /* Map effective ACE to specific rights */ 669 if (!(AceFlags & INHERIT_ONLY_ACE)) 670 { 671 RtlMapGenericMask(&Mask, GenericMapping); 672 Mask &= GenericMapping->GenericAll; 673 674 if (IsInherited) 675 { 676 if (RtlEqualSid(Sid, SeCreatorOwnerSid)) 677 Sid = Owner; 678 else if (RtlEqualSid(Sid, SeCreatorGroupSid)) 679 Sid = Group; 680 AceSize = FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(Sid); 681 682 /* 683 * A generic container ACE becomes two ACEs: 684 * - a specific effective ACE with no inheritance flags 685 * - an inherit-only ACE that keeps the generic rights 686 */ 687 if (IsDirectoryObject && 688 (AceFlags & CONTAINER_INHERIT_ACE) && 689 (Mask != AceSource->Mask || Sid != (PSID)&AceSource->SidStart)) 690 { 691 WriteTwoAces = TRUE; 692 } 693 } 694 } 695 696 while (1) 697 { 698 if (*AclLength >= Written + AceSize) 699 { 700 AceDest->Header.AceType = AceSource->Header.AceType; 701 AceDest->Header.AceFlags = WriteTwoAces ? AceFlags & ~VALID_INHERIT_FLAGS 702 : AceFlags; 703 AceDest->Header.AceSize = AceSize; 704 AceDest->Mask = Mask; 705 RtlCopySid(AceSize - FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart), 706 (PSID)&AceDest->SidStart, 707 Sid); 708 } 709 Written += AceSize; 710 711 AceCount++; 712 CurrentDest += AceSize; 713 714 if (!WriteTwoAces) 715 break; 716 717 /* Second ACE keeps all the generics from the source ACE */ 718 WriteTwoAces = FALSE; 719 AceDest = (PACCESS_ALLOWED_ACE)CurrentDest; 720 AceSize = AceSource->Header.AceSize; 721 Mask = AceSource->Mask; 722 Sid = (PSID)&AceSource->SidStart; 723 AceFlags |= INHERIT_ONLY_ACE; 724 } 725 726 CurrentSource += AceSource->Header.AceSize; 727 } 728 729 if (*AclLength >= sizeof(ACL)) 730 { 731 AclDest->AceCount = AceCount; 732 AclDest->AclSize = Written; 733 } 734 735 if (Written > *AclLength) 736 { 737 *AclLength = Written; 738 return STATUS_BUFFER_TOO_SMALL; 739 } 740 *AclLength = Written; 741 return STATUS_SUCCESS; 742 } 743 744 /** 745 * @brief 746 * Selects an ACL and returns it to the caller. 747 * 748 * @param[in] ExplicitAcl 749 * If specified, the specified ACL to the call will be 750 * the selected ACL for the caller. 751 * 752 * @param[in] ExplicitPresent 753 * If set to TRUE and with specific ACL filled to the call, the 754 * function will immediately return the specific ACL as the selected 755 * ACL for the caller. 756 * 757 * @param[in] ExplicitDefaulted 758 * If set to FALSE and with specific ACL filled to the call, the ACL 759 * is not a default ACL. Otherwise it's a default ACL that we cannot 760 * select it as is. 761 * 762 * @param[in] ParentAcl 763 * If specified, the parent ACL will be used to determine the exact ACL 764 * length to check if the ACL in question is not empty. If the list 765 * is not empty then the function will select such ACL to the caller. 766 * 767 * @param[in] DefaultAcl 768 * If specified, the default ACL will be the selected one for the caller. 769 * 770 * @param[out] AclLength 771 * The size length of an ACL. 772 * 773 * @param[in] Owner 774 * A SID that represents the main user that identifies the ACL. 775 * 776 * @param[in] Group 777 * A SID that represents a group that identifies the ACL. 778 * 779 * @param[out] AclPresent 780 * The returned boolean value, indicating if the ACL that we want to select 781 * does actually exist. 782 * 783 * @param[out] IsInherited 784 * The returned boolean value, indicating if the ACL we want to select it 785 * is actually inherited or not. 786 * 787 * @param[in] IsDirectoryObject 788 * If set to TRUE, the object inherits this ACL. 789 * 790 * @param[in] GenericMapping 791 * Generic mapping of access rights to map only certain effective 792 * ACEs of an ACL that we want to select it. 793 * 794 * @return 795 * Returns the selected access control list (ACL) to the caller, 796 * NULL otherwise. 797 */ 798 PACL 799 SepSelectAcl( 800 _In_opt_ PACL ExplicitAcl, 801 _In_ BOOLEAN ExplicitPresent, 802 _In_ BOOLEAN ExplicitDefaulted, 803 _In_opt_ PACL ParentAcl, 804 _In_opt_ PACL DefaultAcl, 805 _Out_ PULONG AclLength, 806 _In_ PSID Owner, 807 _In_ PSID Group, 808 _Out_ PBOOLEAN AclPresent, 809 _Out_ PBOOLEAN IsInherited, 810 _In_ BOOLEAN IsDirectoryObject, 811 _In_ PGENERIC_MAPPING GenericMapping) 812 { 813 PACL Acl; 814 NTSTATUS Status; 815 816 *AclPresent = TRUE; 817 if (ExplicitPresent && !ExplicitDefaulted) 818 { 819 Acl = ExplicitAcl; 820 } 821 else 822 { 823 if (ParentAcl) 824 { 825 *IsInherited = TRUE; 826 *AclLength = 0; 827 Status = SepPropagateAcl(NULL, 828 AclLength, 829 ParentAcl, 830 Owner, 831 Group, 832 *IsInherited, 833 IsDirectoryObject, 834 GenericMapping); 835 ASSERT(Status == STATUS_BUFFER_TOO_SMALL); 836 837 /* Use the parent ACL only if it's not empty */ 838 if (*AclLength != sizeof(ACL)) 839 return ParentAcl; 840 } 841 842 if (ExplicitPresent) 843 { 844 Acl = ExplicitAcl; 845 } 846 else if (DefaultAcl) 847 { 848 Acl = DefaultAcl; 849 } 850 else 851 { 852 *AclPresent = FALSE; 853 Acl = NULL; 854 } 855 } 856 857 *IsInherited = FALSE; 858 *AclLength = 0; 859 if (Acl) 860 { 861 /* Get the length */ 862 Status = SepPropagateAcl(NULL, 863 AclLength, 864 Acl, 865 Owner, 866 Group, 867 *IsInherited, 868 IsDirectoryObject, 869 GenericMapping); 870 ASSERT(Status == STATUS_BUFFER_TOO_SMALL); 871 } 872 return Acl; 873 } 874 875 /* EOF */ 876