xref: /reactos/ntoskrnl/se/audit.c (revision 5654ce7b)
1 /*
2  * PROJECT:     ReactOS Kernel
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Security auditing functions
5  * COPYRIGHT:   Copyright Eric Kohl
6  *              Copyright Timo Kreuzer <timo.kreuzer@reactos.org>
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 #define SEP_PRIVILEGE_SET_MAX_COUNT 60
16 
17 UNICODE_STRING SeSubsystemName = RTL_CONSTANT_STRING(L"Security");
18 
19 /* PRIVATE FUNCTIONS ***********************************************************/
20 
21 /**
22  * @unimplemented
23  * @brief
24  * Peforms a detailed security auditing with an access token.
25  *
26  * @param[in] Token
27  * A valid token object.
28  *
29  * @return
30  * To be added...
31  */
32 BOOLEAN
33 NTAPI
SeDetailedAuditingWithToken(_In_ PTOKEN Token)34 SeDetailedAuditingWithToken(
35     _In_ PTOKEN Token)
36 {
37     /* FIXME */
38     return FALSE;
39 }
40 
41 /**
42  * @unimplemented
43  * @brief
44  * Peforms a security auditing against a process that is about to
45  * be created.
46  *
47  * @param[in] Process
48  * An object that points to a process which is in process of
49  * creation.
50  *
51  * @return
52  * Nothing.
53  */
54 VOID
55 NTAPI
SeAuditProcessCreate(_In_ PEPROCESS Process)56 SeAuditProcessCreate(
57     _In_ PEPROCESS Process)
58 {
59     /* FIXME */
60 }
61 
62 /**
63  * @unimplemented
64  * @brief
65  * Peforms a security auditing against a process that is about to
66  * be terminated.
67  *
68  * @param[in] Process
69  * An object that points to a process which is in process of
70  * termination.
71  *
72  * @return
73  * Nothing.
74  */
75 VOID
76 NTAPI
SeAuditProcessExit(_In_ PEPROCESS Process)77 SeAuditProcessExit(
78     _In_ PEPROCESS Process)
79 {
80     /* FIXME */
81 }
82 
83 /**
84  * @brief
85  * Initializes a process audit name and returns it to the caller.
86  *
87  * @param[in] FileObject
88  * File object that points to a name to be queried.
89  *
90  * @param[in] DoAudit
91  * If set to TRUE, the function will perform various security
92  * auditing onto the audit name.
93  *
94  * @param[out] AuditInfo
95  * The returned audit info data.
96  *
97  * @return
98  * Returns STATUS_SUCCESS if process audit name initialization
99  * has completed successfully. STATUS_NO_MEMORY is returned if
100  * pool allocation for object name info has failed. A failure
101  * NTSTATUS code is returned otherwise.
102  */
103 NTSTATUS
104 NTAPI
SeInitializeProcessAuditName(_In_ PFILE_OBJECT FileObject,_In_ BOOLEAN DoAudit,_Out_ POBJECT_NAME_INFORMATION * AuditInfo)105 SeInitializeProcessAuditName(
106     _In_ PFILE_OBJECT FileObject,
107     _In_ BOOLEAN DoAudit,
108     _Out_ POBJECT_NAME_INFORMATION *AuditInfo)
109 {
110     OBJECT_NAME_INFORMATION LocalNameInfo;
111     POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
112     ULONG ReturnLength = 8;
113     NTSTATUS Status;
114 
115     PAGED_CODE();
116     ASSERT(AuditInfo);
117 
118     /* Check if we should do auditing */
119     if (DoAudit)
120     {
121         /* FIXME: TODO */
122     }
123 
124     /* Now query the name */
125     Status = ObQueryNameString(FileObject,
126                                &LocalNameInfo,
127                                sizeof(LocalNameInfo),
128                                &ReturnLength);
129     if (((Status == STATUS_BUFFER_OVERFLOW) ||
130          (Status == STATUS_BUFFER_TOO_SMALL) ||
131          (Status == STATUS_INFO_LENGTH_MISMATCH)) &&
132         (ReturnLength != sizeof(LocalNameInfo)))
133     {
134         /* Allocate required size */
135         ObjectNameInfo = ExAllocatePoolWithTag(NonPagedPool,
136                                                ReturnLength,
137                                                TAG_SEPA);
138         if (ObjectNameInfo)
139         {
140             /* Query the name again */
141             Status = ObQueryNameString(FileObject,
142                                        ObjectNameInfo,
143                                        ReturnLength,
144                                        &ReturnLength);
145         }
146     }
147 
148     /* Check if we got here due to failure */
149     if ((ObjectNameInfo) &&
150         (!(NT_SUCCESS(Status)) || (ReturnLength == sizeof(LocalNameInfo))))
151     {
152         /* First, free any buffer we might've allocated */
153         ASSERT(FALSE);
154         if (ObjectNameInfo) ExFreePool(ObjectNameInfo);
155 
156         /* Now allocate a temporary one */
157         ReturnLength = sizeof(OBJECT_NAME_INFORMATION);
158         ObjectNameInfo = ExAllocatePoolWithTag(NonPagedPool,
159                                                sizeof(OBJECT_NAME_INFORMATION),
160                                                TAG_SEPA);
161         if (ObjectNameInfo)
162         {
163             /* Clear it */
164             RtlZeroMemory(ObjectNameInfo, ReturnLength);
165             Status = STATUS_SUCCESS;
166         }
167     }
168 
169     /* Check if memory allocation failed */
170     if (!ObjectNameInfo) Status = STATUS_NO_MEMORY;
171 
172     /* Return the audit name */
173     *AuditInfo = ObjectNameInfo;
174 
175     /* Return status */
176     return Status;
177 }
178 
179 /**
180  * @brief
181  * Finds the process image name of a specific process.
182  *
183  * @param[in] Process
184  * Process object submitted by the caller, where the image name
185  * is to be located.
186  *
187  * @param[out] ProcessImageName
188  * An output Unicode string structure with the located process
189  * image name.
190  *
191  * @return
192  * Returns STATUS_SUCCESS if process image name has been located
193  * successfully. STATUS_NO_MEMORY is returned if pool allocation
194  * for the image name has failed. A failure NTSTATUS code is
195  * returned otherwise.
196  */
197 NTSTATUS
198 NTAPI
SeLocateProcessImageName(_In_ PEPROCESS Process,_Out_ PUNICODE_STRING * ProcessImageName)199 SeLocateProcessImageName(
200     _In_ PEPROCESS Process,
201     _Out_ PUNICODE_STRING *ProcessImageName)
202 {
203     POBJECT_NAME_INFORMATION AuditName;
204     PUNICODE_STRING ImageName;
205     PFILE_OBJECT FileObject;
206     NTSTATUS Status = STATUS_SUCCESS;
207 
208     PAGED_CODE();
209 
210     /* Assume failure */
211     *ProcessImageName = NULL;
212 
213     /* Check if we have audit info */
214     AuditName = Process->SeAuditProcessCreationInfo.ImageFileName;
215     if (!AuditName)
216     {
217         /* Get the file object */
218         Status = PsReferenceProcessFilePointer(Process, &FileObject);
219         if (!NT_SUCCESS(Status)) return Status;
220 
221         /* Initialize the audit structure */
222         Status = SeInitializeProcessAuditName(FileObject, TRUE, &AuditName);
223         if (NT_SUCCESS(Status))
224         {
225             /* Set it */
226             if (InterlockedCompareExchangePointer((PVOID*)&Process->
227                                                   SeAuditProcessCreationInfo.ImageFileName,
228                                                   AuditName,
229                                                   NULL))
230             {
231                 /* Someone beat us to it, deallocate our copy */
232                 ExFreePool(AuditName);
233             }
234         }
235 
236         /* Dereference the file object */
237         ObDereferenceObject(FileObject);
238         if (!NT_SUCCESS(Status)) return Status;
239     }
240 
241     /* Get audit info again, now we have it for sure */
242     AuditName = Process->SeAuditProcessCreationInfo.ImageFileName;
243 
244     /* Allocate the output string */
245     ImageName = ExAllocatePoolWithTag(NonPagedPool,
246                                       AuditName->Name.MaximumLength +
247                                       sizeof(UNICODE_STRING),
248                                       TAG_SEPA);
249     if (!ImageName) return STATUS_NO_MEMORY;
250 
251     /* Make a copy of it */
252     RtlCopyMemory(ImageName,
253                   &AuditName->Name,
254                   AuditName->Name.MaximumLength + sizeof(UNICODE_STRING));
255 
256     /* Fix up the buffer */
257     ImageName->Buffer = (PWSTR)(ImageName + 1);
258 
259     /* Return it */
260     *ProcessImageName = ImageName;
261 
262     /* Return status */
263     return Status;
264 }
265 
266 /**
267  * @brief
268  * Closes an audit alarm event of an object.
269  *
270  * @param[in] SubsystemName
271  * A Unicode string pointing to the name of the subsystem where auditing
272  * alarm event has to be closed.
273  *
274  * @param[in] HandleId
275  * A handle to an ID where such ID represents the identification of the
276  * object where audit alarm is to be closed.
277  *
278  * @param[in] Sid
279  * A SID that represents the user who attempted to close the audit
280  * alarm.
281  *
282  * @return
283  * Nothing.
284  */
285 VOID
286 NTAPI
SepAdtCloseObjectAuditAlarm(_In_ PUNICODE_STRING SubsystemName,_In_ PVOID HandleId,_In_ PSID Sid)287 SepAdtCloseObjectAuditAlarm(
288     _In_ PUNICODE_STRING SubsystemName,
289     _In_ PVOID HandleId,
290     _In_ PSID Sid)
291 {
292     UNIMPLEMENTED;
293 }
294 
295 /**
296  * @brief
297  * Performs an audit alarm to a privileged service request.
298  * This is a worker function.
299  *
300  * @param[in] SubjectContext
301  * A security subject context used for the auditing process.
302  *
303  * @param[in] SubsystemName
304  * A Unicode string that represents the name of a subsystem that
305  * actuated the procedure of alarm auditing of a privileged
306  * service.
307  *
308  * @param[in] ServiceName
309  * A Unicode string that represents the name of a privileged
310  * service request for auditing.
311  *
312  * @param[in] Token
313  * An access token.
314  *
315  * @param[in] PrimaryToken
316  * A primary access token.
317  *
318  * @param[in] Privileges
319  * An array set of privileges used to check if the privileged
320  * service does actually have all the required set of privileges
321  * for security access.
322  *
323  * @param[in] AccessGranted
324  * When auditing is done, the function will return TRUE to the caller
325  * if access is granted, FALSE otherwise.
326  *
327  * @return
328  * Nothing.
329  */
330 VOID
331 NTAPI
SepAdtPrivilegedServiceAuditAlarm(_In_ 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)332 SepAdtPrivilegedServiceAuditAlarm(
333     _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
334     _In_opt_ PUNICODE_STRING SubsystemName,
335     _In_opt_ PUNICODE_STRING ServiceName,
336     _In_ PTOKEN Token,
337     _In_ PTOKEN PrimaryToken,
338     _In_ PPRIVILEGE_SET Privileges,
339     _In_ BOOLEAN AccessGranted)
340 {
341     DPRINT("SepAdtPrivilegedServiceAuditAlarm is unimplemented\n");
342 }
343 
344 /**
345  * @brief
346  * Performs an audit alarm to a privileged service request.
347  *
348  * @param[in] ServiceName
349  * A Unicode string that represents the name of a privileged
350  * service request for auditing.
351  *
352  * @param[in] SubjectContext
353  * A security subject context used for the auditing process.
354  *
355  * @param[in] PrivilegeSet
356  * An array set of privileges used to check if the privileged
357  * service does actually have all the required set of privileges
358  * for security access.
359  *
360  * @param[in] AccessGranted
361  * When auditing is done, the function will return TRUE to the caller
362  * if access is granted, FALSE otherwise.
363  *
364  * @return
365  * Nothing.
366  */
367 VOID
368 NTAPI
SePrivilegedServiceAuditAlarm(_In_opt_ PUNICODE_STRING ServiceName,_In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,_In_ PPRIVILEGE_SET PrivilegeSet,_In_ BOOLEAN AccessGranted)369 SePrivilegedServiceAuditAlarm(
370     _In_opt_ PUNICODE_STRING ServiceName,
371     _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
372     _In_ PPRIVILEGE_SET PrivilegeSet,
373     _In_ BOOLEAN AccessGranted)
374 {
375     PTOKEN EffectiveToken;
376     PSID UserSid;
377     PAGED_CODE();
378 
379     /* Get the effective token */
380     if (SubjectContext->ClientToken != NULL)
381         EffectiveToken = SubjectContext->ClientToken;
382     else
383         EffectiveToken = SubjectContext->PrimaryToken;
384 
385     /* Get the user SID */
386     UserSid = EffectiveToken->UserAndGroups->Sid;
387 
388     /* Check if this is the local system SID */
389     if (RtlEqualSid(UserSid, SeLocalSystemSid))
390     {
391         /* Nothing to do */
392         return;
393     }
394 
395     /* Check if this is the network service or local service SID */
396     if (RtlEqualSid(UserSid, SeExports->SeNetworkServiceSid) ||
397         RtlEqualSid(UserSid, SeExports->SeLocalServiceSid))
398     {
399         // FIXME: should continue for a certain set of privileges
400         return;
401     }
402 
403     /* Call the worker function */
404     SepAdtPrivilegedServiceAuditAlarm(SubjectContext,
405                                       &SeSubsystemName,
406                                       ServiceName,
407                                       SubjectContext->ClientToken,
408                                       SubjectContext->PrimaryToken,
409                                       PrivilegeSet,
410                                       AccessGranted);
411 
412 }
413 
414 /**
415  * @unimplemented
416  * @brief
417  * Worker function that serves as the main heart and brain of the whole
418  * concept and implementation of auditing in the kernel.
419  *
420  * @param[in] SubsystemName
421  * A Unicode string that represents the name of a subsystem that
422  * actuates the auditing process.
423  *
424  * @param[in] HandleId
425  * A handle to an ID used to identify an object where auditing
426  * is to be done.
427  *
428  * @param[in] SubjectContext
429  * Security subject context.
430  *
431  * @param[in] ObjectTypeName
432  * A Unicode string that represents the name of an object type.
433  *
434  * @param[in] ObjectName
435  * The name of the object.
436  *
437  * @param[in] SecurityDescriptor
438  * A security descriptor with internal security information details
439  * for audit.
440  *
441  * @param[in] PrincipalSelfSid
442  * A principal self user SID.
443  *
444  * @param[in] DesiredAccess
445  * The desired access rights masks requested by the caller.
446  *
447  * @param[in] AuditType
448  * Type of audit to start. This parameter influences how an audit
449  * should be done.
450  *
451  * @param[in] HaveAuditPrivilege
452  * If set to TRUE, the security subject context has the audit privilege thus
453  * it is allowed the ability to perform the audit.
454  *
455  * @param[in] ObjectTypeList
456  * A list of object types.
457  *
458  * @param[in] ObjectTypeListLength
459  * The length size of the list.
460  *
461  * @param[in] GenericMapping
462  * The generic mapping table of access rights used whilst performing auditing
463  * sequence procedure.
464  *
465  * @param[out] GrantedAccessList
466  * This parameter is used to return to the caller a list of actual granted access
467  * rights masks that the audited object has.
468  *
469  * @param[out] AccessStatusList
470  * This parameter is used to return to the caller a list of status return codes.
471  * The function may actually return a single NTSTATUS code if the calling thread
472  * sets UseResultList parameter to FALSE.
473  *
474  * @param[out] GenerateOnClose
475  * Returns TRUE if the function has generated a list of granted access rights and
476  * status codes on termination, FALSE otherwise.
477  *
478  * @param[in] UseResultList
479  * If set to TRUE, the caller wants that the function should only return a single
480  * NTSTATUS code.
481  *
482  * @return
483  * Returns STATUS_SUCCESS if the function has completed the whole internal
484  * auditing procedure mechanism with success.
485  */
486 _Must_inspect_result_
487 static
488 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_INTERNAL 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)489 SepAccessCheckAndAuditAlarmWorker(
490     _In_ PUNICODE_STRING SubsystemName,
491     _In_opt_ PVOID HandleId,
492     _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
493     _In_ PUNICODE_STRING ObjectTypeName,
494     _In_ PUNICODE_STRING ObjectName,
495     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
496     _In_opt_ PSID PrincipalSelfSid,
497     _In_ ACCESS_MASK DesiredAccess,
498     _In_ AUDIT_EVENT_TYPE AuditType,
499     _In_ BOOLEAN HaveAuditPrivilege,
500     _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,
501     _In_ ULONG ObjectTypeListLength,
502     _In_ PGENERIC_MAPPING GenericMapping,
503     _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccessList,
504     _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatusList,
505     _Out_ PBOOLEAN GenerateOnClose,
506     _In_ BOOLEAN UseResultList)
507 {
508     ULONG ResultListLength, i;
509 
510     /* Get the length of the result list */
511     ResultListLength = UseResultList ? ObjectTypeListLength : 1;
512 
513     /// FIXME: we should do some real work here...
514     UNIMPLEMENTED;
515 
516     /// HACK: we just pretend all access is granted!
517     for (i = 0; i < ResultListLength; i++)
518     {
519         GrantedAccessList[i] = DesiredAccess;
520         AccessStatusList[i] = STATUS_SUCCESS;
521     }
522 
523     *GenerateOnClose = FALSE;
524 
525     return STATUS_SUCCESS;
526 }
527 
528 /**
529  * @brief
530  * Performs security auditing, if the specific object can be granted
531  * security access or not.
532  *
533  * @param[in] SubsystemName
534  * A Unicode string that represents the name of a subsystem that
535  * actuates the auditing process.
536  *
537  * @param[in] HandleId
538  * A handle to an ID used to identify an object where auditing
539  * is to be done.
540  *
541  * @param[in] SubjectContext
542  * Security subject context.
543  *
544  * @param[in] ObjectTypeName
545  * A Unicode string that represents the name of an object type.
546  *
547  * @param[in] ObjectName
548  * The name of the object.
549  *
550  * @param[in] SecurityDescriptor
551  * A security descriptor with internal security information details
552  * for audit.
553  *
554  * @param[in] PrincipalSelfSid
555  * A principal self user SID.
556  *
557  * @param[in] DesiredAccess
558  * The desired access rights masks requested by the caller.
559  *
560  * @param[in] AuditType
561  * Type of audit to start. This parameter influences how an audit
562  * should be done.
563  *
564  * @param[in] Flags
565  * Flag bitmask parameter.
566  *
567  * @param[in] HaveAuditPrivilege
568  * If set to TRUE, the security subject context has the audit privilege thus
569  * it is allowed the ability to perform the audit.
570  *
571  * @param[in] ObjectTypeList
572  * A list of object types.
573  *
574  * @param[in] ObjectTypeListLength
575  * The length size of the list.
576  *
577  * @param[in] GenericMapping
578  * The generic mapping table of access rights used whilst performing auditing
579  * sequence procedure.
580  *
581  * @param[out] GrantedAccessList
582  * This parameter is used to return to the caller a list of actual granted access
583  * rights masks that the audited object has.
584  *
585  * @param[out] AccessStatusList
586  * This parameter is used to return to the caller a list of status return codes.
587  * The function may actually return a single NTSTATUS code if the calling thread
588  * sets UseResultList parameter to FALSE.
589  *
590  * @param[out] GenerateOnClose
591  * Returns TRUE if the function has generated a list of granted access rights and
592  * status codes on termination, FALSE otherwise.
593  *
594  * @param[in] UseResultList
595  * If set to TRUE, the caller wants that the function should only return a single
596  * NTSTATUS code.
597  *
598  * @return
599  * Returns STATUS_SUCCESS if the function has completed the whole internal
600  * auditing procedure mechanism with success. STATUS_INVALID_PARAMETER is
601  * returned if one of the parameters do not satisfy the general requirements
602  * by the function. STATUS_INSUFFICIENT_RESOURCES is returned if pool memory
603  * allocation has failed. STATUS_PRIVILEGE_NOT_HELD is returned if the current
604  * security subject context does not have the required audit privilege to actually
605  * perform auditing in the first place. STATUS_INVALID_SECURITY_DESCR is returned
606  * if the security descriptor provided by the caller is not valid, that is, such
607  * descriptor doesn't belong to the main user (owner) and current group.
608  * STATUS_GENERIC_NOT_MAPPED is returned if the access rights masks aren't actually
609  * mapped. A failure NTSTATUS code is returned otherwise.
610  */
611 _Must_inspect_result_
612 NTSTATUS
613 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)614 SepAccessCheckAndAuditAlarm(
615     _In_ PUNICODE_STRING SubsystemName,
616     _In_opt_ PVOID HandleId,
617     _In_ PHANDLE ClientTokenHandle,
618     _In_ PUNICODE_STRING ObjectTypeName,
619     _In_ PUNICODE_STRING ObjectName,
620     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
621     _In_opt_ PSID PrincipalSelfSid,
622     _In_ ACCESS_MASK DesiredAccess,
623     _In_ AUDIT_EVENT_TYPE AuditType,
624     _In_ ULONG Flags,
625     _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
626     _In_ ULONG ObjectTypeListLength,
627     _In_ PGENERIC_MAPPING GenericMapping,
628     _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccessList,
629     _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatusList,
630     _Out_ PBOOLEAN GenerateOnClose,
631     _In_ BOOLEAN UseResultList)
632 {
633     SECURITY_SUBJECT_CONTEXT SubjectContext;
634     ULONG ResultListLength;
635     GENERIC_MAPPING LocalGenericMapping;
636     PTOKEN SubjectContextToken, ClientToken;
637     BOOLEAN AllocatedResultLists;
638     BOOLEAN HaveAuditPrivilege;
639     PSECURITY_DESCRIPTOR CapturedSecurityDescriptor;
640     UNICODE_STRING CapturedSubsystemName, CapturedObjectTypeName, CapturedObjectName;
641     ACCESS_MASK GrantedAccess, *SafeGrantedAccessList;
642     NTSTATUS AccessStatus, *SafeAccessStatusList;
643     PSID CapturedPrincipalSelfSid;
644     POBJECT_TYPE_LIST_INTERNAL CapturedObjectTypeList;
645     ULONG i;
646     BOOLEAN LocalGenerateOnClose;
647     NTSTATUS Status;
648     PAGED_CODE();
649 
650     /* Only user mode is supported! */
651     ASSERT(ExGetPreviousMode() != KernelMode);
652 
653     /* Start clean */
654     AllocatedResultLists = FALSE;
655     ClientToken = NULL;
656     CapturedSecurityDescriptor = NULL;
657     CapturedSubsystemName.Buffer = NULL;
658     CapturedObjectTypeName.Buffer = NULL;
659     CapturedObjectName.Buffer = NULL;
660     CapturedPrincipalSelfSid = NULL;
661     CapturedObjectTypeList = NULL;
662 
663     /* Validate AuditType */
664     if ((AuditType != AuditEventObjectAccess) &&
665         (AuditType != AuditEventDirectoryServiceAccess))
666     {
667         DPRINT1("Invalid audit type: %u\n", AuditType);
668         return STATUS_INVALID_PARAMETER;
669     }
670 
671     /* Capture the security subject context */
672     SeCaptureSubjectContext(&SubjectContext);
673 
674     /* Did the caller pass a token handle? */
675     if (ClientTokenHandle == NULL)
676     {
677         /* Check if we have a token in the subject context */
678         if (SubjectContext.ClientToken == NULL)
679         {
680             Status = STATUS_NO_IMPERSONATION_TOKEN;
681             DPRINT1("No token\n");
682             goto Cleanup;
683         }
684 
685         /* Check if we have a valid impersonation level */
686         if (SubjectContext.ImpersonationLevel < SecurityIdentification)
687         {
688             Status = STATUS_BAD_IMPERSONATION_LEVEL;
689             DPRINT1("Invalid impersonation level 0x%lx\n",
690                     SubjectContext.ImpersonationLevel);
691             goto Cleanup;
692         }
693     }
694 
695     /* Are we using a result list? */
696     if (UseResultList)
697     {
698         /* The list length equals the object type list length */
699         ResultListLength = ObjectTypeListLength;
700         if ((ResultListLength == 0) || (ResultListLength > 0x1000))
701         {
702             Status = STATUS_INVALID_PARAMETER;
703             DPRINT1("Invalid ResultListLength: 0x%lx\n", ResultListLength);
704             goto Cleanup;
705         }
706 
707         /* Allocate a safe buffer from paged pool */
708         SafeGrantedAccessList = ExAllocatePoolWithTag(PagedPool,
709                                                       2 * ResultListLength * sizeof(ULONG),
710                                                       TAG_SEPA);
711         if (SafeGrantedAccessList == NULL)
712         {
713             Status = STATUS_INSUFFICIENT_RESOURCES;
714             DPRINT1("Failed to allocate access lists\n");
715             goto Cleanup;
716         }
717 
718         SafeAccessStatusList = (PNTSTATUS)&SafeGrantedAccessList[ResultListLength];
719         AllocatedResultLists = TRUE;
720     }
721     else
722     {
723         /* List length is 1 */
724         ResultListLength = 1;
725         SafeGrantedAccessList = &GrantedAccess;
726         SafeAccessStatusList = &AccessStatus;
727     }
728 
729     _SEH2_TRY
730     {
731         /* Probe output buffers */
732         ProbeForWrite(AccessStatusList,
733                       ResultListLength * sizeof(*AccessStatusList),
734                       sizeof(*AccessStatusList));
735         ProbeForWrite(GrantedAccessList,
736                       ResultListLength * sizeof(*GrantedAccessList),
737                       sizeof(*GrantedAccessList));
738 
739         /* Probe generic mapping and make a local copy */
740         ProbeForRead(GenericMapping, sizeof(*GenericMapping), sizeof(ULONG));
741         LocalGenericMapping = * GenericMapping;
742     }
743     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
744     {
745         Status = _SEH2_GetExceptionCode();
746         DPRINT1("Exception while probing parameters: 0x%lx\n", Status);
747         _SEH2_YIELD(goto Cleanup);
748     }
749     _SEH2_END;
750 
751     /* Do we have a client token? */
752     if (ClientTokenHandle != NULL)
753     {
754         /* Reference the client token */
755         Status = ObReferenceObjectByHandle(*ClientTokenHandle,
756                                            TOKEN_QUERY,
757                                            SeTokenObjectType,
758                                            UserMode,
759                                            (PVOID*)&ClientToken,
760                                            NULL);
761         if (!NT_SUCCESS(Status))
762         {
763             DPRINT1("Failed to reference token handle %p: %lx\n",
764                     *ClientTokenHandle, Status);
765             goto Cleanup;
766         }
767 
768         SubjectContextToken = SubjectContext.ClientToken;
769         SubjectContext.ClientToken = ClientToken;
770     }
771 
772     /* Check for audit privilege */
773     HaveAuditPrivilege = SeCheckAuditPrivilege(&SubjectContext, UserMode);
774     if (!HaveAuditPrivilege && !(Flags & AUDIT_ALLOW_NO_PRIVILEGE))
775     {
776         DPRINT1("Caller does not have SeAuditPrivilege\n");
777         Status = STATUS_PRIVILEGE_NOT_HELD;
778         goto Cleanup;
779     }
780 
781     /* Generic access must already be mapped to non-generic access types! */
782     if (DesiredAccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL))
783     {
784         DPRINT1("Generic access rights requested: 0x%lx\n", DesiredAccess);
785         Status = STATUS_GENERIC_NOT_MAPPED;
786         goto Cleanup;
787     }
788 
789     /* Capture the security descriptor */
790     Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
791                                          UserMode,
792                                          PagedPool,
793                                          FALSE,
794                                          &CapturedSecurityDescriptor);
795     if (!NT_SUCCESS(Status))
796     {
797         DPRINT1("Failed to capture security descriptor!\n");
798         goto Cleanup;
799     }
800 
801     /* Validate the Security descriptor */
802     if ((SepGetOwnerFromDescriptor(CapturedSecurityDescriptor) == NULL) ||
803         (SepGetGroupFromDescriptor(CapturedSecurityDescriptor) == NULL))
804     {
805         Status = STATUS_INVALID_SECURITY_DESCR;
806         DPRINT1("Invalid security descriptor\n");
807         goto Cleanup;
808     }
809 
810     /* Probe and capture the subsystem name */
811     Status = ProbeAndCaptureUnicodeString(&CapturedSubsystemName,
812                                           UserMode,
813                                           SubsystemName);
814     if (!NT_SUCCESS(Status))
815     {
816         DPRINT1("Failed to capture subsystem name!\n");
817         goto Cleanup;
818     }
819 
820     /* Probe and capture the object type name */
821     Status = ProbeAndCaptureUnicodeString(&CapturedObjectTypeName,
822                                           UserMode,
823                                           ObjectTypeName);
824     if (!NT_SUCCESS(Status))
825     {
826         DPRINT1("Failed to capture object type name!\n");
827         goto Cleanup;
828     }
829 
830     /* Probe and capture the object name */
831     Status = ProbeAndCaptureUnicodeString(&CapturedObjectName,
832                                           UserMode,
833                                           ObjectName);
834     if (!NT_SUCCESS(Status))
835     {
836         DPRINT1("Failed to capture object name!\n");
837         goto Cleanup;
838     }
839 
840     /* Check if we have a PrincipalSelfSid */
841     if (PrincipalSelfSid != NULL)
842     {
843         /* Capture it */
844         Status = SepCaptureSid(PrincipalSelfSid,
845                                UserMode,
846                                PagedPool,
847                                FALSE,
848                                &CapturedPrincipalSelfSid);
849         if (!NT_SUCCESS(Status))
850         {
851             DPRINT1("Failed to capture PrincipalSelfSid!\n");
852             goto Cleanup;
853         }
854     }
855 
856     /* Capture the object type list */
857     Status = SeCaptureObjectTypeList(ObjectTypeList,
858                                      ObjectTypeListLength,
859                                      UserMode,
860                                      &CapturedObjectTypeList);
861     if (!NT_SUCCESS(Status))
862     {
863         DPRINT1("Failed to capture object type list!\n");
864         goto Cleanup;
865     }
866 
867     /* Call the worker routine with the captured buffers */
868     Status = SepAccessCheckAndAuditAlarmWorker(&CapturedSubsystemName,
869                                                HandleId,
870                                                &SubjectContext,
871                                                &CapturedObjectTypeName,
872                                                &CapturedObjectName,
873                                                CapturedSecurityDescriptor,
874                                                CapturedPrincipalSelfSid,
875                                                DesiredAccess,
876                                                AuditType,
877                                                HaveAuditPrivilege,
878                                                CapturedObjectTypeList,
879                                                ObjectTypeListLength,
880                                                &LocalGenericMapping,
881                                                SafeGrantedAccessList,
882                                                SafeAccessStatusList,
883                                                &LocalGenerateOnClose,
884                                                UseResultList);
885     if (!NT_SUCCESS(Status))
886         goto Cleanup;
887 
888     /* Enter SEH to copy the data back to user mode */
889     _SEH2_TRY
890     {
891         /* Loop all result entries (only 1 when no list was requested) */
892         ASSERT(UseResultList || (ResultListLength == 1));
893         for (i = 0; i < ResultListLength; i++)
894         {
895             AccessStatusList[i] = SafeAccessStatusList[i];
896             GrantedAccessList[i] = SafeGrantedAccessList[i];
897         }
898 
899         *GenerateOnClose = LocalGenerateOnClose;
900     }
901     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
902     {
903         Status = _SEH2_GetExceptionCode();
904         DPRINT1("Exception while copying back data: 0x%lx\n", Status);
905     }
906     _SEH2_END;
907 
908 Cleanup:
909 
910     if (CapturedObjectTypeList != NULL)
911         SeReleaseObjectTypeList(CapturedObjectTypeList, UserMode);
912 
913     if (CapturedPrincipalSelfSid != NULL)
914         SepReleaseSid(CapturedPrincipalSelfSid, UserMode, FALSE);
915 
916     if (CapturedObjectName.Buffer != NULL)
917         ReleaseCapturedUnicodeString(&CapturedObjectName, UserMode);
918 
919     if (CapturedObjectTypeName.Buffer != NULL)
920         ReleaseCapturedUnicodeString(&CapturedObjectTypeName, UserMode);
921 
922     if (CapturedSubsystemName.Buffer != NULL)
923         ReleaseCapturedUnicodeString(&CapturedSubsystemName, UserMode);
924 
925     if (CapturedSecurityDescriptor != NULL)
926         SeReleaseSecurityDescriptor(CapturedSecurityDescriptor, UserMode, FALSE);
927 
928     if (ClientToken != NULL)
929     {
930         ObDereferenceObject(ClientToken);
931         SubjectContext.ClientToken = SubjectContextToken;
932     }
933 
934     if (AllocatedResultLists)
935         ExFreePoolWithTag(SafeGrantedAccessList, TAG_SEPA);
936 
937     /* Release the security subject context */
938     SeReleaseSubjectContext(&SubjectContext);
939 
940     return Status;
941 }
942 
943 
944 /* PUBLIC FUNCTIONS ***********************************************************/
945 
946 /**
947  * @unimplemented
948  * @brief
949  * Performs an audit against a hard link creation.
950  *
951  * @param[in] FileName
952  * A Unicode string that points to the name of the file.
953  *
954  * @param[in] LinkName
955  * A Unicode string that points to a link.
956  *
957  * @param[out] bSuccess
958  * If TRUE, the function has successfully audited
959  * the hard link and security access can be granted,
960  * FALSE otherwise.
961  *
962  * @return
963  * Nothing.
964  */
965 VOID
966 NTAPI
SeAuditHardLinkCreation(_In_ PUNICODE_STRING FileName,_In_ PUNICODE_STRING LinkName,_In_ BOOLEAN bSuccess)967 SeAuditHardLinkCreation(
968     _In_ PUNICODE_STRING FileName,
969     _In_ PUNICODE_STRING LinkName,
970     _In_ BOOLEAN bSuccess)
971 {
972     UNIMPLEMENTED;
973 }
974 
975 /**
976  * @unimplemented
977  * @brief
978  * Determines whether auditing against file events is being
979  * done or not.
980  *
981  * @param[in] AccessGranted
982  * If set to TRUE, the access attempt is deemed as successful
983  * otherwise set it to FALSE.
984  *
985  * @param[in] SecurityDescriptor
986  * A security descriptor.
987  *
988  * @return
989  * Returns TRUE if auditing is being currently done, FALSE otherwise.
990  */
991 BOOLEAN
992 NTAPI
SeAuditingFileEvents(_In_ BOOLEAN AccessGranted,_In_ PSECURITY_DESCRIPTOR SecurityDescriptor)993 SeAuditingFileEvents(
994     _In_ BOOLEAN AccessGranted,
995     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor)
996 {
997     UNIMPLEMENTED;
998     return FALSE;
999 }
1000 
1001 /**
1002  * @unimplemented
1003  * @brief
1004  * Determines whether auditing against file events with subject context
1005  * is being done or not.
1006  *
1007  * @param[in] AccessGranted
1008  * If set to TRUE, the access attempt is deemed as successful
1009  * otherwise set it to FALSE.
1010  *
1011  * @param[in] SecurityDescriptor
1012  * A security descriptor.
1013  *
1014  * @param[in] SubjectSecurityContext
1015  * If specified, the function will check if security auditing is currently
1016  * being done with this context.
1017  *
1018  * @return
1019  * Returns TRUE if auditing is being currently done, FALSE otherwise.
1020  */
1021 BOOLEAN
1022 NTAPI
SeAuditingFileEventsWithContext(_In_ BOOLEAN AccessGranted,_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,_In_opt_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext)1023 SeAuditingFileEventsWithContext(
1024     _In_ BOOLEAN AccessGranted,
1025     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
1026     _In_opt_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext)
1027 {
1028     UNIMPLEMENTED_ONCE;
1029     return FALSE;
1030 }
1031 
1032 /**
1033  * @unimplemented
1034  * @brief
1035  * Determines whether auditing against hard links events is being
1036  * done or not.
1037  *
1038  * @param[in] AccessGranted
1039  * If set to TRUE, the access attempt is deemed as successful
1040  * otherwise set it to FALSE.
1041  *
1042  * @param[in] SecurityDescriptor
1043  * A security descriptor.
1044  *
1045  * @return
1046  * Returns TRUE if auditing is being currently done, FALSE otherwise.
1047  */
1048 BOOLEAN
1049 NTAPI
SeAuditingHardLinkEvents(_In_ BOOLEAN AccessGranted,_In_ PSECURITY_DESCRIPTOR SecurityDescriptor)1050 SeAuditingHardLinkEvents(
1051     _In_ BOOLEAN AccessGranted,
1052     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor)
1053 {
1054     UNIMPLEMENTED;
1055     return FALSE;
1056 }
1057 
1058 /**
1059  * @unimplemented
1060  * @brief
1061  * Determines whether auditing against hard links events with subject context
1062  * is being done or not.
1063  *
1064  * @param[in] AccessGranted
1065  * If set to TRUE, the access attempt is deemed as successful
1066  * otherwise set it to FALSE.
1067  *
1068  * @param[in] SecurityDescriptor
1069  * A security descriptor.
1070  *
1071  * @param[in] SubjectSecurityContext
1072  * If specified, the function will check if security auditing is currently
1073  * being done with this context.
1074  *
1075  * @return
1076  * Returns TRUE if auditing is being currently done, FALSE otherwise.
1077  */
1078 BOOLEAN
1079 NTAPI
SeAuditingHardLinkEventsWithContext(_In_ BOOLEAN AccessGranted,_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,_In_opt_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext)1080 SeAuditingHardLinkEventsWithContext(
1081     _In_ BOOLEAN AccessGranted,
1082     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
1083     _In_opt_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext)
1084 {
1085     UNIMPLEMENTED;
1086     return FALSE;
1087 }
1088 
1089 /**
1090  * @unimplemented
1091  * @brief
1092  * Determines whether auditing against files or global events with
1093  * subject context is being done or not.
1094  *
1095  * @param[in] AccessGranted
1096  * If set to TRUE, the access attempt is deemed as successful
1097  * otherwise set it to FALSE.
1098  *
1099  * @param[in] SecurityDescriptor
1100  * A security descriptor.
1101  *
1102  * @param[in] SubjectSecurityContext
1103  * If specified, the function will check if security auditing is currently
1104  * being done with this context.
1105  *
1106  * @return
1107  * Returns TRUE if auditing is being currently done, FALSE otherwise.
1108  */
1109 BOOLEAN
1110 NTAPI
SeAuditingFileOrGlobalEvents(_In_ BOOLEAN AccessGranted,_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,_In_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext)1111 SeAuditingFileOrGlobalEvents(
1112     _In_ BOOLEAN AccessGranted,
1113     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
1114     _In_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext)
1115 {
1116     UNIMPLEMENTED;
1117     return FALSE;
1118 }
1119 
1120 /**
1121  * @unimplemented
1122  * @brief
1123  * Closes an alarm audit of an object.
1124  *
1125  * @param[in] Object
1126  * An arbitrary pointer data that points to the object.
1127  *
1128  * @param[in] Handle
1129  * A handle of the said object.
1130  *
1131  * @param[in] PerformAction
1132  * Set this to TRUE to perform any auxiliary action, otherwise
1133  * set to FALSE.
1134  *
1135  * @return
1136  * Nothing.
1137  */
1138 VOID
1139 NTAPI
SeCloseObjectAuditAlarm(_In_ PVOID Object,_In_ HANDLE Handle,_In_ BOOLEAN PerformAction)1140 SeCloseObjectAuditAlarm(
1141     _In_ PVOID Object,
1142     _In_ HANDLE Handle,
1143     _In_ BOOLEAN PerformAction)
1144 {
1145     UNIMPLEMENTED;
1146 }
1147 
1148 /**
1149  * @unimplemented
1150  * @brief
1151  * Deletes an alarm audit of an object.
1152  *
1153  * @param[in] Object
1154  * An arbitrary pointer data that points to the object.
1155  *
1156  * @param[in] Handle
1157  * A handle of the said object.
1158  *
1159  * @return
1160  * Nothing.
1161  */
1162 VOID NTAPI
SeDeleteObjectAuditAlarm(_In_ PVOID Object,_In_ HANDLE Handle)1163 SeDeleteObjectAuditAlarm(
1164     _In_ PVOID Object,
1165     _In_ HANDLE Handle)
1166 {
1167     UNIMPLEMENTED;
1168 }
1169 
1170 /**
1171  * @unimplemented
1172  * @brief
1173  * Creates an audit with alarm notification of an object
1174  * that is being opened.
1175  *
1176  * @param[in] ObjectTypeName
1177  * A Unicode string that points to the object type name.
1178  *
1179  * @param[in] Object
1180  * If specified, the function will use this parameter to
1181  * directly open the object.
1182  *
1183  * @param[in] AbsoluteObjectName
1184  * If specified, the function will use this parameter to
1185  * directly open the object through the absolute name
1186  * of the object.
1187  *
1188  * @param[in] SecurityDescriptor
1189  * A security descriptor.
1190  *
1191  * @param[in] AccessState
1192  * An access state right mask when opening the object.
1193  *
1194  * @param[in] ObjectCreated
1195  * Set this to TRUE if the object has been fully created,
1196  * FALSE otherwise.
1197  *
1198  * @param[in] AccessGranted
1199  * Set this to TRUE if access was deemed as granted.
1200  *
1201  * @param[in] AccessMode
1202  * Processor level access mode.
1203  *
1204  * @param[out] GenerateOnClose
1205  * A boolean flag returned to the caller once audit generation procedure
1206  * finishes.
1207  *
1208  * @return
1209  * Nothing.
1210  */
1211 VOID
1212 NTAPI
SeOpenObjectAuditAlarm(_In_ PUNICODE_STRING ObjectTypeName,_In_opt_ PVOID Object,_In_opt_ PUNICODE_STRING AbsoluteObjectName,_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,_In_ PACCESS_STATE AccessState,_In_ BOOLEAN ObjectCreated,_In_ BOOLEAN AccessGranted,_In_ KPROCESSOR_MODE AccessMode,_Out_ PBOOLEAN GenerateOnClose)1213 SeOpenObjectAuditAlarm(
1214     _In_ PUNICODE_STRING ObjectTypeName,
1215     _In_opt_ PVOID Object,
1216     _In_opt_ PUNICODE_STRING AbsoluteObjectName,
1217     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
1218     _In_ PACCESS_STATE AccessState,
1219     _In_ BOOLEAN ObjectCreated,
1220     _In_ BOOLEAN AccessGranted,
1221     _In_ KPROCESSOR_MODE AccessMode,
1222     _Out_ PBOOLEAN GenerateOnClose)
1223 {
1224     PAGED_CODE();
1225 
1226     /* Audits aren't done on kernel-mode access */
1227     if (AccessMode == KernelMode) return;
1228 
1229     /* Otherwise, unimplemented! */
1230     //UNIMPLEMENTED;
1231     return;
1232 }
1233 
1234 /**
1235  * @unimplemented
1236  * @brief
1237  * Creates an audit with alarm notification of an object
1238  * that is being opened for deletion.
1239  *
1240  * @param[in] ObjectTypeName
1241  * A Unicode string that points to the object type name.
1242  *
1243  * @param[in] Object
1244  * If specified, the function will use this parameter to
1245  * directly open the object.
1246  *
1247  * @param[in] AbsoluteObjectName
1248  * If specified, the function will use this parameter to
1249  * directly open the object through the absolute name
1250  * of the object.
1251  *
1252  * @param[in] SecurityDescriptor
1253  * A security descriptor.
1254  *
1255  * @param[in] AccessState
1256  * An access state right mask when opening the object.
1257  *
1258  * @param[in] ObjectCreated
1259  * Set this to TRUE if the object has been fully created,
1260  * FALSE otherwise.
1261  *
1262  * @param[in] AccessGranted
1263  * Set this to TRUE if access was deemed as granted.
1264  *
1265  * @param[in] AccessMode
1266  * Processor level access mode.
1267  *
1268  * @param[out] GenerateOnClose
1269  * A boolean flag returned to the caller once audit generation procedure
1270  * finishes.
1271  *
1272  * @return
1273  * Nothing.
1274  */
1275 VOID NTAPI
SeOpenObjectForDeleteAuditAlarm(_In_ PUNICODE_STRING ObjectTypeName,_In_opt_ PVOID Object,_In_opt_ PUNICODE_STRING AbsoluteObjectName,_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,_In_ PACCESS_STATE AccessState,_In_ BOOLEAN ObjectCreated,_In_ BOOLEAN AccessGranted,_In_ KPROCESSOR_MODE AccessMode,_Out_ PBOOLEAN GenerateOnClose)1276 SeOpenObjectForDeleteAuditAlarm(
1277     _In_ PUNICODE_STRING ObjectTypeName,
1278     _In_opt_ PVOID Object,
1279     _In_opt_ PUNICODE_STRING AbsoluteObjectName,
1280     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
1281     _In_ PACCESS_STATE AccessState,
1282     _In_ BOOLEAN ObjectCreated,
1283     _In_ BOOLEAN AccessGranted,
1284     _In_ KPROCESSOR_MODE AccessMode,
1285     _Out_ PBOOLEAN GenerateOnClose)
1286 {
1287     UNIMPLEMENTED;
1288 }
1289 
1290 /**
1291  * @unimplemented
1292  * @brief
1293  * Raises an audit with alarm notification message
1294  * when an object tries to acquire this privilege.
1295  *
1296  * @param[in] Handle
1297  * A handle to an object.
1298  *
1299  * @param[in] SubjectContext
1300  * The security subject context for auditing.
1301  *
1302  * @param[in] DesiredAccess
1303  * The desired right access masks requested by the caller.
1304  *
1305  * @param[in] Privileges
1306  * An array set of privileges for auditing.
1307  *
1308  * @param[out] AccessGranted
1309  * When the auditing procedure routine ends, it returns TRUE to the
1310  * caller if the object has the required privileges for access,
1311  * FALSE otherwise.
1312  *
1313  * @param[in] CurrentMode
1314  * Processor level access mode.
1315  *
1316  * @return
1317  * Nothing.
1318  */
1319 VOID
1320 NTAPI
SePrivilegeObjectAuditAlarm(_In_ HANDLE Handle,_In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,_In_ ACCESS_MASK DesiredAccess,_In_ PPRIVILEGE_SET Privileges,_In_ BOOLEAN AccessGranted,_In_ KPROCESSOR_MODE CurrentMode)1321 SePrivilegeObjectAuditAlarm(
1322     _In_ HANDLE Handle,
1323     _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
1324     _In_ ACCESS_MASK DesiredAccess,
1325     _In_ PPRIVILEGE_SET Privileges,
1326     _In_ BOOLEAN AccessGranted,
1327     _In_ KPROCESSOR_MODE CurrentMode)
1328 {
1329     UNIMPLEMENTED;
1330 }
1331 
1332 /* SYSTEM CALLS ***************************************************************/
1333 
1334 /**
1335  * @brief
1336  * Raises an alarm audit message when an object is about
1337  * to be closed.
1338  *
1339  * @param[in] SubsystemName
1340  * A Unicode string that points to the name of the subsystem.
1341  *
1342  * @param[in] HandleId
1343  * A handle of an ID used for identification instance for auditing.
1344  *
1345  * @param[in] GenerateOnClose
1346  * A boolean value previously created by the "open" equivalent of this
1347  * function. If the caller explicitly sets this to FALSE, the function
1348  * assumes that the object is not opened.
1349  *
1350  * @return
1351  * Returns STATUS_SUCCESS if all the operations have completed successfully.
1352  * STATUS_PRIVILEGE_NOT_HELD is returned if the security subject context
1353  * does not have the audit privilege to actually begin auditing procedures
1354  * in the first place.
1355  */
1356 NTSTATUS
1357 NTAPI
NtCloseObjectAuditAlarm(_In_ PUNICODE_STRING SubsystemName,_In_ PVOID HandleId,_In_ BOOLEAN GenerateOnClose)1358 NtCloseObjectAuditAlarm(
1359     _In_ PUNICODE_STRING SubsystemName,
1360     _In_ PVOID HandleId,
1361     _In_ BOOLEAN GenerateOnClose)
1362 {
1363     SECURITY_SUBJECT_CONTEXT SubjectContext;
1364     UNICODE_STRING CapturedSubsystemName;
1365     KPROCESSOR_MODE PreviousMode;
1366     BOOLEAN UseImpersonationToken;
1367     PETHREAD CurrentThread;
1368     BOOLEAN CopyOnOpen, EffectiveOnly;
1369     SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
1370     NTSTATUS Status;
1371     PTOKEN Token;
1372     PAGED_CODE();
1373 
1374     /* Get the previous mode (only user mode is supported!) */
1375     PreviousMode = ExGetPreviousMode();
1376     ASSERT(PreviousMode != KernelMode);
1377 
1378     /* Do we even need to do anything? */
1379     if (!GenerateOnClose)
1380     {
1381         /* Nothing to do, return success */
1382         return STATUS_SUCCESS;
1383     }
1384 
1385     /* Capture the security subject context */
1386     SeCaptureSubjectContext(&SubjectContext);
1387 
1388     /* Check for audit privilege */
1389     if (!SeCheckAuditPrivilege(&SubjectContext, PreviousMode))
1390     {
1391         DPRINT1("Caller does not have SeAuditPrivilege\n");
1392         Status = STATUS_PRIVILEGE_NOT_HELD;
1393         goto Cleanup;
1394     }
1395 
1396     /* Probe and capture the subsystem name */
1397     Status = ProbeAndCaptureUnicodeString(&CapturedSubsystemName,
1398                                           PreviousMode,
1399                                           SubsystemName);
1400     if (!NT_SUCCESS(Status))
1401     {
1402         DPRINT1("Failed to capture subsystem name!\n");
1403         goto Cleanup;
1404     }
1405 
1406     /* Get the current thread and check if it's impersonating */
1407     CurrentThread = PsGetCurrentThread();
1408     if (PsIsThreadImpersonating(CurrentThread))
1409     {
1410         /* Get the impersonation token */
1411         Token = PsReferenceImpersonationToken(CurrentThread,
1412                                               &CopyOnOpen,
1413                                               &EffectiveOnly,
1414                                               &ImpersonationLevel);
1415         UseImpersonationToken = TRUE;
1416     }
1417     else
1418     {
1419         /* Get the primary token */
1420         Token = PsReferencePrimaryToken(PsGetCurrentProcess());
1421         UseImpersonationToken = FALSE;
1422     }
1423 
1424     /* Call the internal function */
1425     SepAdtCloseObjectAuditAlarm(&CapturedSubsystemName,
1426                                 HandleId,
1427                                 Token->UserAndGroups->Sid);
1428 
1429     /* Release the captured subsystem name */
1430     ReleaseCapturedUnicodeString(&CapturedSubsystemName, PreviousMode);
1431 
1432     /* Check what token we used */
1433     if (UseImpersonationToken)
1434     {
1435         /* Release impersonation token */
1436         PsDereferenceImpersonationToken(Token);
1437     }
1438     else
1439     {
1440         /* Release primary token */
1441         PsDereferencePrimaryToken(Token);
1442     }
1443 
1444     Status = STATUS_SUCCESS;
1445 
1446 Cleanup:
1447 
1448     /* Release the security subject context */
1449     SeReleaseSubjectContext(&SubjectContext);
1450 
1451     return Status;
1452 }
1453 
1454 /**
1455  * @unimplemented
1456  * @brief
1457  * Raises an alarm audit message when an object is about
1458  * to be deleted.
1459  *
1460  * @param[in] SubsystemName
1461  * A Unicode string that points to the name of the subsystem.
1462  *
1463  * @param[in] HandleId
1464  * A handle of an ID used for identification instance for auditing.
1465  *
1466  * @param[in] GenerateOnClose
1467  * A boolean value previously created by the "open" equivalent of this
1468  * function. If the caller explicitly sets this to FALSE, the function
1469  * assumes that the object is not opened.
1470  *
1471  * @return
1472  * To be added...
1473  */
1474 NTSTATUS NTAPI
NtDeleteObjectAuditAlarm(_In_ PUNICODE_STRING SubsystemName,_In_ PVOID HandleId,_In_ BOOLEAN GenerateOnClose)1475 NtDeleteObjectAuditAlarm(
1476     _In_ PUNICODE_STRING SubsystemName,
1477     _In_ PVOID HandleId,
1478     _In_ BOOLEAN GenerateOnClose)
1479 {
1480     UNIMPLEMENTED;
1481     return STATUS_NOT_IMPLEMENTED;
1482 }
1483 
1484 /**
1485  * @unimplemented
1486  * @brief
1487  * Raises an alarm audit message when an object is about
1488  * to be opened.
1489  *
1490  * @param[in] SubjectContext
1491  * A security subject context for auditing.
1492  *
1493  * @param[in] SubsystemName
1494  * A Unicode string that points to a name of the subsystem.
1495  *
1496  * @param[in] HandleId
1497  * A handle to an ID used for identification instance for auditing.
1498  *
1499  * @param[in] ObjectTypeName
1500  * A Unicode string that points to an object type name.
1501  *
1502  * @param[in] ObjectName
1503  * The name of the object.
1504  *
1505  * @param[in] SecurityDescriptor
1506  * A security descriptor.
1507  *
1508  * @param[in] ClientToken
1509  * A client access token, representing the client we want to impersonate.
1510  *
1511  * @param[in] DesiredAccess
1512  * The desired access rights masks requested by the caller.
1513  *
1514  * @param[in] GrantedAccess
1515  * The granted access mask rights.
1516  *
1517  * @param[in] Privileges
1518  * If specified, the function will use this set of privileges to audit.
1519  *
1520  * @param[in] ObjectCreation
1521  * Set this to TRUE if the object has just been created.
1522  *
1523  * @param[in] AccessGranted
1524  * Set this to TRUE if the access attempt was deemed as granted.
1525  *
1526  * @param[out] GenerateOnClose
1527  * A boolean flag returned to the caller once audit generation procedure
1528  * finishes.
1529  *
1530  * @return
1531  * Nothing.
1532  */
1533 VOID
1534 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)1535 SepOpenObjectAuditAlarm(
1536     _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
1537     _In_ PUNICODE_STRING SubsystemName,
1538     _In_opt_ PVOID HandleId,
1539     _In_ PUNICODE_STRING ObjectTypeName,
1540     _In_ PUNICODE_STRING ObjectName,
1541     _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor,
1542     _In_ PTOKEN ClientToken,
1543     _In_ ACCESS_MASK DesiredAccess,
1544     _In_ ACCESS_MASK GrantedAccess,
1545     _In_opt_ PPRIVILEGE_SET Privileges,
1546     _In_ BOOLEAN ObjectCreation,
1547     _In_ BOOLEAN AccessGranted,
1548     _Out_ PBOOLEAN GenerateOnClose)
1549 {
1550     DBG_UNREFERENCED_PARAMETER(SubjectContext);
1551     DBG_UNREFERENCED_PARAMETER(SubsystemName);
1552     DBG_UNREFERENCED_PARAMETER(HandleId);
1553     DBG_UNREFERENCED_PARAMETER(ObjectTypeName);
1554     DBG_UNREFERENCED_PARAMETER(ObjectName);
1555     DBG_UNREFERENCED_PARAMETER(SecurityDescriptor);
1556     DBG_UNREFERENCED_PARAMETER(ClientToken);
1557     DBG_UNREFERENCED_PARAMETER(DesiredAccess);
1558     DBG_UNREFERENCED_PARAMETER(GrantedAccess);
1559     DBG_UNREFERENCED_PARAMETER(Privileges);
1560     DBG_UNREFERENCED_PARAMETER(ObjectCreation);
1561     DBG_UNREFERENCED_PARAMETER(AccessGranted);
1562     UNIMPLEMENTED;
1563     *GenerateOnClose = FALSE;
1564 }
1565 
1566 /**
1567  * @brief
1568  * Raises an alarm audit message when an object is about
1569  * to be opened.
1570  *
1571  * @param[in] SubsystemName
1572  * A Unicode string that points to a name of the subsystem.
1573  *
1574  * @param[in] HandleId
1575  * A handle to an ID used for identification instance for auditing.
1576  *
1577  * @param[in] ObjectTypeName
1578  * A Unicode string that points to an object type name.
1579  *
1580  * @param[in] ObjectName
1581  * The name of the object.
1582  *
1583  * @param[in] SecurityDescriptor
1584  * A security descriptor.
1585  *
1586  * @param[in] ClientTokenHandle
1587  * A handle to a client access token.
1588  *
1589  * @param[in] DesiredAccess
1590  * The desired access rights masks requested by the caller.
1591  *
1592  * @param[in] GrantedAccess
1593  * The granted access mask rights.
1594  *
1595  * @param[in] PrivilegeSet
1596  * If specified, the function will use this set of privileges to audit.
1597  *
1598  * @param[in] ObjectCreation
1599  * Set this to TRUE if the object has just been created.
1600  *
1601  * @param[in] AccessGranted
1602  * Set this to TRUE if the access attempt was deemed as granted.
1603  *
1604  * @param[out] GenerateOnClose
1605  * A boolean flag returned to the caller once audit generation procedure
1606  * finishes.
1607  *
1608  * @return
1609  * Returns STATUS_SUCCESS if all the operations have been completed successfully.
1610  * STATUS_PRIVILEGE_NOT_HELD is returned if the given subject context does not
1611  * hold the required audit privilege to actually begin auditing in the first place.
1612  * STATUS_BAD_IMPERSONATION_LEVEL is returned if the security impersonation level
1613  * of the client token is not on par with the impersonation level that alllows
1614  * impersonation. STATUS_INVALID_PARAMETER is returned if the caller has
1615  * submitted a bogus set of privileges as such array set exceeds the maximum
1616  * count of privileges that the kernel can accept. A failure NTSTATUS code
1617  * is returned otherwise.
1618  */
1619 __kernel_entry
1620 NTSTATUS
1621 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)1622 NtOpenObjectAuditAlarm(
1623     _In_ PUNICODE_STRING SubsystemName,
1624     _In_opt_ PVOID HandleId,
1625     _In_ PUNICODE_STRING ObjectTypeName,
1626     _In_ PUNICODE_STRING ObjectName,
1627     _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor,
1628     _In_ HANDLE ClientTokenHandle,
1629     _In_ ACCESS_MASK DesiredAccess,
1630     _In_ ACCESS_MASK GrantedAccess,
1631     _In_opt_ PPRIVILEGE_SET PrivilegeSet,
1632     _In_ BOOLEAN ObjectCreation,
1633     _In_ BOOLEAN AccessGranted,
1634     _Out_ PBOOLEAN GenerateOnClose)
1635 {
1636     PTOKEN ClientToken;
1637     PSECURITY_DESCRIPTOR CapturedSecurityDescriptor;
1638     UNICODE_STRING CapturedSubsystemName, CapturedObjectTypeName, CapturedObjectName;
1639     ULONG PrivilegeCount, PrivilegeSetSize;
1640     volatile PPRIVILEGE_SET CapturedPrivilegeSet;
1641     BOOLEAN LocalGenerateOnClose;
1642     PVOID CapturedHandleId;
1643     SECURITY_SUBJECT_CONTEXT SubjectContext;
1644     NTSTATUS Status;
1645     PAGED_CODE();
1646 
1647     /* Only user mode is supported! */
1648     ASSERT(ExGetPreviousMode() != KernelMode);
1649 
1650     /* Start clean */
1651     ClientToken = NULL;
1652     CapturedSecurityDescriptor = NULL;
1653     CapturedPrivilegeSet = NULL;
1654     CapturedSubsystemName.Buffer = NULL;
1655     CapturedObjectTypeName.Buffer = NULL;
1656     CapturedObjectName.Buffer = NULL;
1657 
1658     /* Reference the client token */
1659     Status = ObReferenceObjectByHandle(ClientTokenHandle,
1660                                        TOKEN_QUERY,
1661                                        SeTokenObjectType,
1662                                        UserMode,
1663                                        (PVOID*)&ClientToken,
1664                                        NULL);
1665     if (!NT_SUCCESS(Status))
1666     {
1667         DPRINT1("Failed to reference token handle %p: %lx\n",
1668                 ClientTokenHandle, Status);
1669         return Status;
1670     }
1671 
1672     /* Capture the security subject context */
1673     SeCaptureSubjectContext(&SubjectContext);
1674 
1675     /* Validate the token's impersonation level */
1676     if ((ClientToken->TokenType == TokenImpersonation) &&
1677         (ClientToken->ImpersonationLevel < SecurityIdentification))
1678     {
1679         DPRINT1("Invalid impersonation level (%u)\n", ClientToken->ImpersonationLevel);
1680         Status = STATUS_BAD_IMPERSONATION_LEVEL;
1681         goto Cleanup;
1682     }
1683 
1684     /* Check for audit privilege */
1685     if (!SeCheckAuditPrivilege(&SubjectContext, UserMode))
1686     {
1687         DPRINT1("Caller does not have SeAuditPrivilege\n");
1688         Status = STATUS_PRIVILEGE_NOT_HELD;
1689         goto Cleanup;
1690     }
1691 
1692     /* Check for NULL SecurityDescriptor */
1693     if (SecurityDescriptor == NULL)
1694     {
1695         /* Nothing to do */
1696         Status = STATUS_SUCCESS;
1697         goto Cleanup;
1698     }
1699 
1700     /* Capture the security descriptor */
1701     Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
1702                                          UserMode,
1703                                          PagedPool,
1704                                          FALSE,
1705                                          &CapturedSecurityDescriptor);
1706     if (!NT_SUCCESS(Status))
1707     {
1708         DPRINT1("Failed to capture security descriptor!\n");
1709         goto Cleanup;
1710     }
1711 
1712     _SEH2_TRY
1713     {
1714         /* Check if we have a privilege set */
1715         if (PrivilegeSet != NULL)
1716         {
1717             /* Probe the basic privilege set structure */
1718             ProbeForRead(PrivilegeSet, sizeof(PRIVILEGE_SET), sizeof(ULONG));
1719 
1720             /* Validate privilege count */
1721             PrivilegeCount = PrivilegeSet->PrivilegeCount;
1722             if (PrivilegeCount > SEP_PRIVILEGE_SET_MAX_COUNT)
1723             {
1724                 Status = STATUS_INVALID_PARAMETER;
1725                 _SEH2_YIELD(goto Cleanup);
1726             }
1727 
1728             /* Calculate the size of the PrivilegeSet structure */
1729             PrivilegeSetSize = FIELD_OFFSET(PRIVILEGE_SET, Privilege[PrivilegeCount]);
1730 
1731             /* Probe the whole structure */
1732             ProbeForRead(PrivilegeSet, PrivilegeSetSize, sizeof(ULONG));
1733 
1734             /* Allocate a temp buffer */
1735             CapturedPrivilegeSet = ExAllocatePoolWithTag(PagedPool,
1736                                                          PrivilegeSetSize,
1737                                                          TAG_PRIVILEGE_SET);
1738             if (CapturedPrivilegeSet == NULL)
1739             {
1740                 DPRINT1("Failed to allocate %u bytes\n", PrivilegeSetSize);
1741                 Status = STATUS_INSUFFICIENT_RESOURCES;
1742                 _SEH2_YIELD(goto Cleanup);
1743             }
1744 
1745             /* Copy the privileges */
1746             RtlCopyMemory(CapturedPrivilegeSet, PrivilegeSet, PrivilegeSetSize);
1747         }
1748 
1749         if (HandleId != NULL)
1750         {
1751             ProbeForRead(HandleId, sizeof(PVOID), sizeof(PVOID));
1752             CapturedHandleId = *(PVOID*)HandleId;
1753         }
1754 
1755         ProbeForWrite(GenerateOnClose, sizeof(BOOLEAN), sizeof(BOOLEAN));
1756     }
1757     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1758     {
1759         Status = _SEH2_GetExceptionCode();
1760         DPRINT1("Exception while probing parameters: 0x%lx\n", Status);
1761         _SEH2_YIELD(goto Cleanup);
1762     }
1763     _SEH2_END;
1764 
1765     /* Probe and capture the subsystem name */
1766     Status = ProbeAndCaptureUnicodeString(&CapturedSubsystemName,
1767                                           UserMode,
1768                                           SubsystemName);
1769     if (!NT_SUCCESS(Status))
1770     {
1771         DPRINT1("Failed to capture subsystem name!\n");
1772         goto Cleanup;
1773     }
1774 
1775     /* Probe and capture the object type name */
1776     Status = ProbeAndCaptureUnicodeString(&CapturedObjectTypeName,
1777                                           UserMode,
1778                                           ObjectTypeName);
1779     if (!NT_SUCCESS(Status))
1780     {
1781         DPRINT1("Failed to capture object type name!\n");
1782         goto Cleanup;
1783     }
1784 
1785     /* Probe and capture the object name */
1786     Status = ProbeAndCaptureUnicodeString(&CapturedObjectName,
1787                                           UserMode,
1788                                           ObjectName);
1789     if (!NT_SUCCESS(Status))
1790     {
1791         DPRINT1("Failed to capture object name!\n");
1792         goto Cleanup;
1793     }
1794 
1795     /* Call the internal function */
1796     SepOpenObjectAuditAlarm(&SubjectContext,
1797                             &CapturedSubsystemName,
1798                             CapturedHandleId,
1799                             &CapturedObjectTypeName,
1800                             &CapturedObjectName,
1801                             CapturedSecurityDescriptor,
1802                             ClientToken,
1803                             DesiredAccess,
1804                             GrantedAccess,
1805                             CapturedPrivilegeSet,
1806                             ObjectCreation,
1807                             AccessGranted,
1808                             &LocalGenerateOnClose);
1809 
1810     Status = STATUS_SUCCESS;
1811 
1812     /* Enter SEH to copy the data back to user mode */
1813     _SEH2_TRY
1814     {
1815         *GenerateOnClose = LocalGenerateOnClose;
1816     }
1817     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1818     {
1819         Status = _SEH2_GetExceptionCode();
1820         DPRINT1("Exception while copying back data: 0x%lx\n", Status);
1821     }
1822     _SEH2_END;
1823 
1824 Cleanup:
1825 
1826     if (CapturedObjectName.Buffer != NULL)
1827         ReleaseCapturedUnicodeString(&CapturedObjectName, UserMode);
1828 
1829     if (CapturedObjectTypeName.Buffer != NULL)
1830         ReleaseCapturedUnicodeString(&CapturedObjectTypeName, UserMode);
1831 
1832     if (CapturedSubsystemName.Buffer != NULL)
1833         ReleaseCapturedUnicodeString(&CapturedSubsystemName, UserMode);
1834 
1835     if (CapturedSecurityDescriptor != NULL)
1836         SeReleaseSecurityDescriptor(CapturedSecurityDescriptor, UserMode, FALSE);
1837 
1838     if (CapturedPrivilegeSet != NULL)
1839         ExFreePoolWithTag(CapturedPrivilegeSet, TAG_PRIVILEGE_SET);
1840 
1841     /* Release the security subject context */
1842     SeReleaseSubjectContext(&SubjectContext);
1843 
1844     ObDereferenceObject(ClientToken);
1845 
1846     return Status;
1847 }
1848 
1849 /**
1850  * @brief
1851  * Raises an alarm audit message when a caller attempts to request
1852  * a privileged service call.
1853  *
1854  * @param[in] SubsystemName
1855  * A Unicode string that points to a name of the subsystem.
1856  *
1857  * @param[in] ServiceName
1858  * A Unicode string that points to a name of the privileged service.
1859  *
1860  * @param[in] ClientTokenHandle
1861  * A handle to a client access token.
1862  *
1863  * @param[in] Privileges
1864  * An array set of privileges.
1865  *
1866  * @param[in] AccessGranted
1867  * Set this to TRUE if the access attempt was deemed as granted.
1868  *
1869  * @return
1870  * Returns STATUS_SUCCESS if all the operations have been completed successfully.
1871  * STATUS_PRIVILEGE_NOT_HELD is returned if the given subject context does not
1872  * hold the required audit privilege to actually begin auditing in the first place.
1873  * STATUS_BAD_IMPERSONATION_LEVEL is returned if the security impersonation level
1874  * of the client token is not on par with the impersonation level that alllows
1875  * impersonation. STATUS_INVALID_PARAMETER is returned if the caller has
1876  * submitted a bogus set of privileges as such array set exceeds the maximum
1877  * count of privileges that the kernel can accept. A failure NTSTATUS code
1878  * is returned otherwise.
1879  */
1880 __kernel_entry
1881 NTSTATUS
1882 NTAPI
NtPrivilegedServiceAuditAlarm(_In_opt_ PUNICODE_STRING SubsystemName,_In_opt_ PUNICODE_STRING ServiceName,_In_ HANDLE ClientTokenHandle,_In_ PPRIVILEGE_SET Privileges,_In_ BOOLEAN AccessGranted)1883 NtPrivilegedServiceAuditAlarm(
1884     _In_opt_ PUNICODE_STRING SubsystemName,
1885     _In_opt_ PUNICODE_STRING ServiceName,
1886     _In_ HANDLE ClientTokenHandle,
1887     _In_ PPRIVILEGE_SET Privileges,
1888     _In_ BOOLEAN AccessGranted)
1889 {
1890     KPROCESSOR_MODE PreviousMode;
1891     PTOKEN ClientToken;
1892     volatile PPRIVILEGE_SET CapturedPrivileges = NULL;
1893     UNICODE_STRING CapturedSubsystemName;
1894     UNICODE_STRING CapturedServiceName;
1895     ULONG PrivilegeCount, PrivilegesSize;
1896     SECURITY_SUBJECT_CONTEXT SubjectContext;
1897     NTSTATUS Status;
1898     PAGED_CODE();
1899 
1900     /* Get the previous mode (only user mode is supported!) */
1901     PreviousMode = ExGetPreviousMode();
1902     ASSERT(PreviousMode != KernelMode);
1903 
1904     CapturedSubsystemName.Buffer = NULL;
1905     CapturedServiceName.Buffer = NULL;
1906 
1907     /* Reference the client token */
1908     Status = ObReferenceObjectByHandle(ClientTokenHandle,
1909                                        TOKEN_QUERY,
1910                                        SeTokenObjectType,
1911                                        PreviousMode,
1912                                        (PVOID*)&ClientToken,
1913                                        NULL);
1914     if (!NT_SUCCESS(Status))
1915     {
1916         DPRINT1("Failed to reference client token: 0x%lx\n", Status);
1917         return Status;
1918     }
1919 
1920     /* Validate the token's impersonation level */
1921     if ((ClientToken->TokenType == TokenImpersonation) &&
1922         (ClientToken->ImpersonationLevel < SecurityIdentification))
1923     {
1924         DPRINT1("Invalid impersonation level (%u)\n", ClientToken->ImpersonationLevel);
1925         ObDereferenceObject(ClientToken);
1926         return STATUS_BAD_IMPERSONATION_LEVEL;
1927     }
1928 
1929     /* Capture the security subject context */
1930     SeCaptureSubjectContext(&SubjectContext);
1931 
1932     /* Check for audit privilege */
1933     if (!SeCheckAuditPrivilege(&SubjectContext, PreviousMode))
1934     {
1935         DPRINT1("Caller does not have SeAuditPrivilege\n");
1936         Status = STATUS_PRIVILEGE_NOT_HELD;
1937         goto Cleanup;
1938     }
1939 
1940     /* Do we have a subsystem name? */
1941     if (SubsystemName != NULL)
1942     {
1943         /* Probe and capture the subsystem name */
1944         Status = ProbeAndCaptureUnicodeString(&CapturedSubsystemName,
1945                                               PreviousMode,
1946                                               SubsystemName);
1947         if (!NT_SUCCESS(Status))
1948         {
1949             DPRINT1("Failed to capture subsystem name!\n");
1950             goto Cleanup;
1951         }
1952     }
1953 
1954     /* Do we have a service name? */
1955     if (ServiceName != NULL)
1956     {
1957         /* Probe and capture the service name */
1958         Status = ProbeAndCaptureUnicodeString(&CapturedServiceName,
1959                                               PreviousMode,
1960                                               ServiceName);
1961         if (!NT_SUCCESS(Status))
1962         {
1963             DPRINT1("Failed to capture service name!\n");
1964             goto Cleanup;
1965         }
1966     }
1967 
1968     _SEH2_TRY
1969     {
1970         /* Probe the basic privilege set structure */
1971         ProbeForRead(Privileges, sizeof(PRIVILEGE_SET), sizeof(ULONG));
1972 
1973         /* Validate privilege count */
1974         PrivilegeCount = Privileges->PrivilegeCount;
1975         if (PrivilegeCount > SEP_PRIVILEGE_SET_MAX_COUNT)
1976         {
1977             Status = STATUS_INVALID_PARAMETER;
1978             _SEH2_YIELD(goto Cleanup);
1979         }
1980 
1981         /* Calculate the size of the Privileges structure */
1982         PrivilegesSize = FIELD_OFFSET(PRIVILEGE_SET, Privilege[PrivilegeCount]);
1983 
1984         /* Probe the whole structure */
1985         ProbeForRead(Privileges, PrivilegesSize, sizeof(ULONG));
1986 
1987         /* Allocate a temp buffer */
1988         CapturedPrivileges = ExAllocatePoolWithTag(PagedPool,
1989                                                    PrivilegesSize,
1990                                                    TAG_PRIVILEGE_SET);
1991         if (CapturedPrivileges == NULL)
1992         {
1993             DPRINT1("Failed to allocate %u bytes\n", PrivilegesSize);
1994             Status = STATUS_INSUFFICIENT_RESOURCES;
1995             _SEH2_YIELD(goto Cleanup);
1996         }
1997 
1998         /* Copy the privileges */
1999         RtlCopyMemory(CapturedPrivileges, Privileges, PrivilegesSize);
2000     }
2001     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2002     {
2003         Status = _SEH2_GetExceptionCode();
2004         DPRINT1("Got exception 0x%lx\n", Status);
2005         _SEH2_YIELD(goto Cleanup);
2006     }
2007     _SEH2_END;
2008 
2009     /* Call the internal function */
2010     SepAdtPrivilegedServiceAuditAlarm(&SubjectContext,
2011                                       SubsystemName ? &CapturedSubsystemName : NULL,
2012                                       ServiceName ? &CapturedServiceName : NULL,
2013                                       ClientToken,
2014                                       SubjectContext.PrimaryToken,
2015                                       CapturedPrivileges,
2016                                       AccessGranted);
2017 
2018     Status = STATUS_SUCCESS;
2019 
2020 Cleanup:
2021     /* Cleanup resources */
2022     if (CapturedSubsystemName.Buffer != NULL)
2023         ReleaseCapturedUnicodeString(&CapturedSubsystemName, PreviousMode);
2024 
2025     if (CapturedServiceName.Buffer != NULL)
2026         ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
2027 
2028     if (CapturedPrivileges != NULL)
2029         ExFreePoolWithTag(CapturedPrivileges, TAG_PRIVILEGE_SET);
2030 
2031     /* Release the security subject context */
2032     SeReleaseSubjectContext(&SubjectContext);
2033 
2034     ObDereferenceObject(ClientToken);
2035 
2036     return Status;
2037 }
2038 
2039 /**
2040  * @brief
2041  * Raises an alarm audit message when a caller attempts to access a
2042  * privileged object.
2043  *
2044  * @param[in] SubsystemName
2045  * A Unicode string that points to a name of the subsystem.
2046  *
2047  * @param[in] HandleId
2048  * A handle to an ID that is used as identification instance for auditing.
2049  *
2050  * @param[in] ClientToken
2051  * A handle to a client access token.
2052  *
2053  * @param[in] DesiredAccess
2054  * A handle to a client access token.
2055  *
2056  * @param[in] Privileges
2057  * An array set of privileges.
2058  *
2059  * @param[in] AccessGranted
2060  * Set this to TRUE if the access attempt was deemed as granted.
2061  *
2062  * @return
2063  * To be added...
2064  */
2065 NTSTATUS NTAPI
NtPrivilegeObjectAuditAlarm(_In_ PUNICODE_STRING SubsystemName,_In_ PVOID HandleId,_In_ HANDLE ClientToken,_In_ ULONG DesiredAccess,_In_ PPRIVILEGE_SET Privileges,_In_ BOOLEAN AccessGranted)2066 NtPrivilegeObjectAuditAlarm(
2067     _In_ PUNICODE_STRING SubsystemName,
2068     _In_ PVOID HandleId,
2069     _In_ HANDLE ClientToken,
2070     _In_ ULONG DesiredAccess,
2071     _In_ PPRIVILEGE_SET Privileges,
2072     _In_ BOOLEAN AccessGranted)
2073 {
2074     UNIMPLEMENTED;
2075     return STATUS_NOT_IMPLEMENTED;
2076 }
2077 
2078 /**
2079  * @brief
2080  * Raises an alarm audit message when a caller attempts to access an
2081  * object and determine if the access can be made.
2082  *
2083  * @param[in] SubsystemName
2084  * A Unicode string that points to a name of the subsystem.
2085  *
2086  * @param[in] HandleId
2087  * A handle to an ID that is used as identification instance for auditing.
2088  *
2089  * @param[in] ObjectTypeName
2090  * The name of the object type.
2091  *
2092  * @param[in] ObjectName
2093  * The object name.
2094  *
2095  * @param[in] SecurityDescriptor
2096  * A security descriptor.
2097  *
2098  * @param[in] DesiredAccess
2099  * The desired access rights masks requested by the caller.
2100  *
2101  * @param[in] GenericMapping
2102  * The generic mapping of access mask rights.
2103  *
2104  * @param[in] ObjectCreation
2105  * Set this to TRUE if the object has just been created.
2106  *
2107  * @param[out] GrantedAccess
2108  * Returns the granted access rights.
2109  *
2110  * @param[out] AccessStatus
2111  * Returns a NTSTATUS status code indicating whether access check
2112  * can be granted or not.
2113  *
2114  * @param[out] GenerateOnClose
2115  * Returns TRUE if the function has generated a list of granted access rights and
2116  * status codes on termination, FALSE otherwise.
2117  *
2118  * @return
2119  * See SepAccessCheckAndAuditAlarm.
2120  */
2121 _Must_inspect_result_
2122 __kernel_entry
2123 NTSTATUS
2124 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)2125 NtAccessCheckAndAuditAlarm(
2126     _In_ PUNICODE_STRING SubsystemName,
2127     _In_opt_ PVOID HandleId,
2128     _In_ PUNICODE_STRING ObjectTypeName,
2129     _In_ PUNICODE_STRING ObjectName,
2130     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
2131     _In_ ACCESS_MASK DesiredAccess,
2132     _In_ PGENERIC_MAPPING GenericMapping,
2133     _In_ BOOLEAN ObjectCreation,
2134     _Out_ PACCESS_MASK GrantedAccess,
2135     _Out_ PNTSTATUS AccessStatus,
2136     _Out_ PBOOLEAN GenerateOnClose)
2137 {
2138     /* Call the internal function */
2139     return SepAccessCheckAndAuditAlarm(SubsystemName,
2140                                        HandleId,
2141                                        NULL,
2142                                        ObjectTypeName,
2143                                        ObjectName,
2144                                        SecurityDescriptor,
2145                                        NULL,
2146                                        DesiredAccess,
2147                                        AuditEventObjectAccess,
2148                                        0,
2149                                        NULL,
2150                                        0,
2151                                        GenericMapping,
2152                                        GrantedAccess,
2153                                        AccessStatus,
2154                                        GenerateOnClose,
2155                                        FALSE);
2156 }
2157 
2158 /**
2159  * @brief
2160  * Raises an alarm audit message when a caller attempts to access an
2161  * object and determine if the access can be made by type.
2162  *
2163  * @param[in] SubsystemName
2164  * A Unicode string that points to a name of the subsystem.
2165  *
2166  * @param[in] HandleId
2167  * A handle to an ID that is used as identification instance for auditing.
2168  *
2169  * @param[in] ObjectTypeName
2170  * The name of the object type.
2171  *
2172  * @param[in] ObjectName
2173  * The object name.
2174  *
2175  * @param[in] SecurityDescriptor
2176  * A security descriptor.
2177  *
2178  * @param[in] PrincipalSelfSid
2179  * A principal self user SID.
2180  *
2181  * @param[in] DesiredAccess
2182  * The desired access rights masks requested by the caller.
2183  *
2184  * @param[in] AuditType
2185  * Type of audit to start, influencing how the audit should
2186  * be done.
2187  *
2188  * @param[in] Flags
2189  * Flag bitmask, used to check if auditing can be done
2190  * without privileges.
2191  *
2192  * @param[in] ObjectTypeList
2193  * A list of object types.
2194  *
2195  * @param[in] ObjectTypeLength
2196  * The length size of the list.
2197  *
2198  * @param[in] GenericMapping
2199  * The generic mapping of access mask rights.
2200  *
2201  * @param[in] ObjectCreation
2202  * Set this to TRUE if the object has just been created.
2203  *
2204  * @param[out] GrantedAccess
2205  * Returns the granted access rights.
2206  *
2207  * @param[out] AccessStatus
2208  * Returns a NTSTATUS status code indicating whether access check
2209  * can be granted or not.
2210  *
2211  * @param[out] GenerateOnClose
2212  * Returns TRUE if the function has generated a list of granted access rights and
2213  * status codes on termination, FALSE otherwise.
2214  *
2215  * @return
2216  * See SepAccessCheckAndAuditAlarm.
2217  */
2218 _Must_inspect_result_
2219 __kernel_entry
2220 NTSTATUS
2221 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)2222 NtAccessCheckByTypeAndAuditAlarm(
2223     _In_ PUNICODE_STRING SubsystemName,
2224     _In_opt_ PVOID HandleId,
2225     _In_ PUNICODE_STRING ObjectTypeName,
2226     _In_ PUNICODE_STRING ObjectName,
2227     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
2228     _In_opt_ PSID PrincipalSelfSid,
2229     _In_ ACCESS_MASK DesiredAccess,
2230     _In_ AUDIT_EVENT_TYPE AuditType,
2231     _In_ ULONG Flags,
2232     _In_reads_opt_(ObjectTypeLength) POBJECT_TYPE_LIST ObjectTypeList,
2233     _In_ ULONG ObjectTypeLength,
2234     _In_ PGENERIC_MAPPING GenericMapping,
2235     _In_ BOOLEAN ObjectCreation,
2236     _Out_ PACCESS_MASK GrantedAccess,
2237     _Out_ PNTSTATUS AccessStatus,
2238     _Out_ PBOOLEAN GenerateOnClose)
2239 {
2240     /* Call the internal function */
2241     return SepAccessCheckAndAuditAlarm(SubsystemName,
2242                                        HandleId,
2243                                        NULL,
2244                                        ObjectTypeName,
2245                                        ObjectName,
2246                                        SecurityDescriptor,
2247                                        PrincipalSelfSid,
2248                                        DesiredAccess,
2249                                        AuditType,
2250                                        Flags,
2251                                        ObjectTypeList,
2252                                        ObjectTypeLength,
2253                                        GenericMapping,
2254                                        GrantedAccess,
2255                                        AccessStatus,
2256                                        GenerateOnClose,
2257                                        FALSE);
2258 }
2259 
2260 /**
2261  * @brief
2262  * Raises an alarm audit message when a caller attempts to access an
2263  * object and determine if the access can be made by given type result.
2264  *
2265  * @param[in] SubsystemName
2266  * A Unicode string that points to a name of the subsystem.
2267  *
2268  * @param[in] HandleId
2269  * A handle to an ID that is used as identification instance for auditing.
2270  *
2271  * @param[in] ObjectTypeName
2272  * The name of the object type.
2273  *
2274  * @param[in] ObjectName
2275  * The object name.
2276  *
2277  * @param[in] SecurityDescriptor
2278  * A security descriptor.
2279  *
2280  * @param[in] PrincipalSelfSid
2281  * A principal self user SID.
2282  *
2283  * @param[in] DesiredAccess
2284  * The desired access rights masks requested by the caller.
2285  *
2286  * @param[in] AuditType
2287  * Type of audit to start, influencing how the audit should
2288  * be done.
2289  *
2290  * @param[in] Flags
2291  * Flag bitmask, used to check if auditing can be done
2292  * without privileges.
2293  *
2294  * @param[in] ObjectTypeList
2295  * A list of object types.
2296  *
2297  * @param[in] ObjectTypeLength
2298  * The length size of the list.
2299  *
2300  * @param[in] GenericMapping
2301  * The generic mapping of access mask rights.
2302  *
2303  * @param[in] ObjectCreation
2304  * Set this to TRUE if the object has just been created.
2305  *
2306  * @param[out] GrantedAccessList
2307  * Returns the granted access rights.
2308  *
2309  * @param[out] AccessStatusList
2310  * Returns a NTSTATUS status code indicating whether access check
2311  * can be granted or not.
2312  *
2313  * @param[out] GenerateOnClose
2314  * Returns TRUE if the function has generated a list of granted access rights and
2315  * status codes on termination, FALSE otherwise.
2316  *
2317  * @return
2318  * See SepAccessCheckAndAuditAlarm.
2319  */
2320 _Must_inspect_result_
2321 __kernel_entry
2322 NTSTATUS
2323 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)2324 NtAccessCheckByTypeResultListAndAuditAlarm(
2325     _In_ PUNICODE_STRING SubsystemName,
2326     _In_opt_ PVOID HandleId,
2327     _In_ PUNICODE_STRING ObjectTypeName,
2328     _In_ PUNICODE_STRING ObjectName,
2329     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
2330     _In_opt_ PSID PrincipalSelfSid,
2331     _In_ ACCESS_MASK DesiredAccess,
2332     _In_ AUDIT_EVENT_TYPE AuditType,
2333     _In_ ULONG Flags,
2334     _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
2335     _In_ ULONG ObjectTypeListLength,
2336     _In_ PGENERIC_MAPPING GenericMapping,
2337     _In_ BOOLEAN ObjectCreation,
2338     _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccessList,
2339     _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatusList,
2340     _Out_ PBOOLEAN GenerateOnClose)
2341 {
2342     /* Call the internal function */
2343     return SepAccessCheckAndAuditAlarm(SubsystemName,
2344                                        HandleId,
2345                                        NULL,
2346                                        ObjectTypeName,
2347                                        ObjectName,
2348                                        SecurityDescriptor,
2349                                        PrincipalSelfSid,
2350                                        DesiredAccess,
2351                                        AuditType,
2352                                        Flags,
2353                                        ObjectTypeList,
2354                                        ObjectTypeListLength,
2355                                        GenericMapping,
2356                                        GrantedAccessList,
2357                                        AccessStatusList,
2358                                        GenerateOnClose,
2359                                        TRUE);
2360 }
2361 
2362 /**
2363  * @brief
2364  * Raises an alarm audit message when a caller attempts to access an
2365  * object and determine if the access can be made by given type result
2366  * and a token handle.
2367  *
2368  * @param[in] SubsystemName
2369  * A Unicode string that points to a name of the subsystem.
2370  *
2371  * @param[in] HandleId
2372  * A handle to an ID that is used as identification instance for auditing.
2373  *
2374  * @param[in] ClientToken
2375  * A handle to a client access token.
2376  *
2377  * @param[in] ObjectTypeName
2378  * The name of the object type.
2379  *
2380  * @param[in] ObjectName
2381  * The object name.
2382  *
2383  * @param[in] SecurityDescriptor
2384  * A security descriptor.
2385  *
2386  * @param[in] PrincipalSelfSid
2387  * A principal self user SID.
2388  *
2389  * @param[in] DesiredAccess
2390  * The desired access rights masks requested by the caller.
2391  *
2392  * @param[in] AuditType
2393  * Type of audit to start, influencing how the audit should
2394  * be done.
2395  *
2396  * @param[in] Flags
2397  * Flag bitmask, used to check if auditing can be done
2398  * without privileges.
2399  *
2400  * @param[in] ObjectTypeList
2401  * A list of object types.
2402  *
2403  * @param[in] ObjectTypeLength
2404  * The length size of the list.
2405  *
2406  * @param[in] GenericMapping
2407  * The generic mapping of access mask rights.
2408  *
2409  * @param[in] ObjectCreation
2410  * Set this to TRUE if the object has just been created.
2411  *
2412  * @param[out] GrantedAccessList
2413  * Returns the granted access rights.
2414  *
2415  * @param[out] AccessStatusList
2416  * Returns a NTSTATUS status code indicating whether access check
2417  * can be granted or not.
2418  *
2419  * @param[out] GenerateOnClose
2420  * Returns TRUE if the function has generated a list of granted access rights and
2421  * status codes on termination, FALSE otherwise.
2422  *
2423  * @return
2424  * See SepAccessCheckAndAuditAlarm.
2425  */
2426 _Must_inspect_result_
2427 __kernel_entry
2428 NTSTATUS
2429 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)2430 NtAccessCheckByTypeResultListAndAuditAlarmByHandle(
2431     _In_ PUNICODE_STRING SubsystemName,
2432     _In_opt_ PVOID HandleId,
2433     _In_ HANDLE ClientToken,
2434     _In_ PUNICODE_STRING ObjectTypeName,
2435     _In_ PUNICODE_STRING ObjectName,
2436     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
2437     _In_opt_ PSID PrincipalSelfSid,
2438     _In_ ACCESS_MASK DesiredAccess,
2439     _In_ AUDIT_EVENT_TYPE AuditType,
2440     _In_ ULONG Flags,
2441     _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
2442     _In_ ULONG ObjectTypeListLength,
2443     _In_ PGENERIC_MAPPING GenericMapping,
2444     _In_ BOOLEAN ObjectCreation,
2445     _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccessList,
2446     _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatusList,
2447     _Out_ PBOOLEAN GenerateOnClose)
2448 {
2449     UNREFERENCED_PARAMETER(ObjectCreation);
2450 
2451     /* Call the internal function */
2452     return SepAccessCheckAndAuditAlarm(SubsystemName,
2453                                        HandleId,
2454                                        &ClientToken,
2455                                        ObjectTypeName,
2456                                        ObjectName,
2457                                        SecurityDescriptor,
2458                                        PrincipalSelfSid,
2459                                        DesiredAccess,
2460                                        AuditType,
2461                                        Flags,
2462                                        ObjectTypeList,
2463                                        ObjectTypeListLength,
2464                                        GenericMapping,
2465                                        GrantedAccessList,
2466                                        AccessStatusList,
2467                                        GenerateOnClose,
2468                                        TRUE);
2469 }
2470 
2471 /* EOF */
2472