1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/ob/obsecure.c 5 * PURPOSE: SRM Interface of the Object Manager 6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 7 * Eric Kohl 8 */ 9 10 /* INCLUDES *****************************************************************/ 11 12 #include <ntoskrnl.h> 13 #define NDEBUG 14 #include <debug.h> 15 16 /* PRIVATE FUNCTIONS *********************************************************/ 17 18 NTSTATUS 19 NTAPI 20 ObAssignObjectSecurityDescriptor(IN PVOID Object, 21 IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL, 22 IN POOL_TYPE PoolType) 23 { 24 POBJECT_HEADER ObjectHeader; 25 NTSTATUS Status; 26 PSECURITY_DESCRIPTOR NewSd; 27 PEX_FAST_REF FastRef; 28 PAGED_CODE(); 29 30 /* Get the object header */ 31 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); 32 FastRef = (PEX_FAST_REF)&ObjectHeader->SecurityDescriptor; 33 if (!SecurityDescriptor) 34 { 35 /* Nothing to assign */ 36 ExInitializeFastReference(FastRef, NULL); 37 return STATUS_SUCCESS; 38 } 39 40 /* Add it to our internal cache */ 41 Status = ObLogSecurityDescriptor(SecurityDescriptor, 42 &NewSd, 43 MAX_FAST_REFS + 1); 44 if (NT_SUCCESS(Status)) 45 { 46 /* Free the old copy */ 47 ExFreePoolWithTag(SecurityDescriptor, TAG_SD); 48 49 /* Set the new pointer */ 50 ASSERT(NewSd); 51 ExInitializeFastReference(FastRef, NewSd); 52 } 53 54 /* Return status */ 55 return Status; 56 } 57 58 NTSTATUS 59 NTAPI 60 ObDeassignSecurity(IN OUT PSECURITY_DESCRIPTOR *SecurityDescriptor) 61 { 62 EX_FAST_REF FastRef; 63 ULONG Count; 64 PSECURITY_DESCRIPTOR OldSecurityDescriptor; 65 66 /* Get the fast reference and capture it */ 67 FastRef = *(PEX_FAST_REF)SecurityDescriptor; 68 69 /* Don't free again later */ 70 *SecurityDescriptor = NULL; 71 72 /* Get the descriptor and reference count */ 73 OldSecurityDescriptor = ExGetObjectFastReference(FastRef); 74 Count = ExGetCountFastReference(FastRef); 75 76 /* Dereference the descriptor */ 77 ObDereferenceSecurityDescriptor(OldSecurityDescriptor, Count + 1); 78 79 /* All done */ 80 return STATUS_SUCCESS; 81 } 82 83 NTSTATUS 84 NTAPI 85 ObQuerySecurityDescriptorInfo(IN PVOID Object, 86 IN PSECURITY_INFORMATION SecurityInformation, 87 OUT PSECURITY_DESCRIPTOR SecurityDescriptor, 88 IN OUT PULONG Length, 89 IN PSECURITY_DESCRIPTOR *OutputSecurityDescriptor) 90 { 91 POBJECT_HEADER ObjectHeader; 92 NTSTATUS Status; 93 PSECURITY_DESCRIPTOR ObjectSd; 94 PAGED_CODE(); 95 96 /* Get the object header */ 97 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); 98 99 /* Get the SD */ 100 ObjectSd = ObpReferenceSecurityDescriptor(ObjectHeader); 101 102 /* Query the information */ 103 Status = SeQuerySecurityDescriptorInfo(SecurityInformation, 104 SecurityDescriptor, 105 Length, 106 &ObjectSd); 107 108 /* Check if we have an object SD and dereference it, if so */ 109 if (ObjectSd) ObDereferenceSecurityDescriptor(ObjectSd, 1); 110 111 /* Return status */ 112 return Status; 113 } 114 115 NTSTATUS 116 NTAPI 117 ObSetSecurityDescriptorInfo(IN PVOID Object, 118 IN PSECURITY_INFORMATION SecurityInformation, 119 IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor, 120 IN OUT PSECURITY_DESCRIPTOR *OutputSecurityDescriptor, 121 IN POOL_TYPE PoolType, 122 IN PGENERIC_MAPPING GenericMapping) 123 { 124 NTSTATUS Status; 125 POBJECT_HEADER ObjectHeader; 126 PSECURITY_DESCRIPTOR OldDescriptor, NewDescriptor, CachedDescriptor; 127 PEX_FAST_REF FastRef; 128 EX_FAST_REF OldValue; 129 ULONG Count; 130 PAGED_CODE(); 131 132 /* Get the object header */ 133 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); 134 while (TRUE) 135 { 136 /* Reference the old descriptor */ 137 OldDescriptor = ObpReferenceSecurityDescriptor(ObjectHeader); 138 NewDescriptor = OldDescriptor; 139 140 /* Set the SD information */ 141 Status = SeSetSecurityDescriptorInfo(Object, 142 SecurityInformation, 143 SecurityDescriptor, 144 &NewDescriptor, 145 PoolType, 146 GenericMapping); 147 if (!NT_SUCCESS(Status)) 148 { 149 /* We failed, dereference the old one */ 150 if (OldDescriptor) ObDereferenceSecurityDescriptor(OldDescriptor, 1); 151 break; 152 } 153 154 /* Now add this to the cache */ 155 Status = ObLogSecurityDescriptor(NewDescriptor, 156 &CachedDescriptor, 157 MAX_FAST_REFS + 1); 158 159 /* Let go of our uncached copy */ 160 ExFreePool(NewDescriptor); 161 162 /* Check for success */ 163 if (!NT_SUCCESS(Status)) 164 { 165 /* We failed, dereference the old one */ 166 ObDereferenceSecurityDescriptor(OldDescriptor, 1); 167 break; 168 } 169 170 /* Do the swap */ 171 FastRef = (PEX_FAST_REF)OutputSecurityDescriptor; 172 OldValue = ExCompareSwapFastReference(FastRef, 173 CachedDescriptor, 174 OldDescriptor); 175 176 /* Make sure the swap worked */ 177 if (ExGetObjectFastReference(OldValue) == OldDescriptor) 178 { 179 /* Flush waiters */ 180 ObpAcquireObjectLock(ObjectHeader); 181 ObpReleaseObjectLock(ObjectHeader); 182 183 /* And dereference the old one */ 184 Count = ExGetCountFastReference(OldValue); 185 ObDereferenceSecurityDescriptor(OldDescriptor, Count + 2); 186 break; 187 } 188 else 189 { 190 /* Someone changed it behind our back -- try again */ 191 ObDereferenceSecurityDescriptor(OldDescriptor, 1); 192 ObDereferenceSecurityDescriptor(CachedDescriptor, 193 MAX_FAST_REFS + 1); 194 } 195 } 196 197 /* Return status */ 198 return Status; 199 } 200 201 BOOLEAN 202 NTAPI 203 ObCheckCreateObjectAccess(IN PVOID Object, 204 IN ACCESS_MASK CreateAccess, 205 IN PACCESS_STATE AccessState, 206 IN PUNICODE_STRING ComponentName, 207 IN BOOLEAN LockHeld, 208 IN KPROCESSOR_MODE AccessMode, 209 OUT PNTSTATUS AccessStatus) 210 { 211 POBJECT_HEADER ObjectHeader; 212 POBJECT_TYPE ObjectType; 213 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; 214 BOOLEAN SdAllocated; 215 BOOLEAN Result = TRUE; 216 ACCESS_MASK GrantedAccess = 0; 217 PPRIVILEGE_SET Privileges = NULL; 218 NTSTATUS Status; 219 PAGED_CODE(); 220 221 /* Get the header and type */ 222 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); 223 ObjectType = ObjectHeader->Type; 224 225 /* Get the security descriptor */ 226 Status = ObGetObjectSecurity(Object, &SecurityDescriptor, &SdAllocated); 227 if (!NT_SUCCESS(Status)) 228 { 229 /* We failed */ 230 *AccessStatus = Status; 231 return FALSE; 232 } 233 234 /* Lock the security context */ 235 SeLockSubjectContext(&AccessState->SubjectSecurityContext); 236 237 /* Check if we have an SD */ 238 if (SecurityDescriptor) 239 { 240 /* Now do the entire access check */ 241 Result = SeAccessCheck(SecurityDescriptor, 242 &AccessState->SubjectSecurityContext, 243 TRUE, 244 CreateAccess, 245 0, 246 &Privileges, 247 &ObjectType->TypeInfo.GenericMapping, 248 AccessMode, 249 &GrantedAccess, 250 AccessStatus); 251 if (Privileges) 252 { 253 /* We got privileges, append them to the access state and free them */ 254 Status = SeAppendPrivileges(AccessState, Privileges); 255 SeFreePrivileges(Privileges); 256 } 257 } 258 259 /* We're done, unlock the context and release security */ 260 SeUnlockSubjectContext(&AccessState->SubjectSecurityContext); 261 ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated); 262 return Result; 263 } 264 265 BOOLEAN 266 NTAPI 267 ObpCheckTraverseAccess(IN PVOID Object, 268 IN ACCESS_MASK TraverseAccess, 269 IN PACCESS_STATE AccessState OPTIONAL, 270 IN BOOLEAN LockHeld, 271 IN KPROCESSOR_MODE AccessMode, 272 OUT PNTSTATUS AccessStatus) 273 { 274 POBJECT_HEADER ObjectHeader; 275 POBJECT_TYPE ObjectType; 276 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; 277 BOOLEAN SdAllocated; 278 BOOLEAN Result; 279 ACCESS_MASK GrantedAccess = 0; 280 PPRIVILEGE_SET Privileges = NULL; 281 NTSTATUS Status; 282 PAGED_CODE(); 283 284 /* Get the header and type */ 285 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); 286 ObjectType = ObjectHeader->Type; 287 288 /* Get the security descriptor */ 289 Status = ObGetObjectSecurity(Object, &SecurityDescriptor, &SdAllocated); 290 if (!NT_SUCCESS(Status)) 291 { 292 /* We failed */ 293 *AccessStatus = Status; 294 return FALSE; 295 } 296 297 /* First try to perform a fast traverse check 298 * If it fails, then the entire access check will 299 * have to be done. 300 */ 301 Result = SeFastTraverseCheck(SecurityDescriptor, 302 AccessState, 303 FILE_WRITE_DATA, 304 AccessMode); 305 if (Result) 306 { 307 ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated); 308 return TRUE; 309 } 310 311 /* Lock the security context */ 312 SeLockSubjectContext(&AccessState->SubjectSecurityContext); 313 314 /* Now do the entire access check */ 315 Result = SeAccessCheck(SecurityDescriptor, 316 &AccessState->SubjectSecurityContext, 317 TRUE, 318 TraverseAccess, 319 0, 320 &Privileges, 321 &ObjectType->TypeInfo.GenericMapping, 322 AccessMode, 323 &GrantedAccess, 324 AccessStatus); 325 if (Privileges) 326 { 327 /* We got privileges, append them to the access state and free them */ 328 Status = SeAppendPrivileges(AccessState, Privileges); 329 SeFreePrivileges(Privileges); 330 } 331 332 /* We're done, unlock the context and release security */ 333 SeUnlockSubjectContext(&AccessState->SubjectSecurityContext); 334 ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated); 335 return Result; 336 } 337 338 BOOLEAN 339 NTAPI 340 ObpCheckObjectReference(IN PVOID Object, 341 IN OUT PACCESS_STATE AccessState, 342 IN BOOLEAN LockHeld, 343 IN KPROCESSOR_MODE AccessMode, 344 OUT PNTSTATUS AccessStatus) 345 { 346 POBJECT_HEADER ObjectHeader; 347 POBJECT_TYPE ObjectType; 348 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; 349 BOOLEAN SdAllocated; 350 BOOLEAN Result; 351 ACCESS_MASK GrantedAccess = 0; 352 PPRIVILEGE_SET Privileges = NULL; 353 NTSTATUS Status; 354 PAGED_CODE(); 355 356 /* Get the header and type */ 357 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); 358 ObjectType = ObjectHeader->Type; 359 360 /* Get the security descriptor */ 361 Status = ObGetObjectSecurity(Object, &SecurityDescriptor, &SdAllocated); 362 if (!NT_SUCCESS(Status)) 363 { 364 /* We failed */ 365 *AccessStatus = Status; 366 return FALSE; 367 } 368 369 /* Lock the security context */ 370 SeLockSubjectContext(&AccessState->SubjectSecurityContext); 371 372 /* Now do the entire access check */ 373 Result = SeAccessCheck(SecurityDescriptor, 374 &AccessState->SubjectSecurityContext, 375 TRUE, 376 AccessState->RemainingDesiredAccess, 377 AccessState->PreviouslyGrantedAccess, 378 &Privileges, 379 &ObjectType->TypeInfo.GenericMapping, 380 AccessMode, 381 &GrantedAccess, 382 AccessStatus); 383 if (Result) 384 { 385 /* Update the access state */ 386 AccessState->RemainingDesiredAccess &= ~GrantedAccess; 387 AccessState->PreviouslyGrantedAccess |= GrantedAccess; 388 } 389 390 /* Check if we have an SD */ 391 if (SecurityDescriptor) 392 { 393 /* Do audit alarm */ 394 #if 0 395 SeObjectReferenceAuditAlarm(&AccessState->OperationID, 396 Object, 397 SecurityDescriptor, 398 &AccessState->SubjectSecurityContext, 399 AccessState->RemainingDesiredAccess | 400 AccessState->PreviouslyGrantedAccess, 401 ((PAUX_ACCESS_DATA)(AccessState->AuxData))-> 402 PrivilegeSet, 403 Result, 404 AccessMode); 405 #endif 406 } 407 408 /* We're done, unlock the context and release security */ 409 SeUnlockSubjectContext(&AccessState->SubjectSecurityContext); 410 ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated); 411 return Result; 412 } 413 414 /*++ 415 * @name ObCheckObjectAccess 416 * 417 * The ObCheckObjectAccess routine <FILLMEIN> 418 * 419 * @param Object 420 * <FILLMEIN> 421 * 422 * @param AccessState 423 * <FILLMEIN> 424 * 425 * @param LockHeld 426 * <FILLMEIN> 427 * 428 * @param AccessMode 429 * <FILLMEIN> 430 * 431 * @param ReturnedStatus 432 * <FILLMEIN> 433 * 434 * @return TRUE if access was granted, FALSE otherwise. 435 * 436 * @remarks None. 437 * 438 *--*/ 439 BOOLEAN 440 NTAPI 441 ObCheckObjectAccess(IN PVOID Object, 442 IN OUT PACCESS_STATE AccessState, 443 IN BOOLEAN LockHeld, 444 IN KPROCESSOR_MODE AccessMode, 445 OUT PNTSTATUS ReturnedStatus) 446 { 447 POBJECT_HEADER ObjectHeader; 448 POBJECT_TYPE ObjectType; 449 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; 450 BOOLEAN SdAllocated; 451 NTSTATUS Status; 452 BOOLEAN Result; 453 ACCESS_MASK GrantedAccess; 454 PPRIVILEGE_SET Privileges = NULL; 455 PAGED_CODE(); 456 457 /* Get the object header and type */ 458 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); 459 ObjectType = ObjectHeader->Type; 460 461 /* Get security information */ 462 Status = ObGetObjectSecurity(Object, &SecurityDescriptor, &SdAllocated); 463 if (!NT_SUCCESS(Status)) 464 { 465 /* Return failure */ 466 *ReturnedStatus = Status; 467 return FALSE; 468 } 469 else if (!SecurityDescriptor) 470 { 471 /* Otherwise, if we don't actually have an SD, return success */ 472 *ReturnedStatus = Status; 473 return TRUE; 474 } 475 476 /* Lock the security context */ 477 SeLockSubjectContext(&AccessState->SubjectSecurityContext); 478 479 /* Now do the entire access check */ 480 Result = SeAccessCheck(SecurityDescriptor, 481 &AccessState->SubjectSecurityContext, 482 TRUE, 483 AccessState->RemainingDesiredAccess, 484 AccessState->PreviouslyGrantedAccess, 485 &Privileges, 486 &ObjectType->TypeInfo.GenericMapping, 487 AccessMode, 488 &GrantedAccess, 489 ReturnedStatus); 490 if (Privileges) 491 { 492 /* We got privileges, append them to the access state and free them */ 493 Status = SeAppendPrivileges(AccessState, Privileges); 494 SeFreePrivileges(Privileges); 495 } 496 497 /* Check if access was granted */ 498 if (Result) 499 { 500 /* Update the access state */ 501 AccessState->RemainingDesiredAccess &= ~(GrantedAccess | 502 MAXIMUM_ALLOWED); 503 AccessState->PreviouslyGrantedAccess |= GrantedAccess; 504 } 505 506 /* Do audit alarm */ 507 SeOpenObjectAuditAlarm(&ObjectType->Name, 508 Object, 509 NULL, 510 SecurityDescriptor, 511 AccessState, 512 FALSE, 513 Result, 514 AccessMode, 515 &AccessState->GenerateOnClose); 516 517 /* We're done, unlock the context and release security */ 518 SeUnlockSubjectContext(&AccessState->SubjectSecurityContext); 519 ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated); 520 return Result; 521 } 522 523 /* PUBLIC FUNCTIONS **********************************************************/ 524 525 /*++ 526 * @name ObAssignSecurity 527 * @implemented NT4 528 * 529 * The ObAssignSecurity routine <FILLMEIN> 530 * 531 * @param AccessState 532 * <FILLMEIN> 533 * 534 * @param SecurityDescriptor 535 * <FILLMEIN> 536 * 537 * @param Object 538 * <FILLMEIN> 539 * 540 * @param Type 541 * <FILLMEIN> 542 * 543 * @return STATUS_SUCCESS or appropriate error value. 544 * 545 * @remarks None. 546 * 547 *--*/ 548 NTSTATUS 549 NTAPI 550 ObAssignSecurity(IN PACCESS_STATE AccessState, 551 IN PSECURITY_DESCRIPTOR SecurityDescriptor, 552 IN PVOID Object, 553 IN POBJECT_TYPE Type) 554 { 555 PSECURITY_DESCRIPTOR NewDescriptor; 556 NTSTATUS Status; 557 KIRQL CalloutIrql; 558 PAGED_CODE(); 559 560 /* Build the new security descriptor */ 561 Status = SeAssignSecurity(SecurityDescriptor, 562 AccessState->SecurityDescriptor, 563 &NewDescriptor, 564 (Type == ObDirectoryType), 565 &AccessState->SubjectSecurityContext, 566 &Type->TypeInfo.GenericMapping, 567 PagedPool); 568 if (!NT_SUCCESS(Status)) return Status; 569 570 /* Call the security method */ 571 ObpCalloutStart(&CalloutIrql); 572 Status = Type->TypeInfo.SecurityProcedure(Object, 573 AssignSecurityDescriptor, 574 NULL, 575 NewDescriptor, 576 NULL, 577 NULL, 578 PagedPool, 579 &Type->TypeInfo.GenericMapping); 580 ObpCalloutEnd(CalloutIrql, "Security", Type, Object); 581 582 /* Check for failure and deassign security if so */ 583 if (!NT_SUCCESS(Status)) SeDeassignSecurity(&NewDescriptor); 584 585 /* Return to caller */ 586 return Status; 587 } 588 589 /*++ 590 * @name ObGetObjectSecurity 591 * @implemented NT4 592 * 593 * The ObGetObjectSecurity routine <FILLMEIN> 594 * 595 * @param Object 596 * <FILLMEIN> 597 * 598 * @param SecurityDescriptor 599 * <FILLMEIN> 600 * 601 * @param MemoryAllocated 602 * <FILLMEIN> 603 * 604 * @return STATUS_SUCCESS or appropriate error value. 605 * 606 * @remarks None. 607 * 608 *--*/ 609 NTSTATUS 610 NTAPI 611 ObGetObjectSecurity(IN PVOID Object, 612 OUT PSECURITY_DESCRIPTOR *SecurityDescriptor, 613 OUT PBOOLEAN MemoryAllocated) 614 { 615 POBJECT_HEADER Header; 616 POBJECT_TYPE Type; 617 ULONG Length = 0; 618 NTSTATUS Status; 619 SECURITY_INFORMATION SecurityInformation; 620 KIRQL CalloutIrql; 621 PAGED_CODE(); 622 623 /* Get the object header and type */ 624 Header = OBJECT_TO_OBJECT_HEADER(Object); 625 Type = Header->Type; 626 627 /* Tell the caller that we didn't have to allocate anything yet */ 628 *MemoryAllocated = FALSE; 629 630 /* Check if the object uses default security */ 631 if (Type->TypeInfo.SecurityProcedure == SeDefaultObjectMethod) 632 { 633 /* Reference the descriptor */ 634 *SecurityDescriptor = ObpReferenceSecurityDescriptor(Header); 635 return STATUS_SUCCESS; 636 } 637 638 /* Set mask to query */ 639 SecurityInformation = OWNER_SECURITY_INFORMATION | 640 GROUP_SECURITY_INFORMATION | 641 DACL_SECURITY_INFORMATION | 642 SACL_SECURITY_INFORMATION; 643 644 /* Get the security descriptor size */ 645 ObpCalloutStart(&CalloutIrql); 646 Status = Type->TypeInfo.SecurityProcedure(Object, 647 QuerySecurityDescriptor, 648 &SecurityInformation, 649 *SecurityDescriptor, 650 &Length, 651 &Header->SecurityDescriptor, 652 Type->TypeInfo.PoolType, 653 &Type->TypeInfo.GenericMapping); 654 ObpCalloutEnd(CalloutIrql, "Security", Type, Object); 655 656 /* Check for failure */ 657 if (Status != STATUS_BUFFER_TOO_SMALL) return Status; 658 659 /* Allocate security descriptor */ 660 *SecurityDescriptor = ExAllocatePoolWithTag(PagedPool, 661 Length, 662 TAG_SEC_QUERY); 663 if (!(*SecurityDescriptor)) return STATUS_INSUFFICIENT_RESOURCES; 664 *MemoryAllocated = TRUE; 665 666 /* Query security descriptor */ 667 ObpCalloutStart(&CalloutIrql); 668 Status = Type->TypeInfo.SecurityProcedure(Object, 669 QuerySecurityDescriptor, 670 &SecurityInformation, 671 *SecurityDescriptor, 672 &Length, 673 &Header->SecurityDescriptor, 674 Type->TypeInfo.PoolType, 675 &Type->TypeInfo.GenericMapping); 676 ObpCalloutEnd(CalloutIrql, "Security", Type, Object); 677 678 /* Check for failure */ 679 if (!NT_SUCCESS(Status)) 680 { 681 /* Free the descriptor and tell the caller we failed */ 682 ExFreePoolWithTag(*SecurityDescriptor, TAG_SEC_QUERY); 683 *MemoryAllocated = FALSE; 684 } 685 686 /* Return status */ 687 return Status; 688 } 689 690 /*++ 691 * @name ObReleaseObjectSecurity 692 * @implemented NT4 693 * 694 * The ObReleaseObjectSecurity routine <FILLMEIN> 695 * 696 * @param SecurityDescriptor 697 * <FILLMEIN> 698 * 699 * @param MemoryAllocated 700 * <FILLMEIN> 701 * 702 * @return STATUS_SUCCESS or appropriate error value. 703 * 704 * @remarks None. 705 * 706 *--*/ 707 VOID 708 NTAPI 709 ObReleaseObjectSecurity(IN PSECURITY_DESCRIPTOR SecurityDescriptor, 710 IN BOOLEAN MemoryAllocated) 711 { 712 PAGED_CODE(); 713 714 /* Nothing to do in this case */ 715 if (!SecurityDescriptor) return; 716 717 /* Check if we had allocated it from memory */ 718 if (MemoryAllocated) 719 { 720 /* Free it */ 721 ExFreePool(SecurityDescriptor); 722 } 723 else 724 { 725 /* Otherwise this means we used an internal descriptor */ 726 ObDereferenceSecurityDescriptor(SecurityDescriptor, 1); 727 } 728 } 729 730 /*++ 731 * @name ObSetSecurityObjectByPointer 732 * @implemented NT5.1 733 * 734 * The ObSetSecurityObjectByPointer routine <FILLMEIN> 735 * 736 * @param SecurityDescriptor 737 * <FILLMEIN> 738 * 739 * @param MemoryAllocated 740 * <FILLMEIN> 741 * 742 * @return STATUS_SUCCESS or appropriate error value. 743 * 744 * @remarks None. 745 * 746 *--*/ 747 NTSTATUS 748 NTAPI 749 ObSetSecurityObjectByPointer(IN PVOID Object, 750 IN SECURITY_INFORMATION SecurityInformation, 751 IN PSECURITY_DESCRIPTOR SecurityDescriptor) 752 { 753 POBJECT_TYPE Type; 754 POBJECT_HEADER Header; 755 PAGED_CODE(); 756 757 /* Get the header and type */ 758 Header = OBJECT_TO_OBJECT_HEADER(Object); 759 Type = Header->Type; 760 761 /* Sanity check */ 762 ASSERT(SecurityDescriptor); 763 764 /* Call the security procedure */ 765 return Type->TypeInfo.SecurityProcedure(Object, 766 SetSecurityDescriptor, 767 &SecurityInformation, 768 SecurityDescriptor, 769 NULL, 770 &Header->SecurityDescriptor, 771 Type->TypeInfo.PoolType, 772 &Type->TypeInfo.GenericMapping); 773 } 774 775 /*++ 776 * @name NtQuerySecurityObject 777 * @implemented NT4 778 * 779 * The NtQuerySecurityObject routine <FILLMEIN> 780 * 781 * @param Handle 782 * <FILLMEIN> 783 * 784 * @param SecurityInformation 785 * <FILLMEIN> 786 * 787 * @param SecurityDescriptor 788 * <FILLMEIN> 789 * 790 * @param Length 791 * <FILLMEIN> 792 * 793 * @param ResultLength 794 * <FILLMEIN> 795 * 796 * @return STATUS_SUCCESS or appropriate error value. 797 * 798 * @remarks None. 799 * 800 *--*/ 801 NTSTATUS 802 NTAPI 803 NtQuerySecurityObject(IN HANDLE Handle, 804 IN SECURITY_INFORMATION SecurityInformation, 805 OUT PSECURITY_DESCRIPTOR SecurityDescriptor, 806 IN ULONG Length, 807 OUT PULONG ResultLength) 808 { 809 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 810 PVOID Object; 811 POBJECT_HEADER Header; 812 POBJECT_TYPE Type; 813 ACCESS_MASK DesiredAccess; 814 NTSTATUS Status; 815 PAGED_CODE(); 816 817 /* Check if we came from user mode */ 818 if (PreviousMode != KernelMode) 819 { 820 /* Enter SEH */ 821 _SEH2_TRY 822 { 823 /* Probe the SD and the length pointer */ 824 ProbeForWrite(SecurityDescriptor, Length, sizeof(ULONG)); 825 ProbeForWriteUlong(ResultLength); 826 } 827 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 828 { 829 /* Return the exception code */ 830 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 831 } 832 _SEH2_END; 833 } 834 835 /* Get the required access rights for the operation */ 836 SeQuerySecurityAccessMask(SecurityInformation, &DesiredAccess); 837 838 /* Reference the object */ 839 Status = ObReferenceObjectByHandle(Handle, 840 DesiredAccess, 841 NULL, 842 PreviousMode, 843 &Object, 844 NULL); 845 if (!NT_SUCCESS(Status)) return Status; 846 847 /* Get the Object Header and Type */ 848 Header = OBJECT_TO_OBJECT_HEADER(Object); 849 Type = Header->Type; 850 851 /* Call the security procedure's query function */ 852 Status = Type->TypeInfo.SecurityProcedure(Object, 853 QuerySecurityDescriptor, 854 &SecurityInformation, 855 SecurityDescriptor, 856 &Length, 857 &Header->SecurityDescriptor, 858 Type->TypeInfo.PoolType, 859 &Type->TypeInfo.GenericMapping); 860 861 /* Dereference the object */ 862 ObDereferenceObject(Object); 863 864 /* Protect write with SEH */ 865 _SEH2_TRY 866 { 867 /* Return the needed length */ 868 *ResultLength = Length; 869 } 870 _SEH2_EXCEPT(ExSystemExceptionFilter()) 871 { 872 /* Get the exception code */ 873 Status = _SEH2_GetExceptionCode(); 874 } 875 _SEH2_END; 876 877 /* Return status */ 878 return Status; 879 } 880 881 /*++ 882 * @name NtSetSecurityObject 883 * @implemented NT4 884 * 885 * The NtSetSecurityObject routine <FILLMEIN> 886 * 887 * @param Handle 888 * <FILLMEIN> 889 * 890 * @param SecurityInformation 891 * <FILLMEIN> 892 * 893 * @param SecurityDescriptor 894 * <FILLMEIN> 895 * 896 * @return STATUS_SUCCESS or appropriate error value. 897 * 898 * @remarks None. 899 * 900 *--*/ 901 NTSTATUS 902 NTAPI 903 NtSetSecurityObject(IN HANDLE Handle, 904 IN SECURITY_INFORMATION SecurityInformation, 905 IN PSECURITY_DESCRIPTOR SecurityDescriptor) 906 { 907 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 908 PVOID Object; 909 SECURITY_DESCRIPTOR_RELATIVE *CapturedDescriptor; 910 ACCESS_MASK DesiredAccess = 0; 911 NTSTATUS Status; 912 PAGED_CODE(); 913 914 /* Make sure the caller doesn't pass a NULL security descriptor! */ 915 if (!SecurityDescriptor) return STATUS_ACCESS_VIOLATION; 916 917 /* Set the required access rights for the operation */ 918 SeSetSecurityAccessMask(SecurityInformation, &DesiredAccess); 919 920 /* Reference the object */ 921 Status = ObReferenceObjectByHandle(Handle, 922 DesiredAccess, 923 NULL, 924 PreviousMode, 925 &Object, 926 NULL); 927 if (NT_SUCCESS(Status)) 928 { 929 /* Capture and make a copy of the security descriptor */ 930 Status = SeCaptureSecurityDescriptor(SecurityDescriptor, 931 PreviousMode, 932 PagedPool, 933 TRUE, 934 (PSECURITY_DESCRIPTOR*) 935 &CapturedDescriptor); 936 if (!NT_SUCCESS(Status)) 937 { 938 /* Fail */ 939 ObDereferenceObject(Object); 940 return Status; 941 } 942 943 /* Sanity check */ 944 ASSERT(CapturedDescriptor->Control & SE_SELF_RELATIVE); 945 946 /* 947 * Make sure the security descriptor passed by the caller 948 * is valid for the operation we're about to perform 949 */ 950 if (((SecurityInformation & OWNER_SECURITY_INFORMATION) && 951 !(CapturedDescriptor->Owner)) || 952 ((SecurityInformation & GROUP_SECURITY_INFORMATION) && 953 !(CapturedDescriptor->Group))) 954 { 955 /* Set the failure status */ 956 Status = STATUS_INVALID_SECURITY_DESCR; 957 } 958 else 959 { 960 /* Set security */ 961 Status = ObSetSecurityObjectByPointer(Object, 962 SecurityInformation, 963 CapturedDescriptor); 964 } 965 966 /* Release the descriptor and return status */ 967 SeReleaseSecurityDescriptor((PSECURITY_DESCRIPTOR)CapturedDescriptor, 968 PreviousMode, 969 TRUE); 970 971 /* Now we can dereference the object */ 972 ObDereferenceObject(Object); 973 } 974 975 return Status; 976 } 977 978 /*++ 979 * @name ObQueryObjectAuditingByHandle 980 * @implemented NT5 981 * 982 * The ObDereferenceSecurityDescriptor routine <FILLMEIN> 983 * 984 * @param SecurityDescriptor 985 * <FILLMEIN> 986 * 987 * @param Count 988 * <FILLMEIN> 989 * 990 * @return STATUS_SUCCESS or appropriate error value. 991 * 992 * @remarks None. 993 * 994 *--*/ 995 NTSTATUS 996 NTAPI 997 ObQueryObjectAuditingByHandle(IN HANDLE Handle, 998 OUT PBOOLEAN GenerateOnClose) 999 { 1000 PHANDLE_TABLE_ENTRY HandleEntry; 1001 PVOID HandleTable; 1002 NTSTATUS Status = STATUS_SUCCESS; 1003 PAGED_CODE(); 1004 1005 /* Check if we're dealing with a kernel handle */ 1006 if (ObpIsKernelHandle(Handle, ExGetPreviousMode())) 1007 { 1008 /* Use the kernel table and convert the handle */ 1009 HandleTable = ObpKernelHandleTable; 1010 Handle = ObKernelHandleToHandle(Handle); 1011 } 1012 else 1013 { 1014 /* Use the process's handle table */ 1015 HandleTable = PsGetCurrentProcess()->ObjectTable; 1016 } 1017 1018 /* Enter a critical region while we touch the handle table */ 1019 KeEnterCriticalRegion(); 1020 1021 /* Map the handle */ 1022 HandleEntry = ExMapHandleToPointer(HandleTable, Handle); 1023 if(HandleEntry) 1024 { 1025 /* Check if the flag is set */ 1026 *GenerateOnClose = HandleEntry->ObAttributes & OBJ_AUDIT_OBJECT_CLOSE; 1027 1028 /* Unlock the entry */ 1029 ExUnlockHandleTableEntry(HandleTable, HandleEntry); 1030 } 1031 else 1032 { 1033 /* Otherwise, fail */ 1034 Status = STATUS_INVALID_HANDLE; 1035 } 1036 1037 /* Leave the critical region and return the status */ 1038 KeLeaveCriticalRegion(); 1039 return Status; 1040 } 1041 1042 /* EOF */ 1043