[STORPORT] Fix x64 build
[reactos.git] / ntoskrnl / se / audit.c
index 608ce41..c10e3bf 100644 (file)
@@ -16,6 +16,8 @@
 
 #define SEP_PRIVILEGE_SET_MAX_COUNT 60
 
+UNICODE_STRING SeSubsystemName = RTL_CONSTANT_STRING(L"Security");
+
 /* PRIVATE FUNCTIONS***********************************************************/
 
 BOOLEAN
@@ -202,9 +204,165 @@ SepAdtPrivilegedServiceAuditAlarm(
     _In_ PTOKEN Token,
     _In_ PTOKEN PrimaryToken,
     _In_ PPRIVILEGE_SET Privileges,
-    _In_ BOOLEAN AccessGranted )
+    _In_ BOOLEAN AccessGranted)
+{
+    DPRINT("SepAdtPrivilegedServiceAuditAlarm is unimplemented\n");
+}
+
+VOID
+NTAPI
+SePrivilegedServiceAuditAlarm(
+    _In_opt_ PUNICODE_STRING ServiceName,
+    _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
+    _In_ PPRIVILEGE_SET PrivilegeSet,
+    _In_ BOOLEAN AccessGranted)
+{
+    PTOKEN EffectiveToken;
+    PSID UserSid;
+    PAGED_CODE();
+
+    /* Get the effective token */
+    if (SubjectContext->ClientToken != NULL)
+        EffectiveToken = SubjectContext->ClientToken;
+    else
+        EffectiveToken = SubjectContext->PrimaryToken;
+
+    /* Get the user SID */
+    UserSid = EffectiveToken->UserAndGroups->Sid;
+
+    /* Check if this is the local system SID */
+    if (RtlEqualSid(UserSid, SeLocalSystemSid))
+    {
+        /* Nothing to do */
+        return;
+    }
+
+    /* Check if this is the network service or local service SID */
+    if (RtlEqualSid(UserSid, SeExports->SeNetworkServiceSid) ||
+        RtlEqualSid(UserSid, SeExports->SeLocalServiceSid))
+    {
+        // FIXME: should continue for a certain set of privileges
+        return;
+    }
+
+    /* Call the worker function */
+    SepAdtPrivilegedServiceAuditAlarm(SubjectContext,
+                                      &SeSubsystemName,
+                                      ServiceName,
+                                      SubjectContext->ClientToken,
+                                      SubjectContext->PrimaryToken,
+                                      PrivilegeSet,
+                                      AccessGranted);
+
+}
+
+
+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;
+        _SEH2_YIELD(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;
+    }
+
+    *GenerateOnClose = FALSE;
+
+    return STATUS_SUCCESS;
 }
 
 _Must_inspect_result_
@@ -213,7 +371,7 @@ 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 +390,33 @@ SepAccessCheckAndAuditAlarm(
     SECURITY_SUBJECT_CONTEXT SubjectContext;
     ULONG ResultListLength;
     GENERIC_MAPPING LocalGenericMapping;
+    PTOKEN SubjectContextToken, ClientToken;
+    BOOLEAN AllocatedResultLists;
+    BOOLEAN HaveAuditPrivilege;
+    PSECURITY_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 +429,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 +443,8 @@ SepAccessCheckAndAuditAlarm(
         if (SubjectContext.ImpersonationLevel < SecurityIdentification)
         {
             Status = STATUS_BAD_IMPERSONATION_LEVEL;
+            DPRINT1("Invalid impersonation level 0x%lx\n",
+                    SubjectContext.ImpersonationLevel);
             goto Cleanup;
         }
     }
@@ -277,13 +457,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 +500,195 @@ SepAccessCheckAndAuditAlarm(
     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
         Status = _SEH2_GetExceptionCode();
-        goto Cleanup;
+        DPRINT1("Exception while probing parameters: 0x%lx\n", Status);
+        _SEH2_YIELD(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 = SeCheckAuditPrivilege(&SubjectContext, 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) */
+        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);
+    }
+    _SEH2_END;
 
 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);
 
