1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * FILE: ntoskrnl/se/acl.c 5 * PURPOSE: Security manager 6 * 7 * PROGRAMMERS: David Welch <welch@cwcom.net> 8 */ 9 10 /* INCLUDES *******************************************************************/ 11 12 #include <ntoskrnl.h> 13 #define NDEBUG 14 #include <debug.h> 15 16 /* GLOBALS ********************************************************************/ 17 18 PACL SePublicDefaultDacl = NULL; 19 PACL SeSystemDefaultDacl = NULL; 20 PACL SePublicDefaultUnrestrictedDacl = NULL; 21 PACL SePublicOpenDacl = NULL; 22 PACL SePublicOpenUnrestrictedDacl = NULL; 23 PACL SeUnrestrictedDacl = NULL; 24 PACL SeSystemAnonymousLogonDacl = NULL; 25 26 /* FUNCTIONS ******************************************************************/ 27 28 CODE_SEG("INIT") 29 BOOLEAN 30 NTAPI 31 SepInitDACLs(VOID) 32 { 33 ULONG AclLength; 34 35 /* create PublicDefaultDacl */ 36 AclLength = sizeof(ACL) + 37 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) + 38 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) + 39 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)); 40 41 SePublicDefaultDacl = ExAllocatePoolWithTag(PagedPool, 42 AclLength, 43 TAG_ACL); 44 if (SePublicDefaultDacl == NULL) 45 return FALSE; 46 47 RtlCreateAcl(SePublicDefaultDacl, 48 AclLength, 49 ACL_REVISION); 50 51 RtlAddAccessAllowedAce(SePublicDefaultDacl, 52 ACL_REVISION, 53 GENERIC_EXECUTE, 54 SeWorldSid); 55 56 RtlAddAccessAllowedAce(SePublicDefaultDacl, 57 ACL_REVISION, 58 GENERIC_ALL, 59 SeLocalSystemSid); 60 61 RtlAddAccessAllowedAce(SePublicDefaultDacl, 62 ACL_REVISION, 63 GENERIC_ALL, 64 SeAliasAdminsSid); 65 66 /* create PublicDefaultUnrestrictedDacl */ 67 AclLength = sizeof(ACL) + 68 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) + 69 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) + 70 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)) + 71 (sizeof(ACE) + RtlLengthSid(SeRestrictedCodeSid)); 72 73 SePublicDefaultUnrestrictedDacl = ExAllocatePoolWithTag(PagedPool, 74 AclLength, 75 TAG_ACL); 76 if (SePublicDefaultUnrestrictedDacl == NULL) 77 return FALSE; 78 79 RtlCreateAcl(SePublicDefaultUnrestrictedDacl, 80 AclLength, 81 ACL_REVISION); 82 83 RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl, 84 ACL_REVISION, 85 GENERIC_EXECUTE, 86 SeWorldSid); 87 88 RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl, 89 ACL_REVISION, 90 GENERIC_ALL, 91 SeLocalSystemSid); 92 93 RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl, 94 ACL_REVISION, 95 GENERIC_ALL, 96 SeAliasAdminsSid); 97 98 RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl, 99 ACL_REVISION, 100 GENERIC_READ | GENERIC_EXECUTE | READ_CONTROL, 101 SeRestrictedCodeSid); 102 103 /* create PublicOpenDacl */ 104 AclLength = sizeof(ACL) + 105 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) + 106 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) + 107 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)); 108 109 SePublicOpenDacl = ExAllocatePoolWithTag(PagedPool, 110 AclLength, 111 TAG_ACL); 112 if (SePublicOpenDacl == NULL) 113 return FALSE; 114 115 RtlCreateAcl(SePublicOpenDacl, 116 AclLength, 117 ACL_REVISION); 118 119 RtlAddAccessAllowedAce(SePublicOpenDacl, 120 ACL_REVISION, 121 GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE, 122 SeWorldSid); 123 124 RtlAddAccessAllowedAce(SePublicOpenDacl, 125 ACL_REVISION, 126 GENERIC_ALL, 127 SeLocalSystemSid); 128 129 RtlAddAccessAllowedAce(SePublicOpenDacl, 130 ACL_REVISION, 131 GENERIC_ALL, 132 SeAliasAdminsSid); 133 134 /* create PublicOpenUnrestrictedDacl */ 135 AclLength = sizeof(ACL) + 136 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) + 137 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) + 138 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)) + 139 (sizeof(ACE) + RtlLengthSid(SeRestrictedCodeSid)); 140 141 SePublicOpenUnrestrictedDacl = ExAllocatePoolWithTag(PagedPool, 142 AclLength, 143 TAG_ACL); 144 if (SePublicOpenUnrestrictedDacl == NULL) 145 return FALSE; 146 147 RtlCreateAcl(SePublicOpenUnrestrictedDacl, 148 AclLength, 149 ACL_REVISION); 150 151 RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl, 152 ACL_REVISION, 153 GENERIC_ALL, 154 SeWorldSid); 155 156 RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl, 157 ACL_REVISION, 158 GENERIC_ALL, 159 SeLocalSystemSid); 160 161 RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl, 162 ACL_REVISION, 163 GENERIC_ALL, 164 SeAliasAdminsSid); 165 166 RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl, 167 ACL_REVISION, 168 GENERIC_READ | GENERIC_EXECUTE, 169 SeRestrictedCodeSid); 170 171 /* create SystemDefaultDacl */ 172 AclLength = sizeof(ACL) + 173 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) + 174 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)); 175 176 SeSystemDefaultDacl = ExAllocatePoolWithTag(PagedPool, 177 AclLength, 178 TAG_ACL); 179 if (SeSystemDefaultDacl == NULL) 180 return FALSE; 181 182 RtlCreateAcl(SeSystemDefaultDacl, 183 AclLength, 184 ACL_REVISION); 185 186 RtlAddAccessAllowedAce(SeSystemDefaultDacl, 187 ACL_REVISION, 188 GENERIC_ALL, 189 SeLocalSystemSid); 190 191 RtlAddAccessAllowedAce(SeSystemDefaultDacl, 192 ACL_REVISION, 193 GENERIC_READ | GENERIC_EXECUTE | READ_CONTROL, 194 SeAliasAdminsSid); 195 196 /* create UnrestrictedDacl */ 197 AclLength = sizeof(ACL) + 198 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) + 199 (sizeof(ACE) + RtlLengthSid(SeRestrictedCodeSid)); 200 201 SeUnrestrictedDacl = ExAllocatePoolWithTag(PagedPool, 202 AclLength, 203 TAG_ACL); 204 if (SeUnrestrictedDacl == NULL) 205 return FALSE; 206 207 RtlCreateAcl(SeUnrestrictedDacl, 208 AclLength, 209 ACL_REVISION); 210 211 RtlAddAccessAllowedAce(SeUnrestrictedDacl, 212 ACL_REVISION, 213 GENERIC_ALL, 214 SeWorldSid); 215 216 RtlAddAccessAllowedAce(SeUnrestrictedDacl, 217 ACL_REVISION, 218 GENERIC_READ | GENERIC_EXECUTE, 219 SeRestrictedCodeSid); 220 221 /* create SystemAnonymousLogonDacl */ 222 AclLength = sizeof(ACL) + 223 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) + 224 (sizeof(ACE) + RtlLengthSid(SeAnonymousLogonSid)); 225 226 SeSystemAnonymousLogonDacl = ExAllocatePoolWithTag(PagedPool, 227 AclLength, 228 TAG_ACL); 229 if (SeSystemAnonymousLogonDacl == NULL) 230 return FALSE; 231 232 RtlCreateAcl(SeSystemAnonymousLogonDacl, 233 AclLength, 234 ACL_REVISION); 235 236 RtlAddAccessAllowedAce(SeSystemAnonymousLogonDacl, 237 ACL_REVISION, 238 GENERIC_ALL, 239 SeWorldSid); 240 241 RtlAddAccessAllowedAce(SeSystemAnonymousLogonDacl, 242 ACL_REVISION, 243 GENERIC_ALL, 244 SeAnonymousLogonSid); 245 246 return TRUE; 247 } 248 249 NTSTATUS 250 NTAPI 251 SepCreateImpersonationTokenDacl( 252 _In_ PTOKEN Token, 253 _In_ PTOKEN PrimaryToken, 254 _Out_ PACL* Dacl) 255 { 256 ULONG AclLength; 257 PACL TokenDacl; 258 259 PAGED_CODE(); 260 261 *Dacl = NULL; 262 263 AclLength = sizeof(ACL) + 264 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)) + 265 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) + 266 (sizeof(ACE) + RtlLengthSid(SeRestrictedCodeSid)) + 267 (sizeof(ACE) + RtlLengthSid(Token->UserAndGroups->Sid)) + 268 (sizeof(ACE) + RtlLengthSid(PrimaryToken->UserAndGroups->Sid)); 269 270 TokenDacl = ExAllocatePoolWithTag(PagedPool, AclLength, TAG_ACL); 271 if (TokenDacl == NULL) 272 { 273 return STATUS_INSUFFICIENT_RESOURCES; 274 } 275 276 RtlCreateAcl(TokenDacl, AclLength, ACL_REVISION); 277 RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL, 278 Token->UserAndGroups->Sid); 279 RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL, 280 PrimaryToken->UserAndGroups->Sid); 281 RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL, 282 SeAliasAdminsSid); 283 RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL, 284 SeLocalSystemSid); 285 286 if (Token->RestrictedSids != NULL || PrimaryToken->RestrictedSids != NULL) 287 { 288 RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL, 289 SeRestrictedCodeSid); 290 } 291 292 *Dacl = TokenDacl; 293 294 return STATUS_SUCCESS; 295 } 296 297 NTSTATUS 298 NTAPI 299 SepCaptureAcl(IN PACL InputAcl, 300 IN KPROCESSOR_MODE AccessMode, 301 IN POOL_TYPE PoolType, 302 IN BOOLEAN CaptureIfKernel, 303 OUT PACL *CapturedAcl) 304 { 305 PACL NewAcl; 306 ULONG AclSize = 0; 307 NTSTATUS Status = STATUS_SUCCESS; 308 309 PAGED_CODE(); 310 311 if (AccessMode != KernelMode) 312 { 313 _SEH2_TRY 314 { 315 ProbeForRead(InputAcl, 316 sizeof(ACL), 317 sizeof(ULONG)); 318 AclSize = InputAcl->AclSize; 319 ProbeForRead(InputAcl, 320 AclSize, 321 sizeof(ULONG)); 322 } 323 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 324 { 325 /* Return the exception code */ 326 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 327 } 328 _SEH2_END; 329 330 NewAcl = ExAllocatePoolWithTag(PoolType, 331 AclSize, 332 TAG_ACL); 333 if (NewAcl != NULL) 334 { 335 _SEH2_TRY 336 { 337 RtlCopyMemory(NewAcl, 338 InputAcl, 339 AclSize); 340 341 *CapturedAcl = NewAcl; 342 } 343 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 344 { 345 /* Free the ACL and return the exception code */ 346 ExFreePoolWithTag(NewAcl, TAG_ACL); 347 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 348 } 349 _SEH2_END; 350 } 351 else 352 { 353 Status = STATUS_INSUFFICIENT_RESOURCES; 354 } 355 } 356 else if (!CaptureIfKernel) 357 { 358 *CapturedAcl = InputAcl; 359 } 360 else 361 { 362 AclSize = InputAcl->AclSize; 363 364 NewAcl = ExAllocatePoolWithTag(PoolType, 365 AclSize, 366 TAG_ACL); 367 368 if (NewAcl != NULL) 369 { 370 RtlCopyMemory(NewAcl, 371 InputAcl, 372 AclSize); 373 374 *CapturedAcl = NewAcl; 375 } 376 else 377 { 378 Status = STATUS_INSUFFICIENT_RESOURCES; 379 } 380 } 381 382 return Status; 383 } 384 385 VOID 386 NTAPI 387 SepReleaseAcl(IN PACL CapturedAcl, 388 IN KPROCESSOR_MODE AccessMode, 389 IN BOOLEAN CaptureIfKernel) 390 { 391 PAGED_CODE(); 392 393 if (CapturedAcl != NULL && 394 (AccessMode != KernelMode || 395 (AccessMode == KernelMode && CaptureIfKernel))) 396 { 397 ExFreePoolWithTag(CapturedAcl, TAG_ACL); 398 } 399 } 400 401 BOOLEAN 402 SepShouldPropagateAce( 403 _In_ UCHAR AceFlags, 404 _Out_ PUCHAR NewAceFlags, 405 _In_ BOOLEAN IsInherited, 406 _In_ BOOLEAN IsDirectoryObject) 407 { 408 if (!IsInherited) 409 { 410 *NewAceFlags = AceFlags; 411 return TRUE; 412 } 413 414 if (!IsDirectoryObject) 415 { 416 if (AceFlags & OBJECT_INHERIT_ACE) 417 { 418 *NewAceFlags = AceFlags & ~VALID_INHERIT_FLAGS; 419 return TRUE; 420 } 421 return FALSE; 422 } 423 424 if (AceFlags & NO_PROPAGATE_INHERIT_ACE) 425 { 426 if (AceFlags & CONTAINER_INHERIT_ACE) 427 { 428 *NewAceFlags = AceFlags & ~VALID_INHERIT_FLAGS; 429 return TRUE; 430 } 431 return FALSE; 432 } 433 434 if (AceFlags & CONTAINER_INHERIT_ACE) 435 { 436 *NewAceFlags = CONTAINER_INHERIT_ACE | (AceFlags & OBJECT_INHERIT_ACE) | (AceFlags & ~VALID_INHERIT_FLAGS); 437 return TRUE; 438 } 439 440 if (AceFlags & OBJECT_INHERIT_ACE) 441 { 442 *NewAceFlags = INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE | (AceFlags & ~VALID_INHERIT_FLAGS); 443 return TRUE; 444 } 445 446 return FALSE; 447 } 448 449 NTSTATUS 450 SepPropagateAcl( 451 _Out_writes_bytes_opt_(AclLength) PACL AclDest, 452 _Inout_ PULONG AclLength, 453 _In_reads_bytes_(AclSource->AclSize) PACL AclSource, 454 _In_ PSID Owner, 455 _In_ PSID Group, 456 _In_ BOOLEAN IsInherited, 457 _In_ BOOLEAN IsDirectoryObject, 458 _In_ PGENERIC_MAPPING GenericMapping) 459 { 460 ACCESS_MASK Mask; 461 PACCESS_ALLOWED_ACE AceSource; 462 PACCESS_ALLOWED_ACE AceDest; 463 PUCHAR CurrentDest; 464 PUCHAR CurrentSource; 465 ULONG i; 466 ULONG Written; 467 UCHAR AceFlags; 468 USHORT AceSize; 469 USHORT AceCount = 0; 470 PSID Sid; 471 BOOLEAN WriteTwoAces; 472 473 ASSERT(RtlValidAcl(AclSource)); 474 ASSERT(AclSource->AclSize % sizeof(ULONG) == 0); 475 ASSERT(AclSource->Sbz1 == 0); 476 ASSERT(AclSource->Sbz2 == 0); 477 478 Written = 0; 479 if (*AclLength >= Written + sizeof(ACL)) 480 { 481 RtlCopyMemory(AclDest, 482 AclSource, 483 sizeof(ACL)); 484 } 485 Written += sizeof(ACL); 486 487 CurrentDest = (PUCHAR)(AclDest + 1); 488 CurrentSource = (PUCHAR)(AclSource + 1); 489 for (i = 0; i < AclSource->AceCount; i++) 490 { 491 ASSERT((ULONG_PTR)CurrentDest % sizeof(ULONG) == 0); 492 ASSERT((ULONG_PTR)CurrentSource % sizeof(ULONG) == 0); 493 AceDest = (PACCESS_ALLOWED_ACE)CurrentDest; 494 AceSource = (PACCESS_ALLOWED_ACE)CurrentSource; 495 496 if (AceSource->Header.AceType > ACCESS_MAX_MS_V2_ACE_TYPE) 497 { 498 /* FIXME: handle object & compound ACEs */ 499 AceSize = AceSource->Header.AceSize; 500 501 if (*AclLength >= Written + AceSize) 502 { 503 RtlCopyMemory(AceDest, AceSource, AceSize); 504 } 505 CurrentDest += AceSize; 506 CurrentSource += AceSize; 507 Written += AceSize; 508 AceCount++; 509 continue; 510 } 511 512 /* These all have the same structure */ 513 ASSERT(AceSource->Header.AceType == ACCESS_ALLOWED_ACE_TYPE || 514 AceSource->Header.AceType == ACCESS_DENIED_ACE_TYPE || 515 AceSource->Header.AceType == SYSTEM_AUDIT_ACE_TYPE || 516 AceSource->Header.AceType == SYSTEM_ALARM_ACE_TYPE); 517 518 ASSERT(AceSource->Header.AceSize % sizeof(ULONG) == 0); 519 ASSERT(AceSource->Header.AceSize >= sizeof(*AceSource)); 520 if (!SepShouldPropagateAce(AceSource->Header.AceFlags, 521 &AceFlags, 522 IsInherited, 523 IsDirectoryObject)) 524 { 525 CurrentSource += AceSource->Header.AceSize; 526 continue; 527 } 528 529 /* FIXME: filter out duplicate ACEs */ 530 AceSize = AceSource->Header.AceSize; 531 Mask = AceSource->Mask; 532 Sid = (PSID)&AceSource->SidStart; 533 ASSERT(AceSize >= FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(Sid)); 534 535 WriteTwoAces = FALSE; 536 /* Map effective ACE to specific rights */ 537 if (!(AceFlags & INHERIT_ONLY_ACE)) 538 { 539 RtlMapGenericMask(&Mask, GenericMapping); 540 Mask &= GenericMapping->GenericAll; 541 542 if (IsInherited) 543 { 544 if (RtlEqualSid(Sid, SeCreatorOwnerSid)) 545 Sid = Owner; 546 else if (RtlEqualSid(Sid, SeCreatorGroupSid)) 547 Sid = Group; 548 AceSize = FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(Sid); 549 550 /* 551 * A generic container ACE becomes two ACEs: 552 * - a specific effective ACE with no inheritance flags 553 * - an inherit-only ACE that keeps the generic rights 554 */ 555 if (IsDirectoryObject && 556 (AceFlags & CONTAINER_INHERIT_ACE) && 557 (Mask != AceSource->Mask || Sid != (PSID)&AceSource->SidStart)) 558 { 559 WriteTwoAces = TRUE; 560 } 561 } 562 } 563 564 while (1) 565 { 566 if (*AclLength >= Written + AceSize) 567 { 568 AceDest->Header.AceType = AceSource->Header.AceType; 569 AceDest->Header.AceFlags = WriteTwoAces ? AceFlags & ~VALID_INHERIT_FLAGS 570 : AceFlags; 571 AceDest->Header.AceSize = AceSize; 572 AceDest->Mask = Mask; 573 RtlCopySid(AceSize - FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart), 574 (PSID)&AceDest->SidStart, 575 Sid); 576 } 577 Written += AceSize; 578 579 AceCount++; 580 CurrentDest += AceSize; 581 582 if (!WriteTwoAces) 583 break; 584 585 /* Second ACE keeps all the generics from the source ACE */ 586 WriteTwoAces = FALSE; 587 AceDest = (PACCESS_ALLOWED_ACE)CurrentDest; 588 AceSize = AceSource->Header.AceSize; 589 Mask = AceSource->Mask; 590 Sid = (PSID)&AceSource->SidStart; 591 AceFlags |= INHERIT_ONLY_ACE; 592 } 593 594 CurrentSource += AceSource->Header.AceSize; 595 } 596 597 if (*AclLength >= sizeof(ACL)) 598 { 599 AclDest->AceCount = AceCount; 600 AclDest->AclSize = Written; 601 } 602 603 if (Written > *AclLength) 604 { 605 *AclLength = Written; 606 return STATUS_BUFFER_TOO_SMALL; 607 } 608 *AclLength = Written; 609 return STATUS_SUCCESS; 610 } 611 612 PACL 613 SepSelectAcl( 614 _In_opt_ PACL ExplicitAcl, 615 _In_ BOOLEAN ExplicitPresent, 616 _In_ BOOLEAN ExplicitDefaulted, 617 _In_opt_ PACL ParentAcl, 618 _In_opt_ PACL DefaultAcl, 619 _Out_ PULONG AclLength, 620 _In_ PSID Owner, 621 _In_ PSID Group, 622 _Out_ PBOOLEAN AclPresent, 623 _Out_ PBOOLEAN IsInherited, 624 _In_ BOOLEAN IsDirectoryObject, 625 _In_ PGENERIC_MAPPING GenericMapping) 626 { 627 PACL Acl; 628 NTSTATUS Status; 629 630 *AclPresent = TRUE; 631 if (ExplicitPresent && !ExplicitDefaulted) 632 { 633 Acl = ExplicitAcl; 634 } 635 else 636 { 637 if (ParentAcl) 638 { 639 *IsInherited = TRUE; 640 *AclLength = 0; 641 Status = SepPropagateAcl(NULL, 642 AclLength, 643 ParentAcl, 644 Owner, 645 Group, 646 *IsInherited, 647 IsDirectoryObject, 648 GenericMapping); 649 ASSERT(Status == STATUS_BUFFER_TOO_SMALL); 650 651 /* Use the parent ACL only if it's not empty */ 652 if (*AclLength != sizeof(ACL)) 653 return ParentAcl; 654 } 655 656 if (ExplicitPresent) 657 { 658 Acl = ExplicitAcl; 659 } 660 else if (DefaultAcl) 661 { 662 Acl = DefaultAcl; 663 } 664 else 665 { 666 *AclPresent = FALSE; 667 Acl = NULL; 668 } 669 } 670 671 *IsInherited = FALSE; 672 *AclLength = 0; 673 if (Acl) 674 { 675 /* Get the length */ 676 Status = SepPropagateAcl(NULL, 677 AclLength, 678 Acl, 679 Owner, 680 Group, 681 *IsInherited, 682 IsDirectoryObject, 683 GenericMapping); 684 ASSERT(Status == STATUS_BUFFER_TOO_SMALL); 685 } 686 return Acl; 687 } 688 689 /* EOF */ 690