Thomas Weidenmueller <w3seek@reactos.com>
[reactos.git] / reactos / ntoskrnl / ob / object.c
index e3aa062..d9e1580 100644 (file)
@@ -1,26 +1,17 @@
-/* $Id: object.c,v 1.79 2004/07/18 13:03:43 ekohl Exp $
+/* $Id$
  * 
- * COPYRIGHT:     See COPYING in the top level directory
- * PROJECT:       ReactOS kernel
- * FILE:          ntoskrnl/ob/object.c
- * PURPOSE:       Implements generic object managment functions
- * PROGRAMMERS    David Welch (welch@cwcom.net), Skywing (skywing@valhallalegends.com)
- * UPDATE HISTORY:
- *               10/06/98: Created
- *               09/13/03: Fixed various ObXxx routines to not call retention
- *                         checks directly at a raised IRQL.
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS kernel
+ * FILE:            ntoskrnl/ob/object.c
+ * PURPOSE:         Implements generic object managment functions
+ * 
+ * PROGRAMMERS:     David Welch (welch@cwcom.net)
+ *                  Skywing (skywing@valhallalegends.com)
  */
 
 /* INCLUDES *****************************************************************/
 
-#define NTOS_MODE_KERNEL
-#include <ntos.h>
-#include <roscfg.h>
-#include <internal/ob.h>
-#include <internal/ps.h>
-#include <internal/id.h>
-#include <internal/ke.h>
-
+#include <ntoskrnl.h>
 #define NDEBUG
 #include <internal/debug.h>
 
@@ -46,6 +37,333 @@ POBJECT_HEADER BODY_TO_HEADER(PVOID body)
   return(CONTAINING_RECORD((&(chdr->Type)),OBJECT_HEADER,Type));
 }
 
