xref: /reactos/ntoskrnl/se/audit.c (revision 34593d93)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS kernel
4  * FILE:            ntoskrnl/se/audit.c
5  * PURPOSE:         Audit functions
6  *
7  * PROGRAMMERS:     Eric Kohl
8  *                  Timo Kreuzer (timo.kreuzer@reactos.org)
9  */
10 
11 /* INCLUDES *******************************************************************/
12 
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16 
17 #define SEP_PRIVILEGE_SET_MAX_COUNT 60
18 
19 UNICODE_STRING SeSubsystemName = RTL_CONSTANT_STRING(L"Security");
20 
21 /* PRIVATE FUNCTIONS***********************************************************/
22 
23 BOOLEAN
24 NTAPI
25 SeDetailedAuditingWithToken(IN PTOKEN Token)
26 {
27     /* FIXME */
28     return FALSE;
29 }
30 
31 VOID
32 NTAPI
33 SeAuditProcessCreate(IN PEPROCESS Process)
34 {
35     /* FIXME */
36 }
37 
38 VOID
39 NTAPI
40 SeAuditProcessExit(IN PEPROCESS Process)
41 {
42     /* FIXME */
43 }
44 
45 NTSTATUS
46 NTAPI
47 SeInitializeProcessAuditName(IN PFILE_OBJECT FileObject,
48                              IN BOOLEAN DoAudit,
49                              OUT POBJECT_NAME_INFORMATION *AuditInfo)
50 {
51     OBJECT_NAME_INFORMATION LocalNameInfo;
52     POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
53     ULONG ReturnLength = 8;
54     NTSTATUS Status;
55 
56     PAGED_CODE();
57     ASSERT(AuditInfo);
58 
59     /* Check if we should do auditing */
60     if (DoAudit)
61     {
62         /* FIXME: TODO */
63     }
64 
65     /* Now query the name */
66     Status = ObQueryNameString(FileObject,
67                                &LocalNameInfo,
68                                sizeof(LocalNameInfo),
69                                &ReturnLength);
70     if (((Status == STATUS_BUFFER_OVERFLOW) ||
71          (Status == STATUS_BUFFER_TOO_SMALL) ||
72          (Status == STATUS_INFO_LENGTH_MISMATCH)) &&
73         (ReturnLength != sizeof(LocalNameInfo)))
74     {
75         /* Allocate required size */
76         ObjectNameInfo = ExAllocatePoolWithTag(NonPagedPool,
77                                                ReturnLength,
78                                                TAG_SEPA);
79         if (ObjectNameInfo)
80         {
81             /* Query the name again */
82             Status = ObQueryNameString(FileObject,
83                                        ObjectNameInfo,
84                                        ReturnLength,
85                                        &ReturnLength);
86         }
87     }
88 
89     /* Check if we got here due to failure */
90     if ((ObjectNameInfo) &&
91         (!(NT_SUCCESS(Status)) || (ReturnLength == sizeof(LocalNameInfo))))
92     {
93         /* First, free any buffer we might've allocated */
94         ASSERT(FALSE);
95         if (ObjectNameInfo) ExFreePool(ObjectNameInfo);
96 
97         /* Now allocate a temporary one */
98         ReturnLength = sizeof(OBJECT_NAME_INFORMATION);
99         ObjectNameInfo = ExAllocatePoolWithTag(NonPagedPool,
100                                                sizeof(OBJECT_NAME_INFORMATION),
101                                                TAG_SEPA);
102         if (ObjectNameInfo)
103         {
104             /* Clear it */
105             RtlZeroMemory(ObjectNameInfo, ReturnLength);
106             Status = STATUS_SUCCESS;
107         }
108     }
109 
110     /* Check if memory allocation failed */
111     if (!ObjectNameInfo) Status = STATUS_NO_MEMORY;
112 
113     /* Return the audit name */
114     *AuditInfo = ObjectNameInfo;
115 
116     /* Return status */
117     return Status;
118 }
119 
120 NTSTATUS
121 NTAPI
122 SeLocateProcessImageName(IN PEPROCESS Process,
123                          OUT PUNICODE_STRING *ProcessImageName)
124 {
125     POBJECT_NAME_INFORMATION AuditName;
126     PUNICODE_STRING ImageName;
127     PFILE_OBJECT FileObject;
128     NTSTATUS Status = STATUS_SUCCESS;
129 
130     PAGED_CODE();
131 
132     /* Assume failure */
133     *ProcessImageName = NULL;
134 
135     /* Check if we have audit info */
136     AuditName = Process->SeAuditProcessCreationInfo.ImageFileName;
137     if (!AuditName)
138     {
139         /* Get the file object */
140         Status = PsReferenceProcessFilePointer(Process, &FileObject);
141         if (!NT_SUCCESS(Status)) return Status;
142 
143         /* Initialize the audit structure */
144         Status = SeInitializeProcessAuditName(FileObject, TRUE, &AuditName);
145         if (NT_SUCCESS(Status))
146         {
147             /* Set it */
148             if (InterlockedCompareExchangePointer((PVOID*)&Process->
149                                                   SeAuditProcessCreationInfo.ImageFileName,
150                                                   AuditName,
151                                                   NULL))
152             {
153                 /* Someone beat us to it, deallocate our copy */
154                 ExFreePool(AuditName);
155             }
156         }
157 
158         /* Dereference the file object */
159         ObDereferenceObject(FileObject);
160         if (!NT_SUCCESS(Status)) return Status;
161     }
162 
163     /* Get audit info again, now we have it for sure */
164     AuditName = Process->SeAuditProcessCreationInfo.ImageFileName;
165 
166     /* Allocate the output string */
167     ImageName = ExAllocatePoolWithTag(NonPagedPool,
168                                       AuditName->Name.MaximumLength +
169                                       sizeof(UNICODE_STRING),
170                                       TAG_SEPA);
171     if (!ImageName) return STATUS_NO_MEMORY;
172 
173     /* Make a copy of it */
174     RtlCopyMemory(ImageName,
175                   &AuditName->Name,
176                   AuditName->Name.MaximumLength + sizeof(UNICODE_STRING));
177 
178     /* Fix up the buffer */
179     ImageName->Buffer = (PWSTR)(ImageName + 1);
180 
181     /* Return it */
182     *ProcessImageName = ImageName;
183 
184     /* Return status */
185     return Status;
186 }
187 
188 VOID
189 NTAPI
190 SepAdtCloseObjectAuditAlarm(
191     PUNICODE_STRING SubsystemName,
192     PVOID HandleId,
193     PSID Sid)
194 {
195     UNIMPLEMENTED;
196 }
197 
198 VOID
199 NTAPI
200 SepAdtPrivilegedServiceAuditAlarm(
201     PSECURITY_SUBJECT_CONTEXT SubjectContext,
202     _In_opt_ PUNICODE_STRING SubsystemName,
203     _In_opt_ PUNICODE_STRING ServiceName,
204     _In_ PTOKEN Token,
205     _In_ PTOKEN PrimaryToken,
206     _In_ PPRIVILEGE_SET Privileges,
207     _In_ BOOLEAN AccessGranted)
208 {
209     DPRINT("SepAdtPrivilegedServiceAuditAlarm is unimplemented\n");
210 }
211 
212 VOID
213 NTAPI
214 SePrivilegedServiceAuditAlarm(
215     _In_opt_ PUNICODE_STRING ServiceName,
216     _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
217     _In_ PPRIVILEGE_SET PrivilegeSet,
218     _In_ BOOLEAN AccessGranted)
219 {
220     PTOKEN EffectiveToken;
221     PSID UserSid;
222     PAGED_CODE();
223 
224     /* Get the effective token */
225     if (SubjectContext->ClientToken != NULL)
226         EffectiveToken = SubjectContext->ClientToken;
227     else
228         EffectiveToken = SubjectContext->PrimaryToken;
229 
230     /* Get the user SID */
231     UserSid = EffectiveToken->UserAndGroups->Sid;
232 
233     /* Check if this is the local system SID */
234     if (RtlEqualSid(UserSid, SeLocalSystemSid))
235     {
236         /* Nothing to do */
237         return;
238     }
239 
240     /* Check if this is the network service or local service SID */
241     if (RtlEqualSid(UserSid, SeExports->SeNetworkServiceSid) ||
242         RtlEqualSid(UserSid, SeExports->SeLocalServiceSid))
243     {
244         // FIXME: should continue for a certain set of privileges
245         return;
246     }
247 
248     /* Call the worker function */
249     SepAdtPrivilegedServiceAuditAlarm(SubjectContext,
250                                       &SeSubsystemName,
251                                       ServiceName,
252                                       SubjectContext->ClientToken,
253                                       SubjectContext->PrimaryToken,
254                                       PrivilegeSet,
255                                       AccessGranted);
256 
257 }
258 
259 
260 static
261 NTSTATUS
262 SeCaptureObjectTypeList(
263     _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
264     _In_ ULONG ObjectTypeListLength,
265     _In_ KPROCESSOR_MODE PreviousMode,
266     _Out_ POBJECT_TYPE_LIST *CapturedObjectTypeList)
267 {
268     SIZE_T Size;
269 
270     if (PreviousMode == KernelMode)
271     {
272         return STATUS_NOT_IMPLEMENTED;
273     }
274 
275     if (ObjectTypeListLength == 0)
276     {
277         *CapturedObjectTypeList = NULL;
278         return STATUS_SUCCESS;
279     }
280 
281     if (ObjectTypeList == NULL)
282     {
283         return STATUS_INVALID_PARAMETER;
284     }
285 
286     /* Calculate the list size and check for integer overflow */
287     Size = ObjectTypeListLength * sizeof(OBJECT_TYPE_LIST);
288     if (Size == 0)
289     {
290         return STATUS_INVALID_PARAMETER;
291     }
292 
293     /* Allocate a new list */
294     *CapturedObjectTypeList = ExAllocatePoolWithTag(PagedPool, Size, TAG_SEPA);
295     if (*CapturedObjectTypeList == NULL)
296     {
297         return STATUS_INSUFFICIENT_RESOURCES;
298     }
299 
300     _SEH2_TRY
301     {
302         ProbeForRead(ObjectTypeList, Size, sizeof(ULONG));
303         RtlCopyMemory(*CapturedObjectTypeList, ObjectTypeList, Size);
304     }
305     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
306     {
307         ExFreePoolWithTag(*CapturedObjectTypeList, TAG_SEPA);
308         *CapturedObjectTypeList = NULL;
309         _SEH2_YIELD(return _SEH2_GetExceptionCode());
310     }
311     _SEH2_END;
312 
313     return STATUS_SUCCESS;
314 }
315 
316 static
317 VOID
318 SeReleaseObjectTypeList(
319     _In_  _Post_invalid_ POBJECT_TYPE_LIST CapturedObjectTypeList,
320     _In_ KPROCESSOR_MODE PreviousMode)
321 {
322     if ((PreviousMode != KernelMode) && (CapturedObjectTypeList != NULL))
323         ExFreePoolWithTag(CapturedObjectTypeList, TAG_SEPA);
324 }
325 
326 _Must_inspect_result_
327 static
328 NTSTATUS
329 SepAccessCheckAndAuditAlarmWorker(
330     _In_ PUNICODE_STRING SubsystemName,
331     _In_opt_ PVOID HandleId,
332     _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
333     _In_ PUNICODE_STRING ObjectTypeName,
334     _In_ PUNICODE_STRING ObjectName,
335     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
336     _In_opt_ PSID PrincipalSelfSid,
337     _In_ ACCESS_MASK DesiredAccess,
338     _In_ AUDIT_EVENT_TYPE AuditType,
339     _In_ BOOLEAN HaveAuditPrivilege,
340     _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
341     _In_ ULONG ObjectTypeListLength,
342     _In_ PGENERIC_MAPPING GenericMapping,
343     _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccessList,
344     _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatusList,
345     _Out_ PBOOLEAN GenerateOnClose,
346     _In_ BOOLEAN UseResultList)
347 {
348     ULONG ResultListLength, i;
349 
350     /* Get the length of the result list */
351     ResultListLength = UseResultList ? ObjectTypeListLength : 1;
352 
353     /// FIXME: we should do some real work here...
354     UNIMPLEMENTED;
355 
356     /// HACK: we just pretend all access is granted!
357     for (i = 0; i < ResultListLength; i++)
358     {
359         GrantedAccessList[i] = DesiredAccess;
360         AccessStatusList[i] = STATUS_SUCCESS;
361     }
362 
363     *GenerateOnClose = FALSE;
364 
365     return STATUS_SUCCESS;
366 }
367 
368 _Must_inspect_result_
369 NTSTATUS
370 NTAPI
371 SepAccessCheckAndAuditAlarm(
372     _In_ PUNICODE_STRING SubsystemName,
373     _In_opt_ PVOID HandleId,
374     _In_ PHANDLE ClientTokenHandle,
375     _In_ PUNICODE_STRING ObjectTypeName,
376     _In_ PUNICODE_STRING ObjectName,
377     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
378     _In_opt_ PSID PrincipalSelfSid,
379     _In_ ACCESS_MASK DesiredAccess,
380     _In_ AUDIT_EVENT_TYPE AuditType,
381     _In_ ULONG Flags,
382     _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
383     _In_ ULONG ObjectTypeListLength,
384     _In_ PGENERIC_MAPPING GenericMapping,
385     _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccessList,
386     _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatusList,
387     _Out_ PBOOLEAN GenerateOnClose,
388     _In_ BOOLEAN UseResultList)
389 {
390     SECURITY_SUBJECT_CONTEXT SubjectContext;
391     ULONG ResultListLength;
392     GENERIC_MAPPING LocalGenericMapping;
393     PTOKEN SubjectContextToken, ClientToken;
394     BOOLEAN AllocatedResultLists;
395     BOOLEAN HaveAuditPrivilege;
396     PSECURITY_DESCRIPTOR CapturedSecurityDescriptor;
397     UNICODE_STRING CapturedSubsystemName, CapturedObjectTypeName, CapturedObjectName;
398     ACCESS_MASK GrantedAccess, *SafeGrantedAccessList;
399     NTSTATUS AccessStatus, *SafeAccessStatusList;
400     PSID CapturedPrincipalSelfSid;
401     POBJECT_TYPE_LIST CapturedObjectTypeList;
402     ULONG i;
403     BOOLEAN LocalGenerateOnClose;
404     NTSTATUS Status;
405     PAGED_CODE();
406 
407     /* Only user mode is supported! */
408     ASSERT(ExGetPreviousMode() != KernelMode);
409 
410     /* Start clean */
411     AllocatedResultLists = FALSE;
412     ClientToken = NULL;
413     CapturedSecurityDescriptor = NULL;
414     CapturedSubsystemName.Buffer = NULL;
415     CapturedObjectTypeName.Buffer = NULL;
416     CapturedObjectName.Buffer = NULL;
417     CapturedPrincipalSelfSid = NULL;
418     CapturedObjectTypeList = NULL;
419 
420     /* Validate AuditType */
421     if ((AuditType != AuditEventObjectAccess) &&
422         (AuditType != AuditEventDirectoryServiceAccess))
423     {
424         DPRINT1("Invalid audit type: %u\n", AuditType);
425         return STATUS_INVALID_PARAMETER;
426     }
427 
428     /* Capture the security subject context */
429     SeCaptureSubjectContext(&SubjectContext);
430 
431     /* Did the caller pass a token handle? */
432     if (ClientTokenHandle == NULL)
433     {
434         /* Check if we have a token in the subject context */
435         if (SubjectContext.ClientToken == NULL)
436         {
437             Status = STATUS_NO_IMPERSONATION_TOKEN;
438             DPRINT1("No token\n");
439             goto Cleanup;
440         }
441 
442         /* Check if we have a valid impersonation level */
443         if (SubjectContext.ImpersonationLevel < SecurityIdentification)
444         {
445             Status = STATUS_BAD_IMPERSONATION_LEVEL;
446             DPRINT1("Invalid impersonation level 0x%lx\n",
447                     SubjectContext.ImpersonationLevel);
448             goto Cleanup;
449         }
450     }
451 
452     /* Are we using a result list? */
453     if (UseResultList)
454     {
455         /* The list length equals the object type list length */
456         ResultListLength = ObjectTypeListLength;
457         if ((ResultListLength == 0) || (ResultListLength > 0x1000))
458         {
459             Status = STATUS_INVALID_PARAMETER;
460             DPRINT1("Invalid ResultListLength: 0x%lx\n", ResultListLength);
461             goto Cleanup;
462         }
463 
464         /* Allocate a safe buffer from paged pool */
465         SafeGrantedAccessList = ExAllocatePoolWithTag(PagedPool,
466                                                       2 * ResultListLength * sizeof(ULONG),
467                                                       TAG_SEPA);
468         if (SafeGrantedAccessList == NULL)
469         {
470             Status = STATUS_INSUFFICIENT_RESOURCES;
471             DPRINT1("Failed to allocate access lists\n");
472             goto Cleanup;
473         }
474 
475         SafeAccessStatusList = (PNTSTATUS)&SafeGrantedAccessList[ResultListLength];
476         AllocatedResultLists = TRUE;
477     }
478     else
479     {
480         /* List length is 1 */
481         ResultListLength = 1;
482         SafeGrantedAccessList = &GrantedAccess;
483         SafeAccessStatusList = &AccessStatus;
484     }
485 
486     _SEH2_TRY
487     {
488         /* Probe output buffers */
489         ProbeForWrite(AccessStatusList,
490                       ResultListLength * sizeof(*AccessStatusList),
491                       sizeof(*AccessStatusList));
492         ProbeForWrite(GrantedAccessList,
493                       ResultListLength * sizeof(*GrantedAccessList),
494                       sizeof(*GrantedAccessList));
495 
496         /* Probe generic mapping and make a local copy */
497         ProbeForRead(GenericMapping, sizeof(*GenericMapping), sizeof(ULONG));
498         LocalGenericMapping = * GenericMapping;
499     }
500     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
501     {
502         Status = _SEH2_GetExceptionCode();
503         DPRINT1("Exception while probing parameters: 0x%lx\n", Status);
504         _SEH2_YIELD(goto Cleanup);
505     }
506     _SEH2_END;
507 
508     /* Do we have a client token? */
509     if (ClientTokenHandle != NULL)
510     {
511         /* Reference the client token */
512         Status = ObReferenceObjectByHandle(*ClientTokenHandle,
513                                            TOKEN_QUERY,
514                                            SeTokenObjectType,
515                                            UserMode,
516                                            (PVOID*)&ClientToken,
517                                            NULL);
518         if (!NT_SUCCESS(Status))
519         {
520             DPRINT1("Failed to reference token handle %p: %lx\n",
521                     *ClientTokenHandle, Status);
522             goto Cleanup;
523         }
524 
525         SubjectContextToken = SubjectContext.ClientToken;
526         SubjectContext.ClientToken = ClientToken;
527     }
528 
529     /* Check for audit privilege */
530     HaveAuditPrivilege = SeCheckAuditPrivilege(&SubjectContext, UserMode);
531     if (!HaveAuditPrivilege && !(Flags & AUDIT_ALLOW_NO_PRIVILEGE))
532     {
533         DPRINT1("Caller does not have SeAuditPrivilege\n");
534         Status = STATUS_PRIVILEGE_NOT_HELD;
535         goto Cleanup;
536     }
537 
538     /* Generic access must already be mapped to non-generic access types! */
539     if (DesiredAccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL))
540     {
541         DPRINT1("Generic access rights requested: 0x%lx\n", DesiredAccess);
542         Status = STATUS_GENERIC_NOT_MAPPED;
543         goto Cleanup;
544     }
545 
546     /* Capture the security descriptor */
547     Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
548                                          UserMode,
549                                          PagedPool,
550                                          FALSE,
551                                          &CapturedSecurityDescriptor);
552     if (!NT_SUCCESS(Status))
553     {
554         DPRINT1("Failed to capture security descriptor!\n");
555         goto Cleanup;
556     }
557 
558     /* Validate the Security descriptor */
559     if ((SepGetOwnerFromDescriptor(CapturedSecurityDescriptor) == NULL) ||
560         (SepGetGroupFromDescriptor(CapturedSecurityDescriptor) == NULL))
561     {
562         Status = STATUS_INVALID_SECURITY_DESCR;
563         DPRINT1("Invalid security descriptor\n");
564         goto Cleanup;
565     }
566 
567     /* Probe and capture the subsystem name */
568     Status = ProbeAndCaptureUnicodeString(&CapturedSubsystemName,
569                                           UserMode,
570                                           SubsystemName);
571     if (!NT_SUCCESS(Status))
572     {
573         DPRINT1("Failed to capture subsystem name!\n");
574         goto Cleanup;
575     }
576 
577     /* Probe and capture the object type name */
578     Status = ProbeAndCaptureUnicodeString(&CapturedObjectTypeName,
579                                           UserMode,
580                                           ObjectTypeName);
581     if (!NT_SUCCESS(Status))
582     {
583         DPRINT1("Failed to capture object type name!\n");
584         goto Cleanup;
585     }
586 
587     /* Probe and capture the object name */
588     Status = ProbeAndCaptureUnicodeString(&CapturedObjectName,
589                                           UserMode,
590                                           ObjectName);
591     if (!NT_SUCCESS(Status))
592     {
593         DPRINT1("Failed to capture object name!\n");
594         goto Cleanup;
595     }
596 
597     /* Check if we have a PrincipalSelfSid */
598     if (PrincipalSelfSid != NULL)
599     {
600         /* Capture it */
601         Status = SepCaptureSid(PrincipalSelfSid,
602                                UserMode,
603                                PagedPool,
604                                FALSE,
605                                &CapturedPrincipalSelfSid);
606         if (!NT_SUCCESS(Status))
607         {
608             DPRINT1("Failed to capture PrincipalSelfSid!\n");
609             goto Cleanup;
610         }
611     }
612 
613     /* Capture the object type list */
614     Status = SeCaptureObjectTypeList(ObjectTypeList,
615                                      ObjectTypeListLength,
616                                      UserMode,
617                                      &CapturedObjectTypeList);
618     if (!NT_SUCCESS(Status))
619     {
620         DPRINT1("Failed to capture object type list!\n");
621         goto Cleanup;
622     }
623 
624     /* Call the worker routine with the captured buffers */
625     SepAccessCheckAndAuditAlarmWorker(&CapturedSubsystemName,
626                                       HandleId,
627                                       &SubjectContext,
628                                       &CapturedObjectTypeName,
629                                       &CapturedObjectName,
630                                       CapturedSecurityDescriptor,
631                                       CapturedPrincipalSelfSid,
632                                       DesiredAccess,
633                                       AuditType,
634                                       HaveAuditPrivilege,
635                                       CapturedObjectTypeList,
636                                       ObjectTypeListLength,
637                                       &LocalGenericMapping,
638                                       SafeGrantedAccessList,
639                                       SafeAccessStatusList,
640                                       &LocalGenerateOnClose,
641                                       UseResultList);
642 
643     /* Enter SEH to copy the data back to user mode */
644     _SEH2_TRY
645     {
646         /* Loop all result entries (only 1 when no list was requested) */
647         ASSERT(UseResultList || (ResultListLength == 1));
648         for (i = 0; i < ResultListLength; i++)
649         {
650             AccessStatusList[i] = SafeAccessStatusList[i];
651             GrantedAccessList[i] = SafeGrantedAccessList[i];
652         }
653 
654         *GenerateOnClose = LocalGenerateOnClose;
655     }
656     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
657     {
658         Status = _SEH2_GetExceptionCode();
659         DPRINT1("Exception while copying back data: 0x%lx\n", Status);
660     }
661     _SEH2_END;
662 
663 Cleanup:
664 
665     if (CapturedObjectTypeList != NULL)
666         SeReleaseObjectTypeList(CapturedObjectTypeList, UserMode);
667 
668     if (CapturedPrincipalSelfSid != NULL)
669         SepReleaseSid(CapturedPrincipalSelfSid, UserMode, FALSE);
670 
671     if (CapturedObjectName.Buffer != NULL)
672         ReleaseCapturedUnicodeString(&CapturedObjectName, UserMode);
673 
674     if (CapturedObjectTypeName.Buffer != NULL)
675         ReleaseCapturedUnicodeString(&CapturedObjectTypeName, UserMode);
676 
677     if (CapturedSubsystemName.Buffer != NULL)
678         ReleaseCapturedUnicodeString(&CapturedSubsystemName, UserMode);
679 
680     if (CapturedSecurityDescriptor != NULL)
681         SeReleaseSecurityDescriptor(CapturedSecurityDescriptor, UserMode, FALSE);
682 
683     if (ClientToken != NULL)
684     {
685         ObDereferenceObject(ClientToken);
686         SubjectContext.ClientToken = SubjectContextToken;
687     }
688 
689     if (AllocatedResultLists)
690         ExFreePoolWithTag(SafeGrantedAccessList, TAG_SEPA);
691 
692     /* Release the security subject context */
693     SeReleaseSubjectContext(&SubjectContext);
694 
695     return Status;
696 }
697 
698 
699 /* PUBLIC FUNCTIONS ***********************************************************/
700 
701 /*
702  * @unimplemented
703  */
704 VOID
705 NTAPI
706 SeAuditHardLinkCreation(IN PUNICODE_STRING FileName,
707                         IN PUNICODE_STRING LinkName,
708                         IN BOOLEAN bSuccess)
709 {
710     UNIMPLEMENTED;
711 }
712 
713 /*
714  * @unimplemented
715  */
716 BOOLEAN
717 NTAPI
718 SeAuditingFileEvents(IN BOOLEAN AccessGranted,
719                      IN PSECURITY_DESCRIPTOR SecurityDescriptor)
720 {
721     UNIMPLEMENTED;
722     return FALSE;
723 }
724 
725 /*
726  * @unimplemented
727  */
728 BOOLEAN
729 NTAPI
730 SeAuditingFileEventsWithContext(IN BOOLEAN AccessGranted,
731                                 IN PSECURITY_DESCRIPTOR SecurityDescriptor,
732                                 IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext OPTIONAL)
733 {
734     UNIMPLEMENTED_ONCE;
735     return FALSE;
736 }
737 
738 /*
739  * @unimplemented
740  */
741 BOOLEAN
742 NTAPI
743 SeAuditingHardLinkEvents(IN BOOLEAN AccessGranted,
744                          IN PSECURITY_DESCRIPTOR SecurityDescriptor)
745 {
746     UNIMPLEMENTED;
747     return FALSE;
748 }
749 
750 /*
751  * @unimplemented
752  */
753 BOOLEAN
754 NTAPI
755 SeAuditingHardLinkEventsWithContext(IN BOOLEAN AccessGranted,
756                                     IN PSECURITY_DESCRIPTOR SecurityDescriptor,
757                                     IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext OPTIONAL)
758 {
759     UNIMPLEMENTED;
760     return FALSE;
761 }
762 
763 /*
764  * @unimplemented
765  */
766 BOOLEAN
767 NTAPI
768 SeAuditingFileOrGlobalEvents(IN BOOLEAN AccessGranted,
769                              IN PSECURITY_DESCRIPTOR SecurityDescriptor,
770                              IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext)
771 {
772     UNIMPLEMENTED;
773     return FALSE;
774 }
775 
776 /*
777  * @unimplemented
778  */
779 VOID
780 NTAPI
781 SeCloseObjectAuditAlarm(IN PVOID Object,
782                         IN HANDLE Handle,
783                         IN BOOLEAN PerformAction)
784 {
785     UNIMPLEMENTED;
786 }
787 
788 /*
789  * @unimplemented
790  */
791 VOID NTAPI
792 SeDeleteObjectAuditAlarm(IN PVOID Object,
793                          IN HANDLE Handle)
794 {
795     UNIMPLEMENTED;
796 }
797 
798 /*
799  * @unimplemented
800  */
801 VOID
802 NTAPI
803 SeOpenObjectAuditAlarm(IN PUNICODE_STRING ObjectTypeName,
804                        IN PVOID Object OPTIONAL,
805                        IN PUNICODE_STRING AbsoluteObjectName OPTIONAL,
806                        IN PSECURITY_DESCRIPTOR SecurityDescriptor,
807                        IN PACCESS_STATE AccessState,
808                        IN BOOLEAN ObjectCreated,
809                        IN BOOLEAN AccessGranted,
810                        IN KPROCESSOR_MODE AccessMode,
811                        OUT PBOOLEAN GenerateOnClose)
812 {
813     PAGED_CODE();
814 
815     /* Audits aren't done on kernel-mode access */
816     if (AccessMode == KernelMode) return;
817 
818     /* Otherwise, unimplemented! */
819     //UNIMPLEMENTED;
820     return;
821 }
822 
823 /*
824  * @unimplemented
825  */
826 VOID NTAPI
827 SeOpenObjectForDeleteAuditAlarm(IN PUNICODE_STRING ObjectTypeName,
828                                 IN PVOID Object OPTIONAL,
829                                 IN PUNICODE_STRING AbsoluteObjectName OPTIONAL,
830                                 IN PSECURITY_DESCRIPTOR SecurityDescriptor,
831                                 IN PACCESS_STATE AccessState,
832                                 IN BOOLEAN ObjectCreated,
833                                 IN BOOLEAN AccessGranted,
834                                 IN KPROCESSOR_MODE AccessMode,
835                                 OUT PBOOLEAN GenerateOnClose)
836 {
837     UNIMPLEMENTED;
838 }
839 
840 /*
841  * @unimplemented
842  */
843 VOID
844 NTAPI
845 SePrivilegeObjectAuditAlarm(IN HANDLE Handle,
846                             IN PSECURITY_SUBJECT_CONTEXT SubjectContext,
847                             IN ACCESS_MASK DesiredAccess,
848                             IN PPRIVILEGE_SET Privileges,
849                             IN BOOLEAN AccessGranted,
850                             IN KPROCESSOR_MODE CurrentMode)
851 {
852     UNIMPLEMENTED;
853 }
854 
855 /* SYSTEM CALLS ***************************************************************/
856 
857 NTSTATUS
858 NTAPI
859 NtCloseObjectAuditAlarm(
860     PUNICODE_STRING SubsystemName,
861     PVOID HandleId,
862     BOOLEAN GenerateOnClose)
863 {
864     SECURITY_SUBJECT_CONTEXT SubjectContext;
865     UNICODE_STRING CapturedSubsystemName;
866     KPROCESSOR_MODE PreviousMode;
867     BOOLEAN UseImpersonationToken;
868     PETHREAD CurrentThread;
869     BOOLEAN CopyOnOpen, EffectiveOnly;
870     SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
871     NTSTATUS Status;
872     PTOKEN Token;
873     PAGED_CODE();
874 
875     /* Get the previous mode (only user mode is supported!) */
876     PreviousMode = ExGetPreviousMode();
877     ASSERT(PreviousMode != KernelMode);
878 
879     /* Do we even need to do anything? */
880     if (!GenerateOnClose)
881     {
882         /* Nothing to do, return success */
883         return STATUS_SUCCESS;
884     }
885 
886     /* Capture the security subject context */
887     SeCaptureSubjectContext(&SubjectContext);
888 
889     /* Check for audit privilege */
890     if (!SeCheckAuditPrivilege(&SubjectContext, PreviousMode))
891     {
892         DPRINT1("Caller does not have SeAuditPrivilege\n");
893         Status = STATUS_PRIVILEGE_NOT_HELD;
894         goto Cleanup;
895     }
896 
897     /* Probe and capture the subsystem name */
898     Status = ProbeAndCaptureUnicodeString(&CapturedSubsystemName,
899                                           PreviousMode,
900                                           SubsystemName);
901     if (!NT_SUCCESS(Status))
902     {
903         DPRINT1("Failed to capture subsystem name!\n");
904         goto Cleanup;
905     }
906 
907     /* Get the current thread and check if it's impersonating */
908     CurrentThread = PsGetCurrentThread();
909     if (PsIsThreadImpersonating(CurrentThread))
910     {
911         /* Get the impersonation token */
912         Token = PsReferenceImpersonationToken(CurrentThread,
913                                               &CopyOnOpen,
914                                               &EffectiveOnly,
915                                               &ImpersonationLevel);
916         UseImpersonationToken = TRUE;
917     }
918     else
919     {
920         /* Get the primary token */
921         Token = PsReferencePrimaryToken(PsGetCurrentProcess());
922         UseImpersonationToken = FALSE;
923     }
924 
925     /* Call the internal function */
926     SepAdtCloseObjectAuditAlarm(&CapturedSubsystemName,
927                                 HandleId,
928                                 Token->UserAndGroups->Sid);
929 
930     /* Release the captured subsystem name */
931     ReleaseCapturedUnicodeString(&CapturedSubsystemName, PreviousMode);
932 
933     /* Check what token we used */
934     if (UseImpersonationToken)
935     {
936         /* Release impersonation token */
937         PsDereferenceImpersonationToken(Token);
938     }
939     else
940     {
941         /* Release primary token */
942         PsDereferencePrimaryToken(Token);
943     }
944 
945     Status = STATUS_SUCCESS;
946 
947 Cleanup:
948 
949     /* Release the security subject context */
950     SeReleaseSubjectContext(&SubjectContext);
951 
952     return Status;
953 }
954 
955 
956 NTSTATUS NTAPI
957 NtDeleteObjectAuditAlarm(IN PUNICODE_STRING SubsystemName,
958                          IN PVOID HandleId,
959                          IN BOOLEAN GenerateOnClose)
960 {
961     UNIMPLEMENTED;
962     return STATUS_NOT_IMPLEMENTED;
963 }
964 
965 VOID
966 NTAPI
967 SepOpenObjectAuditAlarm(
968     _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
969     _In_ PUNICODE_STRING SubsystemName,
970     _In_opt_ PVOID HandleId,
971     _In_ PUNICODE_STRING ObjectTypeName,
972     _In_ PUNICODE_STRING ObjectName,
973     _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor,
974     _In_ PTOKEN ClientToken,
975     _In_ ACCESS_MASK DesiredAccess,
976     _In_ ACCESS_MASK GrantedAccess,
977     _In_opt_ PPRIVILEGE_SET Privileges,
978     _In_ BOOLEAN ObjectCreation,
979     _In_ BOOLEAN AccessGranted,
980     _Out_ PBOOLEAN GenerateOnClose)
981 {
982     DBG_UNREFERENCED_PARAMETER(SubjectContext);
983     DBG_UNREFERENCED_PARAMETER(SubsystemName);
984     DBG_UNREFERENCED_PARAMETER(HandleId);
985     DBG_UNREFERENCED_PARAMETER(ObjectTypeName);
986     DBG_UNREFERENCED_PARAMETER(ObjectName);
987     DBG_UNREFERENCED_PARAMETER(SecurityDescriptor);
988     DBG_UNREFERENCED_PARAMETER(ClientToken);
989     DBG_UNREFERENCED_PARAMETER(DesiredAccess);
990     DBG_UNREFERENCED_PARAMETER(GrantedAccess);
991     DBG_UNREFERENCED_PARAMETER(Privileges);
992     DBG_UNREFERENCED_PARAMETER(ObjectCreation);
993     DBG_UNREFERENCED_PARAMETER(AccessGranted);
994     UNIMPLEMENTED;
995     *GenerateOnClose = FALSE;
996 }
997 
998 __kernel_entry
999 NTSTATUS
1000 NTAPI
1001 NtOpenObjectAuditAlarm(
1002     _In_ PUNICODE_STRING SubsystemName,
1003     _In_opt_ PVOID HandleId,
1004     _In_ PUNICODE_STRING ObjectTypeName,
1005     _In_ PUNICODE_STRING ObjectName,
1006     _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor,
1007     _In_ HANDLE ClientTokenHandle,
1008     _In_ ACCESS_MASK DesiredAccess,
1009     _In_ ACCESS_MASK GrantedAccess,
1010     _In_opt_ PPRIVILEGE_SET PrivilegeSet,
1011     _In_ BOOLEAN ObjectCreation,
1012     _In_ BOOLEAN AccessGranted,
1013     _Out_ PBOOLEAN GenerateOnClose)
1014 {
1015     PTOKEN ClientToken;
1016     PSECURITY_DESCRIPTOR CapturedSecurityDescriptor;
1017     UNICODE_STRING CapturedSubsystemName, CapturedObjectTypeName, CapturedObjectName;
1018     ULONG PrivilegeCount, PrivilegeSetSize;
1019     volatile PPRIVILEGE_SET CapturedPrivilegeSet;
1020     BOOLEAN LocalGenerateOnClose;
1021     PVOID CapturedHandleId;
1022     SECURITY_SUBJECT_CONTEXT SubjectContext;
1023     NTSTATUS Status;
1024     PAGED_CODE();
1025 
1026     /* Only user mode is supported! */
1027     ASSERT(ExGetPreviousMode() != KernelMode);
1028 
1029     /* Start clean */
1030     ClientToken = NULL;
1031     CapturedSecurityDescriptor = NULL;
1032     CapturedPrivilegeSet = NULL;
1033     CapturedSubsystemName.Buffer = NULL;
1034     CapturedObjectTypeName.Buffer = NULL;
1035     CapturedObjectName.Buffer = NULL;
1036 
1037     /* Reference the client token */
1038     Status = ObReferenceObjectByHandle(ClientTokenHandle,
1039                                        TOKEN_QUERY,
1040                                        SeTokenObjectType,
1041                                        UserMode,
1042                                        (PVOID*)&ClientToken,
1043                                        NULL);
1044     if (!NT_SUCCESS(Status))
1045     {
1046         DPRINT1("Failed to reference token handle %p: %lx\n",
1047                 ClientTokenHandle, Status);
1048         return Status;
1049     }
1050 
1051     /* Capture the security subject context */
1052     SeCaptureSubjectContext(&SubjectContext);
1053 
1054     /* Validate the token's impersonation level */
1055     if ((ClientToken->TokenType == TokenImpersonation) &&
1056         (ClientToken->ImpersonationLevel < SecurityIdentification))
1057     {
1058         DPRINT1("Invalid impersonation level (%u)\n", ClientToken->ImpersonationLevel);
1059         Status = STATUS_BAD_IMPERSONATION_LEVEL;
1060         goto Cleanup;
1061     }
1062 
1063     /* Check for audit privilege */
1064     if (!SeCheckAuditPrivilege(&SubjectContext, UserMode))
1065     {
1066         DPRINT1("Caller does not have SeAuditPrivilege\n");
1067         Status = STATUS_PRIVILEGE_NOT_HELD;
1068         goto Cleanup;
1069     }
1070 
1071     /* Check for NULL SecurityDescriptor */
1072     if (SecurityDescriptor == NULL)
1073     {
1074         /* Nothing to do */
1075         Status = STATUS_SUCCESS;
1076         goto Cleanup;
1077     }
1078 
1079     /* Capture the security descriptor */
1080     Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
1081                                          UserMode,
1082                                          PagedPool,
1083                                          FALSE,
1084                                          &CapturedSecurityDescriptor);
1085     if (!NT_SUCCESS(Status))
1086     {
1087         DPRINT1("Failed to capture security descriptor!\n");
1088         goto Cleanup;
1089     }
1090 
1091     _SEH2_TRY
1092     {
1093         /* Check if we have a privilege set */
1094         if (PrivilegeSet != NULL)
1095         {
1096             /* Probe the basic privilege set structure */
1097             ProbeForRead(PrivilegeSet, sizeof(PRIVILEGE_SET), sizeof(ULONG));
1098 
1099             /* Validate privilege count */
1100             PrivilegeCount = PrivilegeSet->PrivilegeCount;
1101             if (PrivilegeCount > SEP_PRIVILEGE_SET_MAX_COUNT)
1102             {
1103                 Status = STATUS_INVALID_PARAMETER;
1104                 _SEH2_YIELD(goto Cleanup);
1105             }
1106 
1107             /* Calculate the size of the PrivilegeSet structure */
1108             PrivilegeSetSize = FIELD_OFFSET(PRIVILEGE_SET, Privilege[PrivilegeCount]);
1109 
1110             /* Probe the whole structure */
1111             ProbeForRead(PrivilegeSet, PrivilegeSetSize, sizeof(ULONG));
1112 
1113             /* Allocate a temp buffer */
1114             CapturedPrivilegeSet = ExAllocatePoolWithTag(PagedPool,
1115                                                          PrivilegeSetSize,
1116                                                          TAG_PRIVILEGE_SET);
1117             if (CapturedPrivilegeSet == NULL)
1118             {
1119                 DPRINT1("Failed to allocate %u bytes\n", PrivilegeSetSize);
1120                 Status = STATUS_INSUFFICIENT_RESOURCES;
1121                 _SEH2_YIELD(goto Cleanup);
1122             }
1123 
1124             /* Copy the privileges */
1125             RtlCopyMemory(CapturedPrivilegeSet, PrivilegeSet, PrivilegeSetSize);
1126         }
1127 
1128         if (HandleId != NULL)
1129         {
1130             ProbeForRead(HandleId, sizeof(PVOID), sizeof(PVOID));
1131             CapturedHandleId = *(PVOID*)HandleId;
1132         }
1133 
1134         ProbeForWrite(GenerateOnClose, sizeof(BOOLEAN), sizeof(BOOLEAN));
1135     }
1136     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1137     {
1138         Status = _SEH2_GetExceptionCode();
1139         DPRINT1("Exception while probing parameters: 0x%lx\n", Status);
1140         _SEH2_YIELD(goto Cleanup);
1141     }
1142     _SEH2_END;
1143 
1144     /* Probe and capture the subsystem name */
1145     Status = ProbeAndCaptureUnicodeString(&CapturedSubsystemName,
1146                                           UserMode,
1147                                           SubsystemName);
1148     if (!NT_SUCCESS(Status))
1149     {
1150         DPRINT1("Failed to capture subsystem name!\n");
1151         goto Cleanup;
1152     }
1153 
1154     /* Probe and capture the object type name */
1155     Status = ProbeAndCaptureUnicodeString(&CapturedObjectTypeName,
1156                                           UserMode,
1157                                           ObjectTypeName);
1158     if (!NT_SUCCESS(Status))
1159     {
1160         DPRINT1("Failed to capture object type name!\n");
1161         goto Cleanup;
1162     }
1163 
1164     /* Probe and capture the object name */
1165     Status = ProbeAndCaptureUnicodeString(&CapturedObjectName,
1166                                           UserMode,
1167                                           ObjectName);
1168     if (!NT_SUCCESS(Status))
1169     {
1170         DPRINT1("Failed to capture object name!\n");
1171         goto Cleanup;
1172     }
1173 
1174     /* Call the internal function */
1175     SepOpenObjectAuditAlarm(&SubjectContext,
1176                             &CapturedSubsystemName,
1177                             CapturedHandleId,
1178                             &CapturedObjectTypeName,
1179                             &CapturedObjectName,
1180                             CapturedSecurityDescriptor,
1181                             ClientToken,
1182                             DesiredAccess,
1183                             GrantedAccess,
1184                             CapturedPrivilegeSet,
1185                             ObjectCreation,
1186                             AccessGranted,
1187                             &LocalGenerateOnClose);
1188 
1189     Status = STATUS_SUCCESS;
1190 
1191     /* Enter SEH to copy the data back to user mode */
1192     _SEH2_TRY
1193     {
1194         *GenerateOnClose = LocalGenerateOnClose;
1195     }
1196     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1197     {
1198         Status = _SEH2_GetExceptionCode();
1199         DPRINT1("Exception while copying back data: 0x%lx\n", Status);
1200     }
1201     _SEH2_END;
1202 
1203 Cleanup:
1204 
1205     if (CapturedObjectName.Buffer != NULL)
1206         ReleaseCapturedUnicodeString(&CapturedObjectName, UserMode);
1207 
1208     if (CapturedObjectTypeName.Buffer != NULL)
1209         ReleaseCapturedUnicodeString(&CapturedObjectTypeName, UserMode);
1210 
1211     if (CapturedSubsystemName.Buffer != NULL)
1212         ReleaseCapturedUnicodeString(&CapturedSubsystemName, UserMode);
1213 
1214     if (CapturedSecurityDescriptor != NULL)
1215         SeReleaseSecurityDescriptor(CapturedSecurityDescriptor, UserMode, FALSE);
1216 
1217     if (CapturedPrivilegeSet != NULL)
1218         ExFreePoolWithTag(CapturedPrivilegeSet, TAG_PRIVILEGE_SET);
1219 
1220     /* Release the security subject context */
1221     SeReleaseSubjectContext(&SubjectContext);
1222 
1223     ObDereferenceObject(ClientToken);
1224 
1225     return Status;
1226 }
1227 
1228 
1229 __kernel_entry
1230 NTSTATUS
1231 NTAPI
1232 NtPrivilegedServiceAuditAlarm(
1233     _In_opt_ PUNICODE_STRING SubsystemName,
1234     _In_opt_ PUNICODE_STRING ServiceName,
1235     _In_ HANDLE ClientTokenHandle,
1236     _In_ PPRIVILEGE_SET Privileges,
1237     _In_ BOOLEAN AccessGranted )
1238 {
1239     KPROCESSOR_MODE PreviousMode;
1240     PTOKEN ClientToken;
1241     volatile PPRIVILEGE_SET CapturedPrivileges = NULL;
1242     UNICODE_STRING CapturedSubsystemName;
1243     UNICODE_STRING CapturedServiceName;
1244     ULONG PrivilegeCount, PrivilegesSize;
1245     SECURITY_SUBJECT_CONTEXT SubjectContext;
1246     NTSTATUS Status;
1247     PAGED_CODE();
1248 
1249     /* Get the previous mode (only user mode is supported!) */
1250     PreviousMode = ExGetPreviousMode();
1251     ASSERT(PreviousMode != KernelMode);
1252 
1253     CapturedSubsystemName.Buffer = NULL;
1254     CapturedServiceName.Buffer = NULL;
1255 
1256     /* Reference the client token */
1257     Status = ObReferenceObjectByHandle(ClientTokenHandle,
1258                                        TOKEN_QUERY,
1259                                        SeTokenObjectType,
1260                                        PreviousMode,
1261                                        (PVOID*)&ClientToken,
1262                                        NULL);
1263     if (!NT_SUCCESS(Status))
1264     {
1265         DPRINT1("Failed to reference client token: 0x%lx\n", Status);
1266         return Status;
1267     }
1268 
1269     /* Validate the token's impersonation level */
1270     if ((ClientToken->TokenType == TokenImpersonation) &&
1271         (ClientToken->ImpersonationLevel < SecurityIdentification))
1272     {
1273         DPRINT1("Invalid impersonation level (%u)\n", ClientToken->ImpersonationLevel);
1274         ObDereferenceObject(ClientToken);
1275         return STATUS_BAD_IMPERSONATION_LEVEL;
1276     }
1277 
1278     /* Capture the security subject context */
1279     SeCaptureSubjectContext(&SubjectContext);
1280 
1281     /* Check for audit privilege */
1282     if (!SeCheckAuditPrivilege(&SubjectContext, PreviousMode))
1283     {
1284         DPRINT1("Caller does not have SeAuditPrivilege\n");
1285         Status = STATUS_PRIVILEGE_NOT_HELD;
1286         goto Cleanup;
1287     }
1288 
1289     /* Do we have a subsystem name? */
1290     if (SubsystemName != NULL)
1291     {
1292         /* Probe and capture the subsystem name */
1293         Status = ProbeAndCaptureUnicodeString(&CapturedSubsystemName,
1294                                               PreviousMode,
1295                                               SubsystemName);
1296         if (!NT_SUCCESS(Status))
1297         {
1298             DPRINT1("Failed to capture subsystem name!\n");
1299             goto Cleanup;
1300         }
1301     }
1302 
1303     /* Do we have a service name? */
1304     if (ServiceName != NULL)
1305     {
1306         /* Probe and capture the service name */
1307         Status = ProbeAndCaptureUnicodeString(&CapturedServiceName,
1308                                               PreviousMode,
1309                                               ServiceName);
1310         if (!NT_SUCCESS(Status))
1311         {
1312             DPRINT1("Failed to capture service name!\n");
1313             goto Cleanup;
1314         }
1315     }
1316 
1317     _SEH2_TRY
1318     {
1319         /* Probe the basic privilege set structure */
1320         ProbeForRead(Privileges, sizeof(PRIVILEGE_SET), sizeof(ULONG));
1321 
1322         /* Validate privilege count */
1323         PrivilegeCount = Privileges->PrivilegeCount;
1324         if (PrivilegeCount > SEP_PRIVILEGE_SET_MAX_COUNT)
1325         {
1326             Status = STATUS_INVALID_PARAMETER;
1327             _SEH2_YIELD(goto Cleanup);
1328         }
1329 
1330         /* Calculate the size of the Privileges structure */
1331         PrivilegesSize = FIELD_OFFSET(PRIVILEGE_SET, Privilege[PrivilegeCount]);
1332 
1333         /* Probe the whole structure */
1334         ProbeForRead(Privileges, PrivilegesSize, sizeof(ULONG));
1335 
1336         /* Allocate a temp buffer */
1337         CapturedPrivileges = ExAllocatePoolWithTag(PagedPool,
1338                                                    PrivilegesSize,
1339                                                    TAG_PRIVILEGE_SET);
1340         if (CapturedPrivileges == NULL)
1341         {
1342             DPRINT1("Failed to allocate %u bytes\n", PrivilegesSize);
1343             Status = STATUS_INSUFFICIENT_RESOURCES;
1344             _SEH2_YIELD(goto Cleanup);
1345         }
1346 
1347         /* Copy the privileges */
1348         RtlCopyMemory(CapturedPrivileges, Privileges, PrivilegesSize);
1349     }
1350     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1351     {
1352         Status = _SEH2_GetExceptionCode();
1353         DPRINT1("Got exception 0x%lx\n", Status);
1354         _SEH2_YIELD(goto Cleanup);
1355     }
1356     _SEH2_END;
1357 
1358     /* Call the internal function */
1359     SepAdtPrivilegedServiceAuditAlarm(&SubjectContext,
1360                                       SubsystemName ? &CapturedSubsystemName : NULL,
1361                                       ServiceName ? &CapturedServiceName : NULL,
1362                                       ClientToken,
1363                                       SubjectContext.PrimaryToken,
1364                                       CapturedPrivileges,
1365                                       AccessGranted);
1366 
1367     Status = STATUS_SUCCESS;
1368 
1369 Cleanup:
1370     /* Cleanup resources */
1371     if (CapturedSubsystemName.Buffer != NULL)
1372         ReleaseCapturedUnicodeString(&CapturedSubsystemName, PreviousMode);
1373 
1374     if (CapturedServiceName.Buffer != NULL)
1375         ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
1376 
1377     if (CapturedPrivileges != NULL)
1378         ExFreePoolWithTag(CapturedPrivileges, TAG_PRIVILEGE_SET);
1379 
1380     /* Release the security subject context */
1381     SeReleaseSubjectContext(&SubjectContext);
1382 
1383     ObDereferenceObject(ClientToken);
1384 
1385     return Status;
1386 }
1387 
1388 
1389 NTSTATUS NTAPI
1390 NtPrivilegeObjectAuditAlarm(IN PUNICODE_STRING SubsystemName,
1391                             IN PVOID HandleId,
1392                             IN HANDLE ClientToken,
1393                             IN ULONG DesiredAccess,
1394                             IN PPRIVILEGE_SET Privileges,
1395                             IN BOOLEAN AccessGranted)
1396 {
1397     UNIMPLEMENTED;
1398     return STATUS_NOT_IMPLEMENTED;
1399 }
1400 
1401 
1402 _Must_inspect_result_
1403 __kernel_entry
1404 NTSTATUS
1405 NTAPI
1406 NtAccessCheckAndAuditAlarm(
1407     _In_ PUNICODE_STRING SubsystemName,
1408     _In_opt_ PVOID HandleId,
1409     _In_ PUNICODE_STRING ObjectTypeName,
1410     _In_ PUNICODE_STRING ObjectName,
1411     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
1412     _In_ ACCESS_MASK DesiredAccess,
1413     _In_ PGENERIC_MAPPING GenericMapping,
1414     _In_ BOOLEAN ObjectCreation,
1415     _Out_ PACCESS_MASK GrantedAccess,
1416     _Out_ PNTSTATUS AccessStatus,
1417     _Out_ PBOOLEAN GenerateOnClose)
1418 {
1419     /* Call the internal function */
1420     return SepAccessCheckAndAuditAlarm(SubsystemName,
1421                                        HandleId,
1422                                        NULL,
1423                                        ObjectTypeName,
1424                                        ObjectName,
1425                                        SecurityDescriptor,
1426                                        NULL,
1427                                        DesiredAccess,
1428                                        AuditEventObjectAccess,
1429                                        0,
1430                                        NULL,
1431                                        0,
1432                                        GenericMapping,
1433                                        GrantedAccess,
1434                                        AccessStatus,
1435                                        GenerateOnClose,
1436                                        FALSE);
1437 }
1438 
1439 _Must_inspect_result_
1440 __kernel_entry
1441 NTSTATUS
1442 NTAPI
1443 NtAccessCheckByTypeAndAuditAlarm(
1444     _In_ PUNICODE_STRING SubsystemName,
1445     _In_opt_ PVOID HandleId,
1446     _In_ PUNICODE_STRING ObjectTypeName,
1447     _In_ PUNICODE_STRING ObjectName,
1448     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
1449     _In_opt_ PSID PrincipalSelfSid,
1450     _In_ ACCESS_MASK DesiredAccess,
1451     _In_ AUDIT_EVENT_TYPE AuditType,
1452     _In_ ULONG Flags,
1453     _In_reads_opt_(ObjectTypeLength) POBJECT_TYPE_LIST ObjectTypeList,
1454     _In_ ULONG ObjectTypeLength,
1455     _In_ PGENERIC_MAPPING GenericMapping,
1456     _In_ BOOLEAN ObjectCreation,
1457     _Out_ PACCESS_MASK GrantedAccess,
1458     _Out_ PNTSTATUS AccessStatus,
1459     _Out_ PBOOLEAN GenerateOnClose)
1460 {
1461     /* Call the internal function */
1462     return SepAccessCheckAndAuditAlarm(SubsystemName,
1463                                        HandleId,
1464                                        NULL,
1465                                        ObjectTypeName,
1466                                        ObjectName,
1467                                        SecurityDescriptor,
1468                                        PrincipalSelfSid,
1469                                        DesiredAccess,
1470                                        AuditType,
1471                                        Flags,
1472                                        ObjectTypeList,
1473                                        ObjectTypeLength,
1474                                        GenericMapping,
1475                                        GrantedAccess,
1476                                        AccessStatus,
1477                                        GenerateOnClose,
1478                                        FALSE);
1479 }
1480 
1481 _Must_inspect_result_
1482 __kernel_entry
1483 NTSTATUS
1484 NTAPI
1485 NtAccessCheckByTypeResultListAndAuditAlarm(
1486     _In_ PUNICODE_STRING SubsystemName,
1487     _In_opt_ PVOID HandleId,
1488     _In_ PUNICODE_STRING ObjectTypeName,
1489     _In_ PUNICODE_STRING ObjectName,
1490     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
1491     _In_opt_ PSID PrincipalSelfSid,
1492     _In_ ACCESS_MASK DesiredAccess,
1493     _In_ AUDIT_EVENT_TYPE AuditType,
1494     _In_ ULONG Flags,
1495     _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
1496     _In_ ULONG ObjectTypeListLength,
1497     _In_ PGENERIC_MAPPING GenericMapping,
1498     _In_ BOOLEAN ObjectCreation,
1499     _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccessList,
1500     _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatusList,
1501     _Out_ PBOOLEAN GenerateOnClose)
1502 {
1503     /* Call the internal function */
1504     return SepAccessCheckAndAuditAlarm(SubsystemName,
1505                                        HandleId,
1506                                        NULL,
1507                                        ObjectTypeName,
1508                                        ObjectName,
1509                                        SecurityDescriptor,
1510                                        PrincipalSelfSid,
1511                                        DesiredAccess,
1512                                        AuditType,
1513                                        Flags,
1514                                        ObjectTypeList,
1515                                        ObjectTypeListLength,
1516                                        GenericMapping,
1517                                        GrantedAccessList,
1518                                        AccessStatusList,
1519                                        GenerateOnClose,
1520                                        TRUE);
1521 }
1522 
1523 _Must_inspect_result_
1524 __kernel_entry
1525 NTSTATUS
1526 NTAPI
1527 NtAccessCheckByTypeResultListAndAuditAlarmByHandle(
1528     _In_ PUNICODE_STRING SubsystemName,
1529     _In_opt_ PVOID HandleId,
1530     _In_ HANDLE ClientToken,
1531     _In_ PUNICODE_STRING ObjectTypeName,
1532     _In_ PUNICODE_STRING ObjectName,
1533     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
1534     _In_opt_ PSID PrincipalSelfSid,
1535     _In_ ACCESS_MASK DesiredAccess,
1536     _In_ AUDIT_EVENT_TYPE AuditType,
1537     _In_ ULONG Flags,
1538     _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
1539     _In_ ULONG ObjectTypeListLength,
1540     _In_ PGENERIC_MAPPING GenericMapping,
1541     _In_ BOOLEAN ObjectCreation,
1542     _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccessList,
1543     _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatusList,
1544     _Out_ PBOOLEAN GenerateOnClose)
1545 {
1546     UNREFERENCED_PARAMETER(ObjectCreation);
1547 
1548     /* Call the internal function */
1549     return SepAccessCheckAndAuditAlarm(SubsystemName,
1550                                        HandleId,
1551                                        &ClientToken,
1552                                        ObjectTypeName,
1553                                        ObjectName,
1554                                        SecurityDescriptor,
1555                                        PrincipalSelfSid,
1556                                        DesiredAccess,
1557                                        AuditType,
1558                                        Flags,
1559                                        ObjectTypeList,
1560                                        ObjectTypeListLength,
1561                                        GenericMapping,
1562                                        GrantedAccessList,
1563                                        AccessStatusList,
1564                                        GenerateOnClose,
1565                                        TRUE);
1566 }
1567 
1568 /* EOF */
1569