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