/* $Id: sd.c,v 1.9 2003/02/15 21:07:49 ekohl Exp $
 *
 * COPYRIGHT:         See COPYING in the top level directory
 * PROJECT:           ReactOS kernel
 * PURPOSE:           Security manager
 * FILE:              kernel/se/sd.c
 * PROGRAMER:         David Welch <welch@cwcom.net>
 * REVISION HISTORY:
 *                 26/07/98: Added stubs for security functions
 */

/* INCLUDES *****************************************************************/

#include <ddk/ntddk.h>
#include <internal/se.h>

#include <internal/debug.h>

/* GLOBALS ******************************************************************/

PSECURITY_DESCRIPTOR SePublicDefaultSd = NULL;
PSECURITY_DESCRIPTOR SePublicDefaultUnrestrictedSd = NULL;
PSECURITY_DESCRIPTOR SePublicOpenSd = NULL;
PSECURITY_DESCRIPTOR SePublicOpenUnrestrictedSd = NULL;
PSECURITY_DESCRIPTOR SeSystemDefaultSd = NULL;
PSECURITY_DESCRIPTOR SeUnrestrictedSd = NULL;

/* FUNCTIONS ***************************************************************/

BOOLEAN
SepInitSDs(VOID)
{
  /* Create PublicDefaultSd */
  SePublicDefaultSd = ExAllocatePool(NonPagedPool,
				     sizeof(SECURITY_DESCRIPTOR));
  if (SePublicDefaultSd == NULL)
    return(FALSE);

  RtlCreateSecurityDescriptor(SePublicDefaultSd,
			      SECURITY_DESCRIPTOR_REVISION);
  RtlSetDaclSecurityDescriptor(SePublicDefaultSd,
			       TRUE,
			       SePublicDefaultDacl,
			       FALSE);

  /* Create PublicDefaultUnrestrictedSd */
  SePublicDefaultUnrestrictedSd = ExAllocatePool(NonPagedPool,
						 sizeof(SECURITY_DESCRIPTOR));
  if (SePublicDefaultUnrestrictedSd == NULL)
    return(FALSE);

  RtlCreateSecurityDescriptor(SePublicDefaultUnrestrictedSd,
			      SECURITY_DESCRIPTOR_REVISION);
  RtlSetDaclSecurityDescriptor(SePublicDefaultUnrestrictedSd,
			       TRUE,
			       SePublicDefaultUnrestrictedDacl,
			       FALSE);

  /* Create PublicOpenSd */
  SePublicOpenSd = ExAllocatePool(NonPagedPool,
				  sizeof(SECURITY_DESCRIPTOR));
  if (SePublicOpenSd == NULL)
    return(FALSE);

  RtlCreateSecurityDescriptor(SePublicOpenSd,
			      SECURITY_DESCRIPTOR_REVISION);
  RtlSetDaclSecurityDescriptor(SePublicOpenSd,
			       TRUE,
			       SePublicOpenDacl,
			       FALSE);

  /* Create PublicOpenUnrestrictedSd */
  SePublicOpenUnrestrictedSd = ExAllocatePool(NonPagedPool,
					      sizeof(SECURITY_DESCRIPTOR));
  if (SePublicOpenUnrestrictedSd == NULL)
    return(FALSE);

  RtlCreateSecurityDescriptor(SePublicOpenUnrestrictedSd,
			      SECURITY_DESCRIPTOR_REVISION);
  RtlSetDaclSecurityDescriptor(SePublicOpenUnrestrictedSd,
			       TRUE,
			       SePublicOpenUnrestrictedDacl,
			       FALSE);

  /* Create SystemDefaultSd */
  SeSystemDefaultSd = ExAllocatePool(NonPagedPool,
				     sizeof(SECURITY_DESCRIPTOR));
  if (SeSystemDefaultSd == NULL)
    return(FALSE);

  RtlCreateSecurityDescriptor(SeSystemDefaultSd,
			      SECURITY_DESCRIPTOR_REVISION);
  RtlSetDaclSecurityDescriptor(SeSystemDefaultSd,
			       TRUE,
			       SeSystemDefaultDacl,
			       FALSE);

  /* Create UnrestrictedSd */
  SeUnrestrictedSd = ExAllocatePool(NonPagedPool,
				    sizeof(SECURITY_DESCRIPTOR));
  if (SeUnrestrictedSd == NULL)
    return(FALSE);

  RtlCreateSecurityDescriptor(SeUnrestrictedSd,
			      SECURITY_DESCRIPTOR_REVISION);
  RtlSetDaclSecurityDescriptor(SeUnrestrictedSd,
			       TRUE,
			       SeUnrestrictedDacl,
			       FALSE);

  return(TRUE);
}


