[NTOSKRNL]
authorTimo Kreuzer <timo.kreuzer@reactos.org>
Thu, 6 Feb 2014 19:26:05 +0000 (19:26 +0000)
committerTimo Kreuzer <timo.kreuzer@reactos.org>
Thu, 6 Feb 2014 19:26:05 +0000 (19:26 +0000)
Implement SepAccessCheckAndAuditAlarm, which now does proper argument capturing and forwards those to SepAccessCheckAndAuditAlarmWorker, which for now only grants access without checking.

svn path=/trunk/; revision=62016

reactos/ntoskrnl/se/audit.c

index 608ce41..a9bf546 100644 (file)
@@ -207,13 +207,119 @@ SepAdtPrivilegedServiceAuditAlarm(
     UNIMPLEMENTED;
 }
 
+static
+NTSTATUS
+SeCaptureObjectTypeList(
+    _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
+    _In_ ULONG ObjectTypeListLength,
+    _In_ KPROCESSOR_MODE PreviousMode,
+    _Out_ POBJECT_TYPE_LIST *CapturedObjectTypeList)
+{
+    SIZE_T Size;
+
+    if (PreviousMode == KernelMode)
+    {
+        return STATUS_NOT_IMPLEMENTED;
+    }
+
+    if (ObjectTypeListLength == 0)
+    {
+        *CapturedObjectTypeList = NULL;
+        return STATUS_SUCCESS;
+    }
+
+    if (ObjectTypeList == NULL)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Calculate the list size and check for integer overflow */
+    Size = ObjectTypeListLength * sizeof(OBJECT_TYPE_LIST);
+    if (Size == 0)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Allocate a new list */
+    *CapturedObjectTypeList = ExAllocatePoolWithTag(PagedPool, Size, TAG_SEPA);
+    if (*CapturedObjectTypeList == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    _SEH2_TRY
+    {
+        ProbeForRead(ObjectTypeList, Size, sizeof(ULONG));
+        RtlCopyMemory(*CapturedObjectTypeList, ObjectTypeList, Size);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        ExFreePoolWithTag(*CapturedObjectTypeList, TAG_SEPA);
+        *CapturedObjectTypeList = NULL;
+        return _SEH2_GetExceptionCode();
+    }
+    _SEH2_END;
+
+    return STATUS_SUCCESS;
+}
+
+static
+VOID
+SeReleaseObjectTypeList(
+    _In_  _Post_invalid_ POBJECT_TYPE_LIST CapturedObjectTypeList,
+    _In_ KPROCESSOR_MODE PreviousMode)
+{
+    if ((PreviousMode != KernelMode) && (CapturedObjectTypeList != NULL))
+        ExFreePoolWithTag(CapturedObjectTypeList, TAG_SEPA);
+}
+
+_Must_inspect_result_
+static
+NTSTATUS
+SepAccessCheckAndAuditAlarmWorker(
+    _In_ PUNICODE_STRING SubsystemName,
+    _In_opt_ PVOID HandleId,
+    _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
+    _In_ PUNICODE_STRING ObjectTypeName,
+    _In_ PUNICODE_STRING ObjectName,
+    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+    _In_opt_ PSID PrincipalSelfSid,
+    _In_ ACCESS_MASK DesiredAccess,
+    _In_ AUDIT_EVENT_TYPE AuditType,
+    _In_ BOOLEAN HaveAuditPrivilege,
+    _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
+    _In_ ULONG ObjectTypeListLength,
+    _In_ PGENERIC_MAPPING GenericMapping,
+    _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccessList,
+    _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatusList,
+    _Out_ PBOOLEAN GenerateOnClose,
+    _In_ BOOLEAN UseResultList)
+{
+    ULONG ResultListLength, i;
+
+    /* Get the length of the result list */
+    ResultListLength = UseResultList ? ObjectTypeListLength : 1;
+
+    /// FIXME: we should do some real work here...
+    UNIMPLEMENTED;
+
+    /// HACK: we just pretend all access is granted!
+    for (i = 0; i < ResultListLength; i++)
+    {
+        GrantedAccessList[i] = DesiredAccess;
+        AccessStatusList[i] = STATUS_SUCCESS;
+    }
+
+    return STATUS_SUCCESS;
+}
+
 _Must_inspect_result_
 NTSTATUS
 NTAPI
 SepAccessCheckAndAuditAlarm(
     _In_ PUNICODE_STRING SubsystemName,
     _In_opt_ PVOID HandleId,
-    _In_ PHANDLE ClientToken,
+    _In_ PHANDLE ClientTokenHandle,
     _In_ PUNICODE_STRING ObjectTypeName,
     _In_ PUNICODE_STRING ObjectName,
     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
@@ -232,14 +338,33 @@ SepAccessCheckAndAuditAlarm(
     SECURITY_SUBJECT_CONTEXT SubjectContext;
     ULONG ResultListLength;
     GENERIC_MAPPING LocalGenericMapping;
+    PTOKEN SubjectContextToken, ClientToken;
+    BOOLEAN AllocatedResultLists;
+    BOOLEAN HaveAuditPrivilege;
+    PISECURITY_DESCRIPTOR CapturedSecurityDescriptor;
+    UNICODE_STRING CapturedSubsystemName, CapturedObjectTypeName, CapturedObjectName;
+    ACCESS_MASK GrantedAccess, *SafeGrantedAccessList;
+    NTSTATUS AccessStatus, *SafeAccessStatusList;
+    PSID CapturedPrincipalSelfSid;
+    POBJECT_TYPE_LIST CapturedObjectTypeList;
+    ULONG i;
+    BOOLEAN LocalGenerateOnClose;
     NTSTATUS Status;
     PAGED_CODE();
 
-    DBG_UNREFERENCED_LOCAL_VARIABLE(LocalGenericMapping);
-
     /* Only user mode is supported! */
     ASSERT(ExGetPreviousMode() != KernelMode);
 
+    /* Start clean */
+    AllocatedResultLists = FALSE;
+    ClientToken = NULL;
+    CapturedSecurityDescriptor = NULL;
+    CapturedSubsystemName.Buffer = NULL;
+    CapturedObjectTypeName.Buffer = NULL;
+    CapturedObjectName.Buffer = NULL;
+    CapturedPrincipalSelfSid = NULL;
+    CapturedObjectTypeList = NULL;
+
     /* Validate AuditType */
     if ((AuditType != AuditEventObjectAccess) &&
         (AuditType != AuditEventDirectoryServiceAccess))
@@ -252,12 +377,13 @@ SepAccessCheckAndAuditAlarm(
     SeCaptureSubjectContext(&SubjectContext);
 
     /* Did the caller pass a token handle? */
-    if (ClientToken == NULL)
+    if (ClientTokenHandle == NULL)
     {
         /* Check if we have a token in the subject context */
         if (SubjectContext.ClientToken == NULL)
         {
             Status = STATUS_NO_IMPERSONATION_TOKEN;
+            DPRINT1("No token\n");
             goto Cleanup;
         }
 
@@ -265,6 +391,8 @@ SepAccessCheckAndAuditAlarm(
         if (SubjectContext.ImpersonationLevel < SecurityIdentification)
         {
             Status = STATUS_BAD_IMPERSONATION_LEVEL;
+            DPRINT1("Invalid impersonation level 0x%lx\n",
+                    SubjectContext.ImpersonationLevel);
             goto Cleanup;
         }
     }
@@ -277,13 +405,30 @@ SepAccessCheckAndAuditAlarm(
         if ((ResultListLength == 0) || (ResultListLength > 0x1000))
         {
             Status = STATUS_INVALID_PARAMETER;
+            DPRINT1("Invalud ResultListLength: 0x%lx\n", ResultListLength);
             goto Cleanup;
         }
+
+        /* Allocate a safe buffer from paged pool */
+        SafeGrantedAccessList = ExAllocatePoolWithTag(PagedPool,
+                                                      2 * ResultListLength * sizeof(ULONG),
+                                                      TAG_SEPA);
+        if (SafeGrantedAccessList == NULL)
+        {
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            DPRINT1("Failed to allocate access lists\n");
+            goto Cleanup;
+        }
+
+        SafeAccessStatusList = (PNTSTATUS)&SafeGrantedAccessList[ResultListLength];
+        AllocatedResultLists = TRUE;
     }
     else
     {
         /* List length is 1 */
         ResultListLength = 1;
+        SafeGrantedAccessList = &GrantedAccess;
+        SafeAccessStatusList = &AccessStatus;
     }
 
     _SEH2_TRY
@@ -303,18 +448,194 @@ SepAccessCheckAndAuditAlarm(
     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
         Status = _SEH2_GetExceptionCode();
+        DPRINT1("Exception while probing parameters: 0x%lx\n", Status);
         goto Cleanup;
     }
     _SEH2_END;
 
+    /* Do we have a client token? */
+    if (ClientTokenHandle != NULL)
+    {
+        /* Reference the client token */
+        Status = ObReferenceObjectByHandle(*ClientTokenHandle,
+                                           TOKEN_QUERY,
+                                           SeTokenObjectType,
+                                           UserMode,
+                                           (PVOID*)&ClientToken,
+                                           NULL);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Failed to reference token handle %p: %lx\n",
+                    *ClientTokenHandle, Status);
+            goto Cleanup;
+        }
+
+        SubjectContextToken = SubjectContext.ClientToken;
+        SubjectContext.ClientToken = ClientToken;
+    }
 
-    UNIMPLEMENTED;
+    /* Check for audit privilege */
+    HaveAuditPrivilege = SeSinglePrivilegeCheck(SeAuditPrivilege, UserMode);
+    if (!HaveAuditPrivilege && !(Flags & AUDIT_ALLOW_NO_PRIVILEGE))
+    {
+        DPRINT1("Caller does not have SeAuditPrivilege\n");
+        Status = STATUS_PRIVILEGE_NOT_HELD;
+        goto Cleanup;
+    }
 
-    /* For now pretend everything else is ok */
-    Status = STATUS_SUCCESS;
+    /* Generic access must already be mapped to non-generic access types! */
+    if (DesiredAccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL))
+    {
+        DPRINT1("Generic access rights requested: 0x%lx\n", DesiredAccess);
+        Status = STATUS_GENERIC_NOT_MAPPED;
+        goto Cleanup;
+    }
+
+    /* Capture the security descriptor */
+    Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
+                                         UserMode,
+                                         PagedPool,
+                                         FALSE,
+                                         &CapturedSecurityDescriptor);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to capture security descriptor!\n");
+        goto Cleanup;
+    }
+
+    /* Validate the Security descriptor */
+    if ((SepGetOwnerFromDescriptor(CapturedSecurityDescriptor) == NULL) ||
+        (SepGetGroupFromDescriptor(CapturedSecurityDescriptor) == NULL))
+    {
+        Status = STATUS_INVALID_SECURITY_DESCR;
+        DPRINT1("Invalid security descriptor\n");
+        goto Cleanup;
+    }
+
+    /* Probe and capture the subsystem name */
+    Status = ProbeAndCaptureUnicodeString(&CapturedSubsystemName,
+                                          UserMode,
+                                          SubsystemName);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to capture subsystem name!\n");
+        goto Cleanup;
+    }
+
+    /* Probe and capture the object type name */
+    Status = ProbeAndCaptureUnicodeString(&CapturedObjectTypeName,
+                                          UserMode,
+                                          ObjectTypeName);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to capture object type name!\n");
+        goto Cleanup;
+    }
+
+    /* Probe and capture the object name */
+    Status = ProbeAndCaptureUnicodeString(&CapturedObjectName,
+                                          UserMode,
+                                          ObjectName);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to capture object name!\n");
+        goto Cleanup;
+    }
+
+    /* Check if we have a PrincipalSelfSid */
+    if (PrincipalSelfSid != NULL)
+    {
+        /* Capture it */
+        Status = SepCaptureSid(PrincipalSelfSid,
+                               UserMode,
+                               PagedPool,
+                               FALSE,
+                               &CapturedPrincipalSelfSid);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Failed to capture PrincipalSelfSid!\n");
+            goto Cleanup;
+        }
+    }
+
+    /* Capture the object type list */
+    Status = SeCaptureObjectTypeList(ObjectTypeList,
+                                     ObjectTypeListLength,
+                                     UserMode,
+                                     &CapturedObjectTypeList);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to capture object type list!\n");
+        goto Cleanup;
+    }
+
+    /* Call the worker routine with the captured buffers */
+    SepAccessCheckAndAuditAlarmWorker(&CapturedSubsystemName,
+                                      HandleId,
+                                      &SubjectContext,
+                                      &CapturedObjectTypeName,
+                                      &CapturedObjectName,
+                                      CapturedSecurityDescriptor,
+                                      CapturedPrincipalSelfSid,
+                                      DesiredAccess,
+                                      AuditType,
+                                      HaveAuditPrivilege,
+                                      CapturedObjectTypeList,
+                                      ObjectTypeListLength,
+                                      &LocalGenericMapping,
+                                      SafeGrantedAccessList,
+                                      SafeAccessStatusList,
+                                      &LocalGenerateOnClose,
+                                      UseResultList);
+
+    /* Enter SEH to copy the data back to user mode */
+    _SEH2_TRY
+    {
+        /* Loop all result entries (only 1 when no list was requested) */
+        NT_ASSERT(UseResultList || (ResultListLength == 1));
+        for (i = 0; i < ResultListLength; i++)
+        {
+            AccessStatusList[i] = SafeAccessStatusList[i];
+            GrantedAccessList[i] = SafeGrantedAccessList[i];
+        }
+
+        *GenerateOnClose = LocalGenerateOnClose;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        Status = _SEH2_GetExceptionCode();
+        DPRINT1("Exception while copying back data: 0x%lx\n", Status);
+    }
 
 Cleanup:
 
