Sync with trunk r63935.
[reactos.git] / ntoskrnl / se / audit.c
index 92b87fa..5f8177e 100644 (file)
@@ -5,6 +5,7 @@
  * PURPOSE:         Audit functions
  *
  * PROGRAMMERS:     Eric Kohl
+ *                  Timo Kreuzer (timo.kreuzer@reactos.org)
  */
 
 /* INCLUDES *******************************************************************/
 #define NDEBUG
 #include <debug.h>
 
+#define SEP_PRIVILEGE_SET_MAX_COUNT 60
+
+UNICODE_STRING SeSubsystemName = RTL_CONSTANT_STRING(L"Security");
+
 /* PRIVATE FUNCTIONS***********************************************************/
 
 BOOLEAN
@@ -180,6 +185,517 @@ 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)
+{
+    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;
+        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 = SeCheckAuditPrivilege(&SubjectContext, 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 +856,100 @@ 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;
-}
+    SECURITY_SUBJECT_CONTEXT SubjectContext;
+    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;
+    }
+
+    /* Capture the security subject context */
+    SeCaptureSubjectContext(&SubjectContext);
+
+    /* Check for audit privilege */
+    if (!SeCheckAuditPrivilege(&SubjectContext, PreviousMode))
+    {
+        DPRINT1("Caller does not have SeAuditPrivilege\n");
+        Status = STATUS_PRIVILEGE_NOT_HELD;
+        goto Cleanup;
+    }
+
+    /* Probe and capture the subsystem name */
+    Status = ProbeAndCaptureUnicodeString(&CapturedSubsystemName,
+                                          PreviousMode,
+                                          SubsystemName);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to capture subsystem name!\n");
+        goto Cleanup;
+    }
+
+    /* 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);
+    }
+
+    Status = STATUS_SUCCESS;
+
+Cleanup:
+
+    /* Release the security subject context */
+    SeReleaseSubjectContext(&SubjectContext);
+
+    return Status;
 }
 
 
@@ -376,35 +962,427 @@ 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);
 
-NTSTATUS NTAPI
-NtPrivilegedServiceAuditAlarm(IN PUNICODE_STRING SubsystemName,
-                              IN PUNICODE_STRING ServiceName,
-                              IN HANDLE ClientToken,
-                              IN PPRIVILEGE_SET Privileges,
-                              IN BOOLEAN AccessGranted)
+    /* 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;
+                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,
+                                                         'rPeS');
+            if (CapturedPrivilegeSet == NULL)
+            {
+                DPRINT1("Failed to allocate %u bytes\n", PrivilegeSetSize);
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                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);
+        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, 'rPeS');
+
+    /* Release the security subject context */
+    SeReleaseSubjectContext(&SubjectContext);
+
+    ObDereferenceObject(ClientToken);
+
+    return Status;
+}
+
+
+__kernel_entry
+NTSTATUS
+NTAPI
+NtPrivilegedServiceAuditAlarm(
+    _In_opt_ PUNICODE_STRING SubsystemName,
+    _In_opt_ PUNICODE_STRING ServiceName,
+    _In_ HANDLE ClientTokenHandle,
+    _In_ PPRIVILEGE_SET Privileges,
+    _In_ BOOLEAN AccessGranted )
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    KPROCESSOR_MODE PreviousMode;
+    PTOKEN ClientToken;
+    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(ClientTokenHandle,
+                                       TOKEN_QUERY,
+                                       SeTokenObjectType,
+                                       PreviousMode,
+                                       (PVOID*)&ClientToken,
+                                       NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to reference client token: 0x%lx\n", Status);
+        return Status;
+    }
+
+    /* Validate the token's impersonation level */
+    if ((ClientToken->TokenType == TokenImpersonation) &&
+        (ClientToken->ImpersonationLevel < SecurityIdentification))
+    {
+        DPRINT1("Invalid impersonation level (%u)\n", ClientToken->ImpersonationLevel);
+        ObDereferenceObject(ClientToken);
+        return STATUS_BAD_IMPERSONATION_LEVEL;
+    }
+
+    /* Capture the security subject context */
+    SeCaptureSubjectContext(&SubjectContext);
+
+    /* Check for audit privilege */
+    if (!SeCheckAuditPrivilege(&SubjectContext, PreviousMode))
+    {
+        DPRINT1("Caller does not have SeAuditPrivilege\n");
+        Status = STATUS_PRIVILEGE_NOT_HELD;
+        goto Cleanup;
+    }
+
+    /* 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;
+
+    /* Call the internal function */
+    SepAdtPrivilegedServiceAuditAlarm(&SubjectContext,
+                                      SubsystemName ? &CapturedSubsystemName : NULL,
+                                      ServiceName ? &CapturedServiceName : NULL,
+                                      ClientToken,
+                                      SubjectContext.PrimaryToken,
+                                      CapturedPrivileges,
+                                      AccessGranted);
+
+    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, 'rPeS');
+
+    /* Release the security subject context */
+    SeReleaseSubjectContext(&SubjectContext);
+
+    ObDereferenceObject(ClientToken);
+
+    return Status;
 }
 
 
@@ -420,4 +1398,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 */