@@ -487,6 +861,7 @@ NtCloseObjectAuditAlarm(
     PVOID HandleId,
     BOOLEAN GenerateOnClose)
 {
+    SECURITY_SUBJECT_CONTEXT SubjectContext;
     UNICODE_STRING CapturedSubsystemName;
     KPROCESSOR_MODE PreviousMode;
     BOOLEAN UseImpersonationToken;
@@ -508,11 +883,15 @@ NtCloseObjectAuditAlarm(
         return STATUS_SUCCESS;
     }
 
-    /* Validate privilege */
-    if (!SeSinglePrivilegeCheck(SeAuditPrivilege, PreviousMode))
+    /* Capture the security subject context */
+    SeCaptureSubjectContext(&SubjectContext);
+
+    /* Check for audit privilege */
+    if (!SeCheckAuditPrivilege(&SubjectContext, PreviousMode))
     {
         DPRINT1("Caller does not have SeAuditPrivilege\n");
-        return STATUS_PRIVILEGE_NOT_HELD;
+        Status = STATUS_PRIVILEGE_NOT_HELD;
+        goto Cleanup;
     }
 
     /* Probe and capture the subsystem name */
@@ -522,7 +901,7 @@ NtCloseObjectAuditAlarm(
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("Failed to capture subsystem name!\n");
-        return Status;
+        goto Cleanup;
     }
 
     /* Get the current thread and check if it's impersonating */
@@ -563,7 +942,14 @@ NtCloseObjectAuditAlarm(
         PsDereferencePrimaryToken(Token);
     }
 
-    return STATUS_SUCCESS;
+    Status = STATUS_SUCCESS;
+
+Cleanup:
+
+    /* Release the security subject context */
+    SeReleaseSubjectContext(&SubjectContext);
+
+    return Status;
 }
 
 
@@ -576,23 +962,267 @@ NtDeleteObjectAuditAlarm(IN PUNICODE_STRING SubsystemName,
     return STATUS_NOT_IMPLEMENTED;
 }
 
