Fix GCC build
[reactos.git] / reactos / ntoskrnl / se / audit.c
index 92b87fa..d198cc3 100644 (file)
@@ -5,6 +5,7 @@
  * PURPOSE:         Audit functions
  *
  * PROGRAMMERS:     Eric Kohl
+ *                  Timo Kreuzer (timo.kreuzer@reactos.org)
  */
 
 /* INCLUDES *******************************************************************/
@@ -13,6 +14,8 @@
 #define NDEBUG
 #include <debug.h>
 
+#define SEP_PRIVILEGE_SET_MAX_COUNT 60
+
 /* PRIVATE FUNCTIONS***********************************************************/
 
 BOOLEAN
@@ -180,6 +183,469 @@ SeLocateProcessImageName(IN PEPROCESS Process,
     return Status;
 }
 
+VOID
+NTAPI
+SepAdtCloseObjectAuditAlarm(
+    PUNICODE_STRING SubsystemName,
+    PVOID HandleId,
+    PSID Sid)
+{
+    UNIMPLEMENTED;
+}
+
+VOID
+NTAPI
+SepAdtPrivilegedServiceAuditAlarm(
+    PSECURITY_SUBJECT_CONTEXT SubjectContext,
+    _In_opt_ PUNICODE_STRING SubsystemName,
+    _In_opt_ PUNICODE_STRING ServiceName,
+    _In_ PTOKEN Token,
+    _In_ PTOKEN PrimaryToken,
+    _In_ PPRIVILEGE_SET Privileges,
+    _In_ BOOLEAN AccessGranted )
+{
+    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;
+    }
+
+    *GenerateOnClose = FALSE;
+
+    return STATUS_SUCCESS;
+}
+
+_Must_inspect_result_
+NTSTATUS
+NTAPI
+SepAccessCheckAndAuditAlarm(
+    _In_ PUNICODE_STRING SubsystemName,
+    _In_opt_ PVOID HandleId,
+    _In_ PHANDLE ClientTokenHandle,
+    _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_ ULONG Flags,
+    _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)
+{
+    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();
+
+    /* 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))
+    {
+        DPRINT1("Invalid audit type: %u\n", AuditType);
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Capture the security subject context */
+    SeCaptureSubjectContext(&SubjectContext);
+
+    /* Did the caller pass a token handle? */
+    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;
+        }
+
+        /* Check if we have a valid impersonation level */
+        if (SubjectContext.ImpersonationLevel < SecurityIdentification)
+        {
+            Status = STATUS_BAD_IMPERSONATION_LEVEL;
+            DPRINT1("Invalid impersonation level 0x%lx\n",
+                    SubjectContext.ImpersonationLevel);
+            goto Cleanup;
+        }
+    }
+
+    /* Are we using a result list? */
+    if (UseResultList)
+    {
+        /* The list length equals the object type list length */
+        ResultListLength = ObjectTypeListLength;
+        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
+    {
+        /* Probe output buffers */
+        ProbeForWrite(AccessStatusList,
+                      ResultListLength * sizeof(*AccessStatusList),
+                      sizeof(*AccessStatusList));
+        ProbeForWrite(GrantedAccessList,
+                      ResultListLength * sizeof(*GrantedAccessList),
+                      sizeof(*GrantedAccessList));
+
+        /* Probe generic mapping and make a local copy */
+        ProbeForRead(GenericMapping, sizeof(*GenericMapping), sizeof(ULONG));
+        LocalGenericMapping = * GenericMapping;
+    }
+    _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;
+    }
+
+    /* 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;
+    }
+
+    /* 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);
+    }
+    _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);
+
+    return Status;
+}
+
+
 /* PUBLIC FUNCTIONS ***********************************************************/
 
 /*
@@ -340,30 +806,88 @@ SePrivilegeObjectAuditAlarm(IN HANDLE Handle,
 
 NTSTATUS
 NTAPI
-NtAccessCheckAndAuditAlarm(IN PUNICODE_STRING SubsystemName,
-                           IN HANDLE HandleId,
-                           IN PUNICODE_STRING ObjectTypeName,
-                           IN PUNICODE_STRING ObjectName,
-                           IN PSECURITY_DESCRIPTOR SecurityDescriptor,
-                           IN ACCESS_MASK DesiredAccess,
-                           IN PGENERIC_MAPPING GenericMapping,
-                           IN BOOLEAN ObjectCreation,
-                           OUT PACCESS_MASK GrantedAccess,
-                           OUT PNTSTATUS AccessStatus,
-                           OUT PBOOLEAN GenerateOnClose)
+NtCloseObjectAuditAlarm(
+    PUNICODE_STRING SubsystemName,
+    PVOID HandleId,
+    BOOLEAN GenerateOnClose)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-}
+    UNICODE_STRING CapturedSubsystemName;
+    KPROCESSOR_MODE PreviousMode;
+    BOOLEAN UseImpersonationToken;
+    PETHREAD CurrentThread;
+    BOOLEAN CopyOnOpen, EffectiveOnly;
+    SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
+    NTSTATUS Status;
+    PTOKEN Token;
+    PAGED_CODE();
 
+    /* Get the previous mode (only user mode is supported!) */
+    PreviousMode = ExGetPreviousMode();
+    ASSERT(PreviousMode != KernelMode);
 
