#define SEP_PRIVILEGE_SET_MAX_COUNT 60
+UNICODE_STRING SeSubsystemName = RTL_CONSTANT_STRING(L"Security");
+
/* PRIVATE FUNCTIONS***********************************************************/
BOOLEAN
_In_ PTOKEN Token,
_In_ PTOKEN PrimaryToken,
_In_ PPRIVILEGE_SET Privileges,
- _In_ BOOLEAN AccessGranted )
+ _In_ BOOLEAN AccessGranted)
+{
+ DPRINT("SepAdtPrivilegedServiceAuditAlarm is unimplemented\n");
+}
+
+VOID
+NTAPI
+SePrivilegedServiceAuditAlarm(
+ _In_opt_ PUNICODE_STRING ServiceName,
+ _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
+ _In_ PPRIVILEGE_SET PrivilegeSet,
+ _In_ BOOLEAN AccessGranted)
+{
+ PTOKEN EffectiveToken;
+ PSID UserSid;
+ PAGED_CODE();
+
+ /* Get the effective token */
+ if (SubjectContext->ClientToken != NULL)
+ EffectiveToken = SubjectContext->ClientToken;
+ else
+ EffectiveToken = SubjectContext->PrimaryToken;
+
+ /* Get the user SID */
+ UserSid = EffectiveToken->UserAndGroups->Sid;
+
+ /* Check if this is the local system SID */
+ if (RtlEqualSid(UserSid, SeLocalSystemSid))
+ {
+ /* Nothing to do */
+ return;
+ }
+
+ /* Check if this is the network service or local service SID */
+ if (RtlEqualSid(UserSid, SeExports->SeNetworkServiceSid) ||
+ RtlEqualSid(UserSid, SeExports->SeLocalServiceSid))
+ {
+ // FIXME: should continue for a certain set of privileges
+ return;
+ }
+
+ /* Call the worker function */
+ SepAdtPrivilegedServiceAuditAlarm(SubjectContext,
+ &SeSubsystemName,
+ ServiceName,
+ SubjectContext->ClientToken,
+ SubjectContext->PrimaryToken,
+ PrivilegeSet,
+ AccessGranted);
+
+}
+
+
+static
+NTSTATUS
+SeCaptureObjectTypeList(
+ _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
+ _In_ ULONG ObjectTypeListLength,
+ _In_ KPROCESSOR_MODE PreviousMode,
+ _Out_ POBJECT_TYPE_LIST *CapturedObjectTypeList)
+{
+ SIZE_T Size;
+
+ if (PreviousMode == KernelMode)
+ {
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (ObjectTypeListLength == 0)
+ {
+ *CapturedObjectTypeList = NULL;
+ return STATUS_SUCCESS;
+ }
+
+ if (ObjectTypeList == NULL)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Calculate the list size and check for integer overflow */
+ Size = ObjectTypeListLength * sizeof(OBJECT_TYPE_LIST);
+ if (Size == 0)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Allocate a new list */
+ *CapturedObjectTypeList = ExAllocatePoolWithTag(PagedPool, Size, TAG_SEPA);
+ if (*CapturedObjectTypeList == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ _SEH2_TRY
+ {
+ ProbeForRead(ObjectTypeList, Size, sizeof(ULONG));
+ RtlCopyMemory(*CapturedObjectTypeList, ObjectTypeList, Size);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ExFreePoolWithTag(*CapturedObjectTypeList, TAG_SEPA);
+ *CapturedObjectTypeList = NULL;
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+
+ return STATUS_SUCCESS;
+}
+
+static
+VOID
+SeReleaseObjectTypeList(
+ _In_ _Post_invalid_ POBJECT_TYPE_LIST CapturedObjectTypeList,
+ _In_ KPROCESSOR_MODE PreviousMode)
+{
+ if ((PreviousMode != KernelMode) && (CapturedObjectTypeList != NULL))
+ ExFreePoolWithTag(CapturedObjectTypeList, TAG_SEPA);
+}
+
+_Must_inspect_result_
+static
+NTSTATUS
+SepAccessCheckAndAuditAlarmWorker(
+ _In_ PUNICODE_STRING SubsystemName,
+ _In_opt_ PVOID HandleId,
+ _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
+ _In_ PUNICODE_STRING ObjectTypeName,
+ _In_ PUNICODE_STRING ObjectName,
+ _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _In_opt_ PSID PrincipalSelfSid,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ AUDIT_EVENT_TYPE AuditType,
+ _In_ BOOLEAN HaveAuditPrivilege,
+ _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
+ _In_ ULONG ObjectTypeListLength,
+ _In_ PGENERIC_MAPPING GenericMapping,
+ _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccessList,
+ _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatusList,
+ _Out_ PBOOLEAN GenerateOnClose,
+ _In_ BOOLEAN UseResultList)
{
+ ULONG ResultListLength, i;
+
+ /* Get the length of the result list */
+ ResultListLength = UseResultList ? ObjectTypeListLength : 1;
+
+ /// FIXME: we should do some real work here...
UNIMPLEMENTED;
+
+ /// HACK: we just pretend all access is granted!
+ for (i = 0; i < ResultListLength; i++)
+ {
+ GrantedAccessList[i] = DesiredAccess;
+ AccessStatusList[i] = STATUS_SUCCESS;
+ }
+
+ *GenerateOnClose = FALSE;
+
+ return STATUS_SUCCESS;
}
_Must_inspect_result_
SepAccessCheckAndAuditAlarm(
_In_ PUNICODE_STRING SubsystemName,
_In_opt_ PVOID HandleId,
- _In_ PHANDLE ClientToken,
+ _In_ PHANDLE ClientTokenHandle,
_In_ PUNICODE_STRING ObjectTypeName,
_In_ PUNICODE_STRING ObjectName,
_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
SECURITY_SUBJECT_CONTEXT SubjectContext;
ULONG ResultListLength;
GENERIC_MAPPING LocalGenericMapping;
+ PTOKEN SubjectContextToken, ClientToken;
+ BOOLEAN AllocatedResultLists;
+ BOOLEAN HaveAuditPrivilege;
+ PSECURITY_DESCRIPTOR CapturedSecurityDescriptor;
+ UNICODE_STRING CapturedSubsystemName, CapturedObjectTypeName, CapturedObjectName;
+ ACCESS_MASK GrantedAccess, *SafeGrantedAccessList;
+ NTSTATUS AccessStatus, *SafeAccessStatusList;
+ PSID CapturedPrincipalSelfSid;
+ POBJECT_TYPE_LIST CapturedObjectTypeList;
+ ULONG i;
+ BOOLEAN LocalGenerateOnClose;
NTSTATUS Status;
PAGED_CODE();
- DBG_UNREFERENCED_LOCAL_VARIABLE(LocalGenericMapping);
-
/* Only user mode is supported! */
ASSERT(ExGetPreviousMode() != KernelMode);
+ /* Start clean */
+ AllocatedResultLists = FALSE;
+ ClientToken = NULL;
+ CapturedSecurityDescriptor = NULL;
+ CapturedSubsystemName.Buffer = NULL;
+ CapturedObjectTypeName.Buffer = NULL;
+ CapturedObjectName.Buffer = NULL;
+ CapturedPrincipalSelfSid = NULL;
+ CapturedObjectTypeList = NULL;
+
/* Validate AuditType */
if ((AuditType != AuditEventObjectAccess) &&
(AuditType != AuditEventDirectoryServiceAccess))
SeCaptureSubjectContext(&SubjectContext);
/* Did the caller pass a token handle? */
- if (ClientToken == NULL)
+ if (ClientTokenHandle == NULL)
{
/* Check if we have a token in the subject context */
if (SubjectContext.ClientToken == NULL)
{
Status = STATUS_NO_IMPERSONATION_TOKEN;
+ DPRINT1("No token\n");
goto Cleanup;
}
if (SubjectContext.ImpersonationLevel < SecurityIdentification)
{
Status = STATUS_BAD_IMPERSONATION_LEVEL;
+ DPRINT1("Invalid impersonation level 0x%lx\n",
+ SubjectContext.ImpersonationLevel);
goto Cleanup;
}
}
if ((ResultListLength == 0) || (ResultListLength > 0x1000))
{
Status = STATUS_INVALID_PARAMETER;
+ DPRINT1("Invalud ResultListLength: 0x%lx\n", ResultListLength);
goto Cleanup;
}
+
+ /* Allocate a safe buffer from paged pool */
+ SafeGrantedAccessList = ExAllocatePoolWithTag(PagedPool,
+ 2 * ResultListLength * sizeof(ULONG),
+ TAG_SEPA);
+ if (SafeGrantedAccessList == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ DPRINT1("Failed to allocate access lists\n");
+ goto Cleanup;
+ }
+
+ SafeAccessStatusList = (PNTSTATUS)&SafeGrantedAccessList[ResultListLength];
+ AllocatedResultLists = TRUE;
}
else
{
/* List length is 1 */
ResultListLength = 1;
+ SafeGrantedAccessList = &GrantedAccess;
+ SafeAccessStatusList = &AccessStatus;
}
_SEH2_TRY
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
- goto Cleanup;
+ DPRINT1("Exception while probing parameters: 0x%lx\n", Status);
+ _SEH2_YIELD(goto Cleanup);
}
_SEH2_END;
+ /* Do we have a client token? */
+ if (ClientTokenHandle != NULL)
+ {
+ /* Reference the client token */
+ Status = ObReferenceObjectByHandle(*ClientTokenHandle,
+ TOKEN_QUERY,
+ SeTokenObjectType,
+ UserMode,
+ (PVOID*)&ClientToken,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to reference token handle %p: %lx\n",
+ *ClientTokenHandle, Status);
+ goto Cleanup;
+ }
+
+ SubjectContextToken = SubjectContext.ClientToken;
+ SubjectContext.ClientToken = ClientToken;
+ }
- UNIMPLEMENTED;
+ /* Check for audit privilege */
+ HaveAuditPrivilege = SeCheckAuditPrivilege(&SubjectContext, UserMode);
+ if (!HaveAuditPrivilege && !(Flags & AUDIT_ALLOW_NO_PRIVILEGE))
+ {
+ DPRINT1("Caller does not have SeAuditPrivilege\n");
+ Status = STATUS_PRIVILEGE_NOT_HELD;
+ goto Cleanup;
+ }
- /* For now pretend everything else is ok */
- Status = STATUS_SUCCESS;
+ /* Generic access must already be mapped to non-generic access types! */
+ if (DesiredAccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL))
+ {
+ DPRINT1("Generic access rights requested: 0x%lx\n", DesiredAccess);
+ Status = STATUS_GENERIC_NOT_MAPPED;
+ goto Cleanup;
+ }
+
+ /* Capture the security descriptor */
+ Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
+ UserMode,
+ PagedPool,
+ FALSE,
+ &CapturedSecurityDescriptor);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to capture security descriptor!\n");
+ goto Cleanup;
+ }
+
+ /* Validate the Security descriptor */
+ if ((SepGetOwnerFromDescriptor(CapturedSecurityDescriptor) == NULL) ||
+ (SepGetGroupFromDescriptor(CapturedSecurityDescriptor) == NULL))
+ {
+ Status = STATUS_INVALID_SECURITY_DESCR;
+ DPRINT1("Invalid security descriptor\n");
+ goto Cleanup;
+ }
+
+ /* Probe and capture the subsystem name */
+ Status = ProbeAndCaptureUnicodeString(&CapturedSubsystemName,
+ UserMode,
+ SubsystemName);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to capture subsystem name!\n");
+ goto Cleanup;
+ }
+
+ /* Probe and capture the object type name */
+ Status = ProbeAndCaptureUnicodeString(&CapturedObjectTypeName,
+ UserMode,
+ ObjectTypeName);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to capture object type name!\n");
+ goto Cleanup;
+ }
+
+ /* Probe and capture the object name */
+ Status = ProbeAndCaptureUnicodeString(&CapturedObjectName,
+ UserMode,
+ ObjectName);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to capture object name!\n");
+ goto Cleanup;
+ }
+
+ /* Check if we have a PrincipalSelfSid */
+ if (PrincipalSelfSid != NULL)
+ {
+ /* Capture it */
+ Status = SepCaptureSid(PrincipalSelfSid,
+ UserMode,
+ PagedPool,
+ FALSE,
+ &CapturedPrincipalSelfSid);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to capture PrincipalSelfSid!\n");
+ goto Cleanup;
+ }
+ }
+
+ /* Capture the object type list */
+ Status = SeCaptureObjectTypeList(ObjectTypeList,
+ ObjectTypeListLength,
+ UserMode,
+ &CapturedObjectTypeList);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to capture object type list!\n");
+ goto Cleanup;
+ }
+
+ /* Call the worker routine with the captured buffers */
+ SepAccessCheckAndAuditAlarmWorker(&CapturedSubsystemName,
+ HandleId,
+ &SubjectContext,
+ &CapturedObjectTypeName,
+ &CapturedObjectName,
+ CapturedSecurityDescriptor,
+ CapturedPrincipalSelfSid,
+ DesiredAccess,
+ AuditType,
+ HaveAuditPrivilege,
+ CapturedObjectTypeList,
+ ObjectTypeListLength,
+ &LocalGenericMapping,
+ SafeGrantedAccessList,
+ SafeAccessStatusList,
+ &LocalGenerateOnClose,
+ UseResultList);
+
+ /* Enter SEH to copy the data back to user mode */
+ _SEH2_TRY
+ {
+ /* Loop all result entries (only 1 when no list was requested) */
+ ASSERT(UseResultList || (ResultListLength == 1));
+ for (i = 0; i < ResultListLength; i++)
+ {
+ AccessStatusList[i] = SafeAccessStatusList[i];
+ GrantedAccessList[i] = SafeGrantedAccessList[i];
+ }
+
+ *GenerateOnClose = LocalGenerateOnClose;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ DPRINT1("Exception while copying back data: 0x%lx\n", Status);
+ }
+ _SEH2_END;
Cleanup:
+ if (CapturedObjectTypeList != NULL)
+ SeReleaseObjectTypeList(CapturedObjectTypeList, UserMode);
+
+ if (CapturedPrincipalSelfSid != NULL)
+ SepReleaseSid(CapturedPrincipalSelfSid, UserMode, FALSE);
+
+ if (CapturedObjectName.Buffer != NULL)
+ ReleaseCapturedUnicodeString(&CapturedObjectName, UserMode);
+
+ if (CapturedObjectTypeName.Buffer != NULL)
+ ReleaseCapturedUnicodeString(&CapturedObjectTypeName, UserMode);
+
+ if (CapturedSubsystemName.Buffer != NULL)
+ ReleaseCapturedUnicodeString(&CapturedSubsystemName, UserMode);
+
+ if (CapturedSecurityDescriptor != NULL)
+ SeReleaseSecurityDescriptor(CapturedSecurityDescriptor, UserMode, FALSE);
+
+ if (ClientToken != NULL)
+ {
+ ObDereferenceObject(ClientToken);
+ SubjectContext.ClientToken = SubjectContextToken;
+ }
+
+ if (AllocatedResultLists)
+ ExFreePoolWithTag(SafeGrantedAccessList, TAG_SEPA);
+
/* Release the security subject context */
SeReleaseSubjectContext(&SubjectContext);
PVOID HandleId,
BOOLEAN GenerateOnClose)
{
+ SECURITY_SUBJECT_CONTEXT SubjectContext;
UNICODE_STRING CapturedSubsystemName;
KPROCESSOR_MODE PreviousMode;
BOOLEAN UseImpersonationToken;
return STATUS_SUCCESS;
}
- /* Validate privilege */
- if (!SeSinglePrivilegeCheck(SeAuditPrivilege, PreviousMode))
+ /* Capture the security subject context */
+ SeCaptureSubjectContext(&SubjectContext);
+
+ /* Check for audit privilege */
+ if (!SeCheckAuditPrivilege(&SubjectContext, PreviousMode))
{
DPRINT1("Caller does not have SeAuditPrivilege\n");
- return STATUS_PRIVILEGE_NOT_HELD;
+ Status = STATUS_PRIVILEGE_NOT_HELD;
+ goto Cleanup;
}
/* Probe and capture the subsystem name */
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to capture subsystem name!\n");
- return Status;
+ goto Cleanup;
}
/* Get the current thread and check if it's impersonating */
PsDereferencePrimaryToken(Token);
}
- return STATUS_SUCCESS;
+ Status = STATUS_SUCCESS;
+
+Cleanup:
+
+ /* Release the security subject context */
+ SeReleaseSubjectContext(&SubjectContext);
+
+ return Status;
}
return STATUS_NOT_IMPLEMENTED;
}
-
-NTSTATUS NTAPI
-NtOpenObjectAuditAlarm(IN PUNICODE_STRING SubsystemName,
- IN PVOID HandleId,
- IN PUNICODE_STRING ObjectTypeName,
- IN PUNICODE_STRING ObjectName,
- IN PSECURITY_DESCRIPTOR SecurityDescriptor,
- IN HANDLE ClientToken,
- IN ULONG DesiredAccess,
- IN ULONG GrantedAccess,
- IN PPRIVILEGE_SET Privileges,
- IN BOOLEAN ObjectCreation,
- IN BOOLEAN AccessGranted,
- OUT PBOOLEAN GenerateOnClose)
+VOID
+NTAPI
+SepOpenObjectAuditAlarm(
+ _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
+ _In_ PUNICODE_STRING SubsystemName,
+ _In_opt_ PVOID HandleId,
+ _In_ PUNICODE_STRING ObjectTypeName,
+ _In_ PUNICODE_STRING ObjectName,
+ _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _In_ PTOKEN ClientToken,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ ACCESS_MASK GrantedAccess,
+ _In_opt_ PPRIVILEGE_SET Privileges,
+ _In_ BOOLEAN ObjectCreation,
+ _In_ BOOLEAN AccessGranted,
+ _Out_ PBOOLEAN GenerateOnClose)
{
+ DBG_UNREFERENCED_PARAMETER(SubjectContext);
+ DBG_UNREFERENCED_PARAMETER(SubsystemName);
+ DBG_UNREFERENCED_PARAMETER(HandleId);
+ DBG_UNREFERENCED_PARAMETER(ObjectTypeName);
+ DBG_UNREFERENCED_PARAMETER(ObjectName);
+ DBG_UNREFERENCED_PARAMETER(SecurityDescriptor);
+ DBG_UNREFERENCED_PARAMETER(ClientToken);
+ DBG_UNREFERENCED_PARAMETER(DesiredAccess);
+ DBG_UNREFERENCED_PARAMETER(GrantedAccess);
+ DBG_UNREFERENCED_PARAMETER(Privileges);
+ DBG_UNREFERENCED_PARAMETER(ObjectCreation);
+ DBG_UNREFERENCED_PARAMETER(AccessGranted);
UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ *GenerateOnClose = FALSE;
+}
+
+__kernel_entry
+NTSTATUS
+NTAPI
+NtOpenObjectAuditAlarm(
+ _In_ PUNICODE_STRING SubsystemName,
+ _In_opt_ PVOID HandleId,
+ _In_ PUNICODE_STRING ObjectTypeName,
+ _In_ PUNICODE_STRING ObjectName,
+ _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _In_ HANDLE ClientTokenHandle,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ ACCESS_MASK GrantedAccess,
+ _In_opt_ PPRIVILEGE_SET PrivilegeSet,
+ _In_ BOOLEAN ObjectCreation,
+ _In_ BOOLEAN AccessGranted,
+ _Out_ PBOOLEAN GenerateOnClose)
+{
+ PTOKEN ClientToken;
+ PSECURITY_DESCRIPTOR CapturedSecurityDescriptor;
+ UNICODE_STRING CapturedSubsystemName, CapturedObjectTypeName, CapturedObjectName;
+ ULONG PrivilegeCount, PrivilegeSetSize;
+ volatile PPRIVILEGE_SET CapturedPrivilegeSet;
+ BOOLEAN LocalGenerateOnClose;
+ PVOID CapturedHandleId;
+ SECURITY_SUBJECT_CONTEXT SubjectContext;
+ NTSTATUS Status;
+ PAGED_CODE();
+
+ /* Only user mode is supported! */
+ ASSERT(ExGetPreviousMode() != KernelMode);
+
+ /* Start clean */
+ ClientToken = NULL;
+ CapturedSecurityDescriptor = NULL;
+ CapturedPrivilegeSet = NULL;
+ CapturedSubsystemName.Buffer = NULL;
+ CapturedObjectTypeName.Buffer = NULL;
+ CapturedObjectName.Buffer = NULL;
+
+ /* Reference the client token */
+ Status = ObReferenceObjectByHandle(ClientTokenHandle,
+ TOKEN_QUERY,
+ SeTokenObjectType,
+ UserMode,
+ (PVOID*)&ClientToken,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to reference token handle %p: %lx\n",
+ ClientTokenHandle, Status);
+ return Status;
+ }
+
+ /* Capture the security subject context */
+ SeCaptureSubjectContext(&SubjectContext);
+
+ /* Validate the token's impersonation level */
+ if ((ClientToken->TokenType == TokenImpersonation) &&
+ (ClientToken->ImpersonationLevel < SecurityIdentification))
+ {
+ DPRINT1("Invalid impersonation level (%u)\n", ClientToken->ImpersonationLevel);
+ Status = STATUS_BAD_IMPERSONATION_LEVEL;
+ goto Cleanup;
+ }
+
+ /* Check for audit privilege */
+ if (!SeCheckAuditPrivilege(&SubjectContext, UserMode))
+ {
+ DPRINT1("Caller does not have SeAuditPrivilege\n");
+ Status = STATUS_PRIVILEGE_NOT_HELD;
+ goto Cleanup;
+ }
+
+ /* Check for NULL SecurityDescriptor */
+ if (SecurityDescriptor == NULL)
+ {
+ /* Nothing to do */
+ Status = STATUS_SUCCESS;
+ goto Cleanup;
+ }
+
+ /* Capture the security descriptor */
+ Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
+ UserMode,
+ PagedPool,
+ FALSE,
+ &CapturedSecurityDescriptor);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to capture security descriptor!\n");
+ goto Cleanup;
+ }
+
+ _SEH2_TRY
+ {
+ /* Check if we have a privilege set */
+ if (PrivilegeSet != NULL)
+ {
+ /* Probe the basic privilege set structure */
+ ProbeForRead(PrivilegeSet, sizeof(PRIVILEGE_SET), sizeof(ULONG));
+
+ /* Validate privilege count */
+ PrivilegeCount = PrivilegeSet->PrivilegeCount;
+ if (PrivilegeCount > SEP_PRIVILEGE_SET_MAX_COUNT)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ _SEH2_YIELD(goto Cleanup);
+ }
+
+ /* Calculate the size of the PrivilegeSet structure */
+ PrivilegeSetSize = FIELD_OFFSET(PRIVILEGE_SET, Privilege[PrivilegeCount]);
+
+ /* Probe the whole structure */
+ ProbeForRead(PrivilegeSet, PrivilegeSetSize, sizeof(ULONG));
+
+ /* Allocate a temp buffer */
+ CapturedPrivilegeSet = ExAllocatePoolWithTag(PagedPool,
+ PrivilegeSetSize,
+ TAG_PRIVILEGE_SET);
+ if (CapturedPrivilegeSet == NULL)
+ {
+ DPRINT1("Failed to allocate %u bytes\n", PrivilegeSetSize);
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ _SEH2_YIELD(goto Cleanup);
+ }
+
+ /* Copy the privileges */
+ RtlCopyMemory(CapturedPrivilegeSet, PrivilegeSet, PrivilegeSetSize);
+ }
+
+ if (HandleId != NULL)
+ {
+ ProbeForRead(HandleId, sizeof(PVOID), sizeof(PVOID));
+ CapturedHandleId = *(PVOID*)HandleId;
+ }
+
+ ProbeForWrite(GenerateOnClose, sizeof(BOOLEAN), sizeof(BOOLEAN));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ DPRINT1("Exception while probing parameters: 0x%lx\n", Status);
+ _SEH2_YIELD(goto Cleanup);
+ }
+ _SEH2_END;
+
+ /* Probe and capture the subsystem name */
+ Status = ProbeAndCaptureUnicodeString(&CapturedSubsystemName,
+ UserMode,
+ SubsystemName);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to capture subsystem name!\n");
+ goto Cleanup;
+ }
+
+ /* Probe and capture the object type name */
+ Status = ProbeAndCaptureUnicodeString(&CapturedObjectTypeName,
+ UserMode,
+ ObjectTypeName);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to capture object type name!\n");
+ goto Cleanup;
+ }
+
+ /* Probe and capture the object name */
+ Status = ProbeAndCaptureUnicodeString(&CapturedObjectName,
+ UserMode,
+ ObjectName);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to capture object name!\n");
+ goto Cleanup;
+ }
+
+ /* Call the internal function */
+ SepOpenObjectAuditAlarm(&SubjectContext,
+ &CapturedSubsystemName,
+ CapturedHandleId,
+ &CapturedObjectTypeName,
+ &CapturedObjectName,
+ CapturedSecurityDescriptor,
+ ClientToken,
+ DesiredAccess,
+ GrantedAccess,
+ CapturedPrivilegeSet,
+ ObjectCreation,
+ AccessGranted,
+ &LocalGenerateOnClose);
+
+ Status = STATUS_SUCCESS;
+
+ /* Enter SEH to copy the data back to user mode */
+ _SEH2_TRY
+ {
+ *GenerateOnClose = LocalGenerateOnClose;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ DPRINT1("Exception while copying back data: 0x%lx\n", Status);
+ }
+ _SEH2_END;
+
+Cleanup:
+
+ if (CapturedObjectName.Buffer != NULL)
+ ReleaseCapturedUnicodeString(&CapturedObjectName, UserMode);
+
+ if (CapturedObjectTypeName.Buffer != NULL)
+ ReleaseCapturedUnicodeString(&CapturedObjectTypeName, UserMode);
+
+ if (CapturedSubsystemName.Buffer != NULL)
+ ReleaseCapturedUnicodeString(&CapturedSubsystemName, UserMode);
+
+ if (CapturedSecurityDescriptor != NULL)
+ SeReleaseSecurityDescriptor(CapturedSecurityDescriptor, UserMode, FALSE);
+
+ if (CapturedPrivilegeSet != NULL)
+ ExFreePoolWithTag(CapturedPrivilegeSet, TAG_PRIVILEGE_SET);
+
+ /* Release the security subject context */
+ SeReleaseSubjectContext(&SubjectContext);
+
+ ObDereferenceObject(ClientToken);
+
+ return Status;
}
NtPrivilegedServiceAuditAlarm(
_In_opt_ PUNICODE_STRING SubsystemName,
_In_opt_ PUNICODE_STRING ServiceName,
- _In_ HANDLE ClientToken,
+ _In_ HANDLE ClientTokenHandle,
_In_ PPRIVILEGE_SET Privileges,
_In_ BOOLEAN AccessGranted )
{
KPROCESSOR_MODE PreviousMode;
- PTOKEN Token;
+ PTOKEN ClientToken;
volatile PPRIVILEGE_SET CapturedPrivileges = NULL;
UNICODE_STRING CapturedSubsystemName;
UNICODE_STRING CapturedServiceName;
PreviousMode = ExGetPreviousMode();
ASSERT(PreviousMode != KernelMode);
+ CapturedSubsystemName.Buffer = NULL;
+ CapturedServiceName.Buffer = NULL;
+
/* Reference the client token */
- Status = ObReferenceObjectByHandle(ClientToken,
+ Status = ObReferenceObjectByHandle(ClientTokenHandle,
TOKEN_QUERY,
SeTokenObjectType,
PreviousMode,
- (PVOID*)&Token,
+ (PVOID*)&ClientToken,
NULL);
if (!NT_SUCCESS(Status))
{
}
/* Validate the token's impersonation level */
- if ((Token->TokenType == TokenImpersonation) &&
- (Token->ImpersonationLevel < SecurityIdentification))
+ if ((ClientToken->TokenType == TokenImpersonation) &&
+ (ClientToken->ImpersonationLevel < SecurityIdentification))
{
- DPRINT1("Invalid impersonation level (%u)\n", Token->ImpersonationLevel);
- ObfDereferenceObject(Token);
+ DPRINT1("Invalid impersonation level (%u)\n", ClientToken->ImpersonationLevel);
+ ObDereferenceObject(ClientToken);
return STATUS_BAD_IMPERSONATION_LEVEL;
}
- /* Validate privilege */
- if (!SeSinglePrivilegeCheck(SeAuditPrivilege, PreviousMode))
+ /* Capture the security subject context */
+ SeCaptureSubjectContext(&SubjectContext);
+
+ /* Check for audit privilege */
+ if (!SeCheckAuditPrivilege(&SubjectContext, PreviousMode))
{
DPRINT1("Caller does not have SeAuditPrivilege\n");
- ObfDereferenceObject(Token);
- return STATUS_PRIVILEGE_NOT_HELD;
+ Status = STATUS_PRIVILEGE_NOT_HELD;
+ goto Cleanup;
}
/* Do we have a subsystem name? */
if (PrivilegeCount > SEP_PRIVILEGE_SET_MAX_COUNT)
{
Status = STATUS_INVALID_PARAMETER;
- goto Cleanup;
+ _SEH2_YIELD(goto Cleanup);
}
/* Calculate the size of the Privileges structure */
/* Allocate a temp buffer */
CapturedPrivileges = ExAllocatePoolWithTag(PagedPool,
PrivilegesSize,
- 'rPeS');
+ TAG_PRIVILEGE_SET);
if (CapturedPrivileges == NULL)
{
DPRINT1("Failed to allocate %u bytes\n", PrivilegesSize);
Status = STATUS_INSUFFICIENT_RESOURCES;
- goto Cleanup;
+ _SEH2_YIELD(goto Cleanup);
}
/* Copy the privileges */
{
Status = _SEH2_GetExceptionCode();
DPRINT1("Got exception 0x%lx\n", Status);
- goto Cleanup;
+ _SEH2_YIELD(goto Cleanup);
}
_SEH2_END;
- /* Capture the security subject context */
- SeCaptureSubjectContext(&SubjectContext);
-
/* Call the internal function */
SepAdtPrivilegedServiceAuditAlarm(&SubjectContext,
- &CapturedSubsystemName,
- &CapturedServiceName,
- Token,
+ SubsystemName ? &CapturedSubsystemName : NULL,
+ ServiceName ? &CapturedServiceName : NULL,
+ ClientToken,
SubjectContext.PrimaryToken,
CapturedPrivileges,
AccessGranted);
- /* Release the security subject context */
- SeReleaseSubjectContext(&SubjectContext);
-
Status = STATUS_SUCCESS;
Cleanup:
/* Cleanup resources */
- if (SubsystemName != NULL)
+ if (CapturedSubsystemName.Buffer != NULL)
ReleaseCapturedUnicodeString(&CapturedSubsystemName, PreviousMode);
- if (ServiceName != NULL)
+
+ if (CapturedServiceName.Buffer != NULL)
ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
+
if (CapturedPrivileges != NULL)
- ExFreePoolWithTag(CapturedPrivileges, 0);
- ObDereferenceObject(Token);
+ ExFreePoolWithTag(CapturedPrivileges, TAG_PRIVILEGE_SET);
+
+ /* Release the security subject context */
+ SeReleaseSubjectContext(&SubjectContext);
+
+ ObDereferenceObject(ClientToken);
return Status;
}