-
-NTSTATUS NTAPI
-NtOpenObjectAuditAlarm(IN PUNICODE_STRING SubsystemName,
-                       IN PVOID HandleId,
-                       IN PUNICODE_STRING ObjectTypeName,
-                       IN PUNICODE_STRING ObjectName,
-                       IN PSECURITY_DESCRIPTOR SecurityDescriptor,
-                       IN HANDLE ClientToken,
-                       IN ULONG DesiredAccess,
-                       IN ULONG GrantedAccess,
-                       IN PPRIVILEGE_SET Privileges,
-                       IN BOOLEAN ObjectCreation,
-                       IN BOOLEAN AccessGranted,
-                       OUT PBOOLEAN GenerateOnClose)
+VOID
+NTAPI
+SepOpenObjectAuditAlarm(
+    _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
+    _In_ PUNICODE_STRING SubsystemName,
+    _In_opt_ PVOID HandleId,
+    _In_ PUNICODE_STRING ObjectTypeName,
+    _In_ PUNICODE_STRING ObjectName,
+    _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+    _In_ PTOKEN ClientToken,
+    _In_ ACCESS_MASK DesiredAccess,
+    _In_ ACCESS_MASK GrantedAccess,
+    _In_opt_ PPRIVILEGE_SET Privileges,
+    _In_ BOOLEAN ObjectCreation,
+    _In_ BOOLEAN AccessGranted,
+    _Out_ PBOOLEAN GenerateOnClose)
 {
+    DBG_UNREFERENCED_PARAMETER(SubjectContext);
+    DBG_UNREFERENCED_PARAMETER(SubsystemName);
+    DBG_UNREFERENCED_PARAMETER(HandleId);
+    DBG_UNREFERENCED_PARAMETER(ObjectTypeName);
+    DBG_UNREFERENCED_PARAMETER(ObjectName);
+    DBG_UNREFERENCED_PARAMETER(SecurityDescriptor);
+    DBG_UNREFERENCED_PARAMETER(ClientToken);
+    DBG_UNREFERENCED_PARAMETER(DesiredAccess);
+    DBG_UNREFERENCED_PARAMETER(GrantedAccess);
+    DBG_UNREFERENCED_PARAMETER(Privileges);
+    DBG_UNREFERENCED_PARAMETER(ObjectCreation);
+    DBG_UNREFERENCED_PARAMETER(AccessGranted);
     UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    *GenerateOnClose = FALSE;
+}
+
+__kernel_entry
+NTSTATUS
+NTAPI
+NtOpenObjectAuditAlarm(
+    _In_ PUNICODE_STRING SubsystemName,
+    _In_opt_ PVOID HandleId,
+    _In_ PUNICODE_STRING ObjectTypeName,
+    _In_ PUNICODE_STRING ObjectName,
+    _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+    _In_ HANDLE ClientTokenHandle,
+    _In_ ACCESS_MASK DesiredAccess,
+    _In_ ACCESS_MASK GrantedAccess,
+    _In_opt_ PPRIVILEGE_SET PrivilegeSet,
+    _In_ BOOLEAN ObjectCreation,
+    _In_ BOOLEAN AccessGranted,
+    _Out_ PBOOLEAN GenerateOnClose)
+{
+    PTOKEN ClientToken;
+    PSECURITY_DESCRIPTOR CapturedSecurityDescriptor;
+    UNICODE_STRING CapturedSubsystemName, CapturedObjectTypeName, CapturedObjectName;
+    ULONG PrivilegeCount, PrivilegeSetSize;
+    volatile PPRIVILEGE_SET CapturedPrivilegeSet;
+    BOOLEAN LocalGenerateOnClose;
+    PVOID CapturedHandleId;
+    SECURITY_SUBJECT_CONTEXT SubjectContext;
+    NTSTATUS Status;
+    PAGED_CODE();
+
+    /* Only user mode is supported! */
+    ASSERT(ExGetPreviousMode() != KernelMode);
+
+    /* Start clean */
+    ClientToken = NULL;
+    CapturedSecurityDescriptor = NULL;
+    CapturedPrivilegeSet = NULL;
+    CapturedSubsystemName.Buffer = NULL;
+    CapturedObjectTypeName.Buffer = NULL;
+    CapturedObjectName.Buffer = 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);
+        return Status;
+    }
+
+    /* Capture the security subject context */
+    SeCaptureSubjectContext(&SubjectContext);
+
+    /* Validate the token's impersonation level */
+    if ((ClientToken->TokenType == TokenImpersonation) &&
+        (ClientToken->ImpersonationLevel < SecurityIdentification))
+    {
+        DPRINT1("Invalid impersonation level (%u)\n", ClientToken->ImpersonationLevel);
+        Status = STATUS_BAD_IMPERSONATION_LEVEL;
+        goto Cleanup;
+    }
+
+    /* Check for audit privilege */
+    if (!SeCheckAuditPrivilege(&SubjectContext, UserMode))
+    {
+        DPRINT1("Caller does not have SeAuditPrivilege\n");
+        Status = STATUS_PRIVILEGE_NOT_HELD;
+        goto Cleanup;
+    }
+
+    /* Check for NULL SecurityDescriptor */
+    if (SecurityDescriptor == NULL)
+    {
+        /* Nothing to do */
+        Status = STATUS_SUCCESS;
+        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;
+    }
+
+    _SEH2_TRY
+    {
+        /* Check if we have a privilege set */
+        if (PrivilegeSet != NULL)
+        {
+            /* Probe the basic privilege set structure */
+            ProbeForRead(PrivilegeSet, sizeof(PRIVILEGE_SET), sizeof(ULONG));
+
+            /* Validate privilege count */
+            PrivilegeCount = PrivilegeSet->PrivilegeCount;
+            if (PrivilegeCount > SEP_PRIVILEGE_SET_MAX_COUNT)
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                _SEH2_YIELD(goto Cleanup);
+            }
+
+            /* Calculate the size of the PrivilegeSet structure */
+            PrivilegeSetSize = FIELD_OFFSET(PRIVILEGE_SET, Privilege[PrivilegeCount]);
+
+            /* Probe the whole structure */
+            ProbeForRead(PrivilegeSet, PrivilegeSetSize, sizeof(ULONG));
+
+            /* Allocate a temp buffer */
+            CapturedPrivilegeSet = ExAllocatePoolWithTag(PagedPool,
+                                                         PrivilegeSetSize,
+                                                         TAG_PRIVILEGE_SET);
+            if (CapturedPrivilegeSet == NULL)
+            {
+                DPRINT1("Failed to allocate %u bytes\n", PrivilegeSetSize);
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                _SEH2_YIELD(goto Cleanup);
+            }
+
+            /* Copy the privileges */
+            RtlCopyMemory(CapturedPrivilegeSet, PrivilegeSet, PrivilegeSetSize);
+        }
+
+        if (HandleId != NULL)
+        {
+            ProbeForRead(HandleId, sizeof(PVOID), sizeof(PVOID));
+            CapturedHandleId = *(PVOID*)HandleId;
+        }
+
+        ProbeForWrite(GenerateOnClose, sizeof(BOOLEAN), sizeof(BOOLEAN));
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        Status = _SEH2_GetExceptionCode();
+        DPRINT1("Exception while probing parameters: 0x%lx\n", Status);
+        _SEH2_YIELD(goto Cleanup);
+    }
+    _SEH2_END;
+
+    /* 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;
+    }
+
+    /* Call the internal function */
+    SepOpenObjectAuditAlarm(&SubjectContext,
+                            &CapturedSubsystemName,
+                            CapturedHandleId,
+                            &CapturedObjectTypeName,
+                            &CapturedObjectName,
+                            CapturedSecurityDescriptor,
+                            ClientToken,
+                            DesiredAccess,
+                            GrantedAccess,
+                            CapturedPrivilegeSet,
+                            ObjectCreation,
+                            AccessGranted,
+                            &LocalGenerateOnClose);
+
+    Status = STATUS_SUCCESS;
+
+    /* Enter SEH to copy the data back to user mode */
+    _SEH2_TRY
+    {
+        *GenerateOnClose = LocalGenerateOnClose;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        Status = _SEH2_GetExceptionCode();
+        DPRINT1("Exception while copying back data: 0x%lx\n", Status);
+    }
+    _SEH2_END;
+
+Cleanup:
+
+    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 (CapturedPrivilegeSet != NULL)
+        ExFreePoolWithTag(CapturedPrivilegeSet, TAG_PRIVILEGE_SET);
+
+    /* Release the security subject context */
+    SeReleaseSubjectContext(&SubjectContext);
+
+    ObDereferenceObject(ClientToken);
+
+    return Status;
 }
 
 