-NTSTATUS NTAPI
-NtCloseObjectAuditAlarm(IN PUNICODE_STRING SubsystemName,
-                        IN PVOID HandleId,
-                        IN BOOLEAN GenerateOnClose)
-{
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    /* Do we even need to do anything? */
+    if (!GenerateOnClose)
+    {
+        /* Nothing to do, return success */
+        return STATUS_SUCCESS;
+    }
+
+    /* Validate privilege */
+    if (!SeSinglePrivilegeCheck(SeAuditPrivilege, PreviousMode))
+    {
+        DPRINT1("Caller does not have SeAuditPrivilege\n");
+        return STATUS_PRIVILEGE_NOT_HELD;
+    }
+
+    /* Probe and capture the subsystem name */
+    Status = ProbeAndCaptureUnicodeString(&CapturedSubsystemName,
+                                          PreviousMode,
+                                          SubsystemName);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to capture subsystem name!\n");
+        return Status;
+    }
+
+    /* Get the current thread and check if it's impersonating */
+    CurrentThread = PsGetCurrentThread();
+    if (PsIsThreadImpersonating(CurrentThread))
+    {
+        /* Get the impersonation token */
+        Token = PsReferenceImpersonationToken(CurrentThread,
+                                              &CopyOnOpen,
+                                              &EffectiveOnly,
+                                              &ImpersonationLevel);
+        UseImpersonationToken = TRUE;
+    }
+    else
+    {
+        /* Get the primary token */
+        Token = PsReferencePrimaryToken(PsGetCurrentProcess());
+        UseImpersonationToken = FALSE;
+    }
+
+    /* Call the internal function */
+    SepAdtCloseObjectAuditAlarm(&CapturedSubsystemName,
+                                HandleId,
+                                Token->UserAndGroups->Sid);
+
+    /* Release the captured subsystem name */
+    ReleaseCapturedUnicodeString(&CapturedSubsystemName, PreviousMode);
+
+    /* Check what token we used */
+    if (UseImpersonationToken)
+    {
+        /* Release impersonation token */
+        PsDereferenceImpersonationToken(Token);
+    }
+    else
+    {
+        /* Release primary token */
+        PsDereferencePrimaryToken(Token);
+    }
+
+    return STATUS_SUCCESS;
 }
 
 
@@ -396,15 +920,160 @@ NtOpenObjectAuditAlarm(IN PUNICODE_STRING SubsystemName,
 }
 
 
