mirror of
https://github.com/reactos/reactos.git
synced 2024-08-28 22:28:36 +00:00
836 lines
27 KiB
C
836 lines
27 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS system libraries
|
|
* FILE: lib/rtl/security.c
|
|
* PURPOSE: Security related functions and Security Objects
|
|
* PROGRAMMER: Eric Kohl
|
|
*/
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include <rtl.h>
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* PRIVATE FUNCTIONS **********************************************************/
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlpSetSecurityObject(IN PVOID Object OPTIONAL,
|
|
IN SECURITY_INFORMATION SecurityInformation,
|
|
IN PSECURITY_DESCRIPTOR ModificationDescriptor,
|
|
IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
|
|
IN ULONG AutoInheritFlags,
|
|
IN ULONG PoolType,
|
|
IN PGENERIC_MAPPING GenericMapping,
|
|
IN HANDLE Token OPTIONAL)
|
|
{
|
|
PISECURITY_DESCRIPTOR_RELATIVE pNewSd = NULL;
|
|
PSID pOwnerSid = NULL;
|
|
PSID pGroupSid = NULL;
|
|
PACL pDacl = NULL;
|
|
PACL pSacl = NULL;
|
|
BOOLEAN Defaulted;
|
|
BOOLEAN Present;
|
|
ULONG ulOwnerSidSize = 0, ulGroupSidSize = 0;
|
|
ULONG ulDaclSize = 0, ulSaclSize = 0;
|
|
ULONG ulNewSdSize;
|
|
SECURITY_DESCRIPTOR_CONTROL Control = SE_SELF_RELATIVE;
|
|
PUCHAR pDest;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
DPRINT("RtlpSetSecurityObject()\n");
|
|
|
|
/* Change the Owner SID */
|
|
if (SecurityInformation & OWNER_SECURITY_INFORMATION)
|
|
{
|
|
Status = RtlGetOwnerSecurityDescriptor(ModificationDescriptor, &pOwnerSid, &Defaulted);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
}
|
|
else
|
|
{
|
|
Status = RtlGetOwnerSecurityDescriptor(*ObjectsSecurityDescriptor, &pOwnerSid, &Defaulted);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
}
|
|
|
|
if (pOwnerSid == NULL || !RtlValidSid(pOwnerSid))
|
|
return STATUS_INVALID_OWNER;
|
|
|
|
ulOwnerSidSize = RtlLengthSid(pOwnerSid);
|
|
|
|
/* Change the Group SID */
|
|
if (SecurityInformation & GROUP_SECURITY_INFORMATION)
|
|
{
|
|
Status = RtlGetGroupSecurityDescriptor(ModificationDescriptor, &pGroupSid, &Defaulted);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
}
|
|
else
|
|
{
|
|
Status = RtlGetGroupSecurityDescriptor(*ObjectsSecurityDescriptor, &pGroupSid, &Defaulted);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
}
|
|
|
|
if (pGroupSid == NULL || !RtlValidSid(pGroupSid))
|
|
return STATUS_INVALID_PRIMARY_GROUP;
|
|
|
|
ulGroupSidSize = ROUND_UP(RtlLengthSid(pGroupSid), sizeof(ULONG));
|
|
|
|
/* Change the DACL */
|
|
if (SecurityInformation & DACL_SECURITY_INFORMATION)
|
|
{
|
|
Status = RtlGetDaclSecurityDescriptor(ModificationDescriptor, &Present, &pDacl, &Defaulted);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
Control |= SE_DACL_PRESENT;
|
|
}
|
|
else
|
|
{
|
|
Status = RtlGetDaclSecurityDescriptor(*ObjectsSecurityDescriptor, &Present, &pDacl, &Defaulted);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
if (Present)
|
|
Control |= SE_DACL_PRESENT;
|
|
|
|
if (Defaulted)
|
|
Control |= SE_DACL_DEFAULTED;
|
|
}
|
|
|
|
if (pDacl != NULL)
|
|
ulDaclSize = pDacl->AclSize;
|
|
|
|
/* Change the SACL */
|
|
if (SecurityInformation & SACL_SECURITY_INFORMATION)
|
|
{
|
|
Status = RtlGetSaclSecurityDescriptor(ModificationDescriptor, &Present, &pSacl, &Defaulted);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
Control |= SE_SACL_PRESENT;
|
|
}
|
|
else
|
|
{
|
|
Status = RtlGetSaclSecurityDescriptor(*ObjectsSecurityDescriptor, &Present, &pSacl, &Defaulted);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
if (Present)
|
|
Control |= SE_SACL_PRESENT;
|
|
|
|
if (Defaulted)
|
|
Control |= SE_SACL_DEFAULTED;
|
|
}
|
|
|
|
if (pSacl != NULL)
|
|
ulSaclSize = pSacl->AclSize;
|
|
|
|
/* Calculate the size of the new security descriptor */
|
|
ulNewSdSize = sizeof(SECURITY_DESCRIPTOR_RELATIVE) +
|
|
ROUND_UP(ulOwnerSidSize, sizeof(ULONG)) +
|
|
ROUND_UP(ulGroupSidSize, sizeof(ULONG)) +
|
|
ROUND_UP(ulDaclSize, sizeof(ULONG)) +
|
|
ROUND_UP(ulSaclSize, sizeof(ULONG));
|
|
|
|
/* Allocate the new security descriptor */
|
|
pNewSd = RtlAllocateHeap(RtlGetProcessHeap(), 0, ulNewSdSize);
|
|
if (pNewSd == NULL)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
DPRINT1("New security descriptor allocation failed (Status 0x%08lx)\n", Status);
|
|
goto done;
|
|
}
|
|
|
|
/* Initialize the new security descriptor */
|
|
Status = RtlCreateSecurityDescriptorRelative(pNewSd, SECURITY_DESCRIPTOR_REVISION);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("New security descriptor creation failed (Status 0x%08lx)\n", Status);
|
|
goto done;
|
|
}
|
|
|
|
/* Set the security descriptor control flags */
|
|
pNewSd->Control = Control;
|
|
|
|
pDest = (PUCHAR)((ULONG_PTR)pNewSd + sizeof(SECURITY_DESCRIPTOR_RELATIVE));
|
|
|
|
/* Copy the SACL */
|
|
if (pSacl != NULL)
|
|
{
|
|
RtlCopyMemory(pDest, pSacl, ulSaclSize);
|
|
pNewSd->Sacl = (ULONG_PTR)pDest - (ULONG_PTR)pNewSd;
|
|
pDest = pDest + ROUND_UP(ulSaclSize, sizeof(ULONG));
|
|
}
|
|
|
|
/* Copy the DACL */
|
|
if (pDacl != NULL)
|
|
{
|
|
RtlCopyMemory(pDest, pDacl, ulDaclSize);
|
|
pNewSd->Dacl = (ULONG_PTR)pDest - (ULONG_PTR)pNewSd;
|
|
pDest = pDest + ROUND_UP(ulDaclSize, sizeof(ULONG));
|
|
}
|
|
|
|
/* Copy the Owner SID */
|
|
RtlCopyMemory(pDest, pOwnerSid, ulOwnerSidSize);
|
|
pNewSd->Owner = (ULONG_PTR)pDest - (ULONG_PTR)pNewSd;
|
|
pDest = pDest + ROUND_UP(ulOwnerSidSize, sizeof(ULONG));
|
|
|
|
/* Copy the Group SID */
|
|
RtlCopyMemory(pDest, pGroupSid, ulGroupSidSize);
|
|
pNewSd->Group = (ULONG_PTR)pDest - (ULONG_PTR)pNewSd;
|
|
|
|
/* Free the old security descriptor */
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, (PVOID)*ObjectsSecurityDescriptor);
|
|
|
|
/* Return the new security descriptor */
|
|
*ObjectsSecurityDescriptor = (PSECURITY_DESCRIPTOR)pNewSd;
|
|
|
|
done:
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
if (pNewSd != NULL)
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, pNewSd);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlpNewSecurityObject(IN PSECURITY_DESCRIPTOR ParentDescriptor,
|
|
IN PSECURITY_DESCRIPTOR CreatorDescriptor,
|
|
OUT PSECURITY_DESCRIPTOR *NewDescriptor,
|
|
IN LPGUID *ObjectTypes,
|
|
IN ULONG GuidCount,
|
|
IN BOOLEAN IsDirectoryObject,
|
|
IN ULONG AutoInheritFlags,
|
|
IN HANDLE Token,
|
|
IN PGENERIC_MAPPING GenericMapping)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlpConvertToAutoInheritSecurityObject(IN PSECURITY_DESCRIPTOR ParentDescriptor,
|
|
IN PSECURITY_DESCRIPTOR CreatorDescriptor,
|
|
OUT PSECURITY_DESCRIPTOR *NewDescriptor,
|
|
IN LPGUID ObjectType,
|
|
IN BOOLEAN IsDirectoryObject,
|
|
IN PGENERIC_MAPPING GenericMapping)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlDefaultNpAcl(OUT PACL *pAcl)
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE TokenHandle;
|
|
PTOKEN_OWNER OwnerSid;
|
|
ULONG ReturnLength = 0;
|
|
ULONG AclSize;
|
|
SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
|
|
SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY};
|
|
|
|
/*
|
|
* Temporary buffer large enough to hold a maximum of two SIDs.
|
|
* An alternative is to call RtlAllocateAndInitializeSid many times...
|
|
*/
|
|
UCHAR SidBuffer[16];
|
|
PSID Sid = (PSID)&SidBuffer;
|
|
|
|
ASSERT(RtlLengthRequiredSid(2) == 16);
|
|
|
|
/* Initialize the user ACL pointer */
|
|
*pAcl = NULL;
|
|
|
|
/*
|
|
* Try to retrieve the SID of the current owner. For that,
|
|
* we first attempt to get the current thread level token.
|
|
*/
|
|
Status = NtOpenThreadToken(NtCurrentThread(),
|
|
TOKEN_QUERY,
|
|
TRUE,
|
|
&TokenHandle);
|
|
if (Status == STATUS_NO_TOKEN)
|
|
{
|
|
/*
|
|
* No thread level token, so use the process level token.
|
|
* This is the common case since the only time a thread
|
|
* has a token is when it is impersonating.
|
|
*/
|
|
Status = NtOpenProcessToken(NtCurrentProcess(),
|
|
TOKEN_QUERY,
|
|
&TokenHandle);
|
|
}
|
|
/* Fail if we didn't succeed in retrieving a handle to the token */
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
/*
|
|
* Retrieve the owner SID from the token.
|
|
*/
|
|
|
|
/* Query the needed size... */
|
|
Status = NtQueryInformationToken(TokenHandle,
|
|
TokenOwner,
|
|
NULL, 0,
|
|
&ReturnLength);
|
|
/* ... so that we must fail with STATUS_BUFFER_TOO_SMALL error */
|
|
if (Status != STATUS_BUFFER_TOO_SMALL) goto Cleanup1;
|
|
|
|
/* Allocate space for the owner SID */
|
|
OwnerSid = RtlAllocateHeap(RtlGetProcessHeap(), 0, ReturnLength);
|
|
if (OwnerSid == NULL)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Cleanup1;
|
|
}
|
|
|
|
/* Retrieve the owner SID; we must succeed */
|
|
Status = NtQueryInformationToken(TokenHandle,
|
|
TokenOwner,
|
|
OwnerSid,
|
|
ReturnLength,
|
|
&ReturnLength);
|
|
if (!NT_SUCCESS(Status)) goto Cleanup2;
|
|
|
|
/*
|
|
* Allocate one ACL with 5 ACEs.
|
|
*
|
|
* NOTE: sizeof(ACE) == sizeof(ACCESS_ALLOWED_ACE) - sizeof(((ACCESS_ALLOWED_ACE*)NULL)->SidStart)
|
|
* (see kernel32/client/debugger.c line 54).
|
|
*/
|
|
AclSize = sizeof(ACL) + // Header
|
|
5 * sizeof(ACE /*ACCESS_ALLOWED_ACE*/) + // 5 ACEs:
|
|
RtlLengthRequiredSid(1) + // LocalSystem
|
|
RtlLengthRequiredSid(2) + // Administrators
|
|
RtlLengthRequiredSid(1) + // Anonymous
|
|
RtlLengthRequiredSid(1) + // World
|
|
RtlLengthSid(OwnerSid->Owner); // Owner
|
|
|
|
*pAcl = RtlAllocateHeap(RtlGetProcessHeap(), 0, AclSize);
|
|
if (*pAcl == NULL)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Cleanup2;
|
|
}
|
|
|
|
/*
|
|
* Build the ACL and add the five ACEs.
|
|
*/
|
|
Status = RtlCreateAcl(*pAcl, AclSize, ACL_REVISION2);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
/* Local System SID - Generic All */
|
|
Status = RtlInitializeSid(Sid, &NtAuthority, 1);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
*RtlSubAuthoritySid(Sid, 0) = SECURITY_LOCAL_SYSTEM_RID;
|
|
Status = RtlAddAccessAllowedAce(*pAcl, ACL_REVISION2, GENERIC_ALL, Sid);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
/* Administrators SID - Generic All */
|
|
Status = RtlInitializeSid(Sid, &NtAuthority, 2);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
*RtlSubAuthoritySid(Sid, 0) = SECURITY_BUILTIN_DOMAIN_RID;
|
|
*RtlSubAuthoritySid(Sid, 1) = DOMAIN_ALIAS_RID_ADMINS;
|
|
Status = RtlAddAccessAllowedAce(*pAcl, ACL_REVISION2, GENERIC_ALL, Sid);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
/* Owner SID - Generic All */
|
|
RtlAddAccessAllowedAce(*pAcl, ACL_REVISION2, GENERIC_ALL, OwnerSid->Owner);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
/* Anonymous SID - Generic Read */
|
|
Status = RtlInitializeSid(Sid, &NtAuthority, 1);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
*RtlSubAuthoritySid(Sid, 0) = SECURITY_ANONYMOUS_LOGON_RID;
|
|
Status = RtlAddAccessAllowedAce(*pAcl, ACL_REVISION2, GENERIC_READ, Sid);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
/* World SID - Generic Read */
|
|
Status = RtlInitializeSid(Sid, &WorldAuthority, 1);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
*RtlSubAuthoritySid(Sid, 0) = SECURITY_WORLD_RID;
|
|
Status = RtlAddAccessAllowedAce(*pAcl, ACL_REVISION2, GENERIC_READ, Sid);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
/* If some problem happened, cleanup everything */
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, *pAcl);
|
|
*pAcl = NULL;
|
|
}
|
|
|
|
Cleanup2:
|
|
/* Get rid of the owner SID */
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, OwnerSid);
|
|
|
|
Cleanup1:
|
|
/* Close the token handle */
|
|
NtClose(TokenHandle);
|
|
|
|
/* Done */
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlCreateAndSetSD(IN PVOID AceData,
|
|
IN ULONG AceCount,
|
|
IN PSID OwnerSid OPTIONAL,
|
|
IN PSID GroupSid OPTIONAL,
|
|
OUT PSECURITY_DESCRIPTOR *NewDescriptor)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlDeleteSecurityObject(IN PSECURITY_DESCRIPTOR *ObjectDescriptor)
|
|
{
|
|
DPRINT1("RtlDeleteSecurityObject(%p)\n", ObjectDescriptor);
|
|
|
|
/* Free the object from the heap */
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, *ObjectDescriptor);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlNewSecurityObject(IN PSECURITY_DESCRIPTOR ParentDescriptor,
|
|
IN PSECURITY_DESCRIPTOR CreatorDescriptor,
|
|
OUT PSECURITY_DESCRIPTOR *NewDescriptor,
|
|
IN BOOLEAN IsDirectoryObject,
|
|
IN HANDLE Token,
|
|
IN PGENERIC_MAPPING GenericMapping)
|
|
{
|
|
DPRINT1("RtlNewSecurityObject(%p)\n", ParentDescriptor);
|
|
|
|
/* Call the internal API */
|
|
return RtlpNewSecurityObject(ParentDescriptor,
|
|
CreatorDescriptor,
|
|
NewDescriptor,
|
|
NULL,
|
|
0,
|
|
IsDirectoryObject,
|
|
0,
|
|
Token,
|
|
GenericMapping);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlNewSecurityObjectEx(IN PSECURITY_DESCRIPTOR ParentDescriptor,
|
|
IN PSECURITY_DESCRIPTOR CreatorDescriptor,
|
|
OUT PSECURITY_DESCRIPTOR *NewDescriptor,
|
|
IN LPGUID ObjectType,
|
|
IN BOOLEAN IsDirectoryObject,
|
|
IN ULONG AutoInheritFlags,
|
|
IN HANDLE Token,
|
|
IN PGENERIC_MAPPING GenericMapping)
|
|
{
|
|
DPRINT1("RtlNewSecurityObjectEx(%p)\n", ParentDescriptor);
|
|
|
|
/* Call the internal API */
|
|
return RtlpNewSecurityObject(ParentDescriptor,
|
|
CreatorDescriptor,
|
|
NewDescriptor,
|
|
ObjectType ? &ObjectType : NULL,
|
|
ObjectType ? 1 : 0,
|
|
IsDirectoryObject,
|
|
AutoInheritFlags,
|
|
Token,
|
|
GenericMapping);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlNewSecurityObjectWithMultipleInheritance(IN PSECURITY_DESCRIPTOR ParentDescriptor,
|
|
IN PSECURITY_DESCRIPTOR CreatorDescriptor,
|
|
OUT PSECURITY_DESCRIPTOR *NewDescriptor,
|
|
IN LPGUID *ObjectTypes,
|
|
IN ULONG GuidCount,
|
|
IN BOOLEAN IsDirectoryObject,
|
|
IN ULONG AutoInheritFlags,
|
|
IN HANDLE Token,
|
|
IN PGENERIC_MAPPING GenericMapping)
|
|
{
|
|
DPRINT1("RtlNewSecurityObjectWithMultipleInheritance(%p)\n", ParentDescriptor);
|
|
|
|
/* Call the internal API */
|
|
return RtlpNewSecurityObject(ParentDescriptor,
|
|
CreatorDescriptor,
|
|
NewDescriptor,
|
|
ObjectTypes,
|
|
GuidCount,
|
|
IsDirectoryObject,
|
|
AutoInheritFlags,
|
|
Token,
|
|
GenericMapping);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlNewInstanceSecurityObject(IN BOOLEAN ParentDescriptorChanged,
|
|
IN BOOLEAN CreatorDescriptorChanged,
|
|
IN PLUID OldClientTokenModifiedId,
|
|
OUT PLUID NewClientTokenModifiedId,
|
|
IN PSECURITY_DESCRIPTOR ParentDescriptor,
|
|
IN PSECURITY_DESCRIPTOR CreatorDescriptor,
|
|
OUT PSECURITY_DESCRIPTOR *NewDescriptor,
|
|
IN BOOLEAN IsDirectoryObject,
|
|
IN HANDLE Token,
|
|
IN PGENERIC_MAPPING GenericMapping)
|
|
{
|
|
TOKEN_STATISTICS TokenStats;
|
|
ULONG Size;
|
|
NTSTATUS Status;
|
|
DPRINT1("RtlNewInstanceSecurityObject(%p)\n", ParentDescriptor);
|
|
|
|
/* Query the token statistics */
|
|
Status = NtQueryInformationToken(Token,
|
|
TokenStatistics,
|
|
&TokenStats,
|
|
sizeof(TokenStats),
|
|
&Size);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
/* Return the LUID */
|
|
*NewClientTokenModifiedId = TokenStats.ModifiedId;
|
|
|
|
/* Check if the LUID changed */
|
|
if (RtlEqualLuid(NewClientTokenModifiedId, OldClientTokenModifiedId))
|
|
{
|
|
/* Did nothing change? */
|
|
if (!(ParentDescriptorChanged) && !(CreatorDescriptorChanged))
|
|
{
|
|
/* There's no new descriptor, we're done */
|
|
*NewDescriptor = NULL;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/* Call the standard API */
|
|
return RtlNewSecurityObject(ParentDescriptor,
|
|
CreatorDescriptor,
|
|
NewDescriptor,
|
|
IsDirectoryObject,
|
|
Token,
|
|
GenericMapping);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlCreateUserSecurityObject(IN PVOID AceData,
|
|
IN ULONG AceCount,
|
|
IN PSID OwnerSid,
|
|
IN PSID GroupSid,
|
|
IN BOOLEAN IsDirectoryObject,
|
|
IN PGENERIC_MAPPING GenericMapping,
|
|
OUT PSECURITY_DESCRIPTOR *NewDescriptor)
|
|
{
|
|
NTSTATUS Status;
|
|
PSECURITY_DESCRIPTOR Sd;
|
|
HANDLE TokenHandle;
|
|
DPRINT1("RtlCreateUserSecurityObject(%p)\n", AceData);
|
|
|
|
/* Create the security descriptor based on the ACE Data */
|
|
Status = RtlCreateAndSetSD(AceData,
|
|
AceCount,
|
|
OwnerSid,
|
|
GroupSid,
|
|
&Sd);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
/* Open the process token */
|
|
Status = NtOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &TokenHandle);
|
|
if (!NT_SUCCESS(Status)) goto Quickie;
|
|
|
|
/* Create the security object */
|
|
Status = RtlNewSecurityObject(NULL,
|
|
Sd,
|
|
NewDescriptor,
|
|
IsDirectoryObject,
|
|
TokenHandle,
|
|
GenericMapping);
|
|
|
|
/* We're done, close the token handle */
|
|
NtClose(TokenHandle);
|
|
|
|
Quickie:
|
|
/* Free the SD and return status */
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlNewSecurityGrantedAccess(IN ACCESS_MASK DesiredAccess,
|
|
OUT PPRIVILEGE_SET Privileges,
|
|
IN OUT PULONG Length,
|
|
IN HANDLE Token,
|
|
IN PGENERIC_MAPPING GenericMapping,
|
|
OUT PACCESS_MASK RemainingDesiredAccess)
|
|
{
|
|
NTSTATUS Status;
|
|
BOOLEAN Granted, CallerToken;
|
|
TOKEN_STATISTICS TokenStats;
|
|
ULONG Size;
|
|
DPRINT1("RtlNewSecurityGrantedAccess(%lx)\n", DesiredAccess);
|
|
|
|
/* Has the caller passed a token? */
|
|
if (!Token)
|
|
{
|
|
/* Remember that we'll have to close the handle */
|
|
CallerToken = FALSE;
|
|
|
|
/* Nope, open it */
|
|
Status = NtOpenThreadToken(NtCurrentThread(), TOKEN_QUERY, TRUE, &Token);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
}
|
|
else
|
|
{
|
|
/* Yep, use it */
|
|
CallerToken = TRUE;
|
|
}
|
|
|
|
/* Get information on the token */
|
|
Status = NtQueryInformationToken(Token,
|
|
TokenStatistics,
|
|
&TokenStats,
|
|
sizeof(TokenStats),
|
|
&Size);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
/* Windows doesn't do anything with the token statistics! */
|
|
|
|
/* Map the access and return it back decoded */
|
|
RtlMapGenericMask(&DesiredAccess, GenericMapping);
|
|
*RemainingDesiredAccess = DesiredAccess;
|
|
|
|
/* Check if one of the rights requested was the SACL right */
|
|
if (DesiredAccess & ACCESS_SYSTEM_SECURITY)
|
|
{
|
|
/* Pretend that it's allowed FIXME: Do privilege check */
|
|
DPRINT1("Missing privilege check for SE_SECURITY_PRIVILEGE");
|
|
Granted = TRUE;
|
|
*RemainingDesiredAccess &= ~ACCESS_SYSTEM_SECURITY;
|
|
}
|
|
else
|
|
{
|
|
/* Nothing to grant */
|
|
Granted = FALSE;
|
|
}
|
|
|
|
/* If the caller did not pass in a token, close the handle to ours */
|
|
if (!CallerToken) NtClose(Token);
|
|
|
|
/* We need space to return only 1 privilege -- already part of the struct */
|
|
Size = sizeof(PRIVILEGE_SET);
|
|
if (Size > *Length)
|
|
{
|
|
/* Tell the caller how much space we need and fail */
|
|
*Length = Size;
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
/* Check if the SACL right was granted... */
|
|
RtlZeroMemory(Privileges, Size);
|
|
if (Granted)
|
|
{
|
|
/* Yes, return it in the structure */
|
|
Privileges->PrivilegeCount = 1;
|
|
Privileges->Privilege[0].Luid.LowPart = SE_SECURITY_PRIVILEGE;
|
|
Privileges->Privilege[0].Luid.HighPart = 0;
|
|
Privileges->Privilege[0].Attributes = SE_PRIVILEGE_USED_FOR_ACCESS;
|
|
}
|
|
|
|
/* All done */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlQuerySecurityObject(IN PSECURITY_DESCRIPTOR ObjectDescriptor,
|
|
IN SECURITY_INFORMATION SecurityInformation,
|
|
OUT PSECURITY_DESCRIPTOR ResultantDescriptor,
|
|
IN ULONG DescriptorLength,
|
|
OUT PULONG ReturnLength)
|
|
{
|
|
NTSTATUS Status;
|
|
SECURITY_DESCRIPTOR desc;
|
|
BOOLEAN defaulted, present;
|
|
PACL pacl;
|
|
PSID psid;
|
|
|
|
Status = RtlCreateSecurityDescriptor(&desc, SECURITY_DESCRIPTOR_REVISION);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
if (SecurityInformation & OWNER_SECURITY_INFORMATION)
|
|
{
|
|
Status = RtlGetOwnerSecurityDescriptor(ObjectDescriptor, &psid, &defaulted);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
Status = RtlSetOwnerSecurityDescriptor(&desc, psid, defaulted);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
}
|
|
|
|
if (SecurityInformation & GROUP_SECURITY_INFORMATION)
|
|
{
|
|
Status = RtlGetGroupSecurityDescriptor(ObjectDescriptor, &psid, &defaulted);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
Status = RtlSetGroupSecurityDescriptor(&desc, psid, defaulted);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
}
|
|
|
|
if (SecurityInformation & DACL_SECURITY_INFORMATION)
|
|
{
|
|
Status = RtlGetDaclSecurityDescriptor(ObjectDescriptor, &present, &pacl, &defaulted);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
Status = RtlSetDaclSecurityDescriptor(&desc, present, pacl, defaulted);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
}
|
|
|
|
if (SecurityInformation & SACL_SECURITY_INFORMATION)
|
|
{
|
|
Status = RtlGetSaclSecurityDescriptor(ObjectDescriptor, &present, &pacl, &defaulted);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
Status = RtlSetSaclSecurityDescriptor(&desc, present, pacl, defaulted);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
}
|
|
|
|
*ReturnLength = DescriptorLength;
|
|
return RtlAbsoluteToSelfRelativeSD(&desc, ResultantDescriptor, ReturnLength);
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlSetSecurityObject(IN SECURITY_INFORMATION SecurityInformation,
|
|
IN PSECURITY_DESCRIPTOR ModificationDescriptor,
|
|
IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
|
|
IN PGENERIC_MAPPING GenericMapping,
|
|
IN HANDLE Token OPTIONAL)
|
|
{
|
|
/* Call the internal API */
|
|
return RtlpSetSecurityObject(NULL,
|
|
SecurityInformation,
|
|
ModificationDescriptor,
|
|
ObjectsSecurityDescriptor,
|
|
0,
|
|
PagedPool,
|
|
GenericMapping,
|
|
Token);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlSetSecurityObjectEx(IN SECURITY_INFORMATION SecurityInformation,
|
|
IN PSECURITY_DESCRIPTOR ModificationDescriptor,
|
|
IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
|
|
IN ULONG AutoInheritFlags,
|
|
IN PGENERIC_MAPPING GenericMapping,
|
|
IN HANDLE Token OPTIONAL)
|
|
{
|
|
/* Call the internal API */
|
|
return RtlpSetSecurityObject(NULL,
|
|
SecurityInformation,
|
|
ModificationDescriptor,
|
|
ObjectsSecurityDescriptor,
|
|
AutoInheritFlags,
|
|
PagedPool,
|
|
GenericMapping,
|
|
Token);
|
|
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlConvertToAutoInheritSecurityObject(IN PSECURITY_DESCRIPTOR ParentDescriptor,
|
|
IN PSECURITY_DESCRIPTOR CreatorDescriptor,
|
|
OUT PSECURITY_DESCRIPTOR *NewDescriptor,
|
|
IN LPGUID ObjectType,
|
|
IN BOOLEAN IsDirectoryObject,
|
|
IN PGENERIC_MAPPING GenericMapping)
|
|
{
|
|
/* Call the internal API */
|
|
return RtlpConvertToAutoInheritSecurityObject(ParentDescriptor,
|
|
CreatorDescriptor,
|
|
NewDescriptor,
|
|
ObjectType,
|
|
IsDirectoryObject,
|
|
GenericMapping);
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlRegisterSecureMemoryCacheCallback(IN PRTL_SECURE_MEMORY_CACHE_CALLBACK Callback)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
BOOLEAN
|
|
NTAPI
|
|
RtlFlushSecureMemoryCache(IN PVOID MemoryCache,
|
|
IN OPTIONAL SIZE_T MemoryLength)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return FALSE;
|
|
}
|