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