-NTSTATUS NTAPI
-NtPrivilegedServiceAuditAlarm(IN PUNICODE_STRING SubsystemName,
-                              IN PUNICODE_STRING ServiceName,
-                              IN HANDLE ClientToken,
-                              IN PPRIVILEGE_SET Privileges,
-                              IN BOOLEAN AccessGranted)
+__kernel_entry
+NTSTATUS
+NTAPI
+NtPrivilegedServiceAuditAlarm(
+    _In_opt_ PUNICODE_STRING SubsystemName,
+    _In_opt_ PUNICODE_STRING ServiceName,
+    _In_ HANDLE ClientToken,
+    _In_ PPRIVILEGE_SET Privileges,
+    _In_ BOOLEAN AccessGranted )
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    KPROCESSOR_MODE PreviousMode;
+    PTOKEN Token;
+    volatile PPRIVILEGE_SET CapturedPrivileges = NULL;
+    UNICODE_STRING CapturedSubsystemName;
+    UNICODE_STRING CapturedServiceName;
+    ULONG PrivilegeCount, PrivilegesSize;
+    SECURITY_SUBJECT_CONTEXT SubjectContext;
+    NTSTATUS Status;
+    PAGED_CODE();
+
+    /* Get the previous mode (only user mode is supported!) */
+    PreviousMode = ExGetPreviousMode();
+    ASSERT(PreviousMode != KernelMode);
+
+    CapturedSubsystemName.Buffer = NULL;
+    CapturedServiceName.Buffer = NULL;
+
+    /* Reference the client token */
+    Status = ObReferenceObjectByHandle(ClientToken,
+                                       TOKEN_QUERY,
+                                       SeTokenObjectType,
+                                       PreviousMode,
+                                       (PVOID*)&Token,
+                                       NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to reference client token: 0x%lx\n", Status);
+        return Status;
+    }
+
+    /* Validate the token's impersonation level */
+    if ((Token->TokenType == TokenImpersonation) &&
+        (Token->ImpersonationLevel < SecurityIdentification))
+    {
+        DPRINT1("Invalid impersonation level (%u)\n", Token->ImpersonationLevel);
+        ObfDereferenceObject(Token);
+        return STATUS_BAD_IMPERSONATION_LEVEL;
+    }
+
+    /* Validate privilege */
+    if (!SeSinglePrivilegeCheck(SeAuditPrivilege, PreviousMode))
+    {
+        DPRINT1("Caller does not have SeAuditPrivilege\n");
+        ObfDereferenceObject(Token);
+        return STATUS_PRIVILEGE_NOT_HELD;
+    }
+
+    /* Do we have a subsystem name? */
+    if (SubsystemName != NULL)
+    {
+        /* Probe and capture the subsystem name */
+        Status = ProbeAndCaptureUnicodeString(&CapturedSubsystemName,
+                                              PreviousMode,
+                                              SubsystemName);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Failed to capture subsystem name!\n");
+            goto Cleanup;
+        }
+    }
+
+    /* Do we have a service name? */
+    if (ServiceName != NULL)
+    {
+        /* Probe and capture the service name */
+        Status = ProbeAndCaptureUnicodeString(&CapturedServiceName,
+                                              PreviousMode,
+                                              ServiceName);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Failed to capture service name!\n");
+            goto Cleanup;
+        }
+    }
+
+    _SEH2_TRY
+    {
+        /* Probe the basic privilege set structure */
+        ProbeForRead(Privileges, sizeof(PRIVILEGE_SET), sizeof(ULONG));
+
+        /* Validate privilege count */
+        PrivilegeCount = Privileges->PrivilegeCount;
+        if (PrivilegeCount > SEP_PRIVILEGE_SET_MAX_COUNT)
+        {
+            Status = STATUS_INVALID_PARAMETER;
+            goto Cleanup;
+        }
+
+        /* Calculate the size of the Privileges structure */
+        PrivilegesSize = FIELD_OFFSET(PRIVILEGE_SET, Privilege[PrivilegeCount]);
+
+        /* Probe the whole structure */
+        ProbeForRead(Privileges, PrivilegesSize, sizeof(ULONG));
+
+        /* Allocate a temp buffer */
+        CapturedPrivileges = ExAllocatePoolWithTag(PagedPool,
+                                                   PrivilegesSize,
+                                                   'rPeS');
+        if (CapturedPrivileges == NULL)
+        {
+            DPRINT1("Failed to allocate %u bytes\n", PrivilegesSize);
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            goto Cleanup;
+        }
+
+        /* Copy the privileges */
+        RtlCopyMemory(CapturedPrivileges, Privileges, PrivilegesSize);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        Status = _SEH2_GetExceptionCode();
+        DPRINT1("Got exception 0x%lx\n", Status);
+        goto Cleanup;
+    }
+    _SEH2_END;
+
+    /* Capture the security subject context */
+    SeCaptureSubjectContext(&SubjectContext);
+
+    /* Call the internal function */
+    SepAdtPrivilegedServiceAuditAlarm(&SubjectContext,
+                                      SubsystemName ? &CapturedSubsystemName : NULL,
+                                      ServiceName ? &CapturedServiceName : NULL,
+                                      Token,
+                                      SubjectContext.PrimaryToken,
+                                      CapturedPrivileges,
+                                      AccessGranted);
+
+    /* Release the security subject context */
+    SeReleaseSubjectContext(&SubjectContext);
+
+    Status = STATUS_SUCCESS;
+
+Cleanup:
+    /* Cleanup resources */
+    if (CapturedSubsystemName.Buffer != NULL)
+        ReleaseCapturedUnicodeString(&CapturedSubsystemName, PreviousMode);
+    if (CapturedServiceName.Buffer != NULL)
+        ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
+    if (CapturedPrivileges != NULL)
+        ExFreePoolWithTag(CapturedPrivileges, 0);
+    ObDereferenceObject(Token);
+
+    return Status;
 }
 
 
@@ -420,4 +1089,171 @@ NtPrivilegeObjectAuditAlarm(IN PUNICODE_STRING SubsystemName,
     return STATUS_NOT_IMPLEMENTED;
 }
 
