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 ));
|
||
}
|