reactos/ntoskrnl/config/cmse.c

356 lines
11 KiB
C
Raw Normal View History

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/config/cmse.c
* PURPOSE: Configuration Manager - Security Subsystem Interface
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "ntoskrnl.h"
#define NDEBUG
#include "debug.h"
/* GLOBALS *******************************************************************/
/* FUNCTIONS *****************************************************************/
PSECURITY_DESCRIPTOR
NTAPI
CmpHiveRootSecurityDescriptor(VOID)
{
NTSTATUS Status;
PSECURITY_DESCRIPTOR SecurityDescriptor;
PACL Acl, AclCopy;
PSID Sid[4];
SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY};
SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
ULONG AceLength, AclLength, SidLength;
PACE_HEADER AceHeader;
ULONG i;
PAGED_CODE();
/* Phase 1: Allocate SIDs */
SidLength = RtlLengthRequiredSid(1);
Sid[0] = ExAllocatePoolWithTag(PagedPool, SidLength, TAG_CMSD);
Sid[1] = ExAllocatePoolWithTag(PagedPool, SidLength, TAG_CMSD);
Sid[2] = ExAllocatePoolWithTag(PagedPool, SidLength, TAG_CMSD);
SidLength = RtlLengthRequiredSid(2);
Sid[3] = ExAllocatePoolWithTag(PagedPool, SidLength, TAG_CMSD);
/* Make sure all SIDs were allocated */
if (!Sid[0] || !Sid[1] || !Sid[2] || !Sid[3])
{
/* Bugcheck */
KeBugCheckEx(REGISTRY_ERROR, 11, 1, 0, 0);
}
/* Phase 2: Initialize all SIDs */
Status = RtlInitializeSid(Sid[0], &WorldAuthority, 1);
Status |= RtlInitializeSid(Sid[1], &NtAuthority, 1);
Status |= RtlInitializeSid(Sid[2], &NtAuthority, 1);
Status |= RtlInitializeSid(Sid[3], &NtAuthority, 2);
if (!NT_SUCCESS(Status)) KeBugCheckEx(REGISTRY_ERROR, 11, 2, 0, 0);
/* Phase 2: Setup SID Sub Authorities */
*RtlSubAuthoritySid(Sid[0], 0) = SECURITY_WORLD_RID;
*RtlSubAuthoritySid(Sid[1], 0) = SECURITY_RESTRICTED_CODE_RID;
*RtlSubAuthoritySid(Sid[2], 0) = SECURITY_LOCAL_SYSTEM_RID;
*RtlSubAuthoritySid(Sid[3], 0) = SECURITY_BUILTIN_DOMAIN_RID;
*RtlSubAuthoritySid(Sid[3], 1) = DOMAIN_ALIAS_RID_ADMINS;
/* Make sure all SIDs are valid */
ASSERT(RtlValidSid(Sid[0]));
ASSERT(RtlValidSid(Sid[1]));
ASSERT(RtlValidSid(Sid[2]));
ASSERT(RtlValidSid(Sid[3]));
/* Phase 3: Calculate ACL Length */
AclLength = sizeof(ACL);
for (i = 0; i < 4; i++)
{
/* This is what MSDN says to do */
AceLength = FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart);
AceLength += SeLengthSid(Sid[i]);
AclLength += AceLength;
}
/* Phase 3: Allocate the ACL */
Acl = ExAllocatePoolWithTag(PagedPool, AclLength, TAG_CMSD);
if (!Acl) KeBugCheckEx(REGISTRY_ERROR, 11, 3, 0, 0);
/* Phase 4: Create the ACL */
Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION);
if (!NT_SUCCESS(Status)) KeBugCheckEx(REGISTRY_ERROR, 11, 4, Status, 0);
/* Phase 5: Build the ACL */
Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION, KEY_ALL_ACCESS, Sid[2]);
Status |= RtlAddAccessAllowedAce(Acl, ACL_REVISION, KEY_ALL_ACCESS, Sid[3]);
Status |= RtlAddAccessAllowedAce(Acl, ACL_REVISION, KEY_READ, Sid[0]);
Status |= RtlAddAccessAllowedAce(Acl, ACL_REVISION, KEY_READ, Sid[1]);
if (!NT_SUCCESS(Status)) KeBugCheckEx(REGISTRY_ERROR, 11, 5, Status, 0);
/* Phase 5: Make the ACEs inheritable */
Status = RtlGetAce(Acl, 0, (PVOID*)&AceHeader);
ASSERT(NT_SUCCESS(Status));
AceHeader->AceFlags |= CONTAINER_INHERIT_ACE;
Status = RtlGetAce(Acl, 1, (PVOID*)&AceHeader);
ASSERT(NT_SUCCESS(Status));
AceHeader->AceFlags |= CONTAINER_INHERIT_ACE;
Status = RtlGetAce(Acl, 2, (PVOID*)&AceHeader);
ASSERT(NT_SUCCESS(Status));
AceHeader->AceFlags |= CONTAINER_INHERIT_ACE;
Status = RtlGetAce(Acl, 3, (PVOID*)&AceHeader);
ASSERT(NT_SUCCESS(Status));
AceHeader->AceFlags |= CONTAINER_INHERIT_ACE;
/* Phase 6: Allocate the security descriptor and make space for the ACL */
SecurityDescriptor = ExAllocatePoolWithTag(PagedPool,
sizeof(SECURITY_DESCRIPTOR) +
AclLength,
TAG_CMSD);
if (!SecurityDescriptor) KeBugCheckEx(REGISTRY_ERROR, 11, 6, 0, 0);
/* Phase 6: Make a copy of the ACL */
AclCopy = (PACL)((PISECURITY_DESCRIPTOR)SecurityDescriptor + 1);
RtlCopyMemory(AclCopy, Acl, AclLength);
/* Phase 7: Create the security descriptor */
Status = RtlCreateSecurityDescriptor(SecurityDescriptor,
SECURITY_DESCRIPTOR_REVISION);
if (!NT_SUCCESS(Status)) KeBugCheckEx(REGISTRY_ERROR, 11, 7, Status, 0);
/* Phase 8: Set the ACL as a DACL */
Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor,
TRUE,
AclCopy,
FALSE);
if (!NT_SUCCESS(Status)) KeBugCheckEx(REGISTRY_ERROR, 11, 8, Status, 0);
/* Free the SIDs and original ACL */
for (i = 0; i < 4; i++) ExFreePoolWithTag(Sid[i], TAG_CMSD);
ExFreePoolWithTag(Acl, TAG_CMSD);
/* Return the security descriptor */
return SecurityDescriptor;
}
NTSTATUS
CmpQuerySecurityDescriptor(IN PCM_KEY_CONTROL_BLOCK Kcb,
IN SECURITY_INFORMATION SecurityInformation,
OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
IN OUT PULONG BufferLength)
{
PISECURITY_DESCRIPTOR_RELATIVE RelSd;
ULONG SidSize;
ULONG AclSize;
ULONG SdSize;
NTSTATUS Status;
SECURITY_DESCRIPTOR_CONTROL Control = 0;
ULONG Owner = 0;
ULONG Group = 0;
ULONG Dacl = 0;
DBG_UNREFERENCED_PARAMETER(Kcb);
DPRINT("CmpQuerySecurityDescriptor()\n");
if (SecurityInformation == 0)
{
return STATUS_ACCESS_DENIED;
}
SidSize = RtlLengthSid(SeWorldSid);
RelSd = SecurityDescriptor;
SdSize = sizeof(*RelSd);
if (SecurityInformation & OWNER_SECURITY_INFORMATION)
{
Owner = SdSize;
SdSize += SidSize;
}
if (SecurityInformation & GROUP_SECURITY_INFORMATION)
{
Group = SdSize;
SdSize += SidSize;
}
if (SecurityInformation & DACL_SECURITY_INFORMATION)
{
Control |= SE_DACL_PRESENT;
Dacl = SdSize;
AclSize = sizeof(ACL) + sizeof(ACE) + SidSize;
SdSize += AclSize;
}
if (SecurityInformation & SACL_SECURITY_INFORMATION)
{
Control |= SE_SACL_PRESENT;
}
if (*BufferLength < SdSize)
{
*BufferLength = SdSize;
return STATUS_BUFFER_TOO_SMALL;
}
*BufferLength = SdSize;
Status = RtlCreateSecurityDescriptorRelative(RelSd,
SECURITY_DESCRIPTOR_REVISION);
if (!NT_SUCCESS(Status))
return Status;
RelSd->Control |= Control;
RelSd->Owner = Owner;
RelSd->Group = Group;
RelSd->Dacl = Dacl;
if (Owner)
RtlCopyMemory((PUCHAR)RelSd + Owner,
SeWorldSid,
SidSize);
if (Group)
RtlCopyMemory((PUCHAR)RelSd + Group,
SeWorldSid,
SidSize);
if (Dacl)
{
Status = RtlCreateAcl((PACL)((PUCHAR)RelSd + Dacl),
AclSize,
ACL_REVISION);
if (NT_SUCCESS(Status))
{
Status = RtlAddAccessAllowedAce((PACL)((PUCHAR)RelSd + Dacl),
ACL_REVISION,
GENERIC_ALL,
SeWorldSid);
}
}
ASSERT(Status == STATUS_SUCCESS);
return Status;
}
NTSTATUS
CmpSetSecurityDescriptor(IN PCM_KEY_CONTROL_BLOCK Kcb,
IN PSECURITY_INFORMATION SecurityInformation,
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN POOL_TYPE PoolType,
IN PGENERIC_MAPPING GenericMapping)
{
DPRINT("CmpSetSecurityDescriptor()\n");
return STATUS_SUCCESS;
}
NTSTATUS
CmpAssignSecurityDescriptor(IN PCM_KEY_CONTROL_BLOCK Kcb,
IN PSECURITY_DESCRIPTOR SecurityDescriptor)
{
DPRINT("CmpAssignSecurityDescriptor(%p %p)\n",
Kcb, SecurityDescriptor);
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
CmpSecurityMethod(IN PVOID ObjectBody,
IN SECURITY_OPERATION_CODE OperationCode,
IN PSECURITY_INFORMATION SecurityInformation,
IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
IN OUT PULONG BufferLength,
IN OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
IN POOL_TYPE PoolType,
IN PGENERIC_MAPPING GenericMapping)
{
PCM_KEY_CONTROL_BLOCK Kcb;
NTSTATUS Status = STATUS_SUCCESS;
DBG_UNREFERENCED_PARAMETER(OldSecurityDescriptor);
DBG_UNREFERENCED_PARAMETER(GenericMapping);
Kcb = ((PCM_KEY_BODY)ObjectBody)->KeyControlBlock;
/* Acquire the hive lock */
CmpLockRegistry();
/* Acquire the KCB lock */
if (OperationCode == QuerySecurityDescriptor)
{
/* Avoid recursive locking if somebody already holds it */
if (!((PCM_KEY_BODY)ObjectBody)->KcbLocked)
{
CmpAcquireKcbLockShared(Kcb);
}
}
else
{
ASSERT(!((PCM_KEY_BODY)ObjectBody)->KcbLocked);
CmpAcquireKcbLockExclusive(Kcb);
}
/* Don't touch deleted keys */
if (Kcb->Delete)
{
/* Release the KCB lock */
CmpReleaseKcbLock(Kcb);
/* Release the hive lock */
CmpUnlockRegistry();
return STATUS_KEY_DELETED;
}
switch (OperationCode)
{
case SetSecurityDescriptor:
DPRINT("Set security descriptor\n");
ASSERT((PoolType == PagedPool) || (PoolType == NonPagedPool));
Status = CmpSetSecurityDescriptor(Kcb,
SecurityInformation,
SecurityDescriptor,
PoolType,
GenericMapping);
break;
case QuerySecurityDescriptor:
DPRINT("Query security descriptor\n");
Status = CmpQuerySecurityDescriptor(Kcb,
*SecurityInformation,
SecurityDescriptor,
BufferLength);
break;
case DeleteSecurityDescriptor:
DPRINT("Delete security descriptor\n");
/* HACK */
break;
case AssignSecurityDescriptor:
DPRINT("Assign security descriptor\n");
Status = CmpAssignSecurityDescriptor(Kcb,
SecurityDescriptor);
break;
default:
KeBugCheckEx(SECURITY_SYSTEM, 0, STATUS_INVALID_PARAMETER, 0, 0);
}
/*
* Release the KCB lock, but only if we locked it ourselves and
* nobody else was locking it by themselves.
*/
if (!((PCM_KEY_BODY)ObjectBody)->KcbLocked)
{
CmpReleaseKcbLock(Kcb);
}
/* Release the hive lock */
CmpUnlockRegistry();
return Status;
}