1153 lines
33 KiB
C
1153 lines
33 KiB
C
/*++
|
||
|
||
Copyright (c) 2000 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
adtqueue.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the routines for the Authz audit queue.
|
||
|
||
Author:
|
||
|
||
Jeff Hamblin - May 2000
|
||
|
||
Environment:
|
||
|
||
User mode only.
|
||
|
||
Revision History:
|
||
|
||
Created - May 2000
|
||
|
||
--*/
|
||
|
||
/*++
|
||
|
||
The Authz Audit Queue Algorithm
|
||
|
||
The following are used in the queueing algorithm:
|
||
|
||
hAuthzAuditQueueLowEvent - event that is signalled when threads are free
|
||
to place audits on the queue (queue is below high water mark). Note that
|
||
this is an auto reset event: when the event is signalled, exactly one
|
||
waiting thread is scheduled to run and the event then returns to a
|
||
nonsignalled state.
|
||
|
||
bAuthzAuditQueueHighEvent - boolean indicating that audits may not be
|
||
added (queue is over high water mark).
|
||
|
||
hAuthzAuditAddedEvent - event that is signalled when the queue is empty and an
|
||
audit get placed on the queue. The dequeueing thread runs when this is signalled.
|
||
|
||
hAuthzAuditQueueEmptyEvent - signals when the queue is empty.
|
||
|
||
AuthzAuditQueue - doubly linked list. This is the audit queue.
|
||
|
||
AuthzAuditQueueLength - The current number of audits in the queue.
|
||
|
||
hAuthzAuditThread - the dequeueing thread.
|
||
|
||
AuthzAuditQueueLock - critical section locking the queue and related
|
||
variables.
|
||
|
||
Assume that the Resource Manager wishes to monitor the queue length and
|
||
has specified High and Low water marks to control the growth of the queue.
|
||
If the queue length reaches the High water mark, then all queueing threads
|
||
will be blocked until the dequeueing thread has reduced the queue length
|
||
to the Low water mark.
|
||
|
||
Here is the flow of code for a thread attempting to log an audit (via
|
||
AuthziLogAuditEvent()) when the Resource Manager is monitoring the queue
|
||
length:
|
||
|
||
if QueueLength > .75 * HighWater # this is heuristic to save unnecessary
|
||
wait until the LowEvent is signalled # kernel transitions
|
||
enter queue critical section
|
||
{
|
||
insert audit on queue
|
||
QueueLength ++
|
||
signal AuditAddedEvent # notifying the dequeue thread
|
||
if (QueueLength >= HighWater)
|
||
{
|
||
bHigh = TRUE
|
||
}
|
||
}
|
||
leave critical section
|
||
|
||
...[code overhead, execute cleanup code in AuthziLogAuditEvent ...]
|
||
|
||
enter queue critical section
|
||
{
|
||
if (!bHigh)
|
||
{
|
||
if (QueueLength <= HighWater)
|
||
{
|
||
signal LowEvent #allow other threads to run
|
||
}
|
||
}
|
||
ASSERT(FALSE);
|
||
}
|
||
leave critical section
|
||
|
||
Here is the algorithm for the dequeueing thread:
|
||
|
||
while (TRUE)
|
||
{
|
||
wait for AuditAdded event
|
||
while (QueueLength > 0)
|
||
{
|
||
enter queue critical section
|
||
{
|
||
remove audit from head of list
|
||
QueueLength--
|
||
if (bHigh)
|
||
{
|
||
if (QueueLength <= LowWater)
|
||
{
|
||
bHigh = FALSE
|
||
signal LowEvent # tell threads it is okay to queue
|
||
}
|
||
}
|
||
}
|
||
release critical section
|
||
|
||
Send to LSA
|
||
}
|
||
|
||
enter critical section
|
||
{
|
||
if (QueueLength == 0)
|
||
{
|
||
reset AuditAdded event # make myself wait
|
||
}
|
||
}
|
||
release critical section
|
||
}
|
||
|
||
--*/
|
||
|
||
#include "pch.h"
|
||
|
||
#pragma hdrstop
|
||
|
||
#include <authzp.h>
|
||
#include <authzi.h>
|
||
|
||
#ifdef AUTHZ_AUDIT_COUNTER
|
||
LONG AuthzpAuditsEnqueued = 0;
|
||
LONG AuthzpAuditsDequeued = 0;
|
||
#endif
|
||
|
||
|
||
BOOL
|
||
AuthzpEnQueueAuditEvent(
|
||
PAUTHZI_AUDIT_QUEUE pQueue,
|
||
PAUTHZ_AUDIT_QUEUE_ENTRY pAudit
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description
|
||
|
||
This enqueues an audit without regard to any queue size limits. It does minimal event management.
|
||
|
||
Arguments
|
||
|
||
pQueue - Pointer to the queue to place the audit on.
|
||
pAudit - Pointer to the audit to enqueue.
|
||
|
||
Return Value
|
||
|
||
Boolean, TRUE on success, FALSE on failure.
|
||
Extended information available with GetLastError().
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOL b = TRUE;
|
||
|
||
RtlEnterCriticalSection(&pQueue->AuthzAuditQueueLock);
|
||
InsertTailList(&pQueue->AuthzAuditQueue, &pAudit->list);
|
||
pQueue->AuthzAuditQueueLength++;
|
||
|
||
#ifdef AUTHZ_AUDIT_COUNTER
|
||
InterlockedIncrement(&AuthzpAuditsEnqueued);
|
||
#endif
|
||
|
||
//
|
||
// Only set the AuditAdded event if the length goes from 0 to 1. This
|
||
// saves us redundant kernel transitions.
|
||
//
|
||
|
||
if (pQueue->AuthzAuditQueueLength == 1)
|
||
{
|
||
b = SetEvent(pQueue->hAuthzAuditAddedEvent);
|
||
if (!b)
|
||
{
|
||
ASSERT(L"AUTHZ: SetEvent on hAuthzAuditAddedEvent handle failed." && FALSE);
|
||
goto Cleanup;
|
||
}
|
||
|
||
b = ResetEvent(pQueue->hAuthzAuditQueueEmptyEvent);
|
||
if (!b)
|
||
{
|
||
ASSERT(L"AUTHZ: ResetEvent on hAuthzAuditQueueEmptyEvent handle failed." && FALSE);
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
|
||
Cleanup:
|
||
|
||
RtlLeaveCriticalSection(&pQueue->AuthzAuditQueueLock);
|
||
return b;
|
||
}
|
||
|
||
|
||
BOOL
|
||
AuthzpEnQueueAuditEventMonitor(
|
||
PAUTHZI_AUDIT_QUEUE pQueue,
|
||
PAUTHZ_AUDIT_QUEUE_ENTRY pAudit
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description
|
||
|
||
This enqueues an audit and sets appropriate events for queue size monitoring.
|
||
|
||
Arguments
|
||
|
||
pQueue - pointer to the queue to place audit on.
|
||
pAudit - pointer to the audit to queue.
|
||
|
||
Return Value
|
||
|
||
Boolean, TRUE on success, FALSE on failure.
|
||
Extended information available with GetLastError().
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOL b = TRUE;
|
||
|
||
RtlEnterCriticalSection(&pQueue->AuthzAuditQueueLock);
|
||
InsertTailList(&pQueue->AuthzAuditQueue, &pAudit->list);
|
||
pQueue->AuthzAuditQueueLength++;
|
||
|
||
#ifdef AUTHZ_AUDIT_COUNTER
|
||
InterlockedIncrement(&AuthzpAuditsEnqueued);
|
||
#endif
|
||
|
||
//
|
||
// Only set the AuditAdded event if the length goes from 0 to 1. This
|
||
// saves us redundant kernel transitions.
|
||
//
|
||
|
||
if (pQueue->AuthzAuditQueueLength == 1)
|
||
{
|
||
b = SetEvent(pQueue->hAuthzAuditAddedEvent);
|
||
if (!b)
|
||
{
|
||
ASSERT(L"AUTHZ: SetEvent on hAuthzAuditAddedEvent handle failed." && FALSE);
|
||
goto Cleanup;
|
||
}
|
||
|
||
b = ResetEvent(pQueue->hAuthzAuditQueueEmptyEvent);
|
||
if (!b)
|
||
{
|
||
ASSERT(L"AUTHZ: ResetEvent on hAuthzAuditQueueEmptyEvent handle failed." && FALSE);
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
|
||
if (pQueue->AuthzAuditQueueLength >= pQueue->dwAuditQueueHigh)
|
||
{
|
||
#ifdef AUTHZ_DEBUG_QUEUE
|
||
wprintf(L"___Setting HIGH water mark ON\n");
|
||
fflush(stdout);
|
||
#endif
|
||
pQueue->bAuthzAuditQueueHighEvent = TRUE;
|
||
}
|
||
|
||
Cleanup:
|
||
|
||
RtlLeaveCriticalSection(&pQueue->AuthzAuditQueueLock);
|
||
return b;
|
||
}
|
||
|
||
|
||
ULONG
|
||
AuthzpDeQueueThreadWorker(
|
||
LPVOID lpParameter
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description
|
||
|
||
This is the function run by the dequeueing thread. It pulls audits from the queue
|
||
and sends them to LSA.
|
||
|
||
Arguments
|
||
|
||
lpParameter - generic thread parameter. The actual parameter passed in is of
|
||
type PAUTHZI_AUDIT_QUEUE.
|
||
|
||
Return Value
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOL b;
|
||
PAUTHZ_AUDIT_QUEUE_ENTRY pAuditEntry = NULL;
|
||
PAUTHZI_AUDIT_QUEUE pQueue = (PAUTHZI_AUDIT_QUEUE) lpParameter;
|
||
DWORD dwError;
|
||
|
||
while (pQueue->bWorker)
|
||
{
|
||
|
||
//
|
||
// The thread waits until there are audits in the queue.
|
||
//
|
||
|
||
dwError = WaitForSingleObject(
|
||
pQueue->hAuthzAuditAddedEvent,
|
||
INFINITE
|
||
);
|
||
|
||
//
|
||
// If the wait does not succeed either something is very wrong or the hAuthzAuditAddedEvent
|
||
// was closed, indicating that the RM is freeing its hRMAuditInfo. The thread should exit.
|
||
//
|
||
|
||
if (WAIT_OBJECT_0 != dwError)
|
||
{
|
||
ASSERT(L"WaitForSingleObject on hAuthzAuditAddedEvent failed." && FALSE);
|
||
}
|
||
|
||
//
|
||
// The thread remains active while there are audits in the queue.
|
||
//
|
||
|
||
while (pQueue->AuthzAuditQueueLength > 0)
|
||
{
|
||
RtlEnterCriticalSection(&pQueue->AuthzAuditQueueLock);
|
||
pAuditEntry = (PAUTHZ_AUDIT_QUEUE_ENTRY) (pQueue->AuthzAuditQueue).Flink;
|
||
RemoveEntryList(&pAuditEntry->list);
|
||
pQueue->AuthzAuditQueueLength--;
|
||
|
||
#ifdef AUTHZ_AUDIT_COUNTER
|
||
InterlockedIncrement(&AuthzpAuditsDequeued);
|
||
#endif
|
||
|
||
if (FLAG_ON(pQueue->Flags, AUTHZ_MONITOR_AUDIT_QUEUE_SIZE))
|
||
{
|
||
if (TRUE == pQueue->bAuthzAuditQueueHighEvent)
|
||
{
|
||
if (pQueue->AuthzAuditQueueLength <= pQueue->dwAuditQueueLow)
|
||
{
|
||
|
||
//
|
||
// If the High flag is on and the length is now reduced to the low water mark, then
|
||
// set appropriate events.
|
||
//
|
||
|
||
pQueue->bAuthzAuditQueueHighEvent = FALSE;
|
||
b = SetEvent(pQueue->hAuthzAuditQueueLowEvent);
|
||
if (!b)
|
||
{
|
||
ASSERT(L"SetEvent on hAuthzAuditQueueLowEvent failed." && FALSE);
|
||
}
|
||
#ifdef AUTHZ_DEBUG_QUEUE
|
||
wprintf(L"** _____ TURNING HIGH WATER OFF _____\n");
|
||
fflush(stdout);
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
|
||
RtlLeaveCriticalSection(&pQueue->AuthzAuditQueueLock);
|
||
|
||
b = AuthzpSendAuditToLsa(
|
||
(AUDIT_HANDLE)(pAuditEntry->pAAETO->hAudit),
|
||
pAuditEntry->Flags,
|
||
pAuditEntry->pAuditParams,
|
||
pAuditEntry->pReserved
|
||
);
|
||
|
||
#ifdef AUTHZ_DEBUG_QUEUE
|
||
if (!b)
|
||
{
|
||
DbgPrint("Error in AuthzpSendAuditToLsa() :: Error = %d = 0x%x\n", GetLastError(), GetLastError());
|
||
DbgPrint("Context = 0x%x\n", pAuditEntry->pAAETO->hAudit);
|
||
DbgPrint("Flags = 0x%x\n", pAuditEntry->Flags);
|
||
DbgPrint("Params = 0x%x\n", pAuditEntry->pAuditParams);
|
||
ASSERT(FALSE);
|
||
}
|
||
#endif
|
||
b = AuthzpDereferenceAuditEventType((AUTHZ_AUDIT_EVENT_TYPE_HANDLE)pAuditEntry->pAAETO);
|
||
if (!b)
|
||
{
|
||
ASSERT(FALSE && L"Deref AuditEventType failed.");
|
||
}
|
||
AuthzpFree(pAuditEntry->pAuditParams);
|
||
AuthzpFree(pAuditEntry);
|
||
}
|
||
|
||
RtlEnterCriticalSection(&pQueue->AuthzAuditQueueLock);
|
||
if (0 == pQueue->AuthzAuditQueueLength)
|
||
{
|
||
b = ResetEvent(pQueue->hAuthzAuditAddedEvent);
|
||
if (!b)
|
||
{
|
||
ASSERT(L"ResetEvent on hAuthzAuditAddedEvent failed." && FALSE);
|
||
}
|
||
b = SetEvent(pQueue->hAuthzAuditQueueEmptyEvent);
|
||
if (!b)
|
||
{
|
||
ASSERT(L"SetEvent on hAuthzAuditQueueEmptyEvent failed." && FALSE);
|
||
}
|
||
}
|
||
RtlLeaveCriticalSection(&pQueue->AuthzAuditQueueLock);
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
BOOL
|
||
AuthzpCreateAndLogAudit(
|
||
IN DWORD AuditTypeFlag,
|
||
IN PAUTHZI_CLIENT_CONTEXT pAuthzClientContext,
|
||
IN PAUTHZI_AUDIT_EVENT pAuditEvent,
|
||
IN PAUTHZI_RESOURCE_MANAGER pRM,
|
||
IN PIOBJECT_TYPE_LIST LocalTypeList,
|
||
IN PAUTHZ_ACCESS_REQUEST pRequest,
|
||
IN PAUTHZ_ACCESS_REPLY pReply
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description
|
||
|
||
This is called from AuthzpGenerateAudit as a wrapper around LSA and
|
||
AuthziLogAuditEvent functionality. It places the appropriate audit
|
||
information on a queue for sending to LSA.
|
||
|
||
Arguments
|
||
|
||
AuditTypeFlag - mask to specify success | failure audit generation. Only
|
||
one bit at a time.
|
||
|
||
pAuthzClientContext - pointer to Authz context representing the client.
|
||
|
||
pAuditEvent - Object specific audit info will be passed in this structure.
|
||
|
||
pRM - Resource manager that generates the audit.
|
||
|
||
LocalTypeList - Internal object type list structure.
|
||
|
||
pRequest - specifies the desired access mask, principal self sid, the
|
||
object type list structure (if any).
|
||
|
||
pReply - The reply structure to return the results.
|
||
|
||
Return Value
|
||
|
||
TRUE if successful, FALSE if not.
|
||
Extended information available with GetLastError().
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
#define AUTHZ_BUFFER_CAPTURE_MAX 200
|
||
|
||
BOOL b;
|
||
AUDIT_PARAMS AuditParams = {0};
|
||
AUDIT_PARAM ParamArray[SE_MAX_AUDIT_PARAMETERS] = {0};
|
||
PAUTHZI_AUDIT_EVENT pCapturedAuditEvent = NULL;
|
||
UCHAR pBuffer[AUTHZ_BUFFER_CAPTURE_MAX] = {0};
|
||
AUDIT_OBJECT_TYPE FixedObjectTypeToAudit = {0};
|
||
AUDIT_OBJECT_TYPES ObjectTypeListAudit = {0};
|
||
PAUDIT_OBJECT_TYPE ObjectTypesToAudit = NULL;
|
||
USHORT ObjectTypeAuditCount = 0;
|
||
LONG i = 0;
|
||
LONG j = 0;
|
||
DWORD APF_AuditTypeFlag = 0;
|
||
ACCESS_MASK MaskToAudit = 0;
|
||
|
||
//
|
||
// Capture pAuditEvent, as we may change the pAuditParams member and would like to
|
||
// avoid the inevitable race that would follow.
|
||
//
|
||
|
||
if (AUTHZ_BUFFER_CAPTURE_MAX >= pAuditEvent->dwSize)
|
||
{
|
||
pCapturedAuditEvent = (PAUTHZI_AUDIT_EVENT) pBuffer;
|
||
RtlCopyMemory(
|
||
pCapturedAuditEvent,
|
||
pAuditEvent,
|
||
pAuditEvent->dwSize
|
||
);
|
||
}
|
||
else
|
||
{
|
||
pCapturedAuditEvent = AuthzpAlloc(pAuditEvent->dwSize);
|
||
|
||
if (AUTHZ_ALLOCATION_FAILED(pCapturedAuditEvent))
|
||
{
|
||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||
b = FALSE;
|
||
goto Cleanup;
|
||
}
|
||
|
||
RtlCopyMemory(
|
||
pCapturedAuditEvent,
|
||
pAuditEvent,
|
||
pAuditEvent->dwSize
|
||
);
|
||
|
||
}
|
||
|
||
//
|
||
// Make sure only one valid bit is on in the AuditTypeFlag. If a RM needs to generate
|
||
// both success and failure audits, then two separate calls should be made.
|
||
//
|
||
|
||
ASSERT(!(
|
||
FLAG_ON(AuditTypeFlag, AUTHZ_OBJECT_SUCCESS_AUDIT) &&
|
||
FLAG_ON(AuditTypeFlag, AUTHZ_OBJECT_FAILURE_AUDIT)
|
||
));
|
||
|
||
//
|
||
// Set the APF_AuditTypeFlag. LSA has its own flags for audit success
|
||
// and audit failure. Authz must map the Authz flag to the LSA APF equivalent.
|
||
//
|
||
|
||
if (FLAG_ON(AuditTypeFlag, AUTHZ_OBJECT_SUCCESS_AUDIT))
|
||
{
|
||
APF_AuditTypeFlag = APF_AuditSuccess;
|
||
|
||
//
|
||
// Test if the RM specifically disabled success audits
|
||
//
|
||
|
||
if (FLAG_ON(pCapturedAuditEvent->Flags, AUTHZ_NO_SUCCESS_AUDIT))
|
||
{
|
||
b = TRUE;
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
else if (FLAG_ON(AuditTypeFlag, AUTHZ_OBJECT_FAILURE_AUDIT))
|
||
{
|
||
APF_AuditTypeFlag = APF_AuditFailure;
|
||
|
||
//
|
||
// Test if the RM specifically disabled failure audits
|
||
//
|
||
|
||
if (FLAG_ON(pCapturedAuditEvent->Flags, AUTHZ_NO_FAILURE_AUDIT))
|
||
{
|
||
b = TRUE;
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
b = FALSE;
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Set the AUTHZ_AUDIT_QUEUE_HANDLE and AUTHZ_AUDIT_EVENT_TYPE_HANDLE of the AuditEvent if they are not yet set.
|
||
//
|
||
|
||
if (NULL == pCapturedAuditEvent->hAET)
|
||
{
|
||
if (FLAG_ON(pCapturedAuditEvent->Flags, AUTHZ_DS_CATEGORY_FLAG))
|
||
{
|
||
pCapturedAuditEvent->hAET = pRM->hAETDS;
|
||
}
|
||
else
|
||
{
|
||
pCapturedAuditEvent->hAET = pRM->hAET;
|
||
}
|
||
}
|
||
|
||
if (NULL == pAuditEvent->hAuditQueue)
|
||
{
|
||
pCapturedAuditEvent->hAuditQueue = pRM->hAuditQueue;
|
||
InterlockedCompareExchangePointer(
|
||
&pAuditEvent->hAuditQueue,
|
||
pRM->hAuditQueue,
|
||
NULL
|
||
);
|
||
}
|
||
|
||
//
|
||
// Decide what access bits we should audit
|
||
//
|
||
|
||
MaskToAudit = (APF_AuditTypeFlag == APF_AuditSuccess) ? pReply->GrantedAccessMask[0] : pRequest->DesiredAccess;
|
||
|
||
//
|
||
// If the RM gives us an AUDIT_PARAMS structure to marshall, then we don't
|
||
// need to generate our own.
|
||
//
|
||
|
||
if (AUTHZ_NON_NULL_PTR(pCapturedAuditEvent->pAuditParams))
|
||
{
|
||
|
||
//
|
||
// Capture the AuditParams so that we can change the User SID without racing.
|
||
//
|
||
|
||
RtlCopyMemory(
|
||
&AuditParams,
|
||
pCapturedAuditEvent->pAuditParams,
|
||
sizeof(AUDIT_PARAMS)
|
||
);
|
||
|
||
ASSERT(pCapturedAuditEvent->pAuditParams->Count <= SE_MAX_AUDIT_PARAMETERS);
|
||
|
||
RtlCopyMemory(
|
||
&ParamArray,
|
||
pCapturedAuditEvent->pAuditParams->Parameters,
|
||
sizeof(AUDIT_PARAM) * pCapturedAuditEvent->pAuditParams->Count
|
||
);
|
||
|
||
AuditParams.Parameters = ParamArray;
|
||
|
||
//
|
||
// Replace the SID in the AUDIT_PARAMS with the SID of the current Client Context.
|
||
//
|
||
|
||
if (AUTHZ_NON_NULL_PTR(pAuthzClientContext->Sids[0].Sid))
|
||
{
|
||
AuditParams.Parameters[0].Data0 = (ULONG_PTR) pAuthzClientContext->Sids[0].Sid;
|
||
}
|
||
|
||
AuditParams.Flags = APF_AuditTypeFlag;
|
||
|
||
pCapturedAuditEvent->pAuditParams = &AuditParams;
|
||
|
||
b = AuthziLogAuditEvent(
|
||
0,
|
||
(AUTHZ_AUDIT_EVENT_HANDLE)pCapturedAuditEvent,
|
||
0
|
||
);
|
||
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// The caller has not given us an audit to generate. We will create one, provided that
|
||
// the AuditID specifies the generic object access (SE_AUDITID_OBJECT_OPERATION)
|
||
//
|
||
|
||
if ((NULL != pCapturedAuditEvent->hAET) &&
|
||
(((PAUTHZ_AUDIT_EVENT_TYPE_OLD)pCapturedAuditEvent->hAET)->u.Legacy.AuditId != SE_AUDITID_OBJECT_OPERATION))
|
||
{
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
b = FALSE;
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Create the generic object access audit. There are two codepaths
|
||
// that initialize the AuditParams structure. The first path is taken if
|
||
// there is no ObjectTypeList. The second path is taken if there is an
|
||
// ObjectTypeList.
|
||
//
|
||
|
||
AuditParams.Parameters = ParamArray;
|
||
pCapturedAuditEvent->pAuditParams = &AuditParams;
|
||
|
||
//
|
||
// Check if there is an ObjectTypeList.
|
||
//
|
||
|
||
if (AUTHZ_NON_NULL_PTR(pRequest->ObjectTypeList))
|
||
{
|
||
|
||
//
|
||
// If the length of the structure is 1 then the caller only wants access
|
||
// at the root of the tree.
|
||
//
|
||
|
||
if (1 == pReply->ResultListLength)
|
||
{
|
||
|
||
//
|
||
// Caller only wants access at ObjectTypeList root, so only one ObjectType to
|
||
// audit. For efficiency simply use the stack variable.
|
||
//
|
||
|
||
ObjectTypesToAudit = &FixedObjectTypeToAudit;
|
||
ObjectTypeAuditCount = 1;
|
||
FixedObjectTypeToAudit.AccessMask = pReply->GrantedAccessMask[0];
|
||
|
||
RtlCopyMemory(
|
||
&FixedObjectTypeToAudit.ObjectType,
|
||
&LocalTypeList[0].ObjectType,
|
||
sizeof(GUID)
|
||
);
|
||
}
|
||
else
|
||
{
|
||
|
||
//
|
||
// The caller wants more than access at ObjectTypeList root. He wants the
|
||
// whole thing.
|
||
//
|
||
|
||
//
|
||
// Determine how many GUIDs the client has access to which should be audited
|
||
//
|
||
|
||
for (ObjectTypeAuditCount = 0, i = 0; i < (LONG) pReply->ResultListLength; i++)
|
||
{
|
||
if (FLAG_ON(LocalTypeList[i].Flags, AuditTypeFlag))
|
||
{
|
||
ObjectTypeAuditCount++;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Allocate appropriate storage space for GUID list
|
||
//
|
||
|
||
ObjectTypesToAudit = AuthzpAlloc(sizeof(AUDIT_OBJECT_TYPE) * ObjectTypeAuditCount);
|
||
|
||
if (AUTHZ_ALLOCATION_FAILED(ObjectTypesToAudit))
|
||
{
|
||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||
b = FALSE;
|
||
goto Cleanup;
|
||
}
|
||
|
||
RtlZeroMemory(
|
||
ObjectTypesToAudit,
|
||
sizeof(AUDIT_OBJECT_TYPE) * ObjectTypeAuditCount
|
||
);
|
||
|
||
for (i = 0, j = -1; i < ObjectTypeAuditCount; i++)
|
||
{
|
||
|
||
//
|
||
// One counter tracks position in the alloc'ed array of ObjectTypesToAudit.
|
||
// The other counter picks out the indices in the pReply and LocalTypeList
|
||
// structures that need to be audited for success.
|
||
//
|
||
|
||
//
|
||
// find the next GUID to audit in pReply that client was granted access to.
|
||
//
|
||
|
||
do
|
||
{
|
||
j++;
|
||
}
|
||
while (!FLAG_ON(LocalTypeList[j].Flags, AuditTypeFlag));
|
||
|
||
//
|
||
// In the success audit, the AccessMask records the actual
|
||
// granted bits.
|
||
//
|
||
|
||
ObjectTypesToAudit[i].AccessMask = pReply->GrantedAccessMask[j];
|
||
ObjectTypesToAudit[i].Level = LocalTypeList[j].Level;
|
||
ObjectTypesToAudit[i].Flags = 0;
|
||
|
||
RtlCopyMemory(
|
||
&ObjectTypesToAudit[i].ObjectType,
|
||
&LocalTypeList[j].ObjectType,
|
||
sizeof(GUID)
|
||
);
|
||
}
|
||
|
||
}
|
||
|
||
ObjectTypeListAudit.Count = ObjectTypeAuditCount;
|
||
ObjectTypeListAudit.pObjectTypes = ObjectTypesToAudit;
|
||
ObjectTypeListAudit.Flags = 0;
|
||
|
||
b = AuthziInitializeAuditParamsWithRM(
|
||
APF_AuditTypeFlag,
|
||
(AUTHZ_RESOURCE_MANAGER_HANDLE)pRM,
|
||
9,
|
||
&AuditParams,
|
||
APT_String, pCapturedAuditEvent->szOperationType,
|
||
APT_String, pCapturedAuditEvent->szObjectType,
|
||
APT_String, pCapturedAuditEvent->szObjectName,
|
||
APT_String, L"-",
|
||
APT_LogonId | AP_PrimaryLogonId,
|
||
APT_LogonId, pAuthzClientContext->AuthenticationId,
|
||
APT_Ulong | AP_AccessMask, MaskToAudit, 1,
|
||
APT_ObjectTypeList, &ObjectTypeListAudit, 1,
|
||
APT_String, pCapturedAuditEvent->szAdditionalInfo
|
||
);
|
||
|
||
if (!b)
|
||
{
|
||
#ifdef AUTHZ_DEBUG_QUEUE
|
||
DbgPrint("AuthzInitializeAuditParams failed %d\n", GetLastError());
|
||
#endif
|
||
goto Cleanup;
|
||
}
|
||
} // matches "if (AUTHZ_NON_NULL_PTR(pRequest->ObjectTypeList))"
|
||
else
|
||
{
|
||
b = AuthziInitializeAuditParamsWithRM(
|
||
APF_AuditTypeFlag,
|
||
(AUTHZ_RESOURCE_MANAGER_HANDLE)pRM,
|
||
9,
|
||
&AuditParams,
|
||
APT_String, pCapturedAuditEvent->szOperationType,
|
||
APT_String, pCapturedAuditEvent->szObjectType,
|
||
APT_String, pCapturedAuditEvent->szObjectName,
|
||
APT_String, L"-",
|
||
APT_LogonId | AP_PrimaryLogonId,
|
||
APT_LogonId, pAuthzClientContext->AuthenticationId,
|
||
APT_Ulong | AP_AccessMask, MaskToAudit, 1,
|
||
APT_String, L"-",
|
||
APT_String, pCapturedAuditEvent->szAdditionalInfo
|
||
);
|
||
|
||
if (!b)
|
||
{
|
||
#ifdef AUTHZ_DEBUG_QUEUE
|
||
DbgPrint("AuthzInitializeAuditParams failed %d\n", GetLastError());
|
||
#endif
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Replace the SID in the AUDIT_PARAMS with the SID of the current Client Context.
|
||
//
|
||
|
||
if (AUTHZ_NON_NULL_PTR(pAuthzClientContext->Sids[0].Sid))
|
||
{
|
||
pCapturedAuditEvent->pAuditParams->Parameters[0].Data0 = (ULONG_PTR) pAuthzClientContext->Sids[0].Sid;
|
||
}
|
||
|
||
//
|
||
// At this point, AuditParams is initialized for an audit. Send to the LSA.
|
||
//
|
||
|
||
b = AuthziLogAuditEvent(
|
||
0,
|
||
(AUTHZ_AUDIT_EVENT_HANDLE)pCapturedAuditEvent,
|
||
0
|
||
);
|
||
|
||
if (!b)
|
||
{
|
||
goto Cleanup;
|
||
}
|
||
|
||
Cleanup:
|
||
|
||
if (ObjectTypesToAudit != &FixedObjectTypeToAudit)
|
||
{
|
||
AuthzpFreeNonNull(ObjectTypesToAudit);
|
||
}
|
||
|
||
if (pCapturedAuditEvent != (PAUTHZI_AUDIT_EVENT)pBuffer)
|
||
{
|
||
AuthzpFreeNonNull(pCapturedAuditEvent);
|
||
}
|
||
|
||
return b;
|
||
}
|
||
|
||
|
||
BOOL
|
||
AuthzpMarshallAuditParams(
|
||
OUT PAUDIT_PARAMS * ppMarshalledAuditParams,
|
||
IN PAUDIT_PARAMS pAuditParams
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will take an AUDIT_PARAMS structure and create a new
|
||
structure that is suitable for sending to LSA. It will be allocated
|
||
as a single chunk of memory.
|
||
|
||
Arguments:
|
||
|
||
ppMarshalledAuditParams - pointer to pointer that will receive the
|
||
marshalled audit parameters. This memory is allocated within the routine.
|
||
The dequeue thread frees this memory.
|
||
|
||
pAuditParams - Original, unmarshalled version of the AUDIT_PARAMS.
|
||
|
||
Return Value:
|
||
|
||
Boolean: TRUE if success, FALSE if failure.
|
||
Extended information available with GetLastError().
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD i = 0;
|
||
DWORD AuditParamsSize = 0;
|
||
PAUDIT_PARAMS pMarshalledAuditParams = NULL;
|
||
BOOL b = TRUE;
|
||
PUCHAR Base = NULL;
|
||
PUCHAR inData0 = NULL;
|
||
|
||
*ppMarshalledAuditParams = NULL;
|
||
|
||
//
|
||
// Begin calculating the total size required for the marshalled version
|
||
// of pAuditParams.
|
||
//
|
||
|
||
AuditParamsSize = sizeof(AUDIT_PARAMS) + sizeof(AUDIT_PARAM) * pAuditParams->Count;
|
||
AuditParamsSize = PtrAlignSize( AuditParamsSize );
|
||
|
||
//
|
||
// Determine how much memory each parameter requires.
|
||
//
|
||
|
||
for (i = 0; i < pAuditParams->Count; i++)
|
||
{
|
||
inData0 = (PUCHAR) pAuditParams->Parameters[i].Data0;
|
||
|
||
switch (pAuditParams->Parameters[i].Type)
|
||
{
|
||
case APT_String:
|
||
{
|
||
|
||
//
|
||
// wcslen returns the number of characters, excluding the terminating NULL. Must check for NULL
|
||
// because the AdditionalInfo string is OPTIONAL.
|
||
//
|
||
|
||
if (AUTHZ_NON_NULL_PTR(inData0))
|
||
{
|
||
AuditParamsSize += (DWORD)(sizeof(WCHAR) * wcslen((PWSTR) inData0) + sizeof(WCHAR));
|
||
AuditParamsSize = PtrAlignSize( AuditParamsSize );
|
||
}
|
||
break;
|
||
}
|
||
case APT_Pointer:
|
||
case APT_Ulong:
|
||
case APT_LogonId:
|
||
{
|
||
break;
|
||
}
|
||
case APT_Sid:
|
||
{
|
||
AuditParamsSize += RtlLengthSid((PSID) inData0);
|
||
AuditParamsSize = PtrAlignSize( AuditParamsSize );
|
||
break;
|
||
}
|
||
case APT_ObjectTypeList:
|
||
{
|
||
AUDIT_OBJECT_TYPES * aot = (AUDIT_OBJECT_TYPES *) inData0;
|
||
|
||
//
|
||
// Need space for AUDIT_OBJECT_TYPES structure, and the AUDIT_OBJECT_TYPE
|
||
// array that it contains.
|
||
//
|
||
|
||
AuditParamsSize += sizeof (AUDIT_OBJECT_TYPES);
|
||
AuditParamsSize = PtrAlignSize( AuditParamsSize );
|
||
AuditParamsSize += sizeof(AUDIT_OBJECT_TYPE) * aot->Count;
|
||
AuditParamsSize = PtrAlignSize( AuditParamsSize );
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
ASSERT(L"Invalid Authz audit parameter" && FALSE);
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
b = FALSE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (!b)
|
||
{
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Allocate space for the marshalled blob.
|
||
//
|
||
|
||
pMarshalledAuditParams = (PAUDIT_PARAMS) AuthzpAlloc(AuditParamsSize);
|
||
|
||
if (AUTHZ_ALLOCATION_FAILED(pMarshalledAuditParams))
|
||
{
|
||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||
b = FALSE;
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Set the fields of the marshalled AUDIT_PARAMS
|
||
//
|
||
|
||
pMarshalledAuditParams->Count = pAuditParams->Count;
|
||
pMarshalledAuditParams->Flags = pAuditParams->Flags;
|
||
pMarshalledAuditParams->Length = pAuditParams->Length;
|
||
pMarshalledAuditParams->Parameters = (AUDIT_PARAM *)((PUCHAR)pMarshalledAuditParams + sizeof(AUDIT_PARAMS));
|
||
|
||
//
|
||
// Base points to the beginning of the "data" section of the marshalled space,
|
||
// that is, Base is the area to copy member fields in and subsequently point at.
|
||
//
|
||
|
||
Base = (PUCHAR)pMarshalledAuditParams;
|
||
Base += PtrAlignSize( sizeof(AUDIT_PARAMS) + sizeof(AUDIT_PARAM) * pAuditParams->Count );
|
||
|
||
ASSERT(Base > (PUCHAR)pMarshalledAuditParams);
|
||
ASSERT(Base < (PUCHAR)((PUCHAR)pMarshalledAuditParams + AuditParamsSize));
|
||
|
||
//
|
||
// Move the Parameters array into the marshalled blob.
|
||
//
|
||
|
||
RtlCopyMemory(
|
||
pMarshalledAuditParams->Parameters,
|
||
pAuditParams->Parameters,
|
||
sizeof(AUDIT_PARAM) * pAuditParams->Count
|
||
);
|
||
|
||
for (i = 0; i < pMarshalledAuditParams->Count; i++)
|
||
{
|
||
inData0 = (PUCHAR) pAuditParams->Parameters[i].Data0;
|
||
|
||
switch (pMarshalledAuditParams->Parameters[i].Type)
|
||
{
|
||
case APT_String:
|
||
{
|
||
if (AUTHZ_NON_NULL_PTR(inData0))
|
||
{
|
||
DWORD StringLength = (DWORD)(sizeof(WCHAR) * wcslen((PWSTR) inData0) + sizeof(WCHAR));
|
||
pMarshalledAuditParams->Parameters[i].Data0 = (ULONG_PTR) Base;
|
||
|
||
RtlCopyMemory(
|
||
(PVOID) Base,
|
||
(PWSTR) inData0,
|
||
StringLength
|
||
);
|
||
|
||
Base += PtrAlignSize( StringLength );
|
||
ASSERT(Base > (PUCHAR)pMarshalledAuditParams);
|
||
ASSERT(Base <= (PUCHAR)((PUCHAR)pMarshalledAuditParams + AuditParamsSize));
|
||
}
|
||
break;
|
||
}
|
||
case APT_Pointer:
|
||
case APT_Ulong:
|
||
case APT_LogonId:
|
||
{
|
||
break;
|
||
}
|
||
case APT_Sid:
|
||
{
|
||
DWORD SidLength = RtlLengthSid((PSID) inData0);
|
||
pMarshalledAuditParams->Parameters[i].Data0 = (ULONG_PTR) Base;
|
||
|
||
RtlCopyMemory(
|
||
(PVOID) Base,
|
||
(PSID) inData0,
|
||
SidLength
|
||
);
|
||
Base += PtrAlignSize( SidLength );
|
||
ASSERT(Base > (PUCHAR)pMarshalledAuditParams);
|
||
ASSERT(Base <= (PUCHAR)((PUCHAR)pMarshalledAuditParams + AuditParamsSize));
|
||
break;
|
||
}
|
||
case APT_ObjectTypeList:
|
||
{
|
||
AUDIT_OBJECT_TYPES *aot = (AUDIT_OBJECT_TYPES *) inData0;
|
||
DWORD OTLength = sizeof(AUDIT_OBJECT_TYPE) * aot->Count;
|
||
|
||
pMarshalledAuditParams->Parameters[i].Data0 = (ULONG_PTR) Base;
|
||
|
||
//
|
||
// Copy the AUDIT_OBJECT_TYPES structure
|
||
//
|
||
|
||
RtlCopyMemory(
|
||
(PVOID) Base,
|
||
aot,
|
||
sizeof(AUDIT_OBJECT_TYPES)
|
||
);
|
||
|
||
Base += PtrAlignSize( sizeof(AUDIT_OBJECT_TYPES) );
|
||
|
||
//
|
||
// Point the pObjectTypes field at the end of the copied blob.
|
||
//
|
||
|
||
((AUDIT_OBJECT_TYPES *)pMarshalledAuditParams->Parameters[i].Data0)->pObjectTypes = (AUDIT_OBJECT_TYPE *) Base;
|
||
|
||
//
|
||
// Copy the AUDIT_OBJECT_TYPE array (pObjectTypes)
|
||
//
|
||
|
||
RtlCopyMemory(
|
||
(PVOID) Base,
|
||
(AUDIT_OBJECT_TYPE *) aot->pObjectTypes,
|
||
OTLength
|
||
);
|
||
|
||
Base += PtrAlignSize( OTLength );
|
||
ASSERT(Base > (PUCHAR)pMarshalledAuditParams);
|
||
ASSERT(Base <= (PUCHAR)((PUCHAR)pMarshalledAuditParams + AuditParamsSize));
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
ASSERT(L"Invalid Authz audit parameter" && FALSE);
|
||
b = FALSE;
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (!b)
|
||
{
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Sanity check on the Base value. If this assertion passes, then I have
|
||
// not exceeded my allocated space.
|
||
//
|
||
|
||
ASSERT(Base == ((PUCHAR)pMarshalledAuditParams + AuditParamsSize));
|
||
|
||
Cleanup:
|
||
|
||
if (b)
|
||
{
|
||
*ppMarshalledAuditParams = pMarshalledAuditParams;
|
||
}
|
||
else
|
||
{
|
||
AuthzpFreeNonNull(pMarshalledAuditParams);
|
||
}
|
||
|
||
return b;
|
||
}
|
||
|
||
|