/* * 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; }