diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/se/semethod.c | |
download | NT4.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.c | 1279 |
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 )); +} |