Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

561 lines
12 KiB

//+-----------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (c) Microsoft Corporation 2000
//
// File: A D T L Q . C
//
// Contents: definitions of types/functions required for
// managing audit queue
//
//
// History:
// 23-May-2000 kumarp created
//
//------------------------------------------------------------------------
#include <lsapch2.h>
#pragma hdrstop
#include "adtp.h"
#include "adtlq.h"
ULONG LsapAdtQueueLength;
LIST_ENTRY LsapAdtLogQueue;
//
// critsec to guard LsapAdtLogQueue and LsapAdtQueueLength
//
RTL_CRITICAL_SECTION LsapAdtQueueLock;
//
// critsec to guard log full policy
//
RTL_CRITICAL_SECTION LsapAdtLogFullLock;
//
// event to wake up LsapAdtAddToQueue
//
HANDLE LsapAdtQueueInsertEvent;
//
// event to wake up LsapAdtDequeueThreadWorker
//
HANDLE LsapAdtQueueRemoveEvent;
//
// thread that writes queue entries to the log
//
HANDLE LsapAdtQueueThread;
NTSTATUS
LsapAdtInitializeLogQueue(
)
/*++
Routine Description:
This function initializes the Audit Log Queue.
Arguments:
None.
Return Values:
NTSTATUS - Standard NT Result Code
Note:
The caller calls LsapAuditFailed()
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
OBJECT_ATTRIBUTES obja;
InitializeObjectAttributes(
&obja,
NULL,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
InitializeListHead(&LsapAdtLogQueue);
LsapAdtQueueLength = 0;
Status = NtCreateEvent(
&LsapAdtQueueInsertEvent,
EVENT_ALL_ACCESS,
&obja,
NotificationEvent,
TRUE
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
Status = NtCreateEvent(
&LsapAdtQueueRemoveEvent,
EVENT_ALL_ACCESS,
&obja,
SynchronizationEvent,
FALSE
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
Status = RtlInitializeCriticalSection(&LsapAdtQueueLock);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
Status = RtlInitializeCriticalSection(&LsapAdtLogFullLock);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
LsapAdtQueueThread = LsapCreateThread(
0,
0,
LsapAdtDequeueThreadWorker,
0,
0,
0
);
if (LsapAdtQueueThread == 0)
{
Status = STATUS_UNSUCCESSFUL;
goto Cleanup;
}
Cleanup:
return Status;
}
NTSTATUS
LsapAdtAddToQueue(
IN PLSAP_ADT_QUEUED_RECORD pAuditRecord
)
/*++
Routine Description:
Insert the specified record in the audit queue
Arguments:
pAuditRecord - record to insert
Return Value:
NTSTATUS - Standard NT Result Code
Notes:
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
BOOLEAN bRetry = FALSE;
LARGE_INTEGER TimeOut;
PLARGE_INTEGER pTimeOut;
static BOOLEAN bEventSet = TRUE;
TimeOut.QuadPart = 10 * 1000 * -10000i64; // 10s
pTimeOut = &TimeOut;
do
{
bRetry = FALSE;
Status = LsapAdtAcquireLogQueueLock();
if (NT_SUCCESS(Status))
{
if (LsapAdtQueueLength < MAX_AUDIT_QUEUE_LENGTH)
{
InsertTailList(&LsapAdtLogQueue, &pAuditRecord->Link);
LsapAdtQueueLength++;
if (LsapAdtQueueLength == 1 || !bEventSet)
{
//
// We only need to set the remove event if
// the queue was empty before.
//
Status = NtSetEvent(LsapAdtQueueRemoveEvent, 0);
if (NT_SUCCESS(Status))
{
bEventSet = TRUE;
}
else
{
DsysAssertMsg(
FALSE,
"LsapAdtAddToQueue: Remove event could not be set");
bEventSet = FALSE;
Status = STATUS_SUCCESS;
}
}
else if (LsapAdtQueueLength == MAX_AUDIT_QUEUE_LENGTH)
{
//
// Reset the insert event since the queue is now full.
//
Status = NtResetEvent(LsapAdtQueueInsertEvent, 0);
DsysAssertMsg(
NT_SUCCESS(Status),
"LsapAdtAddToQueue: Insert event could not be reset and queue is full");
}
}
else
{
bRetry = TRUE;
}
LsapAdtReleaseLogQueueLock();
}
if (bRetry)
{
//
// We could not insert into the queue because it is full.
// There can be two reasons for that:
//
// 1 - Event log is not open yet. We will just
// wait for some time - the log might get opened
// and the insert event get signalled.
//
// 2 - Incoming audit rate is high. We will wait
// until the insert event gets signaled.
//
if (LsapAdtLogHandle == NULL)
{
//
// timeout when EventLog is not yet open
//
pTimeOut = &TimeOut;
}
else
{
//
// infinite timeout
//
pTimeOut = NULL;
}
Status = NtWaitForSingleObject(
LsapAdtQueueInsertEvent,
FALSE, // wait non - alertable
pTimeOut);
//
// STATUS_SUCCESS means the insert event is now signalled, so there should
// be room in the queue for our audit. Just try inserting it again.
//
// STATUS_TIMEOUT means we still cannot write to the log.
// Instead of holding up the caller any longer, just return
// the status.
//
// All other status codes are not expected and lower level failures.
// Return them to the caller.
// We are NOT expecting STATUS_ALERTED or STATUS_USER_APC since our
// wait is non - alertable.
//
if (Status != STATUS_SUCCESS)
{
ASSERT(Status != STATUS_ALERTED && Status != STATUS_USER_APC);
bRetry = FALSE;
}
}
}
while (bRetry);
return Status;
}
NTSTATUS
LsapAdtGetQueueHead(
OUT PLSAP_ADT_QUEUED_RECORD *ppRecord
)
/*++
Routine Description:
Remove and return audit record at the head of the queue
Arguments:
ppRecord - receives a pointer to the record removed
Return Value:
STATUS_SUCCESS on success
STATUS_NOT_FOUND if the queue is empty
Notes:
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PLSAP_ADT_QUEUED_RECORD pRecordAtHead;
static BOOLEAN bEventSet = TRUE;
*ppRecord = NULL;
if (LsapAdtQueueLength > 0)
{
Status = LsapAdtAcquireLogQueueLock();
if (NT_SUCCESS(Status))
{
pRecordAtHead = (PLSAP_ADT_QUEUED_RECORD)RemoveHeadList(
&LsapAdtLogQueue);
DsysAssertMsg(
pRecordAtHead != NULL,
"LsapAdtGetQueueHead: LsapAdtQueueLength > 0 but pRecordAtHead is NULL");
LsapAdtQueueLength--;
if (LsapAdtQueueLength == AUDIT_QUEUE_LOW_WATER_MARK || !bEventSet)
{
//
// Set the insert event so clients can start
// inserting again.
//
Status = NtSetEvent(LsapAdtQueueInsertEvent, 0);
if (NT_SUCCESS(Status))
{
bEventSet = TRUE;
}
else
{
DsysAssertMsg(
LsapAdtQueueLength,
"LsapAdtGetQueueHead: Insert event could not be set and queue is empty");
//
// The event could not be set, so the inserting clients
// are still blocked. Try to set it the next time.
// Also set Status to success since we dequeued an audit.
//
bEventSet = FALSE;
Status = STATUS_SUCCESS;
}
}
*ppRecord = pRecordAtHead;
LsapAdtReleaseLogQueueLock();
}
}
else
{
Status = STATUS_NOT_FOUND;
}
return Status;
}
BOOL
LsapAdtIsValidQueue( )
/*++
Routine Description:
Check if the audit queue looks valid
Arguments:
None
Return Value:
TRUE if queue is valid, FALSE otherwise
Notes:
--*/
{
BOOL fIsValid;
if ( LsapAdtQueueLength > 0 )
{
fIsValid =
(LsapAdtLogQueue.Flink != NULL) &&
(LsapAdtLogQueue.Blink != NULL);
}
else
{
fIsValid =
(LsapAdtLogQueue.Flink == &LsapAdtLogQueue) &&
(LsapAdtLogQueue.Blink == &LsapAdtLogQueue);
}
return fIsValid;
}
NTSTATUS
LsapAdtFlushQueue( )
/*++
Routine Description:
Remove and free each record from the queue
Arguments:
None
Return Value:
NTSTATUS - Standard Nt Result Code
Notes:
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PLSAP_ADT_QUEUED_RECORD pAuditRecord;
//
// Flush out the queue, if there is one.
//
DsysAssertMsg(LsapAdtIsValidQueue(), "LsapAdtFlushQueue");
Status = LsapAdtAcquireLogQueueLock();
if (NT_SUCCESS(Status))
{
do
{
Status = LsapAdtGetQueueHead(&pAuditRecord);
if (NT_SUCCESS(Status))
{
LsapFreeLsaHeap( pAuditRecord );
}
}
while (NT_SUCCESS(Status));
if (Status == STATUS_NOT_FOUND)
{
Status = STATUS_SUCCESS;
}
DsysAssertMsg(LsapAdtQueueLength == 0, "LsapAdtFlushQueue: LsapAuditQueueLength not 0 after queue flush");
LsapAdtReleaseLogQueueLock();
}
return Status;
}
NTSTATUS
LsapAdtAcquireLogQueueLock(
)
/*++
Routine Description:
This function acquires the LSA Audit Log Queue Lock. This lock serializes
all updates to the Audit Log Queue.
Arguments:
None.
Return Value:
NTSTATUS - Standard Nt Result Code
--*/
{
return RtlEnterCriticalSection(&LsapAdtQueueLock);
}
VOID
LsapAdtReleaseLogQueueLock(
VOID
)
/*++
Routine Description:
This function releases the LSA Audit Log Queue Lock. This lock serializes
updates to the Audit Log Queue.
Arguments:
None.
Return Value:
None. Any error occurring within this routine is an internal error.
--*/
{
RtlLeaveCriticalSection(&LsapAdtQueueLock);
}