summaryrefslogtreecommitdiffstats
path: root/private/ntos/se/seastate.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/seastate.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/seastate.c')
-rw-r--r--private/ntos/se/seastate.c599
1 files changed, 599 insertions, 0 deletions
diff --git a/private/ntos/se/seastate.c b/private/ntos/se/seastate.c
new file mode 100644
index 000000000..5bdc56bcc
--- /dev/null
+++ b/private/ntos/se/seastate.c
@@ -0,0 +1,599 @@
+/*++
+
+Module Name:
+
+ SeAstate.c
+
+Abstract:
+
+ This Module implements the privilege check procedures.
+
+Author:
+
+ Robert Reichel (robertre) 20-March-90
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+ v1: robertre
+ new file, move Access State related routines here
+
+--*/
+
+#include "tokenp.h"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE,SeCreateAccessState)
+#pragma alloc_text(PAGE,SeDeleteAccessState)
+#pragma alloc_text(PAGE,SeAppendPrivileges)
+#pragma alloc_text(PAGE,SepConcatenatePrivileges)
+#endif
+
+
+//
+// Define logical sum of all generic accesses.
+//
+
+#define GENERIC_ACCESS (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL)
+
+
+//
+// The PRIVILEGE_SET data structure includes an array including ANYSIZE_ARRAY
+// elements. This definition provides the size of an empty PRIVILEGE_SET
+// (i.e., one with no privileges in it).
+//
+
+#define SEP_PRIVILEGE_SET_HEADER_SIZE \
+ ((ULONG)sizeof(PRIVILEGE_SET) - \
+ (ANYSIZE_ARRAY * (ULONG)sizeof(LUID_AND_ATTRIBUTES)))
+
+
+
+
+
+#if 0
+NTSTATUS
+SeCreateAccessState(
+ IN PACCESS_STATE AccessState,
+ IN ACCESS_MASK DesiredAccess,
+ IN PGENERIC_MAPPING GenericMapping OPTIONAL
+ )
+
+/*++
+Routine Description:
+
+ This routine initializes an ACCESS_STATE structure. This consists
+ of:
+
+ - zeroing the entire structure
+
+ - mapping generic access types in the passed DesiredAccess
+ and putting it into the structure
+
+ - "capturing" the Subject Context, which must be held for the
+ duration of the access attempt (at least until auditing is performed).
+
+ - Allocating an Operation ID, which is an LUID that will be used
+ to associate different parts of the access attempt in the audit
+ log.
+
+Arguments:
+
+ AccessState - a pointer to the structure to be initialized.
+
+ DesiredAccess - Access mask containing the desired access
+
+ GenericMapping - Optionally supplies a pointer to a generic mapping
+ that may be used to map any generic access requests that may
+ have been passed in the DesiredAccess parameter.
+
+ Note that if this parameter is not supplied, it must be filled
+ in at some later point. The IO system does this in IopParseDevice.
+
+Return Value:
+
+ Error if the attempt to allocate an LUID fails.
+
+ Note that this error may be safely ignored if it is known that all
+ security checks will be performed with PreviousMode == KernelMode.
+ Know what you're doing if you choose to ignore this.
+
+--*/
+
+{
+
+ ACCESS_MASK MappedAccessMask;
+ PSECURITY_DESCRIPTOR InputSecurityDescriptor = NULL;
+ PAUX_ACCESS_DATA AuxData;
+
+ PAGED_CODE();
+
+ //
+ // Don't modify what he passed in
+ //
+
+ MappedAccessMask = DesiredAccess;
+
+ //
+ // Map generic access to object specific access iff generic access types
+ // are specified and a generic access mapping table is provided.
+ //
+
+ if ( ((DesiredAccess & GENERIC_ACCESS) != 0) &&
+ ARGUMENT_PRESENT(GenericMapping) ) {
+
+ RtlMapGenericMask(
+ &MappedAccessMask,
+ GenericMapping
+ );
+ }
+
+ RtlZeroMemory(AccessState, sizeof(ACCESS_STATE));
+
+ //
+ // Assume RtlZeroMemory has initialized these fields properly
+ //
+
+ ASSERT( AccessState->SecurityDescriptor == NULL );
+ ASSERT( AccessState->PrivilegesAllocated == FALSE );
+
+ AccessState->AuxData = ExAllocatePool( PagedPool, sizeof( AUX_ACCESS_DATA ));
+
+ if (AccessState->AuxData == NULL) {
+ return( STATUS_NO_MEMORY );
+ }
+
+ AuxData = (PAUX_ACCESS_DATA)AccessState->AuxData;
+
+ SeCaptureSubjectContext(&AccessState->SubjectSecurityContext);
+
+ if (((PTOKEN)EffectiveToken( &AccessState->SubjectSecurityContext ))->TokenFlags & TOKEN_HAS_TRAVERSE_PRIVILEGE ) {
+ AccessState->Flags = TOKEN_HAS_TRAVERSE_PRIVILEGE;
+ }
+
+ AccessState->RemainingDesiredAccess = MappedAccessMask;
+ AccessState->OriginalDesiredAccess = DesiredAccess;
+ AuxData->PrivilegesUsed = (PPRIVILEGE_SET)((ULONG)AccessState +
+ (FIELD_OFFSET(ACCESS_STATE, Privileges)));
+
+ ExAllocateLocallyUniqueId(&AccessState->OperationID);
+
+ if (ARGUMENT_PRESENT(GenericMapping)) {
+ AuxData->GenericMapping = *GenericMapping;
+ }
+
+ return( STATUS_SUCCESS );
+
+}
+
+#endif
+
+
+NTSTATUS
+SeCreateAccessState(
+ IN PACCESS_STATE AccessState,
+ IN PAUX_ACCESS_DATA AuxData,
+ IN ACCESS_MASK DesiredAccess,
+ IN PGENERIC_MAPPING GenericMapping OPTIONAL
+ )
+
+/*++
+Routine Description:
+
+ This routine initializes an ACCESS_STATE structure. This consists
+ of:
+
+ - zeroing the entire structure
+
+ - mapping generic access types in the passed DesiredAccess
+ and putting it into the structure
+
+ - "capturing" the Subject Context, which must be held for the
+ duration of the access attempt (at least until auditing is performed).
+
+ - Allocating an Operation ID, which is an LUID that will be used
+ to associate different parts of the access attempt in the audit
+ log.
+
+Arguments:
+
+ AccessState - a pointer to the structure to be initialized.
+
+ AuxData - Supplies a buffer big enough for an AuxData structure
+ so we don't have to allocate one.
+
+ DesiredAccess - Access mask containing the desired access
+
+ GenericMapping - Optionally supplies a pointer to a generic mapping
+ that may be used to map any generic access requests that may
+ have been passed in the DesiredAccess parameter.
+
+ Note that if this parameter is not supplied, it must be filled
+ in at some later point. The IO system does this in IopParseDevice.
+
+Return Value:
+
+ Error if the attempt to allocate an LUID fails.
+
+ Note that this error may be safely ignored if it is known that all
+ security checks will be performed with PreviousMode == KernelMode.
+ Know what you're doing if you choose to ignore this.
+
+--*/
+
+{
+
+ ACCESS_MASK MappedAccessMask;
+ PSECURITY_DESCRIPTOR InputSecurityDescriptor = NULL;
+
+ PAGED_CODE();
+
+ //
+ // Don't modify what he passed in
+ //
+
+ MappedAccessMask = DesiredAccess;
+
+ //
+ // Map generic access to object specific access iff generic access types
+ // are specified and a generic access mapping table is provided.
+ //
+
+ if ( ((DesiredAccess & GENERIC_ACCESS) != 0) &&
+ ARGUMENT_PRESENT(GenericMapping) ) {
+
+ RtlMapGenericMask(
+ &MappedAccessMask,
+ GenericMapping
+ );
+ }
+
+ RtlZeroMemory(AccessState, sizeof(ACCESS_STATE));
+
+ //
+ // Assume RtlZeroMemory has initialized these fields properly
+ //
+
+ ASSERT( AccessState->SecurityDescriptor == NULL );
+ ASSERT( AccessState->PrivilegesAllocated == FALSE );
+
+ AccessState->AuxData = AuxData;
+
+ SeCaptureSubjectContext(&AccessState->SubjectSecurityContext);
+
+ if (((PTOKEN)EffectiveToken( &AccessState->SubjectSecurityContext ))->TokenFlags & TOKEN_HAS_TRAVERSE_PRIVILEGE ) {
+ AccessState->Flags = TOKEN_HAS_TRAVERSE_PRIVILEGE;
+ }
+
+ AccessState->RemainingDesiredAccess = MappedAccessMask;
+ AccessState->OriginalDesiredAccess = DesiredAccess;
+ AuxData->PrivilegesUsed = (PPRIVILEGE_SET)((ULONG)AccessState +
+ (FIELD_OFFSET(ACCESS_STATE, Privileges)));
+
+ ExAllocateLocallyUniqueId(&AccessState->OperationID);
+
+ if (ARGUMENT_PRESENT(GenericMapping)) {
+ AuxData->GenericMapping = *GenericMapping;
+ }
+
+ return( STATUS_SUCCESS );
+
+}
+
+
+#if 0
+
+
+VOID
+SeDeleteAccessState(
+ PACCESS_STATE AccessState
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deallocates any memory that may have been allocated as
+ part of constructing the access state (normally only for an excessive
+ number of privileges), and frees the Subject Context.
+
+Arguments:
+
+ AccessState - a pointer to the ACCESS_STATE structure to be
+ deallocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PAUX_ACCESS_DATA AuxData;
+
+ PAGED_CODE();
+
+ AuxData = (PAUX_ACCESS_DATA)AccessState->AuxData;
+
+ if (AccessState->PrivilegesAllocated) {
+ ExFreePool( (PVOID)AuxData->PrivilegesUsed );
+ }
+
+ if (AccessState->ObjectName.Buffer != NULL) {
+ ExFreePool(AccessState->ObjectName.Buffer);
+ }
+
+ if (AccessState->ObjectTypeName.Buffer != NULL) {
+ ExFreePool(AccessState->ObjectTypeName.Buffer);
+ }
+
+ ExFreePool( AuxData );
+
+ SeReleaseSubjectContext(&AccessState->SubjectSecurityContext);
+
+ return;
+}
+
+
+#endif
+
+VOID
+SeDeleteAccessState(
+ PACCESS_STATE AccessState
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deallocates any memory that may have been allocated as
+ part of constructing the access state (normally only for an excessive
+ number of privileges), and frees the Subject Context.
+
+Arguments:
+
+ AccessState - a pointer to the ACCESS_STATE structure to be
+ deallocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PAUX_ACCESS_DATA AuxData;
+
+ PAGED_CODE();
+
+ AuxData = (PAUX_ACCESS_DATA)AccessState->AuxData;
+
+ if (AccessState->PrivilegesAllocated) {
+ ExFreePool( (PVOID)AuxData->PrivilegesUsed );
+ }
+
+ if (AccessState->ObjectName.Buffer != NULL) {
+ ExFreePool(AccessState->ObjectName.Buffer);
+ }
+
+ if (AccessState->ObjectTypeName.Buffer != NULL) {
+ ExFreePool(AccessState->ObjectTypeName.Buffer);
+ }
+
+ SeReleaseSubjectContext(&AccessState->SubjectSecurityContext);
+
+ return;
+}
+
+VOID
+SeSetAccessStateGenericMapping (
+ PACCESS_STATE AccessState,
+ PGENERIC_MAPPING GenericMapping
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the GenericMapping field in an AccessState structure.
+ It must be called before access validation is performed if the GenericMapping
+ is not passed in when the AccessState structure is created.
+
+Arguments:
+
+ AccessState - a pointer to the ACCESS_STATE structure to be modified.
+
+ GenericMapping - a pointer to the GenericMapping to be copied into the AccessState.
+
+Return Value:
+
+
+--*/
+{
+ PAUX_ACCESS_DATA AuxData;
+
+ PAGED_CODE();
+
+ AuxData = (PAUX_ACCESS_DATA)AccessState->AuxData;
+
+ AuxData->GenericMapping = *GenericMapping;
+
+ return;
+}
+
+
+
+NTSTATUS
+SeAppendPrivileges(
+ PACCESS_STATE AccessState,
+ PPRIVILEGE_SET Privileges
+ )
+/*++
+
+Routine Description:
+
+ This routine takes a privilege set and adds it to the privilege set
+ imbedded in an ACCESS_STATE structure.
+
+ An AccessState may contain up to three imbedded privileges. To
+ add more, this routine will allocate a block of memory, copy
+ the current privileges into it, and append the new privilege
+ to that block. A bit is set in the AccessState indicating that
+ the pointer to the privilge set in the structure points to pool
+ memory and must be deallocated.
+
+Arguments:
+
+ AccessState - The AccessState structure representing the current
+ access attempt.
+
+ Privileges - A pointer to a privilege set to be added.
+
+Return Value:
+
+ STATUS_INSUFFICIENT_RESOURCES - an attempt to allocate pool memory
+ failed.
+
+--*/
+
+{
+ ULONG NewPrivilegeSetSize;
+ PPRIVILEGE_SET NewPrivilegeSet;
+ PAUX_ACCESS_DATA AuxData;
+
+ PAGED_CODE();
+
+ AuxData = (PAUX_ACCESS_DATA)AccessState->AuxData;
+
+ if (Privileges->PrivilegeCount + AuxData->PrivilegesUsed->PrivilegeCount >
+ INITIAL_PRIVILEGE_COUNT) {
+
+ //
+ // Compute the total size of the two privilege sets
+ //
+
+ NewPrivilegeSetSize = SepPrivilegeSetSize( Privileges ) +
+ SepPrivilegeSetSize( AuxData->PrivilegesUsed );
+
+ NewPrivilegeSet = ExAllocatePoolWithTag( PagedPool, NewPrivilegeSetSize, 'rPeS' );
+
+ if (NewPrivilegeSet == NULL) {
+ return( STATUS_INSUFFICIENT_RESOURCES );
+ }
+
+
+ RtlMoveMemory(
+ NewPrivilegeSet,
+ AuxData->PrivilegesUsed,
+ SepPrivilegeSetSize( AuxData->PrivilegesUsed )
+ );
+
+ //
+ // Note that this will adjust the privilege count in the
+ // structure for us.
+ //
+
+ SepConcatenatePrivileges(
+ NewPrivilegeSet,
+ NewPrivilegeSetSize,
+ Privileges
+ );
+
+ if (AccessState->PrivilegesAllocated) {
+ ExFreePool( AuxData->PrivilegesUsed );
+ }
+
+ AuxData->PrivilegesUsed = NewPrivilegeSet;
+
+ //
+ // Mark that we've allocated memory for the privilege set,
+ // so we know to free it when we're cleaning up.
+ //
+
+ AccessState->PrivilegesAllocated = TRUE;
+
+ } else {
+
+ //
+ // Note that this will adjust the privilege count in the
+ // structure for us.
+ //
+
+ SepConcatenatePrivileges(
+ AuxData->PrivilegesUsed,
+ sizeof(INITIAL_PRIVILEGE_SET),
+ Privileges
+ );
+
+ }
+
+ return( STATUS_SUCCESS );
+
+}
+
+
+VOID
+SepConcatenatePrivileges(
+ IN PPRIVILEGE_SET TargetPrivilegeSet,
+ IN ULONG TargetBufferSize,
+ IN PPRIVILEGE_SET SourcePrivilegeSet
+ )
+
+/*++
+
+Routine Description:
+
+ Takes two privilege sets and appends the second to the end of the
+ first.
+
+ There must be enough space left at the end of the first privilege
+ set to contain the second.
+
+Arguments:
+
+ TargetPrivilegeSet - Supplies a buffer containing a privilege set.
+ The buffer must be large enough to contain the second privilege
+ set.
+
+ TargetBufferSize - Supplies the size of the target buffer.
+
+ SourcePrivilegeSet - Supplies the privilege set to be copied
+ into the target buffer.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PVOID Base;
+ PVOID Source;
+ ULONG Length;
+
+ PAGED_CODE();
+
+ ASSERT( ((ULONG)SepPrivilegeSetSize( TargetPrivilegeSet ) +
+ (ULONG)SepPrivilegeSetSize( SourcePrivilegeSet ) -
+ SEP_PRIVILEGE_SET_HEADER_SIZE ) <=
+ TargetBufferSize
+ );
+
+ Base = (PVOID)((ULONG)TargetPrivilegeSet + SepPrivilegeSetSize( TargetPrivilegeSet ));
+
+ Source = (PVOID) ((ULONG)SourcePrivilegeSet + SEP_PRIVILEGE_SET_HEADER_SIZE);
+
+ Length = SourcePrivilegeSet->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
+
+ RtlMoveMemory(
+ Base,
+ Source,
+ Length
+ );
+
+ TargetPrivilegeSet->PrivilegeCount += SourcePrivilegeSet->PrivilegeCount;
+
+}