NTSTATUS STDCALL
RtlCreateSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
			    ULONG Revision)
{
  if (Revision != SECURITY_DESCRIPTOR_REVISION)
    return(STATUS_UNSUCCESSFUL);

  SecurityDescriptor->Revision = SECURITY_DESCRIPTOR_REVISION;
  SecurityDescriptor->Sbz1 = 0;
  SecurityDescriptor->Control = 0;
  SecurityDescriptor->Owner = NULL;
  SecurityDescriptor->Group = NULL;
  SecurityDescriptor->Sacl = NULL;
  SecurityDescriptor->Dacl = NULL;

  return(STATUS_SUCCESS);
}


ULONG STDCALL
RtlLengthSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor)
{
  PSID Owner;
  PSID Group;
  ULONG Length;
  PACL Dacl;
  PACL Sacl;

  Length = sizeof(SECURITY_DESCRIPTOR);

  if (SecurityDescriptor->Owner != NULL)
    {
      Owner = SecurityDescriptor->Owner;
      if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
	{
	  Owner = (PSID)((ULONG)Owner +
			 (ULONG)SecurityDescriptor);
	}
      Length = Length + ((sizeof(SID) + (Owner->SubAuthorityCount - 1) *
			 sizeof(ULONG) + 3) & 0xfc);
    }

  if (SecurityDescriptor->Group != NULL)
    {
      Group = SecurityDescriptor->Group;
      if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
	{
	  Group = (PSID)((ULONG)Group + (ULONG)SecurityDescriptor);
	}
      Length = Length + ((sizeof(SID) + (Group->SubAuthorityCount - 1) *
			 sizeof(ULONG) + 3) & 0xfc);
    }

  if (SecurityDescriptor->Control & SE_DACL_PRESENT &&
      SecurityDescriptor->Dacl != NULL)
    {
      Dacl = SecurityDescriptor->Dacl;
      if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
	{
	  Dacl = (PACL)((ULONG)Dacl + (PVOID)SecurityDescriptor);
	}
      Length = Length + ((Dacl->AclSize + 3) & 0xfc);
    }

  if (SecurityDescriptor->Control & SE_SACL_PRESENT &&
      SecurityDescriptor->Sacl != NULL)
    {
      Sacl = SecurityDescriptor->Sacl;
      if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
	{
	  Sacl = (PACL)((ULONG)Sacl + (PVOID)SecurityDescriptor);
	}
      Length = Length + ((Sacl->AclSize + 3) & 0xfc);
    }

  return(Length);
}


NTSTATUS STDCALL
RtlGetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
			     PBOOLEAN DaclPresent,
			     PACL* Dacl,
			     PBOOLEAN DaclDefaulted)
{
  if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
    {
      return(STATUS_UNSUCCESSFUL);
    }

  if (!(SecurityDescriptor->Control & SE_DACL_PRESENT))
    {
      *DaclPresent = FALSE;
      return(STATUS_SUCCESS);
    }
  *DaclPresent = TRUE;

  if (SecurityDescriptor->Dacl == NULL)
    {
      *Dacl = NULL;
    }
  else
    {
      if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
	{
	  *Dacl = (PACL)((ULONG)SecurityDescriptor->Dacl +
			 (PVOID)SecurityDescriptor);
	}
      else
	{
	  *Dacl = SecurityDescriptor->Dacl;
	}
    }

  if (SecurityDescriptor->Control & SE_DACL_DEFAULTED)
    {
      *DaclDefaulted = TRUE;
    }
  else
    {
      *DaclDefaulted = FALSE;
    }

  return(STATUS_SUCCESS);
}