+    if (CapturedObjectTypeList != NULL)
+        SeReleaseObjectTypeList(CapturedObjectTypeList, UserMode);
+
+    if (CapturedPrincipalSelfSid != NULL)
+        SepReleaseSid(CapturedPrincipalSelfSid, UserMode, FALSE);
+
+    if (CapturedObjectName.Buffer != NULL)
+        ReleaseCapturedUnicodeString(&CapturedObjectName, UserMode);
+
+    if (CapturedObjectTypeName.Buffer != NULL)
+        ReleaseCapturedUnicodeString(&CapturedObjectTypeName, UserMode);
+
+    if (CapturedSubsystemName.Buffer != NULL)
+        ReleaseCapturedUnicodeString(&CapturedSubsystemName, UserMode);
+
+    if (CapturedSecurityDescriptor != NULL)
+        SeReleaseSecurityDescriptor(CapturedSecurityDescriptor, UserMode, FALSE);
+
+    if (ClientToken != NULL)
+    {
+        ObDereferenceObject(ClientToken);
+        SubjectContext.ClientToken = SubjectContextToken;
+    }
+
+    if (AllocatedResultLists)
+        ExFreePoolWithTag(SafeGrantedAccessList, TAG_SEPA);
+
     /* Release the security subject context */
     SeReleaseSubjectContext(&SubjectContext);
 
