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)
10 /* INCLUDES *****************************************************************/
16 /* PRIVATE FUNCTIONS *********************************************************/
20 ObCheckCreateObjectAccess(IN PVOID Object
,
21 IN ACCESS_MASK CreateAccess
,
22 IN PACCESS_STATE AccessState
,
23 IN PUNICODE_STRING ComponentName
,
25 IN KPROCESSOR_MODE AccessMode
,
26 OUT PNTSTATUS AccessStatus
)
28 POBJECT_HEADER ObjectHeader
;
29 POBJECT_TYPE ObjectType
;
30 PSECURITY_DESCRIPTOR SecurityDescriptor
;
32 BOOLEAN Result
= TRUE
;
33 ACCESS_MASK GrantedAccess
= 0;
34 PPRIVILEGE_SET Privileges
= NULL
;
38 /* Get the header and type */
39 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
40 ObjectType
= ObjectHeader
->Type
;
42 /* Get the security descriptor */
43 Status
= ObGetObjectSecurity(Object
, &SecurityDescriptor
, &SdAllocated
);
44 if (!NT_SUCCESS(Status
))
47 *AccessStatus
= Status
;
51 /* Lock the security context */
52 SeLockSubjectContext(&AccessState
->SubjectSecurityContext
);
54 /* Check if we have an SD */
55 if (SecurityDescriptor
)
57 /* Now do the entire access check */
58 Result
= SeAccessCheck(SecurityDescriptor
,
59 &AccessState
->SubjectSecurityContext
,
64 &ObjectType
->TypeInfo
.GenericMapping
,
70 /* We got privileges, append them to the access state and free them */
71 Status
= SeAppendPrivileges(AccessState
, Privileges
);
72 SeFreePrivileges(Privileges
);
76 /* We're done, unlock the context and release security */
77 SeUnlockSubjectContext(&AccessState
->SubjectSecurityContext
);
78 ObReleaseObjectSecurity(SecurityDescriptor
, SdAllocated
);
84 ObpCheckTraverseAccess(IN PVOID Object
,
85 IN ACCESS_MASK TraverseAccess
,
86 IN PACCESS_STATE AccessState OPTIONAL
,
88 IN KPROCESSOR_MODE AccessMode
,
89 OUT PNTSTATUS AccessStatus
)
91 POBJECT_HEADER ObjectHeader
;
92 POBJECT_TYPE ObjectType
;
93 PSECURITY_DESCRIPTOR SecurityDescriptor
;
96 ACCESS_MASK GrantedAccess
= 0;
97 PPRIVILEGE_SET Privileges
= NULL
;
101 /* Get the header and type */
102 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
103 ObjectType
= ObjectHeader
->Type
;
105 /* Get the security descriptor */
106 Status
= ObGetObjectSecurity(Object
, &SecurityDescriptor
, &SdAllocated
);
107 if (!NT_SUCCESS(Status
))
110 *AccessStatus
= Status
;
114 /* Lock the security context */
115 SeLockSubjectContext(&AccessState
->SubjectSecurityContext
);
117 /* Now do the entire access check */
118 Result
= SeAccessCheck(SecurityDescriptor
,
119 &AccessState
->SubjectSecurityContext
,
124 &ObjectType
->TypeInfo
.GenericMapping
,
130 /* We got privileges, append them to the access state and free them */
131 Status
= SeAppendPrivileges(AccessState
, Privileges
);
132 SeFreePrivileges(Privileges
);
135 /* We're done, unlock the context and release security */
136 SeUnlockSubjectContext(&AccessState
->SubjectSecurityContext
);
137 ObReleaseObjectSecurity(SecurityDescriptor
, SdAllocated
);
143 ObpCheckObjectReference(IN PVOID Object
,
144 IN OUT PACCESS_STATE AccessState
,
146 IN KPROCESSOR_MODE AccessMode
,
147 OUT PNTSTATUS AccessStatus
)
149 POBJECT_HEADER ObjectHeader
;
150 POBJECT_TYPE ObjectType
;
151 PSECURITY_DESCRIPTOR SecurityDescriptor
;
154 ACCESS_MASK GrantedAccess
= 0;
155 PPRIVILEGE_SET Privileges
= NULL
;
159 /* Get the header and type */
160 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
161 ObjectType
= ObjectHeader
->Type
;
163 /* Get the security descriptor */
164 Status
= ObGetObjectSecurity(Object
, &SecurityDescriptor
, &SdAllocated
);
165 if (!NT_SUCCESS(Status
))
168 *AccessStatus
= Status
;
172 /* Lock the security context */
173 SeLockSubjectContext(&AccessState
->SubjectSecurityContext
);
175 /* Now do the entire access check */
176 Result
= SeAccessCheck(SecurityDescriptor
,
177 &AccessState
->SubjectSecurityContext
,
179 AccessState
->RemainingDesiredAccess
,
180 AccessState
->PreviouslyGrantedAccess
,
182 &ObjectType
->TypeInfo
.GenericMapping
,
188 /* Update the access state */
189 AccessState
->RemainingDesiredAccess
&= ~GrantedAccess
;
190 AccessState
->PreviouslyGrantedAccess
|= GrantedAccess
;
193 /* Check if we have an SD */
194 if (SecurityDescriptor
)
198 SeObjectReferenceAuditAlarm(&AccessState
->OperationID
,
201 &AccessState
->SubjectSecurityContext
,
202 AccessState
->RemainingDesiredAccess
|
203 AccessState
->PreviouslyGrantedAccess
,
204 ((PAUX_DATA
)(AccessState
->AuxData
))->
211 /* We're done, unlock the context and release security */
212 SeUnlockSubjectContext(&AccessState
->SubjectSecurityContext
);
213 ObReleaseObjectSecurity(SecurityDescriptor
, SdAllocated
);
218 * @name ObCheckObjectAccess
220 * The ObAssignSecurity routine <FILLMEIN>
234 * @param ReturnedStatus
237 * @return TRUE if access was granted, FALSE otherwise.
244 ObCheckObjectAccess(IN PVOID Object
,
245 IN OUT PACCESS_STATE AccessState
,
247 IN KPROCESSOR_MODE AccessMode
,
248 OUT PNTSTATUS ReturnedStatus
)
250 POBJECT_HEADER ObjectHeader
;
251 POBJECT_TYPE ObjectType
;
252 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
256 ACCESS_MASK GrantedAccess
;
257 PPRIVILEGE_SET Privileges
= NULL
;
260 /* Get the object header and type */
261 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
262 ObjectType
= ObjectHeader
->Type
;
264 /* Get security information */
265 Status
= ObGetObjectSecurity(Object
, &SecurityDescriptor
, &SdAllocated
);
266 if (!NT_SUCCESS(Status
))
269 *ReturnedStatus
= Status
;
272 else if (!SecurityDescriptor
)
274 /* Otherwise, if we don't actually have an SD, return success */
275 *ReturnedStatus
= Status
;
279 /* Lock the security context */
280 SeLockSubjectContext(&AccessState
->SubjectSecurityContext
);
282 /* Now do the entire access check */
283 Result
= SeAccessCheck(SecurityDescriptor
,
284 &AccessState
->SubjectSecurityContext
,
286 AccessState
->RemainingDesiredAccess
,
287 AccessState
->PreviouslyGrantedAccess
,
289 &ObjectType
->TypeInfo
.GenericMapping
,
295 /* We got privileges, append them to the access state and free them */
296 Status
= SeAppendPrivileges(AccessState
, Privileges
);
297 SeFreePrivileges(Privileges
);
300 /* Check if access was granted */
303 /* Update the access state */
304 AccessState
->RemainingDesiredAccess
&= ~(GrantedAccess
|
306 AccessState
->PreviouslyGrantedAccess
|= GrantedAccess
;
310 SeOpenObjectAuditAlarm(&ObjectType
->Name
,
318 &AccessState
->GenerateOnClose
);
320 /* We're done, unlock the context and release security */
321 SeUnlockSubjectContext(&AccessState
->SubjectSecurityContext
);
322 ObReleaseObjectSecurity(SecurityDescriptor
, SdAllocated
);
326 /* PUBLIC FUNCTIONS **********************************************************/
329 * @name ObAssignSecurity
332 * The ObAssignSecurity routine <FILLMEIN>
337 * @param SecurityDescriptor
346 * @return STATUS_SUCCESS or appropriate error value.
353 ObAssignSecurity(IN PACCESS_STATE AccessState
,
354 IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
356 IN POBJECT_TYPE Type
)
358 PSECURITY_DESCRIPTOR NewDescriptor
;
363 /* Build the new security descriptor */
364 Status
= SeAssignSecurity(SecurityDescriptor
,
365 AccessState
->SecurityDescriptor
,
367 (Type
== ObDirectoryType
),
368 &AccessState
->SubjectSecurityContext
,
369 &Type
->TypeInfo
.GenericMapping
,
371 if (!NT_SUCCESS(Status
)) return Status
;
373 /* Call the security method */
374 ObpCalloutStart(&CalloutIrql
);
375 Status
= Type
->TypeInfo
.SecurityProcedure(Object
,
376 AssignSecurityDescriptor
,
382 &Type
->TypeInfo
.GenericMapping
);
383 ObpCalloutEnd(CalloutIrql
, "Security", Type
, Object
);
385 /* Check for failure and deassign security if so */
386 if (!NT_SUCCESS(Status
)) SeDeassignSecurity(&NewDescriptor
);
388 /* Return to caller */
393 * @name ObGetObjectSecurity
396 * The ObGetObjectSecurity routine <FILLMEIN>
401 * @param SecurityDescriptor
404 * @param MemoryAllocated
407 * @return STATUS_SUCCESS or appropriate error value.
414 ObGetObjectSecurity(IN PVOID Object
,
415 OUT PSECURITY_DESCRIPTOR
*SecurityDescriptor
,
416 OUT PBOOLEAN MemoryAllocated
)
418 POBJECT_HEADER Header
;
422 SECURITY_INFORMATION SecurityInformation
;
426 /* Get the object header and type */
427 Header
= OBJECT_TO_OBJECT_HEADER(Object
);
430 /* Tell the caller that we didn't have to allocate anything yet */
431 *MemoryAllocated
= FALSE
;
433 /* Check if the object uses default security */
434 if (Type
->TypeInfo
.SecurityProcedure
== SeDefaultObjectMethod
)
436 /* Reference the descriptor */
437 *SecurityDescriptor
=
438 ObpReferenceCachedSecurityDescriptor(Header
->SecurityDescriptor
);
439 return STATUS_SUCCESS
;
442 /* Set mask to query */
443 SecurityInformation
= OWNER_SECURITY_INFORMATION
|
444 GROUP_SECURITY_INFORMATION
|
445 DACL_SECURITY_INFORMATION
|
446 SACL_SECURITY_INFORMATION
;
448 /* Get the security descriptor size */
449 ObpCalloutStart(&CalloutIrql
);
450 Status
= Type
->TypeInfo
.SecurityProcedure(Object
,
451 QuerySecurityDescriptor
,
452 &SecurityInformation
,
455 &Header
->SecurityDescriptor
,
456 Type
->TypeInfo
.PoolType
,
457 &Type
->TypeInfo
.GenericMapping
);
458 ObpCalloutEnd(CalloutIrql
, "Security", Type
, Object
);
460 /* Check for failure */
461 if (Status
!= STATUS_BUFFER_TOO_SMALL
) return Status
;
463 /* Allocate security descriptor */
464 *SecurityDescriptor
= ExAllocatePoolWithTag(PagedPool
,
467 if (!(*SecurityDescriptor
)) return STATUS_INSUFFICIENT_RESOURCES
;
468 *MemoryAllocated
= TRUE
;
470 /* Query security descriptor */
471 ObpCalloutStart(&CalloutIrql
);
472 Status
= Type
->TypeInfo
.SecurityProcedure(Object
,
473 QuerySecurityDescriptor
,
474 &SecurityInformation
,
477 &Header
->SecurityDescriptor
,
478 Type
->TypeInfo
.PoolType
,
479 &Type
->TypeInfo
.GenericMapping
);
480 ObpCalloutEnd(CalloutIrql
, "Security", Type
, Object
);
482 /* Check for failure */
483 if (!NT_SUCCESS(Status
))
485 /* Free the descriptor and tell the caller we failed */
486 ExFreePool(*SecurityDescriptor
);
487 *MemoryAllocated
= FALSE
;
495 * @name ObReleaseObjectSecurity
498 * The ObReleaseObjectSecurity routine <FILLMEIN>
500 * @param SecurityDescriptor
503 * @param MemoryAllocated
506 * @return STATUS_SUCCESS or appropriate error value.
513 ObReleaseObjectSecurity(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
514 IN BOOLEAN MemoryAllocated
)
518 /* Nothing to do in this case */
519 if (!SecurityDescriptor
) return;
521 /* Check if we had allocated it from memory */
525 ExFreePool(SecurityDescriptor
);
529 /* Otherwise this means we used an internal descriptor */
530 ObpDereferenceCachedSecurityDescriptor(SecurityDescriptor
);
535 * @name ObSetSecurityObjectByPointer
538 * The ObSetSecurityObjectByPointer routine <FILLMEIN>
540 * @param SecurityDescriptor
543 * @param MemoryAllocated
546 * @return STATUS_SUCCESS or appropriate error value.
553 ObSetSecurityObjectByPointer(IN PVOID Object
,
554 IN SECURITY_INFORMATION SecurityInformation
,
555 IN PSECURITY_DESCRIPTOR SecurityDescriptor
)
558 POBJECT_HEADER Header
;
561 /* Get the header and type */
562 Header
= OBJECT_TO_OBJECT_HEADER(Object
);
566 ASSERT(SecurityDescriptor
);
568 /* Call the security procedure */
569 return Type
->TypeInfo
.SecurityProcedure(Object
,
570 SetSecurityDescriptor
,
571 &SecurityInformation
,
574 &Header
->SecurityDescriptor
,
575 Type
->TypeInfo
.PoolType
,
576 &Type
->TypeInfo
.GenericMapping
);
580 * @name NtQuerySecurityObject
583 * The NtQuerySecurityObject routine <FILLMEIN>
588 * @param SecurityInformation
591 * @param SecurityDescriptor
597 * @param ResultLength
600 * @return STATUS_SUCCESS or appropriate error value.
607 NtQuerySecurityObject(IN HANDLE Handle
,
608 IN SECURITY_INFORMATION SecurityInformation
,
609 OUT PSECURITY_DESCRIPTOR SecurityDescriptor
,
611 OUT PULONG ResultLength
)
613 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
615 POBJECT_HEADER Header
;
617 ACCESS_MASK DesiredAccess
;
618 NTSTATUS Status
= STATUS_SUCCESS
;
621 /* Check if we came from user mode */
622 if (PreviousMode
!= KernelMode
)
627 /* Probe the SD and the length pointer */
628 ProbeForWrite(SecurityDescriptor
, Length
, sizeof(ULONG
));
629 ProbeForWriteUlong(ResultLength
);
633 /* Get the exception code */
634 Status
= _SEH_GetExceptionCode();
638 /* Fail if we got an access violation */
639 if (!NT_SUCCESS(Status
)) return Status
;
642 /* Get the required access rights for the operation */
643 SeQuerySecurityAccessMask(SecurityInformation
, &DesiredAccess
);
645 /* Reference the object */
646 Status
= ObReferenceObjectByHandle(Handle
,
652 if (!NT_SUCCESS(Status
)) return Status
;
654 /* Get the Object Header and Type */
655 Header
= OBJECT_TO_OBJECT_HEADER(Object
);
658 /* Call the security procedure's query function */
659 Status
= Type
->TypeInfo
.SecurityProcedure(Object
,
660 QuerySecurityDescriptor
,
661 &SecurityInformation
,
664 &Header
->SecurityDescriptor
,
665 Type
->TypeInfo
.PoolType
,
666 &Type
->TypeInfo
.GenericMapping
);
668 /* Dereference the object */
669 ObDereferenceObject(Object
);
671 /* Protect write with SEH */
674 /* Return the needed length */
675 *ResultLength
= Length
;
677 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
)
679 /* Get the exception code */
680 Status
= _SEH_GetExceptionCode();
689 * @name NtSetSecurityObject
692 * The NtSetSecurityObject routine <FILLMEIN>
697 * @param SecurityInformation
700 * @param SecurityDescriptor
703 * @return STATUS_SUCCESS or appropriate error value.
710 NtSetSecurityObject(IN HANDLE Handle
,
711 IN SECURITY_INFORMATION SecurityInformation
,
712 IN PSECURITY_DESCRIPTOR SecurityDescriptor
)
714 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
716 SECURITY_DESCRIPTOR_RELATIVE
*CapturedDescriptor
;
717 ACCESS_MASK DesiredAccess
;
721 /* Make sure the caller doesn't pass a NULL security descriptor! */
722 if (!SecurityDescriptor
) return STATUS_ACCESS_VIOLATION
;
724 /* Set the required access rights for the operation */
725 SeSetSecurityAccessMask(SecurityInformation
, &DesiredAccess
);
727 /* Reference the object */
728 Status
= ObReferenceObjectByHandle(Handle
,
734 if (NT_SUCCESS(Status
))
736 /* Capture and make a copy of the security descriptor */
737 Status
= SeCaptureSecurityDescriptor(SecurityDescriptor
,
741 (PSECURITY_DESCRIPTOR
*)
742 &CapturedDescriptor
);
743 if (!NT_SUCCESS(Status
))
746 ObDereferenceObject(Object
);
751 ASSERT(CapturedDescriptor
->Control
& SE_SELF_RELATIVE
);
754 * Make sure the security descriptor passed by the caller
755 * is valid for the operation we're about to perform
757 if (((SecurityInformation
& OWNER_SECURITY_INFORMATION
) &&
758 !(CapturedDescriptor
->Owner
)) ||
759 ((SecurityInformation
& GROUP_SECURITY_INFORMATION
) &&
760 !(CapturedDescriptor
->Group
)))
762 /* Set the failure status */
763 Status
= STATUS_INVALID_SECURITY_DESCR
;
768 Status
= ObSetSecurityObjectByPointer(Object
,
773 /* Release the descriptor and return status */
774 SeReleaseSecurityDescriptor((PSECURITY_DESCRIPTOR
)CapturedDescriptor
,
779 /* Now we can dereference the object */
780 ObDereferenceObject(Object
);
785 * @name ObQueryObjectAuditingByHandle
788 * The ObDereferenceSecurityDescriptor routine <FILLMEIN>
790 * @param SecurityDescriptor
796 * @return STATUS_SUCCESS or appropriate error value.
803 ObQueryObjectAuditingByHandle(IN HANDLE Handle
,
804 OUT PBOOLEAN GenerateOnClose
)
806 PHANDLE_TABLE_ENTRY HandleEntry
;
808 NTSTATUS Status
= STATUS_SUCCESS
;
811 /* Check if we're dealing with a kernel handle */
812 if (ObIsKernelHandle(Handle
, ExGetPreviousMode()))
814 /* Use the kernel table and convert the handle */
815 HandleTable
= ObpKernelHandleTable
;
816 Handle
= ObKernelHandleToHandle(Handle
);
820 /* Use the process's handle table */
821 HandleTable
= PsGetCurrentProcess()->ObjectTable
;
824 /* Enter a critical region while we touch the handle table */
825 KeEnterCriticalRegion();
828 HandleEntry
= ExMapHandleToPointer(HandleTable
, Handle
);
831 /* Check if the flag is set */
832 *GenerateOnClose
= HandleEntry
->ObAttributes
& OBJ_AUDIT_OBJECT_CLOSE
;
834 /* Unlock the entry */
835 ExUnlockHandleTableEntry(HandleTable
, HandleEntry
);
839 /* Otherwise, fail */
840 Status
= STATUS_INVALID_HANDLE
;
843 /* Leave the critical region and return the status */
844 KeLeaveCriticalRegion();