NTSTATUS STDCALL
RtlSetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
			     BOOLEAN DaclPresent,
			     PACL Dacl,
			     BOOLEAN DaclDefaulted)
{
  if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
    {
      return(STATUS_UNSUCCESSFUL);
    }

  if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
    {
      return(STATUS_UNSUCCESSFUL);
    }

  if (!DaclPresent)
    {
      SecurityDescriptor->Control = SecurityDescriptor->Control & ~(SE_DACL_PRESENT);
      return(STATUS_SUCCESS);
    }

  SecurityDescriptor->Control = SecurityDescriptor->Control | SE_DACL_PRESENT;
  SecurityDescriptor->Dacl = Dacl;
  SecurityDescriptor->Control = SecurityDescriptor->Control & ~(SE_DACL_DEFAULTED);

  if (DaclDefaulted)
    {
      SecurityDescriptor->Control = SecurityDescriptor->Control | SE_DACL_DEFAULTED;
    }

  return(STATUS_SUCCESS);
}


BOOLEAN STDCALL
RtlValidSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor)
{
  PSID Owner;
  PSID Group;
  PACL Sacl;
  PACL Dacl;

  if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
    {
      return(FALSE);
    }

  Owner = SecurityDescriptor->Owner;
  if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
    {
      Owner = (PSID)((ULONG)Owner + (ULONG)SecurityDescriptor);
    }

  if (!RtlValidSid(Owner))
    {
      return(FALSE);
    }

  Group = SecurityDescriptor->Group;
  if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
    {
      Group = (PSID)((ULONG)Group + (ULONG)SecurityDescriptor);
    }

  if (!RtlValidSid(Group))
    {
      return(FALSE);
    }

  if (SecurityDescriptor->Control & SE_DACL_PRESENT &&
      SecurityDescriptor->Dacl != NULL)
    {
      Dacl = SecurityDescriptor->Dacl;
      if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
	{
	  Dacl = (PACL)((ULONG)Dacl + (ULONG)SecurityDescriptor);
	}

      if (!RtlValidAcl(Dacl))
	{
	  return(FALSE);
	}
    }

  if (SecurityDescriptor->Control & SE_SACL_PRESENT &&
      SecurityDescriptor->Sacl != NULL)
    {
      Sacl = SecurityDescriptor->Sacl;
      if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
	{
	  Sacl = (PACL)((ULONG)Sacl + (ULONG)SecurityDescriptor);
	}

      if (!RtlValidAcl(Sacl))
	{
	  return(FALSE);
	}
    }

  return(TRUE);
}


NTSTATUS STDCALL
RtlSetOwnerSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
			      PSID Owner,
			      BOOLEAN OwnerDefaulted)
{
  if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
    {
      return(STATUS_UNSUCCESSFUL);
    }

  if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
    {
      return(STATUS_UNSUCCESSFUL);
    }

  SecurityDescriptor->Owner = Owner;
  SecurityDescriptor->Control = SecurityDescriptor->Control & ~(SE_OWNER_DEFAULTED);

  if (OwnerDefaulted)
    {
      SecurityDescriptor->Control = SecurityDescriptor->Control | SE_OWNER_DEFAULTED;
    }

  return(STATUS_SUCCESS);
}


NTSTATUS STDCALL
RtlGetOwnerSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
			      PSID* Owner,
			      PBOOLEAN OwnerDefaulted)
{
  if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
    {
      return(STATUS_UNSUCCESSFUL);
    }

  if (SecurityDescriptor->Owner != NULL)
    {
	if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
	  {
	     *Owner = (PSID)((ULONG)SecurityDescriptor->Owner +
			     (PVOID)SecurityDescriptor);
	  }
	else
	  {
	     *Owner = SecurityDescriptor->Owner;
	  }
    }
  else
    {
	*Owner = NULL;
    }
   if (SecurityDescriptor->Control & SE_OWNER_DEFAULTED)
     {
	*OwnerDefaulted = 1;
     }
   else
     {
	*OwnerDefaulted = 0;
     }
   return(STATUS_SUCCESS);
}


