summaryrefslogtreecommitdiffstats
path: root/private/ntos/se/semethod.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/se/semethod.c
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/se/semethod.c')
-rw-r--r--private/ntos/se/semethod.c1279
1 files changed, 1279 insertions, 0 deletions
diff --git a/private/ntos/se/semethod.c b/private/ntos/se/semethod.c
new file mode 100644
index 000000000..9033f4f58
--- /dev/null
+++ b/private/ntos/se/semethod.c
@@ -0,0 +1,1279 @@
+/*++
+
+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 it's 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 "sep.h"
+
+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,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 SeQuerySecurityDescriptorInfo( 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.
+ //
+
+ KeBugCheck( SECURITY_SYSTEM );
+
+ }
+
+}
+
+
+
+
+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.
+
+--*/
+
+{
+ BOOLEAN NewGroupPresent = FALSE;
+ BOOLEAN NewSaclPresent = FALSE;
+ BOOLEAN NewDaclPresent = FALSE;
+ BOOLEAN NewOwnerPresent = FALSE;
+
+ PCHAR Field;
+ PCHAR Base;
+
+ SECURITY_DESCRIPTOR *NewDescriptor;
+
+ NTSTATUS Status;
+
+ PSID NewGroup;
+ PSID NewOwner;
+
+ PACL NewDacl;
+ PACL NewSacl;
+ PACL ServerDacl;
+
+ ULONG NewDaclSize;
+ ULONG NewSaclSize;
+ ULONG NewOwnerSize;
+ ULONG NewGroupSize;
+ ULONG AllocationSize;
+
+ SECURITY_SUBJECT_CONTEXT SubjectContext;
+
+ BOOLEAN ServerObject;
+ BOOLEAN DaclUntrusted;
+ BOOLEAN ServerDaclAllocated = FALSE;
+
+ PSID SubjectContextOwner;
+ PSID SubjectContextGroup;
+ PSID SubjectContextServerOwner;
+ PSID SubjectContextServerGroup;
+ PACL SubjectContextDacl;
+
+
+ //
+ // Typecast to internal representation of security descriptor.
+ // Note that the internal one is not a pointer to a pointer.
+ // It is just a pointer to a security descriptor.
+ //
+
+ SECURITY_DESCRIPTOR *IModificationDescriptor =
+ (SECURITY_DESCRIPTOR *)ModificationDescriptor;
+ SECURITY_DESCRIPTOR *IObjectsSecurityDescriptor =
+ (SECURITY_DESCRIPTOR *)*ObjectsSecurityDescriptor;
+
+ 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);
+ }
+
+ ASSERT (IObjectsSecurityDescriptor != NULL);
+
+ //
+ // Validate that the provided SD is in self-relative form
+ //
+
+ if ( !SepAreControlBitsSet(IObjectsSecurityDescriptor, SE_SELF_RELATIVE) ) {
+ return( STATUS_BAD_DESCRIPTOR_FORMAT );
+ }
+
+ //
+ // Check to see if we need to edit the passed acl
+ // either because we're creating a server object, or because
+ // we were passed an untrusted ACL.
+ //
+
+ if ( SepAreControlBitsSet(IModificationDescriptor, SE_SERVER_SECURITY)) {
+ ServerObject = TRUE;
+ } else {
+ ServerObject = FALSE;
+ }
+
+ if ( SepAreControlBitsSet(IModificationDescriptor, SE_DACL_UNTRUSTED)) {
+ DaclUntrusted = TRUE;
+ } else {
+ DaclUntrusted = FALSE;
+ }
+
+ //
+ // The basic algorithm of setting a security descriptor is to
+ // figure out where each component of the object's resultant
+ // security descriptor is to come from: the original security
+ // descriptor, or the new one.
+ //
+
+
+ //
+ // Copy the system acl if specified
+ //
+
+ if (((*SecurityInformation) & SACL_SECURITY_INFORMATION)) {
+
+ NewSacl = SepSaclAddrSecurityDescriptor( IModificationDescriptor );
+ NewSaclPresent = TRUE;
+
+ } else {
+
+ NewSacl = SepSaclAddrSecurityDescriptor( IObjectsSecurityDescriptor );
+ }
+
+ //
+ // Copy the Discretionary acl if specified
+ //
+
+ if (((*SecurityInformation) & DACL_SECURITY_INFORMATION)) {
+
+ NewDacl = SepDaclAddrSecurityDescriptor( IModificationDescriptor );
+ NewDaclPresent = TRUE;
+
+ if (ServerObject) {
+
+ SeCaptureSubjectContext( &SubjectContext );
+
+ SepGetDefaultsSubjectContext(
+ &SubjectContext,
+ &SubjectContextOwner,
+ &SubjectContextGroup,
+ &SubjectContextServerOwner,
+ &SubjectContextServerGroup,
+ &SubjectContextDacl
+ );
+
+ Status = SepCreateServerAcl(
+ NewDacl,
+ DaclUntrusted,
+ SubjectContextServerOwner,
+ &ServerDacl,
+ &ServerDaclAllocated
+ );
+
+ SeReleaseSubjectContext( &SubjectContext );
+
+ if (!NT_SUCCESS( Status )) {
+ return( Status );
+ }
+
+ NewDacl = ServerDacl;
+ }
+
+ } else {
+
+ NewDacl = SepDaclAddrSecurityDescriptor( IObjectsSecurityDescriptor );
+ }
+
+ //
+ // Copy the Owner SID if specified
+ //
+
+ //
+ // if he's setting the owner field, make sure he's
+ // allowed to set that value as an owner.
+ //
+
+ if (((*SecurityInformation) & OWNER_SECURITY_INFORMATION)) {
+
+ SeCaptureSubjectContext( &SubjectContext );
+
+ NewOwner = SepOwnerAddrSecurityDescriptor( IModificationDescriptor );
+ NewOwnerPresent = TRUE;
+
+ if (!SepValidOwnerSubjectContext( &SubjectContext, NewOwner, ServerObject ) ) {
+
+ SeReleaseSubjectContext( &SubjectContext );
+ return( STATUS_INVALID_OWNER );
+
+ } else {
+
+ SeReleaseSubjectContext( &SubjectContext );
+ }
+
+ } else {
+
+ NewOwner = SepOwnerAddrSecurityDescriptor ( IObjectsSecurityDescriptor );
+ }
+
+ ASSERT( NewOwner != NULL );
+
+ //
+ // Copy the Group SID if specified
+ //
+
+ if (((*SecurityInformation) & GROUP_SECURITY_INFORMATION)) {
+
+ NewGroup = SepGroupAddrSecurityDescriptor(IModificationDescriptor);
+ NewGroupPresent = TRUE;
+
+ } else {
+
+ NewGroup = SepGroupAddrSecurityDescriptor( IObjectsSecurityDescriptor );
+ }
+
+ if (NewGroup != NULL) {
+ if (!RtlValidSid( NewGroup )) {
+ return( STATUS_INVALID_PRIMARY_GROUP );
+ }
+ }
+
+ //
+ // Everything is assignable by the requestor.
+ // Calculate the memory needed to house all the information in
+ // a self-relative security descriptor.
+ //
+ // Also map the ACEs for application to the target object
+ // type, if they haven't already been mapped.
+ //
+
+ NewOwnerSize = (ULONG)LongAlign(SeLengthSid(NewOwner));
+
+ if (NewGroup != NULL) {
+ NewGroupSize = (ULONG)LongAlign(SeLengthSid(NewGroup));
+ } else {
+ NewGroupSize = 0;
+ }
+
+
+ if (NewSacl != NULL) {
+ NewSaclSize = (ULONG)LongAlign(NewSacl->AclSize);
+ } else {
+ NewSaclSize = 0;
+ }
+
+ if (NewDacl !=NULL) {
+ NewDaclSize = (ULONG)LongAlign(NewDacl->AclSize);
+ } else {
+ NewDaclSize = 0;
+ }
+
+ AllocationSize = (ULONG)LongAlign(sizeof(SECURITY_DESCRIPTOR)) +
+ NewOwnerSize +
+ NewGroupSize +
+ NewSaclSize +
+ NewDaclSize;
+
+ //
+ // Allocate and initialize the security descriptor as
+ // self-relative form.
+ //
+
+ NewDescriptor = (SECURITY_DESCRIPTOR *)
+ ExAllocatePoolWithTag(PoolType, AllocationSize, 'dSeS');
+
+ if (NewDescriptor == NULL) {
+ return( STATUS_NO_MEMORY );
+ }
+
+ Status = RtlCreateSecurityDescriptor(
+ NewDescriptor,
+ SECURITY_DESCRIPTOR_REVISION
+ );
+
+ ASSERT( NT_SUCCESS( Status ) );
+
+ //
+ // We must check to make sure that the Group and Dacl size
+ // do not exceed the quota preallocated for this object's
+ // security when it was created.
+ //
+ // Update SeComputeSecurityQuota if this changes.
+ //
+
+
+ if (ARGUMENT_PRESENT( Object )) {
+
+ Status = ObValidateSecurityQuota(
+ Object,
+ NewGroupSize + NewDaclSize
+ );
+
+ if (!NT_SUCCESS( Status )) {
+
+ //
+ // The new information is too big.
+ //
+
+ ExFreePool( NewDescriptor );
+ return( Status );
+ }
+
+ }
+
+ SepSetControlBits( NewDescriptor, SE_SELF_RELATIVE );
+
+ Base = (PCHAR)NewDescriptor;
+ Field = Base + (ULONG)sizeof(SECURITY_DESCRIPTOR);
+
+ //
+ // Map and Copy in the Sacl
+ //
+
+ //
+ // if new item {
+ // PRESENT=TRUE
+ // DEFAULTED=FALSE
+ // if (new item == NULL) {
+ // set new pointer to NULL
+ // } else {
+ // copy into new SD
+ // }
+ // } else {
+ // copy PRESENT bit
+ // copy DEFAULTED bit
+ // if (new item == NULL) {
+ // set new pointer to NULL
+ // } else {
+ // copy old one into new SD
+ // }
+ // }
+ //
+
+
+
+ if (NewSacl == NULL) {
+ NewDescriptor->Sacl = NULL;
+
+ } else {
+
+ RtlMoveMemory( Field, NewSacl, NewSacl->AclSize );
+ NewDescriptor->Sacl = (PACL)RtlPointerToOffset(Base,Field);
+ SepApplyAclToObject( (PACL)Field, GenericMapping );
+ Field += NewSaclSize;
+ }
+
+
+
+ if (NewSaclPresent) {
+
+ //
+ // defaulted bit is off already
+ //
+
+ SepSetControlBits( NewDescriptor, SE_SACL_PRESENT );
+
+ } else {
+
+ //
+ // Propagate the SE_SACL_DEFAULTED and SE_SACL_PRESENT
+ // bits from the old security descriptor into the new
+ // one.
+ //
+
+ SepPropagateControlBits(
+ NewDescriptor,
+ IObjectsSecurityDescriptor,
+ SE_SACL_DEFAULTED | SE_SACL_PRESENT
+ );
+
+ }
+
+ //
+ // Fill in Dacl field in new SD
+ //
+
+ if (NewDacl == NULL) {
+ NewDescriptor->Dacl = NULL;
+
+ } else {
+
+ RtlMoveMemory( Field, NewDacl, NewDacl->AclSize );
+ NewDescriptor->Dacl = (PACL)RtlPointerToOffset(Base,Field);
+ SepApplyAclToObject( (PACL)Field, GenericMapping );
+ Field += NewDaclSize;
+ }
+
+ if (NewDaclPresent) {
+
+ //
+ // defaulted bit is off already
+ //
+
+ SepSetControlBits( NewDescriptor, SE_DACL_PRESENT );
+
+ } else {
+
+ //
+ // Propagate the SE_DACL_DEFAULTED and SE_DACL_PRESENT
+ // bits from the old security descriptor into the new
+ // one.
+ //
+
+ SepPropagateControlBits(
+ NewDescriptor,
+ IObjectsSecurityDescriptor,
+ SE_DACL_DEFAULTED | SE_DACL_PRESENT
+ );
+
+ }
+
+ //
+ // If we allocated memory for a server acl, we can free it now.
+ //
+
+ if (ServerDaclAllocated) {
+ ExFreePool( NewDacl );
+ }
+
+ //
+ // Fill in Owner field in new SD
+ //
+
+ RtlMoveMemory( Field, NewOwner, SeLengthSid(NewOwner) );
+ NewDescriptor->Owner = (PSID)RtlPointerToOffset(Base,Field);
+ Field += NewOwnerSize;
+
+ if (!NewOwnerPresent) {
+
+ //
+ // Propagate the SE_OWNER_DEFAULTED bit from the old SD.
+ // If a new owner is being assigned, we want to leave
+ // SE_OWNER_DEFAULTED off, which means leave it alone.
+ //
+
+ SepPropagateControlBits(
+ NewDescriptor,
+ IObjectsSecurityDescriptor,
+ SE_OWNER_DEFAULTED
+ );
+
+ } else {
+ ASSERT( !SepAreControlBitsSet( NewDescriptor, SE_OWNER_DEFAULTED ) );
+ }
+
+
+ //
+ // Fill in Group field in new SD
+ //
+
+ RtlMoveMemory( Field, NewGroup, SeLengthSid(NewGroup) );
+ NewDescriptor->Group = (PSID)RtlPointerToOffset(Base,Field);
+
+ if (!NewGroupPresent) {
+
+ //
+ // Propagate the SE_GROUP_DEFAULTED bit from the old SD
+ // If a new owner is being assigned, we want to leave
+ // SE_GROUP_DEFAULTED off, which means leave it alone.
+ //
+
+ SepPropagateControlBits(
+ NewDescriptor,
+ IObjectsSecurityDescriptor,
+ SE_GROUP_DEFAULTED
+ );
+ } else {
+ ASSERT( !SepAreControlBitsSet( NewDescriptor, SE_GROUP_DEFAULTED ) );
+
+ }
+
+// //
+// // Free old descriptor
+// //
+//
+// ExFreePool( IObjectsSecurityDescriptor );
+
+ *ObjectsSecurityDescriptor = (PSECURITY_DESCRIPTOR)NewDescriptor;
+
+ //
+ // and now we can return to our caller
+ //
+
+ return STATUS_SUCCESS;
+
+}
+
+
+
+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;
+ ULONG GroupLength;
+ ULONG DaclLength;
+ ULONG SaclLength;
+ PUCHAR NextFree;
+ SECURITY_DESCRIPTOR IObjectSecurity;
+
+ //
+ // Note that IObjectSecurity is not a pointer to a pointer
+ // like ObjectsSecurityDescriptor is.
+ //
+
+ SECURITY_DESCRIPTOR *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);
+
+ //
+ // Now make sure it's large enough for the security descriptor
+ // record
+ //
+
+ if (BufferLength < sizeof(SECURITY_DESCRIPTOR)) {
+
+ 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.
+ //
+
+ RtlCreateSecurityDescriptor( SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION );
+
+ //
+ // Mark it as self-relative
+ //
+
+ SepSetControlBits( 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
+ //
+
+ RtlMoveMemory( (&IObjectSecurity),
+ *ObjectsSecurityDescriptor,
+ sizeof(SECURITY_DESCRIPTOR) );
+
+ IObjectSecurity.Owner = SepOwnerAddrSecurityDescriptor(
+ (SECURITY_DESCRIPTOR *) *ObjectsSecurityDescriptor );
+ IObjectSecurity.Group = SepGroupAddrSecurityDescriptor(
+ (SECURITY_DESCRIPTOR *) *ObjectsSecurityDescriptor );
+ IObjectSecurity.Dacl = SepDaclAddrSecurityDescriptor(
+ (SECURITY_DESCRIPTOR *) *ObjectsSecurityDescriptor );
+ IObjectSecurity.Sacl = SepSaclAddrSecurityDescriptor(
+ (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);
+
+ if ( (((*SecurityInformation) & OWNER_SECURITY_INFORMATION)) &&
+ (IObjectSecurity.Owner != NULL) ) {
+
+ OwnerLength = SeLengthSid( IObjectSecurity.Owner );
+ Size += (ULONG)LongAlign(OwnerLength);
+
+ }
+
+ if ( (((*SecurityInformation) & GROUP_SECURITY_INFORMATION)) &&
+ (IObjectSecurity.Group != NULL) ) {
+
+ GroupLength = SeLengthSid( IObjectSecurity.Group );
+ Size += (ULONG)LongAlign(GroupLength);
+
+ }
+
+ if ( (((*SecurityInformation) & DACL_SECURITY_INFORMATION)) &&
+ (IObjectSecurity.Control & SE_DACL_PRESENT) &&
+ (IObjectSecurity.Dacl != NULL) ) {
+
+
+ DaclLength = (ULONG)LongAlign((IObjectSecurity.Dacl)->AclSize);
+ Size += DaclLength;
+
+ }
+
+ if ( (((*SecurityInformation) & SACL_SECURITY_INFORMATION)) &&
+ (IObjectSecurity.Control & SE_SACL_PRESENT) &&
+ (IObjectSecurity.Sacl != NULL) ) {
+
+ SaclLength = (ULONG)LongAlign((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.
+ //
+
+ RtlCreateSecurityDescriptor( SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION );
+
+ //
+ // Mark the returned Security Descriptor as being in
+ // self-relative format
+ //
+
+ SepSetControlBits( ISecurityDescriptor, SE_SELF_RELATIVE );
+
+ //
+ // NextFree is used to point to the next free spot in the
+ // returned security descriptor.
+ //
+
+ NextFree = LongAlign((PUCHAR)SecurityDescriptor +
+ sizeof(SECURITY_DESCRIPTOR));
+
+ //
+ // 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 = (PACL)((PUCHAR)NextFree - (PUCHAR)SecurityDescriptor);
+
+ SepPropagateControlBits(
+ ISecurityDescriptor,
+ &IObjectSecurity,
+ SE_OWNER_DEFAULTED
+ );
+
+ NextFree += (ULONG)LongAlign(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 = (PACL)((PUCHAR)NextFree - (PUCHAR)SecurityDescriptor);
+
+ SepPropagateControlBits(
+ ISecurityDescriptor,
+ &IObjectSecurity,
+ SE_GROUP_DEFAULTED
+ );
+
+ NextFree += (ULONG)LongAlign(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) &&
+ (IObjectSecurity.Control & SE_DACL_PRESENT) ) {
+
+ SepPropagateControlBits(
+ ISecurityDescriptor,
+ &IObjectSecurity,
+ SE_DACL_PRESENT | SE_DACL_DEFAULTED
+ );
+
+ //
+ // Copy the acl if non-null and update the NextFree pointer,
+ // keeping it longword aligned.
+ //
+
+ if (IObjectSecurity.Dacl != NULL) {
+
+ RtlMoveMemory( NextFree,
+ IObjectSecurity.Dacl,
+ (IObjectSecurity.Dacl)->AclSize );
+
+ ISecurityDescriptor->Dacl = (PACL)((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)) &&
+ (IObjectSecurity.Control & SE_SACL_PRESENT) ) {
+
+ SepPropagateControlBits(
+ ISecurityDescriptor,
+ &IObjectSecurity,
+ SE_SACL_PRESENT | SE_SACL_DEFAULTED
+ );
+
+ //
+ // Copy the acl if non-null and update the NextFree pointer,
+ // keeping it longword aligned.
+ //
+
+ if (IObjectSecurity.Sacl != NULL) {
+
+ RtlMoveMemory( NextFree,
+ IObjectSecurity.Sacl,
+ (IObjectSecurity.Sacl)->AclSize );
+
+ ISecurityDescriptor->Sacl = (PACL)((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 ));
+}