implemented SeCaptureSecurityDescriptor() and SeReleaseSecurityDescriptor(), thanks also to Alex
Modified: trunk/reactos/ntoskrnl/se/sd.c

Modified: trunk/reactos/ntoskrnl/se/sd.c
--- trunk/reactos/ntoskrnl/se/sd.c	2005-01-20 23:25:05 UTC (rev 13174)
+++ trunk/reactos/ntoskrnl/se/sd.c	2005-01-21 02:14:52 UTC (rev 13175)
@@ -110,7 +110,7 @@
 }
 
 /*
- * @unimplemented
+ * @implemented
  */
 NTSTATUS
 STDCALL
@@ -122,8 +122,250 @@
 	OUT PSECURITY_DESCRIPTOR *CapturedSecurityDescriptor
 	)
 {
-	UNIMPLEMENTED;
-	return STATUS_NOT_IMPLEMENTED;
+  SECURITY_DESCRIPTOR DescriptorCopy;
+  PSECURITY_DESCRIPTOR NewDescriptor;
+  ULONG OwnerSAC = 0, GroupSAC = 0;
+  ULONG OwnerSize = 0, GroupSize = 0;
+  ULONG SaclSize = 0, DaclSize = 0;
+  ULONG DescriptorSize;
+  NTSTATUS Status = STATUS_SUCCESS;
+  
+  if(OriginalSecurityDescriptor != NULL)
+  {
+    if(CurrentMode != KernelMode)
+    {
+      _SEH_TRY
+      {
+        ProbeForRead(OriginalSecurityDescriptor,
+                     sizeof(SECURITY_DESCRIPTOR),
+                     sizeof(ULONG));
+
+        /* make a copy on the stack */
+        DescriptorCopy = *OriginalSecurityDescriptor;
+      }
+      _SEH_HANDLE
+      {
+        Status = _SEH_GetExceptionCode();
+      }
+      _SEH_END;
+      
+      if(!NT_SUCCESS(Status))
+      {
+        return Status;
+      }
+    }
+    else
+    {
+      /* make a copy on the stack */
+      DescriptorCopy = *OriginalSecurityDescriptor;
+    }
+    
+    if(CurrentMode == KernelMode && !CaptureIfKernel)
+    {
+      *CapturedSecurityDescriptor = OriginalSecurityDescriptor;
+      return STATUS_SUCCESS;
+    }
+    
+    if(DescriptorCopy.Revision != SECURITY_DESCRIPTOR_REVISION1)
+    {
+      return STATUS_UNKNOWN_REVISION;
+    }
+    
+    if(DescriptorCopy.Control & SE_SELF_RELATIVE)
+    {
+      /* in case we're dealing with a self-relative descriptor, do a basic convert
+         to an absolute descriptor. We do this so we can simply access the data
+         using the pointers without calculating them again. */
+      DescriptorCopy.Control &= ~SE_SELF_RELATIVE;
+      if(DescriptorCopy.Owner != NULL)
+      {
+        DescriptorCopy.Owner = (PSID)((ULONG_PTR)OriginalSecurityDescriptor + (ULONG_PTR)DescriptorCopy.Owner);
+      }
+      if(DescriptorCopy.Group != NULL)
+      {
+        DescriptorCopy.Group = (PSID)((ULONG_PTR)OriginalSecurityDescriptor + (ULONG_PTR)DescriptorCopy.Group);
+      }
+      if(DescriptorCopy.Dacl != NULL)
+      {
+        DescriptorCopy.Dacl = (PACL)((ULONG_PTR)OriginalSecurityDescriptor + (ULONG_PTR)DescriptorCopy.Dacl);
+      }
+      if(DescriptorCopy.Sacl != NULL)
+      {
+        DescriptorCopy.Sacl = (PACL)((ULONG_PTR)OriginalSecurityDescriptor + (ULONG_PTR)DescriptorCopy.Sacl);
+      }
+    }
+    
+    /* determine the size of the SIDs */
+#define DetermineSIDSize(SidType)                                              \
+    do {                                                                       \
+    if(DescriptorCopy.SidType != NULL)                                         \
+    {                                                                          \
+      SID *SidType = (SID*)DescriptorCopy.SidType;                             \
+                                                                               \
+      if(CurrentMode != KernelMode)                                            \
+      {                                                                        \
+        /* securely access the buffers! */                                     \
+        _SEH_TRY                                                               \
+        {                                                                      \
+          ProbeForRead(&SidType->SubAuthorityCount,                            \
+                       sizeof(SidType->SubAuthorityCount),                     \
+                       1);                                                     \
+          SidType##SAC = SidType->SubAuthorityCount;                           \
+          SidType##Size = RtlLengthRequiredSid(SidType##SAC);                  \
+          ProbeForRead(SidType,                                                \
+                       SidType##Size,                                          \
+                       sizeof(ULONG));                                         \
+          if(!RtlValidSid(SidType))                                            \
+          {                                                                    \
+            Status = STATUS_INVALID_SID;                                       \
+          }                                                                    \
+        }                                                                      \
+        _SEH_HANDLE                                                            \
+        {                                                                      \
+          Status = _SEH_GetExceptionCode();                                    \
+        }                                                                      \
+        _SEH_END;                                                              \
+                                                                               \
+        if(!NT_SUCCESS(Status))                                                \
+        {                                                                      \
+          return Status;                                                       \
+        }                                                                      \
+      }                                                                        \
+      else                                                                     \
+      {                                                                        \
+        SidType##SAC = SidType->SubAuthorityCount;                             \
+        SidType##Size = RtlLengthRequiredSid(SidType##SAC);                    \
+      }                                                                        \
+    }                                                                          \
+    } while(0)
+    
+    DetermineSIDSize(Owner);
+    DetermineSIDSize(Group);
+    
+    /* determine the size of the ACLs */
+#define DetermineACLSize(AclType, AclFlag)                                     \
+    do {                                                                       \
+    if((DescriptorCopy.Control & SE_##AclFlag##_PRESENT) &&                    \
+       DescriptorCopy.AclType != NULL)                                         \
+    {                                                                          \
+      PACL AclType = (PACL)DescriptorCopy.AclType;                             \
+                                                                               \
+      if(CurrentMode != KernelMode)                                            \
+      {                                                                        \
+        /* securely access the buffers! */                                     \
+        _SEH_TRY                                                               \
+        {                                                                      \
+          ProbeForRead(&AclType->AclSize,                                      \
+                       sizeof(AclType->AclSize),                               \
+                       1);                                                     \
+          AclType##Size = AclType->AclSize;                                    \
+          ProbeForRead(AclType,                                                \
+                       AclType##Size,                                          \
+                       sizeof(ULONG));                                         \
+          if(!RtlValidAcl(AclType))                                            \
+          {                                                                    \
+            Status = STATUS_INVALID_ACL;                                       \
+          }                                                                    \
+        }                                                                      \
+        _SEH_HANDLE                                                            \
+        {                                                                      \
+          Status = _SEH_GetExceptionCode();                                    \
+        }                                                                      \
+        _SEH_END;                                                              \
+                                                                               \
+        if(!NT_SUCCESS(Status))                                                \
+        {                                                                      \
+          return Status;                                                       \
+        }                                                                      \
+      }                                                                        \
+      else                                                                     \
+      {                                                                        \
+        AclType##Size = AclType->AclSize;                                      \
+      }                                                                        \
+    }                                                                          \
+    else                                                                       \
+    {                                                                          \
+      DescriptorCopy.AclType = NULL;                                           \
+    }                                                                          \
+    } while(0)
+    
+    DetermineACLSize(Sacl, SACL);
+    DetermineACLSize(Dacl, DACL);
+    
+    /* allocate enough memory to store a complete copy of a self-relative
+       security descriptor */
+    DescriptorSize = sizeof(SECURITY_DESCRIPTOR) +
+                     ROUND_UP(OwnerSize, sizeof(ULONG)) +
+                     ROUND_UP(GroupSize, sizeof(ULONG)) +
+                     ROUND_UP(SaclSize, sizeof(ULONG)) +
+                     ROUND_UP(DaclSize, sizeof(ULONG));
+
+    NewDescriptor = ExAllocatePool(PagedPool,
+                                   DescriptorSize);
+    if(NewDescriptor != NULL)
+    {
+      ULONG_PTR Offset = sizeof(SECURITY_DESCRIPTOR);
+      
+      NewDescriptor->Revision = DescriptorCopy.Revision;
+      NewDescriptor->Sbz1 = DescriptorCopy.Sbz1;
+      NewDescriptor->Control = DescriptorCopy.Control | SE_SELF_RELATIVE;
+      
+      /* setup the offsets to the SIDs and ACLs */
+      NewDescriptor->Owner = (PVOID)Offset;
+      Offset += ROUND_UP(OwnerSize, sizeof(ULONG));
+      NewDescriptor->Group = (PVOID)Offset;
+      Offset += ROUND_UP(GroupSize, sizeof(ULONG));
+      NewDescriptor->Sacl = (PVOID)Offset;
+      Offset += ROUND_UP(SaclSize, sizeof(ULONG));
+      NewDescriptor->Dacl = (PVOID)Offset;
+      
+      _SEH_TRY
+      {
+        /* copy the SIDs and ACLs to the new self-relative security descriptor */
+        RtlCopyMemory((PVOID)((ULONG_PTR)NewDescriptor + (ULONG_PTR)NewDescriptor->Owner),
+                      DescriptorCopy.Owner,
+                      OwnerSize);
+        RtlCopyMemory((PVOID)((ULONG_PTR)NewDescriptor + (ULONG_PTR)NewDescriptor->Group),
+                      DescriptorCopy.Group,
+                      GroupSize);
+        RtlCopyMemory((PVOID)((ULONG_PTR)NewDescriptor + (ULONG_PTR)NewDescriptor->Sacl),
+                      DescriptorCopy.Sacl,
+                      SaclSize);
+        RtlCopyMemory((PVOID)((ULONG_PTR)NewDescriptor + (ULONG_PTR)NewDescriptor->Dacl),
+                      DescriptorCopy.Dacl,
+                      DaclSize);
+      }
+      _SEH_HANDLE
+      {
+        Status = _SEH_GetExceptionCode();
+      }
+      _SEH_END;
+      
+      if(NT_SUCCESS(Status))
+      {
+        /* we're finally done! copy the pointer to the captured descriptor to
+           to the caller */
+        *CapturedSecurityDescriptor = NewDescriptor;
+        return STATUS_SUCCESS;
+      }
+      else
+      {
+        /* we failed to copy the data to the new descriptor */
+        ExFreePool(NewDescriptor);
+      }
+    }
+    else
+    {
+      Status = STATUS_INSUFFICIENT_RESOURCES;
+    }
+  }
+  else
+  {
+    /* nothing to do... */
+    *CapturedSecurityDescriptor = NULL;
+  }
+  
+  return Status;
 }
 
 /*
@@ -262,7 +504,7 @@
 }
 
 /*
- * @unimplemented
+ * @implemented
  */
 NTSTATUS
 STDCALL
@@ -272,8 +514,18 @@
 	IN BOOLEAN CaptureIfKernelMode
 	)
 {
-	UNIMPLEMENTED;
-	return STATUS_NOT_IMPLEMENTED;
+  /* WARNING! You need to call this function with the same value for CurrentMode
+              and CaptureIfKernelMode that you previously passed to
+              SeCaptureSecurityDescriptor() in order to avoid memory leaks! */
+  if(CapturedSecurityDescriptor != NULL &&
+     (CurrentMode == UserMode ||
+      (CurrentMode == KernelMode && CaptureIfKernelMode)))
+  {
+    /* only delete the descriptor when SeCaptureSecurityDescriptor() allocated one! */
+    ExFreePool(CapturedSecurityDescriptor);
+  }
+
+  return STATUS_SUCCESS;
 }
 
 /*