NTSTATUS STDCALL
RtlSetGroupSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
			      PSID Group,
			      BOOLEAN GroupDefaulted)
{
  if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
    {
      return(STATUS_UNSUCCESSFUL);
    }

  if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
    {
      return(STATUS_UNSUCCESSFUL);
    }

  SecurityDescriptor->Group = Group;
  SecurityDescriptor->Control = SecurityDescriptor->Control & ~(SE_GROUP_DEFAULTED);

  if (GroupDefaulted)
    {
      SecurityDescriptor->Control = SecurityDescriptor->Control | SE_GROUP_DEFAULTED;
    }

  return(STATUS_SUCCESS);
}


NTSTATUS STDCALL
RtlGetGroupSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
			      PSID* Group,
			      PBOOLEAN GroupDefaulted)
{
  if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
    {
      return(STATUS_UNSUCCESSFUL);
    }

  if (SecurityDescriptor->Group != NULL)
    {
      if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
	{
	  *Group = (PSID)((ULONG)SecurityDescriptor->Group +
			  (PVOID)SecurityDescriptor);
	}
      else
	{
	  *Group = SecurityDescriptor->Group;
	}
    }
  else
    {
      *Group = NULL;
    }

  if (SecurityDescriptor->Control & SE_GROUP_DEFAULTED)
    {
      *GroupDefaulted = TRUE;
    }
  else
    {
      *GroupDefaulted = FALSE;
    }

  return(STATUS_SUCCESS);
}


NTSTATUS STDCALL
RtlGetSaclSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
			     PBOOLEAN SaclPresent,
			     PACL *Sacl,
			     PBOOLEAN SaclDefaulted)
{
  if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
    {
      return(STATUS_UNSUCCESSFUL);
    }

  if (!(SecurityDescriptor->Control & SE_SACL_PRESENT))
    {
      *SaclPresent = FALSE;
      return(STATUS_SUCCESS);
    }
  *SaclPresent = TRUE;

  if (SecurityDescriptor->Sacl == NULL)
    {
      *Sacl = NULL;
    }
  else
    {
      if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
	{
	  *Sacl = (PACL)((ULONG)SecurityDescriptor->Sacl +
			 (PVOID)SecurityDescriptor);
	}
      else
	{
	  *Sacl = SecurityDescriptor->Sacl;
	}
    }

  if (SecurityDescriptor->Control & SE_SACL_DEFAULTED)
    {
      *SaclDefaulted = TRUE;
    }
  else
    {
      *SaclDefaulted = FALSE;
    }

  return(STATUS_SUCCESS);
}


NTSTATUS STDCALL
RtlSetSaclSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
			     BOOLEAN SaclPresent,
			     PACL Sacl,
			     BOOLEAN SaclDefaulted)
{
  if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
    {
      return(STATUS_UNSUCCESSFUL);
    }
  if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
    {
      return(STATUS_UNSUCCESSFUL);
    }

  if (!SaclPresent)
    {
      SecurityDescriptor->Control = SecurityDescriptor->Control & ~(SE_SACL_PRESENT);
      return(STATUS_SUCCESS);
    }

  SecurityDescriptor->Control = SecurityDescriptor->Control | SE_SACL_PRESENT;
  SecurityDescriptor->Sacl = Sacl;
  SecurityDescriptor->Control = SecurityDescriptor->Control & ~(SE_SACL_DEFAULTED);

  if (SaclDefaulted)
    {
      SecurityDescriptor->Control = SecurityDescriptor->Control | SE_SACL_DEFAULTED;
    }

  return(STATUS_SUCCESS);
}


