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 *****************************************************************/
14 #include <internal/debug.h>
16 /* PRIVATE FUNCTIONS *********************************************************/
19 * @name ObCheckObjectAccess
21 * The ObAssignSecurity routine <FILLMEIN>
35 * @param ReturnedStatus
38 * @return TRUE if access was granted, FALSE otherwise.
45 ObCheckObjectAccess(IN PVOID Object
,
46 IN OUT PACCESS_STATE AccessState
,
48 IN KPROCESSOR_MODE AccessMode
,
49 OUT PNTSTATUS ReturnedStatus
)
51 POBJECT_HEADER ObjectHeader
;
52 POBJECT_TYPE ObjectType
;
53 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
57 ACCESS_MASK GrantedAccess
;
58 PPRIVILEGE_SET Privileges
= NULL
;
61 /* Get the object header and type */
62 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
63 ObjectType
= ObjectHeader
->Type
;
65 /* Get security information */
66 Status
= ObGetObjectSecurity(Object
, &SecurityDescriptor
, &SdAllocated
);
67 if (!NT_SUCCESS(Status
))
70 *ReturnedStatus
= Status
;
73 else if (!SecurityDescriptor
)
75 /* Otherwise, if we don't actually have an SD, return success */
76 *ReturnedStatus
= Status
;
80 /* Lock the security context */
81 SeLockSubjectContext(&AccessState
->SubjectSecurityContext
);
83 /* Now do the entire access check */
84 Result
= SeAccessCheck(SecurityDescriptor
,
85 &AccessState
->SubjectSecurityContext
,
87 AccessState
->RemainingDesiredAccess
,
88 AccessState
->PreviouslyGrantedAccess
,
90 &ObjectType
->TypeInfo
.GenericMapping
,
96 /* We got privileges, append them to teh access state and free them */
97 Status
= SeAppendPrivileges(AccessState
, Privileges
);
98 SeFreePrivileges(Privileges
);
101 /* Check if access was granted */
104 /* Update the access state */
105 AccessState
->RemainingDesiredAccess
&= ~(GrantedAccess
|
107 AccessState
->PreviouslyGrantedAccess
|= GrantedAccess
;
111 SeOpenObjectAuditAlarm(&ObjectType
->Name
,
119 &AccessState
->GenerateOnClose
);
121 /* We're done, unlock the context and release security */
122 SeUnlockSubjectContext(&AccessState
->SubjectSecurityContext
);
123 ObReleaseObjectSecurity(SecurityDescriptor
, SdAllocated
);
127 /* PUBLIC FUNCTIONS **********************************************************/
130 * @name ObAssignSecurity
133 * The ObAssignSecurity routine <FILLMEIN>
138 * @param SecurityDescriptor
147 * @return STATUS_SUCCESS or appropriate error value.
154 ObAssignSecurity(IN PACCESS_STATE AccessState
,
155 IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
157 IN POBJECT_TYPE Type
)
159 PSECURITY_DESCRIPTOR NewDescriptor
;
164 /* Build the new security descriptor */
165 Status
= SeAssignSecurity(SecurityDescriptor
,
166 AccessState
->SecurityDescriptor
,
168 (Type
== ObDirectoryType
),
169 &AccessState
->SubjectSecurityContext
,
170 &Type
->TypeInfo
.GenericMapping
,
172 if (!NT_SUCCESS(Status
)) return Status
;
174 /* Call the security method */
175 ObpCalloutStart(&CalloutIrql
);
176 Status
= Type
->TypeInfo
.SecurityProcedure(Object
,
177 AssignSecurityDescriptor
,
183 &Type
->TypeInfo
.GenericMapping
);
184 ObpCalloutEnd(CalloutIrql
, "Security", Type
, Object
);
186 /* Check for failure and deassign security if so */
187 if (!NT_SUCCESS(Status
)) SeDeassignSecurity(&NewDescriptor
);
189 /* Return to caller */
194 * @name ObGetObjectSecurity
197 * The ObGetObjectSecurity routine <FILLMEIN>
202 * @param SecurityDescriptor
205 * @param MemoryAllocated
208 * @return STATUS_SUCCESS or appropriate error value.
215 ObGetObjectSecurity(IN PVOID Object
,
216 OUT PSECURITY_DESCRIPTOR
*SecurityDescriptor
,
217 OUT PBOOLEAN MemoryAllocated
)
219 POBJECT_HEADER Header
;
223 SECURITY_INFORMATION SecurityInformation
;
227 /* Get the object header and type */
228 Header
= OBJECT_TO_OBJECT_HEADER(Object
);
231 /* Tell the caller that we didn't have to allocate anything yet */
232 *MemoryAllocated
= FALSE
;
234 /* Check if the object uses default security */
235 if (Type
->TypeInfo
.SecurityProcedure
== SeDefaultObjectMethod
)
237 /* Reference the descriptor */
238 *SecurityDescriptor
=
239 ObpReferenceCachedSecurityDescriptor(Header
->SecurityDescriptor
);
240 return STATUS_SUCCESS
;
243 /* Set mask to query */
244 SecurityInformation
= OWNER_SECURITY_INFORMATION
|
245 GROUP_SECURITY_INFORMATION
|
246 DACL_SECURITY_INFORMATION
|
247 SACL_SECURITY_INFORMATION
;
249 /* Get the security descriptor size */
250 ObpCalloutStart(&CalloutIrql
);
251 Status
= Type
->TypeInfo
.SecurityProcedure(Object
,
252 QuerySecurityDescriptor
,
253 &SecurityInformation
,
256 &Header
->SecurityDescriptor
,
257 Type
->TypeInfo
.PoolType
,
258 &Type
->TypeInfo
.GenericMapping
);
259 ObpCalloutEnd(CalloutIrql
, "Security", Type
, Object
);
261 /* Check for failure */
262 if (Status
!= STATUS_BUFFER_TOO_SMALL
) return Status
;
264 /* Allocate security descriptor */
265 *SecurityDescriptor
= ExAllocatePoolWithTag(PagedPool
,
268 if (!(*SecurityDescriptor
)) return STATUS_INSUFFICIENT_RESOURCES
;
269 *MemoryAllocated
= TRUE
;
271 /* Query security descriptor */
272 ObpCalloutStart(&CalloutIrql
);
273 Status
= Type
->TypeInfo
.SecurityProcedure(Object
,
274 QuerySecurityDescriptor
,
275 &SecurityInformation
,
278 &Header
->SecurityDescriptor
,
279 Type
->TypeInfo
.PoolType
,
280 &Type
->TypeInfo
.GenericMapping
);
281 ObpCalloutEnd(CalloutIrql
, "Security", Type
, Object
);
283 /* Check for failure */
284 if (!NT_SUCCESS(Status
))
286 /* Free the descriptor and tell the caller we failed */
287 ExFreePool(*SecurityDescriptor
);
288 *MemoryAllocated
= FALSE
;
296 * @name ObReleaseObjectSecurity
299 * The ObReleaseObjectSecurity routine <FILLMEIN>
301 * @param SecurityDescriptor
304 * @param MemoryAllocated
307 * @return STATUS_SUCCESS or appropriate error value.
314 ObReleaseObjectSecurity(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
315 IN BOOLEAN MemoryAllocated
)
319 /* Nothing to do in this case */
320 if (!SecurityDescriptor
) return;
322 /* Check if we had allocated it from memory */
326 ExFreePool(SecurityDescriptor
);
330 /* Otherwise this means we used an internal descriptor */
331 ObpDereferenceCachedSecurityDescriptor(SecurityDescriptor
);
336 * @name ObSetSecurityObjectByPointer
339 * The ObSetSecurityObjectByPointer routine <FILLMEIN>
341 * @param SecurityDescriptor
344 * @param MemoryAllocated
347 * @return STATUS_SUCCESS or appropriate error value.
354 ObSetSecurityObjectByPointer(IN PVOID Object
,
355 IN SECURITY_INFORMATION SecurityInformation
,
356 IN PSECURITY_DESCRIPTOR SecurityDescriptor
)
359 POBJECT_HEADER Header
;
362 /* Get the header and type */
363 Header
= OBJECT_TO_OBJECT_HEADER(Object
);
367 ASSERT(SecurityDescriptor
);
369 /* Call the security procedure */
370 return Type
->TypeInfo
.SecurityProcedure(Object
,
371 SetSecurityDescriptor
,
372 &SecurityInformation
,
375 &Header
->SecurityDescriptor
,
376 Type
->TypeInfo
.PoolType
,
377 &Type
->TypeInfo
.GenericMapping
);
381 * @name NtQuerySecurityObject
384 * The NtQuerySecurityObject routine <FILLMEIN>
389 * @param SecurityInformation
392 * @param SecurityDescriptor
398 * @param ResultLength
401 * @return STATUS_SUCCESS or appropriate error value.
408 NtQuerySecurityObject(IN HANDLE Handle
,
409 IN SECURITY_INFORMATION SecurityInformation
,
410 OUT PSECURITY_DESCRIPTOR SecurityDescriptor
,
412 OUT PULONG ResultLength
)
414 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
416 POBJECT_HEADER Header
;
418 ACCESS_MASK DesiredAccess
;
419 NTSTATUS Status
= STATUS_SUCCESS
;
422 /* Check if we came from user mode */
423 if (PreviousMode
!= KernelMode
)
428 /* Probe the SD and the length pointer */
429 ProbeForWrite(SecurityDescriptor
, Length
, sizeof(ULONG
));
430 ProbeForWriteUlong(ResultLength
);
434 /* Get the exception code */
435 Status
= _SEH_GetExceptionCode();
439 /* Fail if we got an access violation */
440 if (!NT_SUCCESS(Status
)) return Status
;
443 /* Get the required access rights for the operation */
444 SeQuerySecurityAccessMask(SecurityInformation
, &DesiredAccess
);
446 /* Reference the object */
447 Status
= ObReferenceObjectByHandle(Handle
,
453 if (!NT_SUCCESS(Status
)) return Status
;
455 /* Get the Object Header and Type */
456 Header
= OBJECT_TO_OBJECT_HEADER(Object
);
459 /* Call the security procedure's query function */
460 Status
= Type
->TypeInfo
.SecurityProcedure(Object
,
461 QuerySecurityDescriptor
,
462 &SecurityInformation
,
465 &Header
->SecurityDescriptor
,
466 Type
->TypeInfo
.PoolType
,
467 &Type
->TypeInfo
.GenericMapping
);
469 /* Dereference the object */
470 ObDereferenceObject(Object
);
472 /* Protect write with SEH */
475 /* Return the needed length */
476 *ResultLength
= Length
;
478 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
)
480 /* Get the exception code */
481 Status
= _SEH_GetExceptionCode();
490 * @name NtSetSecurityObject
493 * The NtSetSecurityObject routine <FILLMEIN>
498 * @param SecurityInformation
501 * @param SecurityDescriptor
504 * @return STATUS_SUCCESS or appropriate error value.
511 NtSetSecurityObject(IN HANDLE Handle
,
512 IN SECURITY_INFORMATION SecurityInformation
,
513 IN PSECURITY_DESCRIPTOR SecurityDescriptor
)
515 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
517 SECURITY_DESCRIPTOR_RELATIVE
*CapturedDescriptor
;
518 ACCESS_MASK DesiredAccess
;
522 /* Make sure the caller doesn't pass a NULL security descriptor! */
523 if (!SecurityDescriptor
) return STATUS_ACCESS_VIOLATION
;
525 /* Set the required access rights for the operation */
526 SeSetSecurityAccessMask(SecurityInformation
, &DesiredAccess
);
528 /* Reference the object */
529 Status
= ObReferenceObjectByHandle(Handle
,
535 if (NT_SUCCESS(Status
))
537 /* Capture and make a copy of the security descriptor */
538 Status
= SeCaptureSecurityDescriptor(SecurityDescriptor
,
542 (PSECURITY_DESCRIPTOR
*)
543 &CapturedDescriptor
);
544 if (!NT_SUCCESS(Status
))
547 ObDereferenceObject(Object
);
552 ASSERT(CapturedDescriptor
->Control
& SE_SELF_RELATIVE
);
555 * Make sure the security descriptor passed by the caller
556 * is valid for the operation we're about to perform
558 if (((SecurityInformation
& OWNER_SECURITY_INFORMATION
) &&
559 !(CapturedDescriptor
->Owner
)) ||
560 ((SecurityInformation
& GROUP_SECURITY_INFORMATION
) &&
561 !(CapturedDescriptor
->Group
)))
563 /* Set the failure status */
564 Status
= STATUS_INVALID_SECURITY_DESCR
;
569 Status
= ObSetSecurityObjectByPointer(Object
,
574 /* Release the descriptor and return status */
575 SeReleaseSecurityDescriptor((PSECURITY_DESCRIPTOR
)CapturedDescriptor
,
580 /* Now we can dereference the object */
581 ObDereferenceObject(Object
);
586 * @name ObQueryObjectAuditingByHandle
589 * The ObDereferenceSecurityDescriptor routine <FILLMEIN>
591 * @param SecurityDescriptor
597 * @return STATUS_SUCCESS or appropriate error value.
604 ObQueryObjectAuditingByHandle(IN HANDLE Handle
,
605 OUT PBOOLEAN GenerateOnClose
)
607 PHANDLE_TABLE_ENTRY HandleEntry
;
609 NTSTATUS Status
= STATUS_SUCCESS
;
612 /* Check if we're dealing with a kernel handle */
613 if (ObIsKernelHandle(Handle
, ExGetPreviousMode()))
615 /* Use the kernel table and convert the handle */
616 HandleTable
= ObpKernelHandleTable
;
617 Handle
= ObKernelHandleToHandle(Handle
);
621 /* Use the process's handle table */
622 HandleTable
= PsGetCurrentProcess()->ObjectTable
;
625 /* Enter a critical region while we touch the handle table */
626 KeEnterCriticalRegion();
629 HandleEntry
= ExMapHandleToPointer(HandleTable
, Handle
);
632 /* Check if the flag is set */
633 *GenerateOnClose
= (HandleEntry
->ObAttributes
&
634 EX_HANDLE_ENTRY_AUDITONCLOSE
) != 0;
636 /* Unlock the entry */
637 ExUnlockHandleTableEntry(HandleTable
, HandleEntry
);
641 /* Otherwise, fail */
642 Status
= STATUS_INVALID_HANDLE
;
645 /* Leave the critical region and return the status */
646 KeLeaveCriticalRegion();