@@ -602,12 +1232,12 @@ NTAPI
 NtPrivilegedServiceAuditAlarm(
     _In_opt_ PUNICODE_STRING SubsystemName,
     _In_opt_ PUNICODE_STRING ServiceName,
-    _In_ HANDLE ClientToken,
+    _In_ HANDLE ClientTokenHandle,
     _In_ PPRIVILEGE_SET Privileges,
     _In_ BOOLEAN AccessGranted )
 {
     KPROCESSOR_MODE PreviousMode;
-    PTOKEN Token;
+    PTOKEN ClientToken;
     volatile PPRIVILEGE_SET CapturedPrivileges = NULL;
     UNICODE_STRING CapturedSubsystemName;
     UNICODE_STRING CapturedServiceName;
@@ -620,12 +1250,15 @@ NtPrivilegedServiceAuditAlarm(
     PreviousMode = ExGetPreviousMode();
     ASSERT(PreviousMode != KernelMode);
 
+    CapturedSubsystemName.Buffer = NULL;
+    CapturedServiceName.Buffer = NULL;
+
     /* Reference the client token */
-    Status = ObReferenceObjectByHandle(ClientToken,
+    Status = ObReferenceObjectByHandle(ClientTokenHandle,
                                        TOKEN_QUERY,
                                        SeTokenObjectType,
                                        PreviousMode,
-                                       (PVOID*)&Token,
+                                       (PVOID*)&ClientToken,
                                        NULL);
     if (!NT_SUCCESS(Status))
     {
@@ -634,20 +1267,23 @@ NtPrivilegedServiceAuditAlarm(
     }
 
     /* Validate the token's impersonation level */
-    if ((Token->TokenType == TokenImpersonation) &&
-        (Token->ImpersonationLevel < SecurityIdentification))
+    if ((ClientToken->TokenType == TokenImpersonation) &&
+        (ClientToken->ImpersonationLevel < SecurityIdentification))
     {
-        DPRINT1("Invalid impersonation level (%u)\n", Token->ImpersonationLevel);
-        ObfDereferenceObject(Token);
+        DPRINT1("Invalid impersonation level (%u)\n", ClientToken->ImpersonationLevel);
+        ObDereferenceObject(ClientToken);
         return STATUS_BAD_IMPERSONATION_LEVEL;
     }
 
-    /* Validate privilege */
-    if (!SeSinglePrivilegeCheck(SeAuditPrivilege, PreviousMode))
+    /* Capture the security subject context */
+    SeCaptureSubjectContext(&SubjectContext);
+
+    /* Check for audit privilege */
+    if (!SeCheckAuditPrivilege(&SubjectContext, PreviousMode))
     {
         DPRINT1("Caller does not have SeAuditPrivilege\n");
-        ObfDereferenceObject(Token);
-        return STATUS_PRIVILEGE_NOT_HELD;
+        Status = STATUS_PRIVILEGE_NOT_HELD;
+        goto Cleanup;
     }
 
     /* Do we have a subsystem name? */
@@ -688,7 +1324,7 @@ NtPrivilegedServiceAuditAlarm(
         if (PrivilegeCount > SEP_PRIVILEGE_SET_MAX_COUNT)
         {
             Status = STATUS_INVALID_PARAMETER;
-            goto Cleanup;
+            _SEH2_YIELD(goto Cleanup);
         }
 
         /* Calculate the size of the Privileges structure */
@@ -700,12 +1336,12 @@ NtPrivilegedServiceAuditAlarm(
         /* Allocate a temp buffer */
         CapturedPrivileges = ExAllocatePoolWithTag(PagedPool,
                                                    PrivilegesSize,
-                                                   'rPeS');
+                                                   TAG_PRIVILEGE_SET);
         if (CapturedPrivileges == NULL)
         {
             DPRINT1("Failed to allocate %u bytes\n", PrivilegesSize);
             Status = STATUS_INSUFFICIENT_RESOURCES;
-            goto Cleanup;
+            _SEH2_YIELD(goto Cleanup);
         }
 
         /* Copy the privileges */
@@ -715,36 +1351,36 @@ NtPrivilegedServiceAuditAlarm(
     {
         Status = _SEH2_GetExceptionCode();
         DPRINT1("Got exception 0x%lx\n", Status);
-        goto Cleanup;
+        _SEH2_YIELD(goto Cleanup);
     }
     _SEH2_END;
 
-    /* Capture the security subject context */
-    SeCaptureSubjectContext(&SubjectContext);
-
     /* Call the internal function */
     SepAdtPrivilegedServiceAuditAlarm(&SubjectContext,
-                                      &CapturedSubsystemName,
-                                      &CapturedServiceName,
-                                      Token,
+                                      SubsystemName ? &CapturedSubsystemName : NULL,
+                                      ServiceName ? &CapturedServiceName : NULL,
+                                      ClientToken,
                                       SubjectContext.PrimaryToken,
                                       CapturedPrivileges,
                                       AccessGranted);
 
-    /* Release the security subject context */
-    SeReleaseSubjectContext(&SubjectContext);
-
     Status = STATUS_SUCCESS;
 
 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);
-    ObDereferenceObject(Token);
+        ExFreePoolWithTag(CapturedPrivileges, TAG_PRIVILEGE_SET);
+
+    /* Release the security subject context */
+    SeReleaseSubjectContext(&SubjectContext);
+
+    ObDereferenceObject(ClientToken);
 
     return Status;
 }