static VOID
RtlpQuerySecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
			    PSID* Owner,
			    PULONG OwnerLength,
			    PSID* Group,
			    PULONG GroupLength,
			    PACL* Dacl,
			    PULONG DaclLength,
			    PACL* Sacl,
			    PULONG SaclLength)
{
  if (SecurityDescriptor->Owner == NULL)
    {
      *Owner = NULL;
    }
  else
    {
      *Owner = SecurityDescriptor->Owner;
      if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
	{
	  *Owner = (PSID)((ULONG)*Owner + (ULONG)SecurityDescriptor);
	}
    }

  if (*Owner != NULL)
    {
      *OwnerLength = (RtlLengthSid(*Owner) + 3) & ~3;
    }
  else
    {
      *OwnerLength = 0;
    }

  if ((SecurityDescriptor->Control & SE_DACL_PRESENT) &&
      SecurityDescriptor->Dacl != NULL)
    {
      *Dacl = SecurityDescriptor->Dacl;
      if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
	{
	  *Dacl = (PACL)((ULONG)*Dacl + (ULONG)SecurityDescriptor);
	}
    }
  else
    {
      *Dacl = NULL;
    }

  if (*Dacl != NULL)
    {
      *DaclLength = ((*Dacl)->AclSize + 3) & ~3;
    }
  else
    {
      *DaclLength = 0;
    }

  if (SecurityDescriptor->Group != NULL)
    {
      *Group = NULL;
    }
  else
    {
      *Group = SecurityDescriptor->Group;
      if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
	{
	  *Group = (PSID)((ULONG)*Group + (ULONG)SecurityDescriptor);
	}
    }

  if (*Group != NULL)
    {
      *GroupLength = (RtlLengthSid(*Group) + 3) & ~3;
    }
  else
    {
      *GroupLength = 0;
    }

  if ((SecurityDescriptor->Control & SE_SACL_PRESENT) &&
      SecurityDescriptor->Sacl != NULL)
    {
      *Sacl = SecurityDescriptor->Sacl;
      if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
	{
	  *Sacl = (PACL)((ULONG)*Sacl + (ULONG)SecurityDescriptor);
	}
    }
  else
    {
      *Sacl = NULL;
    }

  if (*Sacl != NULL)
    {
      *SaclLength = ((*Sacl)->AclSize + 3) & ~3;
    }
}


NTSTATUS STDCALL
RtlAbsoluteToSelfRelativeSD(PSECURITY_DESCRIPTOR AbsSD,
			    PSECURITY_DESCRIPTOR RelSD,
			    PULONG BufferLength)
{
  PSID Owner;
  PSID Group;
  PACL Sacl;
  PACL Dacl;
  ULONG OwnerLength;
  ULONG GroupLength;
  ULONG SaclLength;
  ULONG DaclLength;
  ULONG TotalLength;
  ULONG Current;

  if (AbsSD->Control & SE_SELF_RELATIVE)
    {
      return(STATUS_BAD_DESCRIPTOR_FORMAT);
    }

  RtlpQuerySecurityDescriptor(AbsSD,
			      &Owner,
			      &OwnerLength,
			      &Group,
			      &GroupLength,
			      &Dacl,
			      &DaclLength,
			      &Sacl,
			      &SaclLength);

  TotalLength = OwnerLength + GroupLength + SaclLength +
		DaclLength + sizeof(SECURITY_DESCRIPTOR);
  if (*BufferLength < TotalLength)
    {
      return(STATUS_BUFFER_TOO_SMALL);
    }

  RtlZeroMemory(RelSD,
		TotalLength);
  memmove(RelSD,
	  AbsSD,
	  sizeof(SECURITY_DESCRIPTOR));
  Current = (ULONG)RelSD + sizeof(SECURITY_DESCRIPTOR);

  if (SaclLength != 0)
    {
      memmove((PVOID)Current,
	      Sacl,
	      SaclLength);
      RelSD->Sacl = (PACL)((ULONG)Current - (ULONG)RelSD);
      Current += SaclLength;
    }

  if (DaclLength != 0)
    {
      memmove((PVOID)Current,
	      Dacl,
	      DaclLength);
      RelSD->Dacl = (PACL)((ULONG)Current - (ULONG)RelSD);
      Current += DaclLength;
    }

  if (OwnerLength != 0)
    {
      memmove((PVOID)Current,
	      Owner,
	      OwnerLength);
      RelSD->Owner = (PSID)((ULONG)Current - (ULONG)RelSD);
      Current += OwnerLength;
    }

  if (GroupLength != 0)
    {
      memmove((PVOID)Current,
	      Group,
	      GroupLength);
      RelSD->Group = (PSID)((ULONG)Current - (ULONG)RelSD);
    }

  RelSD->Control |= SE_SELF_RELATIVE;

  return(STATUS_SUCCESS);
}

/* EOF */