+NTSTATUS
+ObpCaptureObjectAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes  OPTIONAL,
+                           IN KPROCESSOR_MODE AccessMode,
+                           IN POOL_TYPE PoolType,
+                           IN BOOLEAN CaptureIfKernel,
+                           OUT PCAPTURED_OBJECT_ATTRIBUTES CapturedObjectAttributes  OPTIONAL,
+                           OUT PUNICODE_STRING ObjectName  OPTIONAL)
+{
+  OBJECT_ATTRIBUTES AttributesCopy;
+  NTSTATUS Status = STATUS_SUCCESS;
+
+  /* at least one output parameter must be != NULL! */
+  ASSERT(CapturedObjectAttributes != NULL || ObjectName != NULL);
+
+  if(ObjectAttributes == NULL)
+  {
+    /* we're going to return STATUS_SUCCESS! */
+    goto failbasiccleanup;
+  }
+
+  if(AccessMode != KernelMode)
+  {
+    _SEH_TRY
+    {
+      ProbeForRead(ObjectAttributes,
+                   sizeof(ObjectAttributes),
+                   sizeof(ULONG));
+      /* make a copy on the stack */
+      AttributesCopy = *ObjectAttributes;
+    }
+    _SEH_HANDLE
+    {
+      Status = _SEH_GetExceptionCode();
+    }
+    _SEH_END;
+
+    if(!NT_SUCCESS(Status))
+    {
+      DPRINT1("ObpCaptureObjectAttributes failed to probe object attributes\n");
+      goto failbasiccleanup;
+    }
+  }
+  else if(!CaptureIfKernel)
+  {
+    if(ObjectAttributes->Length == sizeof(OBJECT_ATTRIBUTES))
+    {
+      if(ObjectName != NULL)
+      {
+        /* we don't have to capture any memory, the caller considers the passed data
+           as valid */
+        if(ObjectAttributes->ObjectName != NULL)
+        {
+          *ObjectName = *ObjectAttributes->ObjectName;
+        }
+        else
+        {
+          ObjectName->Length = ObjectName->MaximumLength = 0;
+          ObjectName->Buffer = NULL;
+        }
+      }
+      if(CapturedObjectAttributes != NULL)
+      {
+        CapturedObjectAttributes->RootDirectory = ObjectAttributes->RootDirectory;
+        CapturedObjectAttributes->Attributes = ObjectAttributes->Attributes;
+        CapturedObjectAttributes->SecurityDescriptor = ObjectAttributes->SecurityDescriptor;
+        CapturedObjectAttributes->SecurityQualityOfService = ObjectAttributes->SecurityQualityOfService;
+      }
+
+      return STATUS_SUCCESS;
+    }
+    else
+    {
+      Status = STATUS_INVALID_PARAMETER;
+      goto failbasiccleanup;
+    }
+  }
+  else
+  {
+    AttributesCopy = *ObjectAttributes;
+  }
+
+  /* if Length isn't as expected, bail with an invalid parameter status code so
+     the caller knows he passed garbage... */
+  if(AttributesCopy.Length != sizeof(OBJECT_ATTRIBUTES))
+  {
+    Status = STATUS_INVALID_PARAMETER;
+    goto failbasiccleanup;
+  }
+
+  if(CapturedObjectAttributes != NULL)
+  {
+    CapturedObjectAttributes->RootDirectory = AttributesCopy.RootDirectory;
+    CapturedObjectAttributes->Attributes = AttributesCopy.Attributes;
+
+    if(AttributesCopy.SecurityDescriptor != NULL)
+    {
+      Status = SeCaptureSecurityDescriptor(AttributesCopy.SecurityDescriptor,
+                                           AccessMode,
+                                           PoolType,
+                                           TRUE,
+                                           &CapturedObjectAttributes->SecurityDescriptor);
+      if(!NT_SUCCESS(Status))
+      {
+        DPRINT1("Unable to capture the security descriptor!!!\n");
+        goto failbasiccleanup;
+      }
+    }
+    else
+    {
+      CapturedObjectAttributes->SecurityDescriptor = NULL;
+    }
+
+    if(AttributesCopy.SecurityQualityOfService != NULL)
+    {
+      SECURITY_QUALITY_OF_SERVICE SafeQoS;
+
+      _SEH_TRY
+      {
+        ProbeForRead(AttributesCopy.SecurityQualityOfService,
+                     sizeof(SECURITY_QUALITY_OF_SERVICE),
+                     sizeof(ULONG));
+        SafeQoS = *(PSECURITY_QUALITY_OF_SERVICE)AttributesCopy.SecurityQualityOfService;
+      }
+      _SEH_HANDLE
+      {
+        Status = _SEH_GetExceptionCode();
+      }
+      _SEH_END;
+
+      if(!NT_SUCCESS(Status))
+      {
+        DPRINT1("Unable to capture QoS!!!\n");
+        goto failcleanupsdescriptor;
+      }
+
+      if(SafeQoS.Length != sizeof(SECURITY_QUALITY_OF_SERVICE))
+      {
+        DPRINT1("Unable to capture QoS, wrong size!!!\n");
+        Status = STATUS_INVALID_PARAMETER;
+        goto failcleanupsdescriptor;
+      }
+
+      CapturedObjectAttributes->SecurityQualityOfService = ExAllocatePool(PoolType,
+                                                                          sizeof(SECURITY_QUALITY_OF_SERVICE));
+      if(CapturedObjectAttributes->SecurityQualityOfService != NULL)
+      {
+        *CapturedObjectAttributes->SecurityQualityOfService = SafeQoS;
+      }
+      else
+      {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto failcleanupsdescriptor;
+      }
+    }
+    else
+    {
+      CapturedObjectAttributes->SecurityQualityOfService = NULL;
+    }
+  }
+
+  if(ObjectName != NULL)
+  {
+    if(AttributesCopy.ObjectName != NULL)
+    {
+      UNICODE_STRING OriginalCopy;
+
+      if(AccessMode != KernelMode)
+      {
+        _SEH_TRY
+        {
+          /* probe the ObjectName structure and make a local stack copy of it */
+          ProbeForRead(AttributesCopy.ObjectName,
+                       sizeof(UNICODE_STRING),
+                       sizeof(ULONG));
+          OriginalCopy = *AttributesCopy.ObjectName;
+          if(OriginalCopy.Length > 0)
+          {
+            ProbeForRead(OriginalCopy.Buffer,
+                         OriginalCopy.Length,
+                         sizeof(WCHAR));
+          }
+        }
+        _SEH_HANDLE
+        {
+          Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+
+        if(NT_SUCCESS(Status))
+        {
+          if(OriginalCopy.Length > 0)
+          {
+            ObjectName->MaximumLength = OriginalCopy.Length + sizeof(WCHAR);
+            ObjectName->Buffer = ExAllocatePool(PoolType,
+                                                ObjectName->MaximumLength);
+            if(ObjectName->Buffer != NULL)
+            {
+              _SEH_TRY
+              {
+                /* no need to probe OriginalCopy.Buffer again, we already did that
+                   when capturing the UNICODE_STRING structure itself */
+                RtlCopyMemory(ObjectName->Buffer, OriginalCopy.Buffer, OriginalCopy.Length);
+                ObjectName->Buffer[OriginalCopy.Length / sizeof(WCHAR)] = L'\0';
+              }
+              _SEH_HANDLE
+              {
+                Status = _SEH_GetExceptionCode();
+              }
+              _SEH_END;
+
+              if(!NT_SUCCESS(Status))
+              {
+                DPRINT1("ObpCaptureObjectAttributes failed to copy the unicode string!\n");
+              }
+            }
+            else
+            {
+              Status = STATUS_INSUFFICIENT_RESOURCES;
+            }
+          }
+          else if(AttributesCopy.RootDirectory != NULL /* && OriginalCopy.Length == 0 */)
+          {
+            /* if the caller specified a root directory, there must be an object name! */
+            Status = STATUS_OBJECT_NAME_INVALID;
+          }
+        }
+        else
+        {
+          DPRINT1("ObpCaptureObjectAttributes failed to probe the object name UNICODE_STRING structure!\n");
+        }
+      }
+      else /* AccessMode == KernelMode */
+      {
+        OriginalCopy = *AttributesCopy.ObjectName;
+
+        if(OriginalCopy.Length > 0)
+        {
+          ObjectName->MaximumLength = OriginalCopy.Length + sizeof(WCHAR);
+          ObjectName->Buffer = ExAllocatePool(PoolType,
+                                              ObjectName->MaximumLength);
+          if(ObjectName->Buffer != NULL)
+          {
+            RtlCopyMemory(ObjectName->Buffer, OriginalCopy.Buffer, OriginalCopy.Length);
+            ObjectName->Buffer[OriginalCopy.Length / sizeof(WCHAR)] = L'\0';
+          }
+          else
+          {
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+          }
+        }
+        else if(AttributesCopy.RootDirectory != NULL /* && OriginalCopy.Length == 0 */)
+        {
+          /* if the caller specified a root directory, there must be an object name! */
+          Status = STATUS_OBJECT_NAME_INVALID;
+        }
+      }
+    }
+    else
+    {
+      ObjectName->Length = ObjectName->MaximumLength = 0;
+      ObjectName->Buffer = NULL;
+    }
+  }
+
+  if(!NT_SUCCESS(Status))
+  {
+    if(ObjectName->Buffer)
+    {
+      ExFreePool(ObjectName->Buffer);
+    }
+
+failcleanupsdescriptor:
+    if(CapturedObjectAttributes != NULL)
+    {
+      /* cleanup allocated resources */
+      SeReleaseSecurityDescriptor(CapturedObjectAttributes->SecurityDescriptor,
+                                  AccessMode,
+                                  TRUE);
+    }
+
+failbasiccleanup:
+    if(ObjectName != NULL)
+    {
+      ObjectName->Length = ObjectName->MaximumLength = 0;
+      ObjectName->Buffer = NULL;
+    }
+    if(CapturedObjectAttributes != NULL)
+    {
+      RtlZeroMemory(CapturedObjectAttributes, sizeof(CAPTURED_OBJECT_ATTRIBUTES));
+    }
+  }
+
+  return Status;
+}
+
+
+VOID
+ObpReleaseObjectAttributes(IN PCAPTURED_OBJECT_ATTRIBUTES CapturedObjectAttributes  OPTIONAL,
+                           IN PUNICODE_STRING ObjectName  OPTIONAL,
+                           IN KPROCESSOR_MODE AccessMode,
+                           IN BOOLEAN CaptureIfKernel)
+{
+  /* WARNING - You need to pass the same parameters to this function as you passed
+               to ObpCaptureObjectAttributes() to avoid memory leaks */
+  if(AccessMode != KernelMode || CaptureIfKernel)
+  {
+    if(CapturedObjectAttributes != NULL)
+    {
+      if(CapturedObjectAttributes->SecurityDescriptor != NULL)
+      {
+        ExFreePool(CapturedObjectAttributes->SecurityDescriptor);
+        CapturedObjectAttributes->SecurityDescriptor = NULL;
+      }
+      if(CapturedObjectAttributes->SecurityQualityOfService != NULL)
+      {
+        ExFreePool(CapturedObjectAttributes->SecurityQualityOfService);
+        CapturedObjectAttributes->SecurityQualityOfService = NULL;
+      }
+    }
+    if(ObjectName != NULL &&
+       ObjectName->Length > 0)
+    {
+      ExFreePool(ObjectName->Buffer);
+    }
+  }
+}
+
 
 /**********************************************************************
  * NAME                                                        PRIVATE
@@ -85,6 +403,8 @@ ObFindObject(POBJECT_ATTRIBUTES ObjectAttributes,
   UNICODE_STRING PathString;
   ULONG Attributes;
   PUNICODE_STRING ObjectName;
+  
+  PAGED_CODE();
 
   DPRINT("ObFindObject(ObjectAttributes %x, ReturnedObject %x, "
         "RemainingPath %x)\n",ObjectAttributes,ReturnedObject,RemainingPath);
@@ -192,7 +512,7 @@ ObFindObject(POBJECT_ATTRIBUTES ObjectAttributes,
     }
 
   if (current)
-     RtlCreateUnicodeString (RemainingPath, current);
+     RtlpCreateUnicodeString (RemainingPath, current, NonPagedPool);
   RtlFreeUnicodeString (&PathString);
   *ReturnedObject = CurrentObject;
 
@@ -222,6 +542,8 @@ ObQueryNameString (IN PVOID Object,
   POBJECT_HEADER ObjectHeader;
   ULONG LocalReturnLength;
   NTSTATUS Status;
+  
+  PAGED_CODE();
 
   *ReturnLength = 0;
 
@@ -348,8 +670,30 @@ ObCreateObject (IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL,
   BOOLEAN ObjectAttached = FALSE;
   PWCHAR NamePtr;
   PSECURITY_DESCRIPTOR NewSecurityDescriptor = NULL;
+  SECURITY_SUBJECT_CONTEXT SubjectContext;
 
-  assert_irql(APC_LEVEL);
+  PAGED_CODE();
+  
+  if(ObjectAttributesAccessMode == UserMode && ObjectAttributes != NULL)
+  {
+    Status = STATUS_SUCCESS;
+    _SEH_TRY
+    {
+      ProbeForRead(ObjectAttributes,
+                   sizeof(OBJECT_ATTRIBUTES),
+                   sizeof(ULONG));
+    }
+    _SEH_HANDLE
+    {
+      Status = _SEH_GetExceptionCode();
+    }
+    _SEH_END;
+    
+    if(!NT_SUCCESS(Status))
+    {
+      return Status;
+    }
+  }
 
   DPRINT("ObCreateObject(Type %p ObjectAttributes %p, Object %p)\n",
         Type, ObjectAttributes, Object);
@@ -370,8 +714,8 @@ ObCreateObject (IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL,
                            NULL);
       if (!NT_SUCCESS(Status))
        {
-         DPRINT("ObFindObject() failed! (Status 0x%x)\n", Status);
-         return(Status);
+         DPRINT1("ObFindObject() failed! (Status 0x%x)\n", Status);
+         return Status;
        }
     }
   else
@@ -382,11 +726,15 @@ ObCreateObject (IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL,
   Header = (POBJECT_HEADER)ExAllocatePoolWithTag(NonPagedPool,
                                                 OBJECT_ALLOC_SIZE(ObjectSize),
                                                 Type->Tag);
-  if (Header == NULL)
-    return STATUS_INSUFFICIENT_RESOURCES;
+  if (Header == NULL) {
+       DPRINT1("Not enough memory!\n");
+       return STATUS_INSUFFICIENT_RESOURCES;
+  }
+
   RtlZeroMemory(Header, OBJECT_ALLOC_SIZE(ObjectSize));
 
   /* Initialize the object header */
+  DPRINT("Initalizing header\n");
   Header->HandleCount = 0;
   Header->RefCount = 1;
   Header->ObjectType = Type;
@@ -412,6 +760,7 @@ ObCreateObject (IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL,
 
   RtlInitUnicodeString(&(Header->Name),NULL);
 
+  DPRINT("Getting Parent and adding entry\n");
   if (Parent != NULL)
     {
       ParentHeader = BODY_TO_HEADER(Parent);
@@ -432,6 +781,7 @@ ObCreateObject (IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL,
       ObjectAttached = TRUE;
     }
 
+  DPRINT("About to call Create Routine\n");
   if (Header->ObjectType->Create != NULL)
     {
       DPRINT("Calling %x\n", Header->ObjectType->Create);
@@ -452,17 +802,21 @@ ObCreateObject (IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL,
          RtlFreeUnicodeString(&Header->Name);
          RtlFreeUnicodeString(&RemainingPath);
          ExFreePool(Header);
-         return(Status);
+         DPRINT("Create Failed\n");
+         return Status;
        }
     }
   RtlFreeUnicodeString(&RemainingPath);
 
+  SeCaptureSubjectContext(&SubjectContext);
+
+  DPRINT("Security Assignment in progress\n");
   /* Build the new security descriptor */
   Status = SeAssignSecurity((ParentHeader != NULL) ? ParentHeader->SecurityDescriptor : NULL,
                            (ObjectAttributes != NULL) ? ObjectAttributes->SecurityDescriptor : NULL,
                            &NewSecurityDescriptor,
                            (Header->ObjectType == ObDirectoryType),
-                           NULL, //SubjectContext,
+                           &SubjectContext,
                            Header->ObjectType->Mapping,
                            PagedPool);
   if (NT_SUCCESS(Status))
@@ -471,8 +825,12 @@ ObCreateObject (IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL,
 
       if (Header->ObjectType->Security != NULL)
        {
-         /* FIXME: Call the security method */
-         Status = STATUS_SUCCESS;
+         /* Call the security method */
+         Status = Header->ObjectType->Security(HEADER_TO_BODY(Header),
+                                               AssignSecurityDescriptor,
+                                               0,
+                                               NewSecurityDescriptor,
+                                               NULL);
        }
       else
        {
@@ -486,12 +844,16 @@ ObCreateObject (IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL,
       SeDeassignSecurity(&NewSecurityDescriptor);
     }
 
+  DPRINT("Security Complete\n");
+  SeReleaseSubjectContext(&SubjectContext);
+
   if (Object != NULL)
     {
       *Object = HEADER_TO_BODY(Header);
     }
 
-  return(STATUS_SUCCESS);
+  DPRINT("Sucess!\n");
+  return STATUS_SUCCESS;
 }
 
 
@@ -513,6 +875,8 @@ ObReferenceObjectByPointer(IN PVOID Object,
                           IN KPROCESSOR_MODE AccessMode)
 {
    POBJECT_HEADER Header;
+   
+   /* NOTE: should be possible to reference an object above APC_LEVEL! */
 
    DPRINT("ObReferenceObjectByPointer(Object %x, ObjectType %x)\n",
          Object,ObjectType);
@@ -526,7 +890,7 @@ ObReferenceObjectByPointer(IN PVOID Object,
                Header->ObjectType,
                Header->ObjectType->TypeName.Buffer,
                ObjectType,
-    ObjectType->TypeName.Buffer);
+               ObjectType->TypeName.Buffer);
        return(STATUS_UNSUCCESSFUL);
      }
    if (Header->ObjectType == PsProcessType)
@@ -575,6 +939,8 @@ ObOpenObjectByPointer(IN POBJECT Object,
 {
    NTSTATUS Status;
    
+   PAGED_CODE();
+   
    DPRINT("ObOpenObjectByPointer()\n");
    
    Status = ObReferenceObjectByPointer(Object,
@@ -601,10 +967,10 @@ ObOpenObjectByPointer(IN POBJECT Object,
 static NTSTATUS
 ObpDeleteObject(POBJECT_HEADER Header)
 {
-  DPRINT("ObPerformRetentionChecks(Header %p)\n", Header);
+  DPRINT("ObpDeleteObject(Header %p)\n", Header);
   if (KeGetCurrentIrql() != PASSIVE_LEVEL)
     {
-      DPRINT("ObpPerformRetentionChecks called at an unsupported IRQL.  Use ObpPerformRetentionChecksDpcLevel instead.\n");
+      DPRINT("ObpDeleteObject called at an unsupported IRQL.  Use ObpDeleteObjectDpcLevel instead.\n");
       KEBUGCHECK(0);
     }
 
@@ -638,8 +1004,8 @@ ObpDeleteObjectWorkRoutine (IN PVOID Parameter)
   PRETENTION_CHECK_PARAMS Params = (PRETENTION_CHECK_PARAMS)Parameter;
   /* ULONG Tag; */ /* See below */
 
-  assert(Params);
-  assert(KeGetCurrentIrql() == PASSIVE_LEVEL); /* We need PAGED_CODE somewhere... */
+  ASSERT(Params);
+  ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); /* We need PAGED_CODE somewhere... */
 
   /* Turn this on when we have ExFreePoolWithTag
   Tag = Params->ObjectHeader->ObjectType->Tag; */
@@ -704,7 +1070,7 @@ ObpDeleteObjectDpcLevel(IN POBJECT_HEADER ObjectHeader,
       return STATUS_PENDING;
       
     default:
-      DPRINT("ObpPerformRetentionChecksDpcLevel called at unsupported "
+      DPRINT("ObpDeleteObjectDpcLevel called at unsupported "
             "IRQL %u!\n", KeGetCurrentIrql());
       KEBUGCHECK(0);
       return STATUS_UNSUCCESSFUL;
@@ -735,7 +1101,7 @@ ObfReferenceObject(IN PVOID Object)
 {
   POBJECT_HEADER Header;
 
-  assert(Object);
+  ASSERT(Object);
 
   Header = BODY_TO_HEADER(Object);
 
@@ -773,7 +1139,7 @@ ObfDereferenceObject(IN PVOID Object)
   BOOL Permanent;
   ULONG HandleCount;
 
-  assert(Object);
+  ASSERT(Object);
 
   /* Extract the object header. */
   Header = BODY_TO_HEADER(Object);
@@ -785,7 +1151,7 @@ ObfDereferenceObject(IN PVOID Object)
      last reference.
   */
   NewRefCount = InterlockedDecrement(&Header->RefCount);
-  assert(NewRefCount >= 0);
+  ASSERT(NewRefCount >= 0);
 
   /* Check whether the object can now be deleted. */
   if (NewRefCount == 0 &&
@@ -816,11 +1182,13 @@ ULONG STDCALL
 ObGetObjectPointerCount(PVOID Object)
 {
   POBJECT_HEADER Header;
+  
+  PAGED_CODE();
 
-  assert(Object);
+  ASSERT(Object);
   Header = BODY_TO_HEADER(Object);
 
-  return(Header->RefCount);
+  return Header->RefCount;
 }
 
 
@@ -841,11 +1209,13 @@ ULONG
 ObGetObjectHandleCount(PVOID Object)
 {
   POBJECT_HEADER Header;
+  
+  PAGED_CODE();
 
-  assert(Object);
+  ASSERT(Object);
   Header = BODY_TO_HEADER(Object);
 
-  return(Header->HandleCount);
+  return Header->HandleCount;
 }