Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

841 lines
21 KiB

/*++
Copyright (c) 1999-2002 Microsoft Corporation
Module Name:
seutil.c
Abstract:
This module implements general security utilities, and
dispatch routines for security IRPs.
Author:
Keith Moore (keithmo) 25-Mar-1999
Revision History:
--*/
#include "precomp.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, UlAssignSecurity )
#pragma alloc_text( PAGE, UlDeassignSecurity )
#pragma alloc_text( PAGE, UlSetSecurity )
#pragma alloc_text( PAGE, UlQuerySecurity )
#pragma alloc_text( PAGE, UlAccessCheck )
#pragma alloc_text( PAGE, UlSetSecurityDispatch )
#pragma alloc_text( PAGE, UlQuerySecurityDispatch )
#pragma alloc_text( PAGE, UlThreadAdminCheck )
#pragma alloc_text( PAGE, UlCreateSecurityDescriptor )
#pragma alloc_text( PAGE, UlCleanupSecurityDescriptor )
#pragma alloc_test( PAGE, UlMapGenericMask )
#endif // ALLOC_PRAGMA
#if 0
#endif
//
// Public functions.
//
/***************************************************************************++
Routine Description:
Assigns a new security descriptor.
Arguments:
pSecurityDescriptor - Supplies a pointer to the current security
descriptor pointer. The current security descriptor pointer
will be updated with the new security descriptor.
pAccessState - Supplies the ACCESS_STATE structure containing
the state of an access in progress.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlAssignSecurity(
IN OUT PSECURITY_DESCRIPTOR *pSecurityDescriptor,
IN PACCESS_STATE pAccessState
)
{
NTSTATUS status;
//
// Sanity check.
//
PAGED_CODE();
ASSERT( pSecurityDescriptor != NULL );
ASSERT( pAccessState != NULL );
//
// Assign the security descriptor.
//
SeLockSubjectContext( &pAccessState->SubjectSecurityContext );
status = SeAssignSecurity(
NULL, // ParentDescriptor
pAccessState->SecurityDescriptor,
pSecurityDescriptor,
FALSE, // IsDirectoryObject
&pAccessState->SubjectSecurityContext,
IoGetFileObjectGenericMapping(),
PagedPool
);
SeUnlockSubjectContext( &pAccessState->SubjectSecurityContext );
return status;
} // UlAssignSecurity
/***************************************************************************++
Routine Description:
Deletes a security descriptor.
Arguments:
pSecurityDescriptor - Supplies a pointer to the current security
descriptor pointer. The current security descriptor pointer
will be deleted.
--***************************************************************************/
VOID
UlDeassignSecurity(
IN OUT PSECURITY_DESCRIPTOR *pSecurityDescriptor
)
{
//
// Sanity check.
//
PAGED_CODE();
ASSERT( pSecurityDescriptor != NULL );
//
// If there's a security descriptor present, free it.
//
if (*pSecurityDescriptor != NULL)
{
SeDeassignSecurity( pSecurityDescriptor );
}
} // UlDeassignSecurity
/***************************************************************************++
Routine Description:
Sets a new security descriptor.
Arguments:
pSecurityDescriptor - Supplies a pointer to the current security
descriptor pointer. The current security descriptor will be
updated with the new security information.
pSecurityInformation - Indicates which security information is
to be applied to the object.
pNewSecurityDescriptor - Pointer to the new security descriptor
to be applied to the object.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlSetSecurity(
IN OUT PSECURITY_DESCRIPTOR *ppSecurityDescriptor,
IN PSECURITY_INFORMATION pSecurityInformation,
IN PSECURITY_DESCRIPTOR pNewSecurityDescriptor
)
{
NTSTATUS status;
PSECURITY_DESCRIPTOR pOldSecurityDescriptor;
SECURITY_SUBJECT_CONTEXT securitySubjectContext;
PAGED_CODE();
pOldSecurityDescriptor = *ppSecurityDescriptor;
SeCaptureSubjectContext(&securitySubjectContext);
SeLockSubjectContext(&securitySubjectContext);
status = SeSetSecurityDescriptorInfo(
NULL,
pSecurityInformation,
pNewSecurityDescriptor,
ppSecurityDescriptor,
PagedPool,
IoGetFileObjectGenericMapping()
);
SeUnlockSubjectContext(&securitySubjectContext);
SeReleaseSubjectContext(&securitySubjectContext);
if (NT_SUCCESS(status))
{
SeDeassignSecurity(&pOldSecurityDescriptor);
}
return status;
}
/***************************************************************************++
Routine Description:
Query for security descriptor information for an object.
Arguments:
pSecurityInformation - specifies what information is being queried.
pSecurityDescriptor - Supplies a pointer to the security descriptor
to be filled in.
pLength - Address of variable containing length of the above security
descriptor buffer. Upon return, this will contain the length needed
to store the requested information.
ppSecurityDescriptor - Address of a pointer to the objects security
descriptor.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlQuerySecurity(
IN PSECURITY_INFORMATION pSecurityInformation,
OUT PSECURITY_DESCRIPTOR pSecurityDescriptor,
IN OUT PULONG pLength,
IN PSECURITY_DESCRIPTOR *ppSecurityDescriptor
)
{
NTSTATUS status;
SECURITY_SUBJECT_CONTEXT securitySubjectContext;
PAGED_CODE();
SeCaptureSubjectContext(&securitySubjectContext);
SeLockSubjectContext(&securitySubjectContext);
status = SeQuerySecurityDescriptorInfo(
pSecurityInformation,
pSecurityDescriptor,
pLength,
ppSecurityDescriptor
);
SeUnlockSubjectContext(&securitySubjectContext);
SeReleaseSubjectContext(&securitySubjectContext);
return status;
}
/***************************************************************************++
Routine Description:
Determines if a user has access to the specified resource.
Arguments:
pSecurityDescriptor - Supplies the security descriptor protecting
the resource.
pAccessState - Supplies the ACCESS_STATE structure containing
the state of an access in progress.
DesiredAccess - Supplies an access mask describing the user's
desired access to the resource. This mask is assumed to not
contain generic access types.
RequestorMode - Supplies the processor mode by which the access is
being requested.
pObjectName - Supplies the name of the object being referenced.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlAccessCheck(
IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
IN PACCESS_STATE pAccessState,
IN ACCESS_MASK DesiredAccess,
IN KPROCESSOR_MODE RequestorMode,
IN PCWSTR pObjectName
)
{
NTSTATUS status, aaStatus;
BOOLEAN accessGranted;
PPRIVILEGE_SET pPrivileges = NULL;
ACCESS_MASK grantedAccess;
UNICODE_STRING objectName;
UNICODE_STRING typeName;
//
// Sanity check.
//
PAGED_CODE();
ASSERT( pSecurityDescriptor != NULL );
ASSERT( pAccessState != NULL );
//
// Perform the access check.
//
SeLockSubjectContext( &pAccessState->SubjectSecurityContext );
accessGranted = SeAccessCheck(
pSecurityDescriptor,
&pAccessState->SubjectSecurityContext,
TRUE, // SubjectContextLocked
DesiredAccess,
0, // PreviouslyGrantedAccess
&pPrivileges,
IoGetFileObjectGenericMapping(),
RequestorMode,
&grantedAccess,
&status
);
if (pPrivileges != NULL)
{
SeAppendPrivileges( pAccessState, pPrivileges );
SeFreePrivileges( pPrivileges );
}
if (accessGranted)
{
pAccessState->PreviouslyGrantedAccess |= grantedAccess;
pAccessState->RemainingDesiredAccess &= ~(grantedAccess | MAXIMUM_ALLOWED);
}
aaStatus = UlInitUnicodeStringEx( &typeName, L"Ul" );
if ( NT_SUCCESS(aaStatus) )
{
aaStatus = UlInitUnicodeStringEx( &objectName, pObjectName );
if ( NT_SUCCESS(aaStatus) )
{
SeOpenObjectAuditAlarm(
&typeName,
NULL, // Object
&objectName,
pSecurityDescriptor,
pAccessState,
FALSE, // ObjectCreated
accessGranted,
RequestorMode,
&pAccessState->GenerateOnClose
);
}
}
SeUnlockSubjectContext( &pAccessState->SubjectSecurityContext );
if (accessGranted)
{
status = STATUS_SUCCESS;
}
else
{
//
// SeAccessCheck() should have set the completion status.
//
ASSERT( !NT_SUCCESS(status) );
}
return status;
} // UlAccessCheck
NTSTATUS
UlSetSecurityDispatch(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
{
NTSTATUS status;
PIO_STACK_LOCATION pIrpSp;
PFILE_OBJECT pFileObject;
PUL_APP_POOL_PROCESS pProcess;
UNREFERENCED_PARAMETER(pDeviceObject);
PAGED_CODE();
UL_ENTER_DRIVER( "UlSetSecurityDispatch", pIrp );
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
pFileObject = pIrpSp->FileObject;
//
// We only allow changing the security descriptor on app
// pool handles.
//
if (!IS_APP_POOL_FO(pFileObject))
{
status = STATUS_INVALID_PARAMETER;
goto complete;
}
pProcess = GET_APP_POOL_PROCESS(pFileObject);
status = UlSetSecurity(
&pProcess->pAppPool->pSecurityDescriptor,
&pIrpSp->Parameters.SetSecurity.SecurityInformation,
pIrpSp->Parameters.SetSecurity.SecurityDescriptor
);
complete:
pIrp->IoStatus.Status = status;
UlCompleteRequest(pIrp, IO_NO_INCREMENT);
UL_LEAVE_DRIVER( "UlSetSecurityDispatch" );
RETURN(status);
} // UlSetSecurityDispatch
NTSTATUS
UlQuerySecurityDispatch(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
{
NTSTATUS status;
PIO_STACK_LOCATION pIrpSp;
PFILE_OBJECT pFileObject;
PUL_APP_POOL_PROCESS pProcess;
UNREFERENCED_PARAMETER(pDeviceObject);
PAGED_CODE();
UL_ENTER_DRIVER( "UlQuerySecurityDispatch", pIrp );
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
pFileObject = pIrpSp->FileObject;
//
// We only allow querying the security descriptor on app
// pool handles.
//
if (!IS_APP_POOL_FO(pFileObject))
{
status = STATUS_INVALID_PARAMETER;
goto complete;
}
pProcess = GET_APP_POOL_PROCESS(pFileObject);
status = UlQuerySecurity(
&pIrpSp->Parameters.QuerySecurity.SecurityInformation,
pIrp->UserBuffer,
&pIrpSp->Parameters.QuerySecurity.Length,
&pProcess->pAppPool->pSecurityDescriptor
);
if (pIrp->UserIosb)
{
pIrp->UserIosb->Information = pIrpSp->Parameters.QuerySecurity.Length;
}
complete:
pIrp->IoStatus.Status = status;
UlCompleteRequest(pIrp, IO_NO_INCREMENT);
UL_LEAVE_DRIVER( "UlQuerySecurityDispatch" );
RETURN(status);
} // UlQuerySecurityDispatch
/***************************************************************************++
Routine Description:
Determines if this is a thread with Admin/LocalSystem privileges.
Arguments:
DesiredAccess - Supplies an access mask describing the user's
desired access to the resource. This mask is assumed to not
contain generic access types.
RequestorMode - Supplies the processor mode by which the access is
being requested.
pObjectName - Supplies the name of the object being referenced.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlThreadAdminCheck(
IN ACCESS_MASK DesiredAccess,
IN KPROCESSOR_MODE RequestorMode,
IN PCWSTR pObjectName
)
{
ACCESS_STATE AccessState;
AUX_ACCESS_DATA AuxData;
NTSTATUS Status;
Status = SeCreateAccessState(
&AccessState,
&AuxData,
DesiredAccess,
NULL
);
if(NT_SUCCESS(Status))
{
Status = UlAccessCheck(
g_pAdminAllSystemAll,
&AccessState,
DesiredAccess,
RequestorMode,
pObjectName
);
SeDeleteAccessState(&AccessState);
}
return Status;
}
/***************************************************************************++
Routine Description:
Allocates and initializes a security descriptor with the specified
attributes.
Arguments:
pSecurityDescriptor - Supplies a pointer to the security descriptor
to initialize.
pSidMaskPairs - Supplies an array of SID/ACCESS_MASK pairs.
NumSidMaskPairs - Supplies the number of SID/ACESS_MASK pairs.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlCreateSecurityDescriptor(
OUT PSECURITY_DESCRIPTOR pSecurityDescriptor,
IN PSID_MASK_PAIR pSidMaskPairs,
IN ULONG NumSidMaskPairs
)
{
NTSTATUS status;
PACL pDacl;
ULONG daclLength;
ULONG i;
//
// Sanity check.
//
PAGED_CODE();
ASSERT( pSecurityDescriptor != NULL );
ASSERT( pSidMaskPairs != NULL );
ASSERT( NumSidMaskPairs > 0 );
//
// Setup locals so we know how to cleanup on exit.
//
pDacl = NULL;
//
// Initialize the security descriptor.
//
status = RtlCreateSecurityDescriptor(
pSecurityDescriptor, // SecurityDescriptor
SECURITY_DESCRIPTOR_REVISION // Revision
);
if (!NT_SUCCESS(status))
{
goto cleanup;
}
//
// Calculate the DACL length.
//
daclLength = sizeof(ACL);
for (i = 0 ; i < NumSidMaskPairs ; i++)
{
daclLength += sizeof(ACCESS_ALLOWED_ACE);
daclLength += RtlLengthSid( pSidMaskPairs[i].pSid );
}
//
// Allocate & initialize the DACL.
//
pDacl = (PACL) UL_ALLOCATE_POOL(
PagedPool,
daclLength,
UL_SECURITY_DATA_POOL_TAG
);
if (pDacl == NULL)
{
status = STATUS_INSUFFICIENT_RESOURCES;
goto cleanup;
}
status = RtlCreateAcl(
pDacl, // Acl
daclLength, // AclLength
ACL_REVISION // AclRevision
);
if (!NT_SUCCESS(status))
{
goto cleanup;
}
//
// Add the necessary access-allowed ACEs to the DACL.
//
for (i = 0 ; i < NumSidMaskPairs ; i++)
{
status = RtlAddAccessAllowedAceEx(
pDacl, // Acl
ACL_REVISION, // AceRevision
pSidMaskPairs[i].AceFlags, // Inheritance flags
pSidMaskPairs[i].AccessMask, // AccessMask
pSidMaskPairs[i].pSid // Sid
);
if (!NT_SUCCESS(status))
{
goto cleanup;
}
}
//
// Attach the DACL to the security descriptor.
//
status = RtlSetDaclSecurityDescriptor(
pSecurityDescriptor, // SecurityDescriptor
TRUE, // DaclPresent
pDacl, // Dacl
FALSE // DaclDefaulted
);
if (!NT_SUCCESS(status))
{
goto cleanup;
}
//
// Success!
//
ASSERT( NT_SUCCESS(status) );
return STATUS_SUCCESS;
cleanup:
ASSERT( !NT_SUCCESS(status) );
if (pDacl != NULL)
{
UL_FREE_POOL(
pDacl,
UL_SECURITY_DATA_POOL_TAG
);
}
return status;
} // UlpCreateSecurityDescriptor
/***************************************************************************++
Routine Description:
Frees any resources associated with the security descriptor created
by UlpCreateSecurityDescriptor().
Arguments:
pSecurityDescriptor - Supplies the security descriptor to cleanup.
--***************************************************************************/
VOID
UlCleanupSecurityDescriptor(
IN PSECURITY_DESCRIPTOR pSecurityDescriptor
)
{
NTSTATUS status;
PACL pDacl;
BOOLEAN daclPresent;
BOOLEAN daclDefaulted;
//
// Sanity check.
//
PAGED_CODE();
ASSERT( RtlValidSecurityDescriptor( pSecurityDescriptor ) );
//
// Try to retrieve the DACL from the security descriptor.
//
status = RtlGetDaclSecurityDescriptor(
pSecurityDescriptor, // SecurityDescriptor
&daclPresent, // DaclPresent
&pDacl, // Dacl
&daclDefaulted // DaclDefaulted
);
if (NT_SUCCESS(status))
{
if (daclPresent && (pDacl != NULL))
{
UL_FREE_POOL(
pDacl,
UL_SECURITY_DATA_POOL_TAG
);
}
}
} // UlCleanupSecurityDescriptor
/**************************************************************************++
Routine Description:
This routine maps the generic access masks of the ACE's present in the
DACL of the supplied security descriptor.
CODEWORK: Get RtlpApplyAclToObject exported.
Arguments:
pSecurityDescriptor - Supplies security descriptor.
Return Value:
NTSTATUS.
--**************************************************************************/
NTSTATUS
UlMapGenericMask(
PSECURITY_DESCRIPTOR pSecurityDescriptor
)
{
ULONG i;
PACE_HEADER Ace;
PACL Dacl;
NTSTATUS Status;
BOOLEAN Ignore;
BOOLEAN DaclPresent = FALSE;
//
// Get the DACL.
//
Status = RtlGetDaclSecurityDescriptor(
pSecurityDescriptor,
&DaclPresent,
&Dacl,
&Ignore
);
if (!NT_SUCCESS(Status))
{
return Status;
}
if (DaclPresent)
{
//
// RtlpApplyAclToObject(Acl, GenericMapping) is cloned below since
// it is not exported.
//
//
// Now walk the ACL, mapping each ACE as we go.
//
for (i = 0, Ace = FirstAce(Dacl);
i < Dacl->AceCount;
i += 1, Ace = NextAce(Ace))
{
if (IsMSAceType(Ace))
{
RtlApplyAceToObject(Ace, &g_UrlAccessGenericMapping);
}
}
}
return STATUS_SUCCESS;
}
//
// Private functions.
//