@@ -620,6 +941,9 @@ NtPrivilegedServiceAuditAlarm(
     PreviousMode = ExGetPreviousMode();
     ASSERT(PreviousMode != KernelMode);
 
+    CapturedSubsystemName.Buffer = NULL;
+    CapturedServiceName.Buffer = NULL;
+
     /* Reference the client token */
     Status = ObReferenceObjectByHandle(ClientToken,
                                        TOKEN_QUERY,
@@ -724,8 +1048,8 @@ NtPrivilegedServiceAuditAlarm(
 
     /* Call the internal function */
     SepAdtPrivilegedServiceAuditAlarm(&SubjectContext,
-                                      &CapturedSubsystemName,
-                                      &CapturedServiceName,
+                                      SubsystemName ? &CapturedSubsystemName : NULL,
+                                      ServiceName ? &CapturedServiceName : NULL,
                                       Token,
                                       SubjectContext.PrimaryToken,
                                       CapturedPrivileges,
@@ -738,9 +1062,9 @@ NtPrivilegedServiceAuditAlarm(
 
 Cleanup:
     /* Cleanup resources */
-    if (SubsystemName != NULL)
+    if (CapturedSubsystemName.Buffer != NULL)
         ReleaseCapturedUnicodeString(&CapturedSubsystemName, PreviousMode);
-    if (ServiceName != NULL)
+    if (CapturedServiceName.Buffer != NULL)
         ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
     if (CapturedPrivileges != NULL)
         ExFreePoolWithTag(CapturedPrivileges, 0);