+
+_Must_inspect_result_
+__kernel_entry
+NTSTATUS
+NTAPI
+NtAccessCheckAndAuditAlarm(
+    _In_ PUNICODE_STRING SubsystemName,
+    _In_opt_ PVOID HandleId,
+    _In_ PUNICODE_STRING ObjectTypeName,
+    _In_ PUNICODE_STRING ObjectName,
+    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+    _In_ ACCESS_MASK DesiredAccess,
+    _In_ PGENERIC_MAPPING GenericMapping,
+    _In_ BOOLEAN ObjectCreation,
+    _Out_ PACCESS_MASK GrantedAccess,
+    _Out_ PNTSTATUS AccessStatus,
+    _Out_ PBOOLEAN GenerateOnClose)
+{
+    /* Call the internal function */
+    return SepAccessCheckAndAuditAlarm(SubsystemName,
+                                       HandleId,
+                                       NULL,
+                                       ObjectTypeName,
+                                       ObjectName,
+                                       SecurityDescriptor,
+                                       NULL,
+                                       DesiredAccess,
+                                       AuditEventObjectAccess,
+                                       0,
+                                       NULL,
+                                       0,
+                                       GenericMapping,
+                                       GrantedAccess,
+                                       AccessStatus,
+                                       GenerateOnClose,
+                                       FALSE);
+}
+
+_Must_inspect_result_
+__kernel_entry
+NTSTATUS
+NTAPI
+NtAccessCheckByTypeAndAuditAlarm(
+    _In_ PUNICODE_STRING SubsystemName,
+    _In_opt_ PVOID HandleId,
+    _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_ ULONG Flags,
+    _In_reads_opt_(ObjectTypeLength) POBJECT_TYPE_LIST ObjectTypeList,
+    _In_ ULONG ObjectTypeLength,
+    _In_ PGENERIC_MAPPING GenericMapping,
+    _In_ BOOLEAN ObjectCreation,
+    _Out_ PACCESS_MASK GrantedAccess,
+    _Out_ PNTSTATUS AccessStatus,
+    _Out_ PBOOLEAN GenerateOnClose)
+{
+    /* Call the internal function */
+    return SepAccessCheckAndAuditAlarm(SubsystemName,
+                                       HandleId,
+                                       NULL,
+                                       ObjectTypeName,
+                                       ObjectName,
+                                       SecurityDescriptor,
+                                       PrincipalSelfSid,
+                                       DesiredAccess,
+                                       AuditType,
+                                       Flags,
+                                       ObjectTypeList,
+                                       ObjectTypeLength,
+                                       GenericMapping,
+                                       GrantedAccess,
+                                       AccessStatus,
+                                       GenerateOnClose,
+                                       FALSE);
+}
+
+_Must_inspect_result_
+__kernel_entry
+NTSTATUS
+NTAPI
+NtAccessCheckByTypeResultListAndAuditAlarm(
+    _In_ PUNICODE_STRING SubsystemName,
+    _In_opt_ PVOID HandleId,
+    _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_ ULONG Flags,
+    _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
+    _In_ ULONG ObjectTypeListLength,
+    _In_ PGENERIC_MAPPING GenericMapping,
+    _In_ BOOLEAN ObjectCreation,
+    _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccessList,
+    _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatusList,
+    _Out_ PBOOLEAN GenerateOnClose)
+{
+    /* Call the internal function */
+    return SepAccessCheckAndAuditAlarm(SubsystemName,
+                                       HandleId,
+                                       NULL,
+                                       ObjectTypeName,
+                                       ObjectName,
+                                       SecurityDescriptor,
+                                       PrincipalSelfSid,
+                                       DesiredAccess,
+                                       AuditType,
+                                       Flags,
+                                       ObjectTypeList,
+                                       ObjectTypeListLength,
+                                       GenericMapping,
+                                       GrantedAccessList,
+                                       AccessStatusList,
+                                       GenerateOnClose,
+                                       TRUE);
+}
+
+_Must_inspect_result_
+__kernel_entry
+NTSTATUS
+NTAPI
+NtAccessCheckByTypeResultListAndAuditAlarmByHandle(
+    _In_ PUNICODE_STRING SubsystemName,
+    _In_opt_ PVOID HandleId,
+    _In_ HANDLE ClientToken,
+    _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_ ULONG Flags,
+    _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
+    _In_ ULONG ObjectTypeListLength,
+    _In_ PGENERIC_MAPPING GenericMapping,
+    _In_ BOOLEAN ObjectCreation,
+    _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccessList,
+    _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatusList,
+    _Out_ PBOOLEAN GenerateOnClose)
+{
+    UNREFERENCED_PARAMETER(ObjectCreation);
+
+    /* Call the internal function */
+    return SepAccessCheckAndAuditAlarm(SubsystemName,
+                                       HandleId,
+                                       &ClientToken,
+                                       ObjectTypeName,
+                                       ObjectName,
+                                       SecurityDescriptor,
+                                       PrincipalSelfSid,
+                                       DesiredAccess,
+                                       AuditType,
+                                       Flags,
+                                       ObjectTypeList,
+                                       ObjectTypeListLength,
+                                       GenericMapping,
+                                       GrantedAccessList,
+                                       AccessStatusList,
+                                       GenerateOnClose,
+                                       TRUE);
+}
+
 /* EOF */