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