951 lines
28 KiB
C
951 lines
28 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1989 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
Semethod.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This Module implements the SeDefaultObjectMethod procedure. This
|
|||
|
procedure and SeAssignSecurity are the only two procedures that will
|
|||
|
place a security descriptor on an object. Therefore they must understand
|
|||
|
and agree on how a descriptor is allocated from pool so that they can
|
|||
|
deallocate and reallocate pool as necessary. Any security descriptor
|
|||
|
that is attached to an object by these procedures has the following
|
|||
|
pool allocation plan.
|
|||
|
|
|||
|
1. if the objects security descriptor is null then there is no pool
|
|||
|
allocated
|
|||
|
|
|||
|
2. otherwise there is at least one pool allocation for the security
|
|||
|
descriptor header. if its ACL fields are null then there are no
|
|||
|
other pool allocations (this should never happen).
|
|||
|
|
|||
|
3. There is a separate pool allocation for each ACL in the descriptor.
|
|||
|
So a maximum of three pool allocations can occur for each attached
|
|||
|
security descriptor.
|
|||
|
|
|||
|
4 Everytime an acl is replace in a descriptor we see if we can use
|
|||
|
the old ACL and if so then we try and keep the ACL size as large
|
|||
|
as possible.
|
|||
|
|
|||
|
Note that this is different from the algorithm used to capture
|
|||
|
a security descriptor (which puts everything in one pool allocation).
|
|||
|
Also note that this can be easily optimized at a later time (if necessary)
|
|||
|
to use only one allocation.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Gary Kimura (GaryKi) 9-Nov-1989
|
|||
|
Jim Kelly (JimK) 10-May-1990
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel Mode
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "pch.h"
|
|||
|
|
|||
|
#pragma hdrstop
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SepDefaultDeleteMethod (
|
|||
|
IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(PAGE,SeSetSecurityAccessMask)
|
|||
|
#pragma alloc_text(PAGE,SeQuerySecurityAccessMask)
|
|||
|
#pragma alloc_text(PAGE,SeDefaultObjectMethod)
|
|||
|
#pragma alloc_text(PAGE,SeSetSecurityDescriptorInfo)
|
|||
|
#pragma alloc_text(PAGE,SeSetSecurityDescriptorInfoEx)
|
|||
|
#pragma alloc_text(PAGE,SeQuerySecurityDescriptorInfo)
|
|||
|
#pragma alloc_text(PAGE,SepDefaultDeleteMethod)
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
SeSetSecurityAccessMask(
|
|||
|
IN SECURITY_INFORMATION SecurityInformation,
|
|||
|
OUT PACCESS_MASK DesiredAccess
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine builds an access mask representing the accesses necessary
|
|||
|
to set the object security information specified in the SecurityInformation
|
|||
|
parameter. While it is not difficult to determine this information,
|
|||
|
the use of a single routine to generate it will ensure minimal impact
|
|||
|
when the security information associated with an object is extended in
|
|||
|
the future (to include mandatory access control information).
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SecurityInformation - Identifies the object's security information to be
|
|||
|
modified.
|
|||
|
|
|||
|
DesiredAccess - Points to an access mask to be set to represent the
|
|||
|
accesses necessary to modify the information specified in the
|
|||
|
SecurityInformation parameter.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Figure out accesses needed to perform the indicated operation(s).
|
|||
|
//
|
|||
|
|
|||
|
(*DesiredAccess) = 0;
|
|||
|
|
|||
|
if ((SecurityInformation & OWNER_SECURITY_INFORMATION) ||
|
|||
|
(SecurityInformation & GROUP_SECURITY_INFORMATION) ) {
|
|||
|
(*DesiredAccess) |= WRITE_OWNER;
|
|||
|
}
|
|||
|
|
|||
|
if (SecurityInformation & DACL_SECURITY_INFORMATION) {
|
|||
|
(*DesiredAccess) |= WRITE_DAC;
|
|||
|
}
|
|||
|
|
|||
|
if (SecurityInformation & SACL_SECURITY_INFORMATION) {
|
|||
|
(*DesiredAccess) |= ACCESS_SYSTEM_SECURITY;
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
SeQuerySecurityAccessMask(
|
|||
|
IN SECURITY_INFORMATION SecurityInformation,
|
|||
|
OUT PACCESS_MASK DesiredAccess
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine builds an access mask representing the accesses necessary
|
|||
|
to query the object security information specified in the
|
|||
|
SecurityInformation parameter. While it is not difficult to determine
|
|||
|
this information, the use of a single routine to generate it will ensure
|
|||
|
minimal impact when the security information associated with an object is
|
|||
|
extended in the future (to include mandatory access control information).
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SecurityInformation - Identifies the object's security information to be
|
|||
|
queried.
|
|||
|
|
|||
|
DesiredAccess - Points to an access mask to be set to represent the
|
|||
|
accesses necessary to query the information specified in the
|
|||
|
SecurityInformation parameter.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Figure out accesses needed to perform the indicated operation(s).
|
|||
|
//
|
|||
|
|
|||
|
(*DesiredAccess) = 0;
|
|||
|
|
|||
|
if ((SecurityInformation & OWNER_SECURITY_INFORMATION) ||
|
|||
|
(SecurityInformation & GROUP_SECURITY_INFORMATION) ||
|
|||
|
(SecurityInformation & DACL_SECURITY_INFORMATION)) {
|
|||
|
(*DesiredAccess) |= READ_CONTROL;
|
|||
|
}
|
|||
|
|
|||
|
if ((SecurityInformation & SACL_SECURITY_INFORMATION)) {
|
|||
|
(*DesiredAccess) |= ACCESS_SYSTEM_SECURITY;
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SeDefaultObjectMethod (
|
|||
|
IN PVOID Object,
|
|||
|
IN SECURITY_OPERATION_CODE OperationCode,
|
|||
|
IN PSECURITY_INFORMATION SecurityInformation,
|
|||
|
IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
|
|||
|
IN OUT PULONG CapturedLength,
|
|||
|
IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
|
|||
|
IN POOL_TYPE PoolType,
|
|||
|
IN PGENERIC_MAPPING GenericMapping
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This is the default security method for objects. It is responsible
|
|||
|
for either retrieving, setting, and deleting the security descriptor of
|
|||
|
an object. It is not used to assign the original security descriptor
|
|||
|
to an object (use SeAssignSecurity for that purpose).
|
|||
|
|
|||
|
|
|||
|
IT IS ASSUMED THAT THE OBJECT MANAGER HAS ALREADY DONE THE ACCESS
|
|||
|
VALIDATIONS NECESSARY TO ALLOW THE REQUESTED OPERATIONS TO BE PERFORMED.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Object - Supplies a pointer to the object being used.
|
|||
|
|
|||
|
OperationCode - Indicates if the operation is for setting, querying, or
|
|||
|
deleting the object's security descriptor.
|
|||
|
|
|||
|
SecurityInformation - Indicates which security information is being
|
|||
|
queried or set. This argument is ignored for the delete operation.
|
|||
|
|
|||
|
SecurityDescriptor - The meaning of this parameter depends on the
|
|||
|
OperationCode:
|
|||
|
|
|||
|
QuerySecurityDescriptor - For the query operation this supplies the
|
|||
|
buffer to copy the descriptor into. The security descriptor is
|
|||
|
assumed to have been probed up to the size passed in in Length.
|
|||
|
Since it still points into user space, it must always be
|
|||
|
accessed in a try clause in case it should suddenly disappear.
|
|||
|
|
|||
|
SetSecurityDescriptor - For a set operation this supplies the
|
|||
|
security descriptor to copy into the object. The security
|
|||
|
descriptor must be captured before this routine is called.
|
|||
|
|
|||
|
DeleteSecurityDescriptor - It is ignored when deleting a security
|
|||
|
descriptor.
|
|||
|
|
|||
|
AssignSecurityDescriptor - For assign operations this is the
|
|||
|
security descriptor that will be assigned to the object.
|
|||
|
It is assumed to be in kernel space, and is therefore not
|
|||
|
probed or captured.
|
|||
|
|
|||
|
CapturedLength - For the query operation this specifies the length, in
|
|||
|
bytes, of the security descriptor buffer, and upon return contains
|
|||
|
the number of bytes needed to store the descriptor. If the length
|
|||
|
needed is greater than the length supplied the operation will fail.
|
|||
|
It is ignored in the set and delete operation.
|
|||
|
|
|||
|
This parameter is assumed to be captured and probed as appropriate.
|
|||
|
|
|||
|
ObjectsSecurityDescriptor - For the Set operation this supplies the address
|
|||
|
of a pointer to the object's current security descriptor. This routine
|
|||
|
will either modify the security descriptor in place or allocate a new
|
|||
|
security descriptor and use this variable to indicate its new location.
|
|||
|
For the query operation it simply supplies the security descriptor
|
|||
|
being queried. The caller is responsible for freeing the old security
|
|||
|
descriptor.
|
|||
|
|
|||
|
PoolType - For the set operation this specifies the pool type to use if
|
|||
|
a new security descriptor needs to be allocated. It is ignored
|
|||
|
in the query and delete operation.
|
|||
|
|
|||
|
the mapping of generic to specific/standard access types for the object
|
|||
|
being accessed. This mapping structure is expected to be safe to
|
|||
|
access (i.e., captured if necessary) prior to be passed to this routine.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - STATUS_SUCCESS if the operation is successful and an
|
|||
|
appropriate error status otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// If the object's security descriptor is null, then object is not
|
|||
|
// one that has security information associated with it. Return
|
|||
|
// an error.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Make sure the common parts of our input are proper
|
|||
|
//
|
|||
|
|
|||
|
ASSERT( (OperationCode == SetSecurityDescriptor) ||
|
|||
|
(OperationCode == QuerySecurityDescriptor) ||
|
|||
|
(OperationCode == AssignSecurityDescriptor) ||
|
|||
|
(OperationCode == DeleteSecurityDescriptor) );
|
|||
|
|
|||
|
//
|
|||
|
// This routine simply cases off of the operation code to decide
|
|||
|
// which support routine to call
|
|||
|
//
|
|||
|
|
|||
|
switch (OperationCode) {
|
|||
|
|
|||
|
case SetSecurityDescriptor:
|
|||
|
|
|||
|
ASSERT( (PoolType == PagedPool) || (PoolType == NonPagedPool) );
|
|||
|
|
|||
|
return ObSetSecurityDescriptorInfo( Object,
|
|||
|
SecurityInformation,
|
|||
|
SecurityDescriptor,
|
|||
|
ObjectsSecurityDescriptor,
|
|||
|
PoolType,
|
|||
|
GenericMapping
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
case QuerySecurityDescriptor:
|
|||
|
|
|||
|
//
|
|||
|
// check the rest of our input and call the default query security
|
|||
|
// method
|
|||
|
//
|
|||
|
|
|||
|
ASSERT( CapturedLength != NULL );
|
|||
|
|
|||
|
return ObQuerySecurityDescriptorInfo( Object,
|
|||
|
SecurityInformation,
|
|||
|
SecurityDescriptor,
|
|||
|
CapturedLength,
|
|||
|
ObjectsSecurityDescriptor );
|
|||
|
|
|||
|
case DeleteSecurityDescriptor:
|
|||
|
|
|||
|
//
|
|||
|
// call the default delete security method
|
|||
|
//
|
|||
|
|
|||
|
return SepDefaultDeleteMethod( ObjectsSecurityDescriptor );
|
|||
|
|
|||
|
case AssignSecurityDescriptor:
|
|||
|
|
|||
|
ObAssignObjectSecurityDescriptor( Object, SecurityDescriptor, PoolType );
|
|||
|
return( STATUS_SUCCESS );
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
//
|
|||
|
// Bugcheck on any other operation code, We won't get here if
|
|||
|
// the earlier asserts are still checked.
|
|||
|
//
|
|||
|
|
|||
|
KeBugCheckEx( SECURITY_SYSTEM, 0, STATUS_INVALID_PARAMETER, 0, 0 );
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SeSetSecurityDescriptorInfo (
|
|||
|
IN PVOID Object OPTIONAL,
|
|||
|
IN PSECURITY_INFORMATION SecurityInformation,
|
|||
|
IN PSECURITY_DESCRIPTOR ModificationDescriptor,
|
|||
|
IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
|
|||
|
IN POOL_TYPE PoolType,
|
|||
|
IN PGENERIC_MAPPING GenericMapping
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will set an object's security descriptor. The input
|
|||
|
security descriptor must be previously captured.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Object - Optionally supplies the object whose security is
|
|||
|
being adjusted. This is used to update security quota
|
|||
|
information.
|
|||
|
|
|||
|
SecurityInformation - Indicates which security information is
|
|||
|
to be applied to the object. The value(s) to be assigned are
|
|||
|
passed in the SecurityDescriptor parameter.
|
|||
|
|
|||
|
ModificationDescriptor - Supplies the input security descriptor to be
|
|||
|
applied to the object. The caller of this routine is expected
|
|||
|
to probe and capture the passed security descriptor before calling
|
|||
|
and release it after calling.
|
|||
|
|
|||
|
ObjectsSecurityDescriptor - Supplies the address of a pointer to
|
|||
|
the objects security descriptor that is going to be altered by
|
|||
|
this procedure. This structure must be deallocated by the caller.
|
|||
|
|
|||
|
PoolType - Specifies the type of pool to allocate for the objects
|
|||
|
security descriptor.
|
|||
|
|
|||
|
GenericMapping - This argument provides the mapping of generic to
|
|||
|
specific/standard access types for the object being accessed.
|
|||
|
This mapping structure is expected to be safe to access
|
|||
|
(i.e., captured if necessary) prior to be passed to this routine.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - STATUS_SUCCESS if successful and an appropriate error
|
|||
|
value otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Make sure the object already has a security descriptor.
|
|||
|
// Objects that 'may' have security descriptors 'must' have security
|
|||
|
// descriptors. If this one doesn't already have one, then we can't
|
|||
|
// assign one to it.
|
|||
|
//
|
|||
|
|
|||
|
if ((*ObjectsSecurityDescriptor) == NULL) {
|
|||
|
return(STATUS_NO_SECURITY_ON_OBJECT);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Pass this call to the common Rtlp routine.
|
|||
|
//
|
|||
|
|
|||
|
return RtlpSetSecurityObject (
|
|||
|
Object,
|
|||
|
*SecurityInformation,
|
|||
|
ModificationDescriptor,
|
|||
|
ObjectsSecurityDescriptor,
|
|||
|
0, // No Auto Inheritance
|
|||
|
PoolType,
|
|||
|
GenericMapping,
|
|||
|
NULL ); // No Token
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SeSetSecurityDescriptorInfoEx (
|
|||
|
IN PVOID Object OPTIONAL,
|
|||
|
IN PSECURITY_INFORMATION SecurityInformation,
|
|||
|
IN PSECURITY_DESCRIPTOR ModificationDescriptor,
|
|||
|
IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
|
|||
|
IN ULONG AutoInheritFlags,
|
|||
|
IN POOL_TYPE PoolType,
|
|||
|
IN PGENERIC_MAPPING GenericMapping
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will set an object's security descriptor. The input
|
|||
|
security descriptor must be previously captured.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Object - Optionally supplies the object whose security is
|
|||
|
being adjusted. This is used to update security quota
|
|||
|
information.
|
|||
|
|
|||
|
SecurityInformation - Indicates which security information is
|
|||
|
to be applied to the object. The value(s) to be assigned are
|
|||
|
passed in the SecurityDescriptor parameter.
|
|||
|
|
|||
|
ModificationDescriptor - Supplies the input security descriptor to be
|
|||
|
applied to the object. The caller of this routine is expected
|
|||
|
to probe and capture the passed security descriptor before calling
|
|||
|
and release it after calling.
|
|||
|
|
|||
|
ObjectsSecurityDescriptor - Supplies the address of a pointer to
|
|||
|
the objects security descriptor that is going to be altered by
|
|||
|
this procedure. This structure must be deallocated by the caller.
|
|||
|
|
|||
|
AutoInheritFlags - Controls automatic inheritance of ACES.
|
|||
|
Valid values are a bits mask of the logical OR of
|
|||
|
one or more of the following bits:
|
|||
|
|
|||
|
SEF_DACL_AUTO_INHERIT - If set, inherited ACEs from the
|
|||
|
DACL in the ObjectsSecurityDescriptor are preserved and inherited ACEs from
|
|||
|
the ModificationDescriptor are ignored. Inherited ACEs are not supposed
|
|||
|
to be modified; so preserving them across this call is appropriate.
|
|||
|
If a protected server does not itself implement auto inheritance, it should
|
|||
|
not set this bit. The caller of the protected server may implement
|
|||
|
auto inheritance and my indeed be modifying inherited ACEs.
|
|||
|
|
|||
|
SEF_SACL_AUTO_INHERIT - If set, inherited ACEs from the
|
|||
|
SACL in the ObjectsSecurityDescriptor are preserved and inherited ACEs from
|
|||
|
the ModificationDescriptor are ignored. Inherited ACEs are not supposed
|
|||
|
to be modified; so preserving them across this call is appropriate.
|
|||
|
If a protected server does not itself implement auto inheritance, it should
|
|||
|
not set this bit. The caller of the protected server may implement
|
|||
|
auto inheritance and my indeed be modifying inherited ACEs.
|
|||
|
|
|||
|
PoolType - Specifies the type of pool to allocate for the objects
|
|||
|
security descriptor.
|
|||
|
|
|||
|
GenericMapping - This argument provides the mapping of generic to
|
|||
|
specific/standard access types for the object being accessed.
|
|||
|
This mapping structure is expected to be safe to access
|
|||
|
(i.e., captured if necessary) prior to be passed to this routine.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - STATUS_SUCCESS if successful and an appropriate error
|
|||
|
value otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Make sure the object already has a security descriptor.
|
|||
|
// Objects that 'may' have security descriptors 'must' have security
|
|||
|
// descriptors. If this one doesn't already have one, then we can't
|
|||
|
// assign one to it.
|
|||
|
//
|
|||
|
|
|||
|
if ((*ObjectsSecurityDescriptor) == NULL) {
|
|||
|
return(STATUS_NO_SECURITY_ON_OBJECT);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Pass this call to the common Rtlp routine.
|
|||
|
//
|
|||
|
|
|||
|
return RtlpSetSecurityObject (
|
|||
|
Object,
|
|||
|
*SecurityInformation,
|
|||
|
ModificationDescriptor,
|
|||
|
ObjectsSecurityDescriptor,
|
|||
|
AutoInheritFlags,
|
|||
|
PoolType,
|
|||
|
GenericMapping,
|
|||
|
NULL ); // No Token
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SeQuerySecurityDescriptorInfo (
|
|||
|
IN PSECURITY_INFORMATION SecurityInformation,
|
|||
|
OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
|
|||
|
IN OUT PULONG Length,
|
|||
|
IN PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will extract the desired information from the
|
|||
|
passed security descriptor and return the information in
|
|||
|
the passed buffer as a security descriptor in self-relative
|
|||
|
format.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SecurityInformation - Specifies what information is being queried.
|
|||
|
|
|||
|
SecurityDescriptor - Supplies the buffer to output the requested
|
|||
|
information into.
|
|||
|
|
|||
|
This buffer has been probed only to the size indicated by
|
|||
|
the Length parameter. Since it still points into user space,
|
|||
|
it must always be accessed in a try clause.
|
|||
|
|
|||
|
Length - Supplies the address of a variable containing the length of
|
|||
|
the security descriptor buffer. Upon return this variable will
|
|||
|
contain the length needed to store the requested information.
|
|||
|
|
|||
|
ObjectsSecurityDescriptor - Supplies the address of a pointer to
|
|||
|
the objects security descriptor. The passed security descriptor
|
|||
|
must be in self-relative format.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - STATUS_SUCCESS if successful and an appropriate error value
|
|||
|
otherwise
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG BufferLength;
|
|||
|
|
|||
|
ULONG Size;
|
|||
|
ULONG OwnerLength=0;
|
|||
|
ULONG GroupLength=0;
|
|||
|
ULONG DaclLength=0;
|
|||
|
ULONG SaclLength=0;
|
|||
|
PUCHAR NextFree;
|
|||
|
SECURITY_DESCRIPTOR IObjectSecurity;
|
|||
|
|
|||
|
//
|
|||
|
// Note that IObjectSecurity is not a pointer to a pointer
|
|||
|
// like ObjectsSecurityDescriptor is.
|
|||
|
//
|
|||
|
|
|||
|
SECURITY_DESCRIPTOR_RELATIVE *ISecurityDescriptor = SecurityDescriptor;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// We will be accessing user memory throughout this routine,
|
|||
|
// therefore do everything in a try-except clause.
|
|||
|
//
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
BufferLength = *Length;
|
|||
|
|
|||
|
//
|
|||
|
// Check if the object's descriptor is null, and if it is then
|
|||
|
// we only need to return a blank security descriptor record
|
|||
|
//
|
|||
|
|
|||
|
if (*ObjectsSecurityDescriptor == NULL) {
|
|||
|
|
|||
|
*Length = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
|
|||
|
|
|||
|
//
|
|||
|
// Now make sure it's large enough for the security descriptor
|
|||
|
// record
|
|||
|
//
|
|||
|
|
|||
|
if (BufferLength < sizeof(SECURITY_DESCRIPTOR_RELATIVE)) {
|
|||
|
|
|||
|
return STATUS_BUFFER_TOO_SMALL;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// It's large enough to make a blank security descriptor record
|
|||
|
//
|
|||
|
// Note that this parameter has been probed for write by the
|
|||
|
// object manager, however, we still have to be careful when
|
|||
|
// writing to it.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// We do not have to probe this here, because the object
|
|||
|
// manager has probed it for length=BufferLength, which we
|
|||
|
// know at this point is at least as large as a security
|
|||
|
// descriptor.
|
|||
|
//
|
|||
|
|
|||
|
RtlCreateSecurityDescriptorRelative( SecurityDescriptor,
|
|||
|
SECURITY_DESCRIPTOR_REVISION );
|
|||
|
|
|||
|
//
|
|||
|
// Mark it as self-relative
|
|||
|
//
|
|||
|
|
|||
|
RtlpSetControlBits( ISecurityDescriptor, SE_SELF_RELATIVE );
|
|||
|
|
|||
|
//
|
|||
|
// And return to our caller
|
|||
|
//
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Create an absolute format SD on the stack pointing into
|
|||
|
// user space to simplify the following code
|
|||
|
//
|
|||
|
|
|||
|
RtlCopyMemory( (&IObjectSecurity),
|
|||
|
*ObjectsSecurityDescriptor,
|
|||
|
sizeof(SECURITY_DESCRIPTOR_RELATIVE) );
|
|||
|
|
|||
|
IObjectSecurity.Owner = RtlpOwnerAddrSecurityDescriptor(
|
|||
|
(SECURITY_DESCRIPTOR *) *ObjectsSecurityDescriptor );
|
|||
|
IObjectSecurity.Group = RtlpGroupAddrSecurityDescriptor(
|
|||
|
(SECURITY_DESCRIPTOR *) *ObjectsSecurityDescriptor );
|
|||
|
IObjectSecurity.Dacl = RtlpDaclAddrSecurityDescriptor(
|
|||
|
(SECURITY_DESCRIPTOR *) *ObjectsSecurityDescriptor );
|
|||
|
IObjectSecurity.Sacl = RtlpSaclAddrSecurityDescriptor(
|
|||
|
(SECURITY_DESCRIPTOR *) *ObjectsSecurityDescriptor );
|
|||
|
|
|||
|
IObjectSecurity.Control &= ~SE_SELF_RELATIVE;
|
|||
|
|
|||
|
//
|
|||
|
// This is not a blank descriptor so we need to determine the size
|
|||
|
// needed to store the requested information. It is the size of the
|
|||
|
// descriptor record plus the size of each requested component.
|
|||
|
//
|
|||
|
|
|||
|
Size = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
|
|||
|
|
|||
|
if ( (((*SecurityInformation) & OWNER_SECURITY_INFORMATION)) &&
|
|||
|
(IObjectSecurity.Owner != NULL) ) {
|
|||
|
|
|||
|
OwnerLength = SeLengthSid( IObjectSecurity.Owner );
|
|||
|
Size += (ULONG)LongAlignSize(OwnerLength);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if ( (((*SecurityInformation) & GROUP_SECURITY_INFORMATION)) &&
|
|||
|
(IObjectSecurity.Group != NULL) ) {
|
|||
|
|
|||
|
GroupLength = SeLengthSid( IObjectSecurity.Group );
|
|||
|
Size += (ULONG)LongAlignSize(GroupLength);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if ( (((*SecurityInformation) & DACL_SECURITY_INFORMATION)) &&
|
|||
|
(IObjectSecurity.Control & SE_DACL_PRESENT) &&
|
|||
|
(IObjectSecurity.Dacl != NULL) ) {
|
|||
|
|
|||
|
|
|||
|
DaclLength = (ULONG)LongAlignSize((IObjectSecurity.Dacl)->AclSize);
|
|||
|
Size += DaclLength;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if ( (((*SecurityInformation) & SACL_SECURITY_INFORMATION)) &&
|
|||
|
(IObjectSecurity.Control & SE_SACL_PRESENT) &&
|
|||
|
(IObjectSecurity.Sacl != NULL) ) {
|
|||
|
|
|||
|
SaclLength = (ULONG)LongAlignSize((IObjectSecurity.Sacl)->AclSize);
|
|||
|
Size += SaclLength;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Tell the caller how much space this will require
|
|||
|
// (whether we actually fit or not)
|
|||
|
//
|
|||
|
|
|||
|
*Length = Size;
|
|||
|
|
|||
|
//
|
|||
|
// Now make sure the size is less than or equal to the length
|
|||
|
// we were passed
|
|||
|
//
|
|||
|
|
|||
|
if (Size > BufferLength) {
|
|||
|
|
|||
|
return STATUS_BUFFER_TOO_SMALL;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// The length is fine.
|
|||
|
//
|
|||
|
// Fill in the length and flags part of the security descriptor.
|
|||
|
// The real addresses of each acl will be filled in later when we
|
|||
|
// copy the ACLs over.
|
|||
|
//
|
|||
|
// Note that we only set a flag in the descriptor if the information
|
|||
|
// was requested, which is a simple copy of the requested information
|
|||
|
// input variable
|
|||
|
//
|
|||
|
// The output buffer has already been probed to the passed size,
|
|||
|
// so we can just write to it.
|
|||
|
//
|
|||
|
|
|||
|
RtlCreateSecurityDescriptorRelative( SecurityDescriptor,
|
|||
|
SECURITY_DESCRIPTOR_REVISION );
|
|||
|
|
|||
|
//
|
|||
|
// Mark the returned Security Descriptor as being in
|
|||
|
// self-relative format
|
|||
|
//
|
|||
|
|
|||
|
RtlpSetControlBits( ISecurityDescriptor, SE_SELF_RELATIVE );
|
|||
|
|
|||
|
//
|
|||
|
// NextFree is used to point to the next free spot in the
|
|||
|
// returned security descriptor.
|
|||
|
//
|
|||
|
|
|||
|
NextFree = LongAlignPtr((PUCHAR)SecurityDescriptor +
|
|||
|
sizeof(SECURITY_DESCRIPTOR_RELATIVE));
|
|||
|
|
|||
|
//
|
|||
|
// Copy the Owner SID if necessary and update the NextFree pointer,
|
|||
|
// keeping it longword aligned.
|
|||
|
//
|
|||
|
|
|||
|
if ( ((*SecurityInformation) & OWNER_SECURITY_INFORMATION) &&
|
|||
|
((IObjectSecurity.Owner) != NULL) ) {
|
|||
|
|
|||
|
RtlMoveMemory( NextFree,
|
|||
|
IObjectSecurity.Owner,
|
|||
|
OwnerLength );
|
|||
|
|
|||
|
ISecurityDescriptor->Owner = (ULONG)((PUCHAR)NextFree - (PUCHAR)SecurityDescriptor);
|
|||
|
|
|||
|
RtlpPropagateControlBits(
|
|||
|
ISecurityDescriptor,
|
|||
|
&IObjectSecurity,
|
|||
|
SE_OWNER_DEFAULTED
|
|||
|
);
|
|||
|
|
|||
|
NextFree += (ULONG)LongAlignSize(OwnerLength);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Copy the Group SID if necessary and update the NextFree pointer,
|
|||
|
// keeping it longword aligned.
|
|||
|
//
|
|||
|
|
|||
|
if ( ((*SecurityInformation) & GROUP_SECURITY_INFORMATION) &&
|
|||
|
(IObjectSecurity.Group != NULL) ) {
|
|||
|
|
|||
|
RtlMoveMemory( NextFree,
|
|||
|
IObjectSecurity.Group,
|
|||
|
GroupLength );
|
|||
|
|
|||
|
ISecurityDescriptor->Group = (ULONG)((PUCHAR)NextFree - (PUCHAR)SecurityDescriptor);
|
|||
|
|
|||
|
RtlpPropagateControlBits(
|
|||
|
ISecurityDescriptor,
|
|||
|
&IObjectSecurity,
|
|||
|
SE_GROUP_DEFAULTED
|
|||
|
);
|
|||
|
|
|||
|
NextFree += (ULONG)LongAlignSize(GroupLength);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Set discretionary acl information if requested.
|
|||
|
// If not set in object's security,
|
|||
|
// then everything is already set properly.
|
|||
|
//
|
|||
|
|
|||
|
if ( (*SecurityInformation) & DACL_SECURITY_INFORMATION) {
|
|||
|
|
|||
|
RtlpPropagateControlBits(
|
|||
|
ISecurityDescriptor,
|
|||
|
&IObjectSecurity,
|
|||
|
SE_DACL_PRESENT | SE_DACL_DEFAULTED | SE_DACL_PROTECTED | SE_DACL_AUTO_INHERITED
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Copy the acl if non-null and update the NextFree pointer,
|
|||
|
// keeping it longword aligned.
|
|||
|
//
|
|||
|
|
|||
|
if ( (IObjectSecurity.Control & SE_DACL_PRESENT) != 0 &&
|
|||
|
IObjectSecurity.Dacl != NULL) {
|
|||
|
|
|||
|
RtlMoveMemory( NextFree,
|
|||
|
IObjectSecurity.Dacl,
|
|||
|
(IObjectSecurity.Dacl)->AclSize );
|
|||
|
|
|||
|
ISecurityDescriptor->Dacl = (ULONG)((PUCHAR)NextFree - (PUCHAR)SecurityDescriptor);
|
|||
|
|
|||
|
NextFree += DaclLength;
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Set system acl information if requested.
|
|||
|
// If not set in object's security,
|
|||
|
// then everything is already set properly.
|
|||
|
//
|
|||
|
|
|||
|
if ( (*SecurityInformation) & SACL_SECURITY_INFORMATION) {
|
|||
|
|
|||
|
RtlpPropagateControlBits(
|
|||
|
ISecurityDescriptor,
|
|||
|
&IObjectSecurity,
|
|||
|
SE_SACL_PRESENT | SE_SACL_DEFAULTED | SE_SACL_PROTECTED | SE_SACL_AUTO_INHERITED
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Copy the acl if non-null and update the NextFree pointer,
|
|||
|
// keeping it longword aligned.
|
|||
|
//
|
|||
|
if ( (IObjectSecurity.Control & SE_SACL_PRESENT) != 0 &&
|
|||
|
IObjectSecurity.Sacl != NULL) {
|
|||
|
|
|||
|
RtlMoveMemory( NextFree,
|
|||
|
IObjectSecurity.Sacl,
|
|||
|
(IObjectSecurity.Sacl)->AclSize );
|
|||
|
|
|||
|
ISecurityDescriptor->Sacl = (ULONG)((PUCHAR)NextFree - (PUCHAR)SecurityDescriptor);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
return(GetExceptionCode());
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SepDefaultDeleteMethod (
|
|||
|
IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This is a private procedure to delete the security descriptor for
|
|||
|
an object. It cleans up any pool allocations that have occured
|
|||
|
as part of the descriptor.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ObjectsSecurityDescriptor - Supplies the address of a pointer
|
|||
|
to the security descriptor being deleted.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - STATUS_SUCCESS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
return (ObDeassignSecurity ( ObjectsSecurityDescriptor ));
|
|||
|
}
|