mirror of
https://github.com/reactos/reactos.git
synced 2024-07-01 02:10:07 +00:00
1153 lines
29 KiB
C
1153 lines
29 KiB
C
/* $Id$
|
|
*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS kernel
|
|
* FILE: ntoskrnl/se/semgr.c
|
|
* PURPOSE: Security manager
|
|
*
|
|
* PROGRAMMERS: No programmer listed.
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#include <ntoskrnl.h>
|
|
#define NDEBUG
|
|
#include <internal/debug.h>
|
|
|
|
/* GLOBALS ******************************************************************/
|
|
|
|
PSE_EXPORTS SeExports = NULL;
|
|
SE_EXPORTS SepExports;
|
|
|
|
static ERESOURCE SepSubjectContextLock;
|
|
|
|
|
|
/* PROTOTYPES ***************************************************************/
|
|
|
|
static BOOLEAN SepInitExports(VOID);
|
|
|
|
#if defined (ALLOC_PRAGMA)
|
|
#pragma alloc_text(INIT, SeInit1)
|
|
#pragma alloc_text(INIT, SeInit2)
|
|
#pragma alloc_text(INIT, SepInitExports)
|
|
#endif
|
|
|
|
/* FUNCTIONS ****************************************************************/
|
|
|
|
BOOLEAN
|
|
INIT_FUNCTION
|
|
NTAPI
|
|
SeInit1(VOID)
|
|
{
|
|
SepInitLuid();
|
|
|
|
if (!SepInitSecurityIDs())
|
|
return FALSE;
|
|
|
|
if (!SepInitDACLs())
|
|
return FALSE;
|
|
|
|
if (!SepInitSDs())
|
|
return FALSE;
|
|
|
|
SepInitPrivileges();
|
|
|
|
if (!SepInitExports())
|
|
return FALSE;
|
|
|
|
/* Initialize the subject context lock */
|
|
ExInitializeResource(&SepSubjectContextLock);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
INIT_FUNCTION
|
|
NTAPI
|
|
SeInit2(VOID)
|
|
{
|
|
SepInitializeTokenImplementation();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
SeInitSRM(VOID)
|
|
{
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING Name;
|
|
HANDLE DirectoryHandle;
|
|
HANDLE EventHandle;
|
|
NTSTATUS Status;
|
|
|
|
/* Create '\Security' directory */
|
|
RtlInitUnicodeString(&Name,
|
|
L"\\Security");
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&Name,
|
|
OBJ_PERMANENT,
|
|
0,
|
|
NULL);
|
|
Status = ZwCreateDirectoryObject(&DirectoryHandle,
|
|
DIRECTORY_ALL_ACCESS,
|
|
&ObjectAttributes);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failed to create 'Security' directory!\n");
|
|
return FALSE;
|
|
}
|
|
|
|
/* Create 'LSA_AUTHENTICATION_INITALIZED' event */
|
|
RtlInitUnicodeString(&Name,
|
|
L"\\LSA_AUTHENTICATION_INITALIZED");
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&Name,
|
|
OBJ_PERMANENT,
|
|
DirectoryHandle,
|
|
SePublicDefaultSd);
|
|
Status = ZwCreateEvent(&EventHandle,
|
|
EVENT_ALL_ACCESS,
|
|
&ObjectAttributes,
|
|
SynchronizationEvent,
|
|
FALSE);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failed to create 'LSA_AUTHENTICATION_INITALIZED' event!\n");
|
|
NtClose(DirectoryHandle);
|
|
return FALSE;
|
|
}
|
|
|
|
ZwClose(EventHandle);
|
|
ZwClose(DirectoryHandle);
|
|
|
|
/* FIXME: Create SRM port and listener thread */
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static BOOLEAN INIT_FUNCTION
|
|
SepInitExports(VOID)
|
|
{
|
|
SepExports.SeCreateTokenPrivilege = SeCreateTokenPrivilege;
|
|
SepExports.SeAssignPrimaryTokenPrivilege = SeAssignPrimaryTokenPrivilege;
|
|
SepExports.SeLockMemoryPrivilege = SeLockMemoryPrivilege;
|
|
SepExports.SeIncreaseQuotaPrivilege = SeIncreaseQuotaPrivilege;
|
|
SepExports.SeUnsolicitedInputPrivilege = SeUnsolicitedInputPrivilege;
|
|
SepExports.SeTcbPrivilege = SeTcbPrivilege;
|
|
SepExports.SeSecurityPrivilege = SeSecurityPrivilege;
|
|
SepExports.SeTakeOwnershipPrivilege = SeTakeOwnershipPrivilege;
|
|
SepExports.SeLoadDriverPrivilege = SeLoadDriverPrivilege;
|
|
SepExports.SeCreatePagefilePrivilege = SeCreatePagefilePrivilege;
|
|
SepExports.SeIncreaseBasePriorityPrivilege = SeIncreaseBasePriorityPrivilege;
|
|
SepExports.SeSystemProfilePrivilege = SeSystemProfilePrivilege;
|
|
SepExports.SeSystemtimePrivilege = SeSystemtimePrivilege;
|
|
SepExports.SeProfileSingleProcessPrivilege = SeProfileSingleProcessPrivilege;
|
|
SepExports.SeCreatePermanentPrivilege = SeCreatePermanentPrivilege;
|
|
SepExports.SeBackupPrivilege = SeBackupPrivilege;
|
|
SepExports.SeRestorePrivilege = SeRestorePrivilege;
|
|
SepExports.SeShutdownPrivilege = SeShutdownPrivilege;
|
|
SepExports.SeDebugPrivilege = SeDebugPrivilege;
|
|
SepExports.SeAuditPrivilege = SeAuditPrivilege;
|
|
SepExports.SeSystemEnvironmentPrivilege = SeSystemEnvironmentPrivilege;
|
|
SepExports.SeChangeNotifyPrivilege = SeChangeNotifyPrivilege;
|
|
SepExports.SeRemoteShutdownPrivilege = SeRemoteShutdownPrivilege;
|
|
|
|
SepExports.SeNullSid = SeNullSid;
|
|
SepExports.SeWorldSid = SeWorldSid;
|
|
SepExports.SeLocalSid = SeLocalSid;
|
|
SepExports.SeCreatorOwnerSid = SeCreatorOwnerSid;
|
|
SepExports.SeCreatorGroupSid = SeCreatorGroupSid;
|
|
SepExports.SeNtAuthoritySid = SeNtAuthoritySid;
|
|
SepExports.SeDialupSid = SeDialupSid;
|
|
SepExports.SeNetworkSid = SeNetworkSid;
|
|
SepExports.SeBatchSid = SeBatchSid;
|
|
SepExports.SeInteractiveSid = SeInteractiveSid;
|
|
SepExports.SeLocalSystemSid = SeLocalSystemSid;
|
|
SepExports.SeAliasAdminsSid = SeAliasAdminsSid;
|
|
SepExports.SeAliasUsersSid = SeAliasUsersSid;
|
|
SepExports.SeAliasGuestsSid = SeAliasGuestsSid;
|
|
SepExports.SeAliasPowerUsersSid = SeAliasPowerUsersSid;
|
|
SepExports.SeAliasAccountOpsSid = SeAliasAccountOpsSid;
|
|
SepExports.SeAliasSystemOpsSid = SeAliasSystemOpsSid;
|
|
SepExports.SeAliasPrintOpsSid = SeAliasPrintOpsSid;
|
|
SepExports.SeAliasBackupOpsSid = SeAliasBackupOpsSid;
|
|
SepExports.SeAuthenticatedUsersSid = SeAuthenticatedUsersSid;
|
|
SepExports.SeRestrictedSid = SeRestrictedSid;
|
|
SepExports.SeAnonymousLogonSid = SeAnonymousLogonSid;
|
|
|
|
SepExports.SeUndockPrivilege = SeUndockPrivilege;
|
|
SepExports.SeSyncAgentPrivilege = SeSyncAgentPrivilege;
|
|
SepExports.SeEnableDelegationPrivilege = SeEnableDelegationPrivilege;
|
|
|
|
SeExports = &SepExports;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID SepReferenceLogonSession(PLUID AuthenticationId)
|
|
{
|
|
UNIMPLEMENTED;
|
|
}
|
|
|
|
VOID SepDeReferenceLogonSession(PLUID AuthenticationId)
|
|
{
|
|
UNIMPLEMENTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
STDCALL
|
|
SeDefaultObjectMethod(PVOID Object,
|
|
SECURITY_OPERATION_CODE OperationType,
|
|
SECURITY_INFORMATION SecurityInformation,
|
|
PSECURITY_DESCRIPTOR _SecurityDescriptor,
|
|
PULONG ReturnLength,
|
|
PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
|
|
POOL_TYPE PoolType,
|
|
PGENERIC_MAPPING GenericMapping)
|
|
{
|
|
PISECURITY_DESCRIPTOR ObjectSd;
|
|
PISECURITY_DESCRIPTOR NewSd;
|
|
PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor;
|
|
POBJECT_HEADER Header = BODY_TO_HEADER(Object);
|
|
PSID Owner = 0;
|
|
PSID Group = 0;
|
|
PACL Dacl = 0;
|
|
PACL Sacl = 0;
|
|
ULONG OwnerLength = 0;
|
|
ULONG GroupLength = 0;
|
|
ULONG DaclLength = 0;
|
|
ULONG SaclLength = 0;
|
|
ULONG Control = 0;
|
|
ULONG_PTR Current;
|
|
NTSTATUS Status;
|
|
|
|
if (OperationType == SetSecurityDescriptor)
|
|
{
|
|
ObjectSd = Header->SecurityDescriptor;
|
|
|
|
/* Get owner and owner size */
|
|
if (SecurityInformation & OWNER_SECURITY_INFORMATION)
|
|
{
|
|
if (SecurityDescriptor->Owner != NULL)
|
|
{
|
|
if( SecurityDescriptor->Control & SE_SELF_RELATIVE )
|
|
Owner = (PSID)((ULONG_PTR)SecurityDescriptor->Owner +
|
|
(ULONG_PTR)SecurityDescriptor);
|
|
else
|
|
Owner = (PSID)SecurityDescriptor->Owner;
|
|
OwnerLength = ROUND_UP(RtlLengthSid(Owner), 4);
|
|
}
|
|
Control |= (SecurityDescriptor->Control & SE_OWNER_DEFAULTED);
|
|
}
|
|
else
|
|
{
|
|
if (ObjectSd->Owner != NULL)
|
|
{
|
|
Owner = (PSID)((ULONG_PTR)ObjectSd->Owner + (ULONG_PTR)ObjectSd);
|
|
OwnerLength = ROUND_UP(RtlLengthSid(Owner), 4);
|
|
}
|
|
Control |= (ObjectSd->Control & SE_OWNER_DEFAULTED);
|
|
}
|
|
|
|
/* Get group and group size */
|
|
if (SecurityInformation & GROUP_SECURITY_INFORMATION)
|
|
{
|
|
if (SecurityDescriptor->Group != NULL)
|
|
{
|
|
if( SecurityDescriptor->Control & SE_SELF_RELATIVE )
|
|
Group = (PSID)((ULONG_PTR)SecurityDescriptor->Group +
|
|
(ULONG_PTR)SecurityDescriptor);
|
|
else
|
|
Group = (PSID)SecurityDescriptor->Group;
|
|
GroupLength = ROUND_UP(RtlLengthSid(Group), 4);
|
|
}
|
|
Control |= (SecurityDescriptor->Control & SE_GROUP_DEFAULTED);
|
|
}
|
|
else
|
|
{
|
|
if (ObjectSd->Group != NULL)
|
|
{
|
|
Group = (PSID)((ULONG_PTR)ObjectSd->Group + (ULONG_PTR)ObjectSd);
|
|
GroupLength = ROUND_UP(RtlLengthSid(Group), 4);
|
|
}
|
|
Control |= (ObjectSd->Control & SE_GROUP_DEFAULTED);
|
|
}
|
|
|
|
/* Get DACL and DACL size */
|
|
if (SecurityInformation & DACL_SECURITY_INFORMATION)
|
|
{
|
|
if ((SecurityDescriptor->Control & SE_DACL_PRESENT) &&
|
|
(SecurityDescriptor->Dacl != NULL))
|
|
{
|
|
if( SecurityDescriptor->Control & SE_SELF_RELATIVE )
|
|
Dacl = (PACL)((ULONG_PTR)SecurityDescriptor->Dacl +
|
|
(ULONG_PTR)SecurityDescriptor);
|
|
else
|
|
Dacl = (PACL)SecurityDescriptor->Dacl;
|
|
|
|
DaclLength = ROUND_UP((ULONG)Dacl->AclSize, 4);
|
|
}
|
|
Control |= (SecurityDescriptor->Control & (SE_DACL_DEFAULTED | SE_DACL_PRESENT));
|
|
}
|
|
else
|
|
{
|
|
if ((ObjectSd->Control & SE_DACL_PRESENT) &&
|
|
(ObjectSd->Dacl != NULL))
|
|
{
|
|
Dacl = (PACL)((ULONG_PTR)ObjectSd->Dacl + (ULONG_PTR)ObjectSd);
|
|
DaclLength = ROUND_UP((ULONG)Dacl->AclSize, 4);
|
|
}
|
|
Control |= (ObjectSd->Control & (SE_DACL_DEFAULTED | SE_DACL_PRESENT));
|
|
}
|
|
|
|
/* Get SACL and SACL size */
|
|
if (SecurityInformation & SACL_SECURITY_INFORMATION)
|
|
{
|
|
if ((SecurityDescriptor->Control & SE_SACL_PRESENT) &&
|
|
(SecurityDescriptor->Sacl != NULL))
|
|
{
|
|
if( SecurityDescriptor->Control & SE_SELF_RELATIVE )
|
|
Sacl = (PACL)((ULONG_PTR)SecurityDescriptor->Sacl +
|
|
(ULONG_PTR)SecurityDescriptor);
|
|
else
|
|
Sacl = (PACL)SecurityDescriptor->Sacl;
|
|
SaclLength = ROUND_UP((ULONG)Sacl->AclSize, 4);
|
|
}
|
|
Control |= (SecurityDescriptor->Control & (SE_SACL_DEFAULTED | SE_SACL_PRESENT));
|
|
}
|
|
else
|
|
{
|
|
if ((ObjectSd->Control & SE_SACL_PRESENT) &&
|
|
(ObjectSd->Sacl != NULL))
|
|
{
|
|
Sacl = (PACL)((ULONG_PTR)ObjectSd->Sacl + (ULONG_PTR)ObjectSd);
|
|
SaclLength = ROUND_UP((ULONG)Sacl->AclSize, 4);
|
|
}
|
|
Control |= (ObjectSd->Control & (SE_SACL_DEFAULTED | SE_SACL_PRESENT));
|
|
}
|
|
|
|
NewSd = ExAllocatePool(NonPagedPool,
|
|
sizeof(SECURITY_DESCRIPTOR) + OwnerLength + GroupLength +
|
|
DaclLength + SaclLength);
|
|
if (NewSd == NULL)
|
|
{
|
|
ObDereferenceObject(Object);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlCreateSecurityDescriptor(NewSd,
|
|
SECURITY_DESCRIPTOR_REVISION1);
|
|
/* We always build a self-relative descriptor */
|
|
NewSd->Control = Control | SE_SELF_RELATIVE;
|
|
|
|
Current = (ULONG_PTR)NewSd + sizeof(SECURITY_DESCRIPTOR);
|
|
|
|
if (OwnerLength != 0)
|
|
{
|
|
RtlCopyMemory((PVOID)Current,
|
|
Owner,
|
|
OwnerLength);
|
|
NewSd->Owner = (PSID)(Current - (ULONG_PTR)NewSd);
|
|
Current += OwnerLength;
|
|
}
|
|
|
|
if (GroupLength != 0)
|
|
{
|
|
RtlCopyMemory((PVOID)Current,
|
|
Group,
|
|
GroupLength);
|
|
NewSd->Group = (PSID)(Current - (ULONG_PTR)NewSd);
|
|
Current += GroupLength;
|
|
}
|
|
|
|
if (DaclLength != 0)
|
|
{
|
|
RtlCopyMemory((PVOID)Current,
|
|
Dacl,
|
|
DaclLength);
|
|
NewSd->Dacl = (PACL)(Current - (ULONG_PTR)NewSd);
|
|
Current += DaclLength;
|
|
}
|
|
|
|
if (SaclLength != 0)
|
|
{
|
|
RtlCopyMemory((PVOID)Current,
|
|
Sacl,
|
|
SaclLength);
|
|
NewSd->Sacl = (PACL)(Current - (ULONG_PTR)NewSd);
|
|
Current += SaclLength;
|
|
}
|
|
|
|
/* Add the new SD */
|
|
Status = ObpAddSecurityDescriptor(NewSd,
|
|
&Header->SecurityDescriptor);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Remove the old security descriptor */
|
|
ObpRemoveSecurityDescriptor(ObjectSd);
|
|
}
|
|
else
|
|
{
|
|
/* Restore the old security descriptor */
|
|
Header->SecurityDescriptor = ObjectSd;
|
|
}
|
|
|
|
ExFreePool(NewSd);
|
|
}
|
|
else if (OperationType == QuerySecurityDescriptor)
|
|
{
|
|
Status = SeQuerySecurityDescriptorInfo(&SecurityInformation,
|
|
SecurityDescriptor,
|
|
ReturnLength,
|
|
&Header->SecurityDescriptor);
|
|
}
|
|
else if (OperationType == AssignSecurityDescriptor)
|
|
{
|
|
/* Assign the security descriptor to the object header */
|
|
Status = ObpAddSecurityDescriptor(SecurityDescriptor,
|
|
&Header->SecurityDescriptor);
|
|
}
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID STDCALL
|
|
SeCaptureSubjectContext(OUT PSECURITY_SUBJECT_CONTEXT SubjectContext)
|
|
{
|
|
PETHREAD Thread;
|
|
BOOLEAN CopyOnOpen;
|
|
BOOLEAN EffectiveOnly;
|
|
|
|
PAGED_CODE();
|
|
|
|
Thread = PsGetCurrentThread();
|
|
if (Thread == NULL)
|
|
{
|
|
SubjectContext->ProcessAuditId = 0;
|
|
SubjectContext->PrimaryToken = NULL;
|
|
SubjectContext->ClientToken = NULL;
|
|
SubjectContext->ImpersonationLevel = 0;
|
|
}
|
|
else
|
|
{
|
|
SubjectContext->ProcessAuditId = Thread->ThreadsProcess;
|
|
SubjectContext->ClientToken =
|
|
PsReferenceImpersonationToken(Thread,
|
|
&CopyOnOpen,
|
|
&EffectiveOnly,
|
|
&SubjectContext->ImpersonationLevel);
|
|
SubjectContext->PrimaryToken = PsReferencePrimaryToken(Thread->ThreadsProcess);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID STDCALL
|
|
SeLockSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
KeEnterCriticalRegion();
|
|
ExAcquireResourceExclusiveLite(&SepSubjectContextLock, TRUE);
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID STDCALL
|
|
SeUnlockSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
ExReleaseResourceLite(&SepSubjectContextLock);
|
|
KeLeaveCriticalRegion();
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID STDCALL
|
|
SeReleaseSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (SubjectContext->PrimaryToken != NULL)
|
|
{
|
|
ObDereferenceObject(SubjectContext->PrimaryToken);
|
|
}
|
|
|
|
if (SubjectContext->ClientToken != NULL)
|
|
{
|
|
ObDereferenceObject(SubjectContext->ClientToken);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS STDCALL
|
|
SeDeassignSecurity(PSECURITY_DESCRIPTOR *SecurityDescriptor)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (*SecurityDescriptor != NULL)
|
|
{
|
|
ExFreePool(*SecurityDescriptor);
|
|
*SecurityDescriptor = NULL;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
NTSTATUS STDCALL
|
|
SeAssignSecurityEx(IN PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL,
|
|
IN PSECURITY_DESCRIPTOR ExplicitDescriptor OPTIONAL,
|
|
OUT PSECURITY_DESCRIPTOR *NewDescriptor,
|
|
IN GUID *ObjectType OPTIONAL,
|
|
IN BOOLEAN IsDirectoryObject,
|
|
IN ULONG AutoInheritFlags,
|
|
IN PSECURITY_SUBJECT_CONTEXT SubjectContext,
|
|
IN PGENERIC_MAPPING GenericMapping,
|
|
IN POOL_TYPE PoolType)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/*
|
|
* FUNCTION: Creates a security descriptor for a new object.
|
|
* ARGUMENTS:
|
|
* ParentDescriptor =
|
|
* ExplicitDescriptor =
|
|
* NewDescriptor =
|
|
* IsDirectoryObject =
|
|
* SubjectContext =
|
|
* GeneralMapping =
|
|
* PoolType =
|
|
* RETURNS: Status
|
|
*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS STDCALL
|
|
SeAssignSecurity(PSECURITY_DESCRIPTOR _ParentDescriptor OPTIONAL,
|
|
PSECURITY_DESCRIPTOR _ExplicitDescriptor OPTIONAL,
|
|
PSECURITY_DESCRIPTOR *NewDescriptor,
|
|
BOOLEAN IsDirectoryObject,
|
|
PSECURITY_SUBJECT_CONTEXT SubjectContext,
|
|
PGENERIC_MAPPING GenericMapping,
|
|
POOL_TYPE PoolType)
|
|
{
|
|
PISECURITY_DESCRIPTOR ParentDescriptor = _ParentDescriptor;
|
|
PISECURITY_DESCRIPTOR ExplicitDescriptor = _ExplicitDescriptor;
|
|
PISECURITY_DESCRIPTOR Descriptor;
|
|
PTOKEN Token;
|
|
ULONG OwnerLength = 0;
|
|
ULONG GroupLength = 0;
|
|
ULONG DaclLength = 0;
|
|
ULONG SaclLength = 0;
|
|
ULONG Length = 0;
|
|
ULONG Control = 0;
|
|
ULONG_PTR Current;
|
|
PSID Owner = NULL;
|
|
PSID Group = NULL;
|
|
PACL Dacl = NULL;
|
|
PACL Sacl = NULL;
|
|
|
|
PAGED_CODE();
|
|
|
|
/* Lock subject context */
|
|
SeLockSubjectContext(SubjectContext);
|
|
|
|
if (SubjectContext->ClientToken != NULL)
|
|
{
|
|
Token = SubjectContext->ClientToken;
|
|
}
|
|
else
|
|
{
|
|
Token = SubjectContext->PrimaryToken;
|
|
}
|
|
|
|
|
|
/* Inherit the Owner SID */
|
|
if (ExplicitDescriptor != NULL && ExplicitDescriptor->Owner != NULL)
|
|
{
|
|
DPRINT("Use explicit owner sid!\n");
|
|
Owner = ExplicitDescriptor->Owner;
|
|
|
|
if (ExplicitDescriptor->Control & SE_SELF_RELATIVE)
|
|
{
|
|
Owner = (PSID)(((ULONG_PTR)Owner) + (ULONG_PTR)ExplicitDescriptor);
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Token != NULL)
|
|
{
|
|
DPRINT("Use token owner sid!\n");
|
|
Owner = Token->UserAndGroups[Token->DefaultOwnerIndex].Sid;
|
|
}
|
|
else
|
|
{
|
|
DPRINT("Use default owner sid!\n");
|
|
Owner = SeLocalSystemSid;
|
|
}
|
|
|
|
Control |= SE_OWNER_DEFAULTED;
|
|
}
|
|
|
|
OwnerLength = ROUND_UP(RtlLengthSid(Owner), 4);
|
|
|
|
|
|
/* Inherit the Group SID */
|
|
if (ExplicitDescriptor != NULL && ExplicitDescriptor->Group != NULL)
|
|
{
|
|
DPRINT("Use explicit group sid!\n");
|
|
Group = ExplicitDescriptor->Group;
|
|
if (ExplicitDescriptor->Control & SE_SELF_RELATIVE)
|
|
{
|
|
Group = (PSID)(((ULONG_PTR)Group) + (ULONG_PTR)ExplicitDescriptor);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Token != NULL)
|
|
{
|
|
DPRINT("Use token group sid!\n");
|
|
Group = Token->PrimaryGroup;
|
|
}
|
|
else
|
|
{
|
|
DPRINT("Use default group sid!\n");
|
|
Group = SeLocalSystemSid;
|
|
}
|
|
|
|
Control |= SE_OWNER_DEFAULTED;
|
|
}
|
|
|
|
GroupLength = ROUND_UP(RtlLengthSid(Group), 4);
|
|
|
|
|
|
/* Inherit the DACL */
|
|
if (ExplicitDescriptor != NULL &&
|
|
(ExplicitDescriptor->Control & SE_DACL_PRESENT) &&
|
|
!(ExplicitDescriptor->Control & SE_DACL_DEFAULTED))
|
|
{
|
|
DPRINT("Use explicit DACL!\n");
|
|
Dacl = ExplicitDescriptor->Dacl;
|
|
if (Dacl != NULL && (ExplicitDescriptor->Control & SE_SELF_RELATIVE))
|
|
{
|
|
Dacl = (PACL)(((ULONG_PTR)Dacl) + (ULONG_PTR)ExplicitDescriptor);
|
|
}
|
|
|
|
Control |= SE_DACL_PRESENT;
|
|
}
|
|
else if (ParentDescriptor != NULL &&
|
|
(ParentDescriptor->Control & SE_DACL_PRESENT))
|
|
{
|
|
DPRINT("Use parent DACL!\n");
|
|
/* FIXME: Inherit */
|
|
Dacl = ParentDescriptor->Dacl;
|
|
if (Dacl != NULL && (ParentDescriptor->Control & SE_SELF_RELATIVE))
|
|
{
|
|
Dacl = (PACL)(((ULONG_PTR)Dacl) + (ULONG_PTR)ParentDescriptor);
|
|
}
|
|
Control |= (SE_DACL_PRESENT | SE_DACL_DEFAULTED);
|
|
}
|
|
else if (Token != NULL && Token->DefaultDacl != NULL)
|
|
{
|
|
DPRINT("Use token default DACL!\n");
|
|
/* FIXME: Inherit */
|
|
Dacl = Token->DefaultDacl;
|
|
Control |= (SE_DACL_PRESENT | SE_DACL_DEFAULTED);
|
|
}
|
|
else
|
|
{
|
|
DPRINT("Use NULL DACL!\n");
|
|
Dacl = NULL;
|
|
Control |= (SE_DACL_PRESENT | SE_DACL_DEFAULTED);
|
|
}
|
|
|
|
DaclLength = (Dacl != NULL) ? ROUND_UP(Dacl->AclSize, 4) : 0;
|
|
|
|
|
|
/* Inherit the SACL */
|
|
if (ExplicitDescriptor != NULL &&
|
|
(ExplicitDescriptor->Control & SE_SACL_PRESENT) &&
|
|
!(ExplicitDescriptor->Control & SE_SACL_DEFAULTED))
|
|
{
|
|
DPRINT("Use explicit SACL!\n");
|
|
Sacl = ExplicitDescriptor->Sacl;
|
|
if (Sacl != NULL && (ExplicitDescriptor->Control & SE_SELF_RELATIVE))
|
|
{
|
|
Sacl = (PACL)(((ULONG_PTR)Sacl) + (ULONG_PTR)ExplicitDescriptor);
|
|
}
|
|
|
|
Control |= SE_SACL_PRESENT;
|
|
}
|
|
else if (ParentDescriptor != NULL &&
|
|
(ParentDescriptor->Control & SE_SACL_PRESENT))
|
|
{
|
|
DPRINT("Use parent SACL!\n");
|
|
/* FIXME: Inherit */
|
|
Sacl = ParentDescriptor->Sacl;
|
|
if (Sacl != NULL && (ParentDescriptor->Control & SE_SELF_RELATIVE))
|
|
{
|
|
Sacl = (PACL)(((ULONG_PTR)Sacl) + (ULONG_PTR)ParentDescriptor);
|
|
}
|
|
Control |= (SE_SACL_PRESENT | SE_SACL_DEFAULTED);
|
|
}
|
|
|
|
SaclLength = (Sacl != NULL) ? ROUND_UP(Sacl->AclSize, 4) : 0;
|
|
|
|
|
|
/* Allocate and initialize the new security descriptor */
|
|
Length = sizeof(SECURITY_DESCRIPTOR) +
|
|
OwnerLength + GroupLength + DaclLength + SaclLength;
|
|
|
|
DPRINT("L: sizeof(SECURITY_DESCRIPTOR) %d OwnerLength %d GroupLength %d DaclLength %d SaclLength %d\n",
|
|
sizeof(SECURITY_DESCRIPTOR),
|
|
OwnerLength,
|
|
GroupLength,
|
|
DaclLength,
|
|
SaclLength);
|
|
|
|
Descriptor = ExAllocatePool(PagedPool,
|
|
Length);
|
|
if (Descriptor == NULL)
|
|
{
|
|
DPRINT1("ExAlloctePool() failed\n");
|
|
/* FIXME: Unlock subject context */
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory( Descriptor, Length );
|
|
RtlCreateSecurityDescriptor(Descriptor,
|
|
SECURITY_DESCRIPTOR_REVISION);
|
|
|
|
Descriptor->Control = Control | SE_SELF_RELATIVE;
|
|
|
|
Current = (ULONG_PTR)Descriptor + sizeof(SECURITY_DESCRIPTOR);
|
|
|
|
if (SaclLength != 0)
|
|
{
|
|
RtlCopyMemory((PVOID)Current,
|
|
Sacl,
|
|
SaclLength);
|
|
Descriptor->Sacl = (PACL)((ULONG_PTR)Current - (ULONG_PTR)Descriptor);
|
|
Current += SaclLength;
|
|
}
|
|
|
|
if (DaclLength != 0)
|
|
{
|
|
RtlCopyMemory((PVOID)Current,
|
|
Dacl,
|
|
DaclLength);
|
|
Descriptor->Dacl = (PACL)((ULONG_PTR)Current - (ULONG_PTR)Descriptor);
|
|
Current += DaclLength;
|
|
}
|
|
|
|
if (OwnerLength != 0)
|
|
{
|
|
RtlCopyMemory((PVOID)Current,
|
|
Owner,
|
|
OwnerLength);
|
|
Descriptor->Owner = (PSID)((ULONG_PTR)Current - (ULONG_PTR)Descriptor);
|
|
Current += OwnerLength;
|
|
DPRINT("Owner of %x at %x\n", Descriptor, Descriptor->Owner);
|
|
}
|
|
else
|
|
DPRINT("Owner of %x is zero length\n", Descriptor);
|
|
|
|
if (GroupLength != 0)
|
|
{
|
|
memmove((PVOID)Current,
|
|
Group,
|
|
GroupLength);
|
|
Descriptor->Group = (PSID)((ULONG_PTR)Current - (ULONG_PTR)Descriptor);
|
|
}
|
|
|
|
/* Unlock subject context */
|
|
SeUnlockSubjectContext(SubjectContext);
|
|
|
|
*NewDescriptor = Descriptor;
|
|
|
|
DPRINT("Descrptor %x\n", Descriptor);
|
|
ASSERT(RtlLengthSecurityDescriptor(Descriptor));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
static BOOLEAN
|
|
SepSidInToken(PACCESS_TOKEN _Token,
|
|
PSID Sid)
|
|
{
|
|
ULONG i;
|
|
PTOKEN Token = (PTOKEN)_Token;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (Token->UserAndGroupCount == 0)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
for (i=0; i<Token->UserAndGroupCount; i++)
|
|
{
|
|
if (RtlEqualSid(Sid, Token->UserAndGroups[i].Sid))
|
|
{
|
|
if (Token->UserAndGroups[i].Attributes & SE_GROUP_ENABLED)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
* FUNCTION: Determines whether the requested access rights can be granted
|
|
* to an object protected by a security descriptor and an object owner
|
|
* ARGUMENTS:
|
|
* SecurityDescriptor = Security descriptor protecting the object
|
|
* SubjectSecurityContext = Subject's captured security context
|
|
* SubjectContextLocked = Indicates the user's subject context is locked
|
|
* DesiredAccess = Access rights the caller is trying to acquire
|
|
* PreviouslyGrantedAccess = Specified the access rights already granted
|
|
* Privileges = ?
|
|
* GenericMapping = Generic mapping associated with the object
|
|
* AccessMode = Access mode used for the check
|
|
* GrantedAccess (OUT) = On return specifies the access granted
|
|
* AccessStatus (OUT) = Status indicating why access was denied
|
|
* RETURNS: If access was granted, returns TRUE
|
|
*
|
|
* @implemented
|
|
*/
|
|
BOOLEAN STDCALL
|
|
SeAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
|
|
IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
|
|
IN BOOLEAN SubjectContextLocked,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN ACCESS_MASK PreviouslyGrantedAccess,
|
|
OUT PPRIVILEGE_SET* Privileges,
|
|
IN PGENERIC_MAPPING GenericMapping,
|
|
IN KPROCESSOR_MODE AccessMode,
|
|
OUT PACCESS_MASK GrantedAccess,
|
|
OUT PNTSTATUS AccessStatus)
|
|
{
|
|
LUID_AND_ATTRIBUTES Privilege;
|
|
ACCESS_MASK CurrentAccess;
|
|
PACCESS_TOKEN Token;
|
|
ULONG i;
|
|
PACL Dacl;
|
|
BOOLEAN Present;
|
|
BOOLEAN Defaulted;
|
|
PACE CurrentAce;
|
|
PSID Sid;
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
CurrentAccess = PreviouslyGrantedAccess;
|
|
|
|
if (SubjectContextLocked == FALSE)
|
|
{
|
|
SeLockSubjectContext(SubjectSecurityContext);
|
|
}
|
|
|
|
Token = SubjectSecurityContext->ClientToken ?
|
|
SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken;
|
|
|
|
/* Get the DACL */
|
|
Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor,
|
|
&Present,
|
|
&Dacl,
|
|
&Defaulted);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
if (SubjectContextLocked == FALSE)
|
|
{
|
|
SeUnlockSubjectContext(SubjectSecurityContext);
|
|
}
|
|
|
|
*AccessStatus = Status;
|
|
return FALSE;
|
|
}
|
|
|
|
/* RULE 1: Grant desired access if the object is unprotected */
|
|
if (Present == TRUE && Dacl == NULL)
|
|
{
|
|
if (SubjectContextLocked == FALSE)
|
|
{
|
|
SeUnlockSubjectContext(SubjectSecurityContext);
|
|
}
|
|
|
|
*GrantedAccess = DesiredAccess;
|
|
*AccessStatus = STATUS_SUCCESS;
|
|
return TRUE;
|
|
}
|
|
|
|
CurrentAccess = PreviouslyGrantedAccess;
|
|
|
|
/* RULE 2: Check token for 'take ownership' privilege */
|
|
Privilege.Luid = SeTakeOwnershipPrivilege;
|
|
Privilege.Attributes = SE_PRIVILEGE_ENABLED;
|
|
|
|
if (SepPrivilegeCheck(Token,
|
|
&Privilege,
|
|
1,
|
|
PRIVILEGE_SET_ALL_NECESSARY,
|
|
AccessMode))
|
|
{
|
|
CurrentAccess |= WRITE_OWNER;
|
|
if (DesiredAccess == CurrentAccess)
|
|
{
|
|
if (SubjectContextLocked == FALSE)
|
|
{
|
|
SeUnlockSubjectContext(SubjectSecurityContext);
|
|
}
|
|
|
|
*GrantedAccess = CurrentAccess;
|
|
*AccessStatus = STATUS_SUCCESS;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
/* RULE 3: Check whether the token is the owner */
|
|
Status = RtlGetOwnerSecurityDescriptor(SecurityDescriptor,
|
|
&Sid,
|
|
&Defaulted);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("RtlGetOwnerSecurityDescriptor() failed (Status %lx)\n", Status);
|
|
if (SubjectContextLocked == FALSE)
|
|
{
|
|
SeUnlockSubjectContext(SubjectSecurityContext);
|
|
}
|
|
|
|
*AccessStatus = Status;
|
|
return FALSE;
|
|
}
|
|
|
|
if (SepSidInToken(Token, Sid))
|
|
{
|
|
CurrentAccess |= (READ_CONTROL | WRITE_DAC);
|
|
if (DesiredAccess == CurrentAccess)
|
|
{
|
|
if (SubjectContextLocked == FALSE)
|
|
{
|
|
SeUnlockSubjectContext(SubjectSecurityContext);
|
|
}
|
|
|
|
*GrantedAccess = CurrentAccess;
|
|
*AccessStatus = STATUS_SUCCESS;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
/* Fail if DACL is absent */
|
|
if (Present == FALSE)
|
|
{
|
|
if (SubjectContextLocked == FALSE)
|
|
{
|
|
SeUnlockSubjectContext(SubjectSecurityContext);
|
|
}
|
|
|
|
*GrantedAccess = 0;
|
|
*AccessStatus = STATUS_ACCESS_DENIED;
|
|
return TRUE;
|
|
}
|
|
|
|
/* RULE 4: Grant rights according to the DACL */
|
|
CurrentAce = (PACE)(Dacl + 1);
|
|
for (i = 0; i < Dacl->AceCount; i++)
|
|
{
|
|
Sid = (PSID)(CurrentAce + 1);
|
|
if (CurrentAce->Header.AceType == ACCESS_DENIED_ACE_TYPE)
|
|
{
|
|
if (SepSidInToken(Token, Sid))
|
|
{
|
|
if (SubjectContextLocked == FALSE)
|
|
{
|
|
SeUnlockSubjectContext(SubjectSecurityContext);
|
|
}
|
|
|
|
*GrantedAccess = 0;
|
|
*AccessStatus = STATUS_ACCESS_DENIED;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
|
|
{
|
|
if (SepSidInToken(Token, Sid))
|
|
{
|
|
CurrentAccess |= CurrentAce->AccessMask;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SubjectContextLocked == FALSE)
|
|
{
|
|
SeUnlockSubjectContext(SubjectSecurityContext);
|
|
}
|
|
|
|
DPRINT("CurrentAccess %08lx\n DesiredAccess %08lx\n",
|
|
CurrentAccess, DesiredAccess);
|
|
|
|
*GrantedAccess = CurrentAccess & DesiredAccess;
|
|
|
|
*AccessStatus =
|
|
(*GrantedAccess == DesiredAccess) ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
NTSTATUS STDCALL
|
|
NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
|
|
IN HANDLE TokenHandle,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN PGENERIC_MAPPING GenericMapping,
|
|
OUT PPRIVILEGE_SET PrivilegeSet,
|
|
OUT PULONG ReturnLength,
|
|
OUT PACCESS_MASK GrantedAccess,
|
|
OUT PNTSTATUS AccessStatus)
|
|
{
|
|
SECURITY_SUBJECT_CONTEXT SubjectSecurityContext = {0};
|
|
KPROCESSOR_MODE PreviousMode;
|
|
PTOKEN Token;
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
DPRINT("NtAccessCheck() called\n");
|
|
|
|
PreviousMode = KeGetPreviousMode();
|
|
if (PreviousMode == KernelMode)
|
|
{
|
|
*GrantedAccess = DesiredAccess;
|
|
*AccessStatus = STATUS_SUCCESS;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
Status = ObReferenceObjectByHandle(TokenHandle,
|
|
TOKEN_QUERY,
|
|
SepTokenObjectType,
|
|
PreviousMode,
|
|
(PVOID*)&Token,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failed to reference token (Status %lx)\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
/* Check token type */
|
|
if (Token->TokenType != TokenImpersonation)
|
|
{
|
|
DPRINT1("No impersonation token\n");
|
|
ObDereferenceObject(Token);
|
|
return STATUS_ACCESS_VIOLATION;
|
|
}
|
|
|
|
/* Check impersonation level */
|
|
if (Token->ImpersonationLevel < SecurityAnonymous)
|
|
{
|
|
DPRINT1("Invalid impersonation level\n");
|
|
ObDereferenceObject(Token);
|
|
return STATUS_ACCESS_VIOLATION;
|
|
}
|
|
|
|
SubjectSecurityContext.ClientToken = Token;
|
|
SubjectSecurityContext.ImpersonationLevel = Token->ImpersonationLevel;
|
|
|
|
/* Lock subject context */
|
|
SeLockSubjectContext(&SubjectSecurityContext);
|
|
|
|
if (SeAccessCheck(SecurityDescriptor,
|
|
&SubjectSecurityContext,
|
|
TRUE,
|
|
DesiredAccess,
|
|
0,
|
|
&PrivilegeSet,
|
|
GenericMapping,
|
|
PreviousMode,
|
|
GrantedAccess,
|
|
AccessStatus))
|
|
{
|
|
Status = *AccessStatus;
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_ACCESS_DENIED;
|
|
}
|
|
|
|
/* Unlock subject context */
|
|
SeUnlockSubjectContext(&SubjectSecurityContext);
|
|
|
|
ObDereferenceObject(Token);
|
|
|
|
DPRINT("NtAccessCheck() done\n");
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID STDCALL
|
|
SeQuerySecurityAccessMask(IN SECURITY_INFORMATION SecurityInformation,
|
|
OUT PACCESS_MASK DesiredAccess)
|
|
{
|
|
if (SecurityInformation & (OWNER_SECURITY_INFORMATION |
|
|
GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION))
|
|
{
|
|
*DesiredAccess |= READ_CONTROL;
|
|
}
|
|
if (SecurityInformation & SACL_SECURITY_INFORMATION)
|
|
{
|
|
*DesiredAccess |= ACCESS_SYSTEM_SECURITY;
|
|
}
|
|
}
|
|
|
|
VOID STDCALL
|
|
SeSetSecurityAccessMask(IN SECURITY_INFORMATION SecurityInformation,
|
|
OUT PACCESS_MASK DesiredAccess)
|
|
{
|
|
if (SecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
|
|
{
|
|
*DesiredAccess |= WRITE_OWNER;
|
|
}
|
|
if (SecurityInformation & DACL_SECURITY_INFORMATION)
|
|
{
|
|
*DesiredAccess |= WRITE_DAC;
|
|
}
|
|
if (SecurityInformation & SACL_SECURITY_INFORMATION)
|
|
{
|
|
*DesiredAccess |= ACCESS_SYSTEM_SECURITY;
|
|
}
|
|
}
|
|
|
|
/* EOF */
|